Started rethinking how this machine should behave. Updated and refactoring some things with a few new ideas.
This commit is contained in:
+8
-2
@@ -71,7 +71,7 @@
|
|||||||
For the opcodes that load or store data at the assembly language level we could have the mnemonics
|
For the opcodes that load or store data at the assembly language level we could have the mnemonics
|
||||||
"store" and "load" and have the assembler pick the opcode based on the inclusion of the word "byte"
|
"store" and "load" and have the assembler pick the opcode based on the inclusion of the word "byte"
|
||||||
or "word" for two bytes. That would make the assembly easier to read but put a bit more work on the
|
or "word" for two bytes. That would make the assembly easier to read but put a bit more work on the
|
||||||
assembler.
|
assembler. The Stack Pointer will start 2 bytes above the video memory start.
|
||||||
\section{STOB (Store Byte)}
|
\section{STOB (Store Byte)}
|
||||||
\OpcodeTable{0x20}{stob}{Register}{Address}\\[6pt]
|
\OpcodeTable{0x20}{stob}{Register}{Address}\\[6pt]
|
||||||
Stores a single byte (the lower nibble) from a register to a memory address.
|
Stores a single byte (the lower nibble) from a register to a memory address.
|
||||||
@@ -104,7 +104,7 @@
|
|||||||
Performs subtraction on a register with a value from another (or the same) register.
|
Performs subtraction on a register with a value from another (or the same) register.
|
||||||
\section{JMP (Jump)}
|
\section{JMP (Jump)}
|
||||||
\OpcodeTable{0x20}{jmp}{Address}{None}\\[6pt]
|
\OpcodeTable{0x20}{jmp}{Address}{None}\\[6pt]
|
||||||
Jumps unconditionally to a memory address.
|
Jumps unconditionally to a memory address. Sets the Program Counter to Address.
|
||||||
\section{JZ (Jump if Zero)}
|
\section{JZ (Jump if Zero)}
|
||||||
\OpcodeTable{0x20}{jz}{Register}{None}\\[6pt]
|
\OpcodeTable{0x20}{jz}{Register}{None}\\[6pt]
|
||||||
Jumps to a memory address if the status flag is zero.
|
Jumps to a memory address if the status flag is zero.
|
||||||
@@ -141,4 +141,10 @@
|
|||||||
\section{NOP (No Operation)}
|
\section{NOP (No Operation)}
|
||||||
\OpcodeTable{0x00}{nop}{None}{None}\\[6pt]
|
\OpcodeTable{0x00}{nop}{None}{None}\\[6pt]
|
||||||
Skips a clock cycle, incrementing the program counter.
|
Skips a clock cycle, incrementing the program counter.
|
||||||
|
\section{Push}
|
||||||
|
\OpcodeTable{0x00}{push}{Register}{None}
|
||||||
|
Pushes the value of Register onto the stack, decrementing the Stack Pointer by 2.
|
||||||
|
\section{Pop}
|
||||||
|
\OpcodeTable{0x00}{pop}{Register}{None}
|
||||||
|
Pops the top of the stack into Register, incrementing the Stack Pointer by 2.
|
||||||
\end{document}
|
\end{document}
|
||||||
|
|||||||
+1
-1
@@ -13,7 +13,7 @@ typedef enum {
|
|||||||
typedef enum {
|
typedef enum {
|
||||||
ADD, SUB, JZ, INT, YLD, RET,
|
ADD, SUB, JZ, INT, YLD, RET,
|
||||||
CMP, CMPI, NOP, JMP, CALL, LODW, LAA, LODWI, JE, INC, DEC, LOADB,
|
CMP, CMPI, NOP, JMP, CALL, LODW, LAA, LODWI, JE, INC, DEC, LOADB,
|
||||||
STOB, STOW, JG, JL, AND, XOR, OR, NOT, SHR, SHL
|
STOB, STOW, JG, JL, AND, XOR, OR, NOT, SHR, SHL, POP, PUSH
|
||||||
} Mnemonic;
|
} Mnemonic;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
|||||||
+1
-1
@@ -23,7 +23,7 @@ typedef enum {
|
|||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
DB,
|
DB,
|
||||||
Origin,
|
Include,
|
||||||
Byte
|
Byte
|
||||||
} Directive;
|
} Directive;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
some_stub:
|
||||||
|
pop r8
|
||||||
|
jmp [r8] ;return to the calling code.
|
||||||
+6
-2
@@ -1,9 +1,11 @@
|
|||||||
|
.include "/another_test.asm"
|
||||||
|
|
||||||
.db video_start 0xF37F
|
.db video_start 0xF37F
|
||||||
.db msg "Hello, world!", 0
|
.db msg "Hello, world!", 0
|
||||||
.db NOTERM "No terminating byte here"
|
.db NOTERM "No terminating byte here"
|
||||||
.db null_byte 0
|
.db null_byte 0
|
||||||
|
|
||||||
load r1, [msg] ; Because the lod* instructions can't load an address
|
load r1, msg ; Because the lod* instructions can't load an address
|
||||||
; from anything but a register, this becomes laa r1, [msg]
|
; from anything but a register, this becomes laa r1, [msg]
|
||||||
|
|
||||||
;Routine: string_length
|
;Routine: string_length
|
||||||
@@ -26,4 +28,6 @@ start:
|
|||||||
jmp start
|
jmp start
|
||||||
|
|
||||||
end:
|
end:
|
||||||
ret
|
|
||||||
|
pop r8 ;pop the return address from the stack into register 8
|
||||||
|
jmp [r8] ;jump to that address
|
||||||
|
|||||||
+43
-180
@@ -4,14 +4,9 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sysexits.h>
|
#include <sysexits.h>
|
||||||
#include "../includes/list.h"
|
#include "../includes/list.h"
|
||||||
#include "../includes/parser.h"
|
|
||||||
#include "../includes/futil.h"
|
#include "../includes/futil.h"
|
||||||
#include "../includes/scanner.h"
|
#include "../includes/scanner.h"
|
||||||
|
|
||||||
unsigned char Memory[2000];
|
|
||||||
|
|
||||||
void Setup(IRState*);
|
|
||||||
|
|
||||||
int main(int argc, char* args[]) {
|
int main(int argc, char* args[]) {
|
||||||
if (argc == 1) {
|
if (argc == 1) {
|
||||||
printf("Usage: assm <file1.asm>\n");
|
printf("Usage: assm <file1.asm>\n");
|
||||||
@@ -24,197 +19,65 @@ int main(int argc, char* args[]) {
|
|||||||
if (!ReadAllString(args[1], &source_code, &bytes_read)) return EX_IOERR;
|
if (!ReadAllString(args[1], &source_code, &bytes_read)) return EX_IOERR;
|
||||||
|
|
||||||
List* list = GenerateTokenList(source_code);
|
List* list = GenerateTokenList(source_code);
|
||||||
// char mnemonic[12];
|
char mnemonic[12];
|
||||||
|
|
||||||
// for(int i = 0; i < list->size; i++) {
|
for(int i = 0; i < list->size; i++) {
|
||||||
// Token* t = (Token*) list->content[i];
|
Token* t = (Token*) list->content[i];
|
||||||
|
|
||||||
// if (t->EndOfFile) {
|
if (t->EndOfFile) {
|
||||||
// printf("EOF\n");
|
printf("EOF\n");
|
||||||
// break;
|
break;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// if (t->Class == PunctuationClass){
|
if (t->Class == PunctuationClass){
|
||||||
// if(t->Value.Punctuation == NewLine) {
|
if(t->Value.Punctuation == NewLine) {
|
||||||
// printf("\n");
|
printf("\n");
|
||||||
// continue;
|
continue;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// printf("<%d>", t->LineNumber);
|
printf("<%d>", t->LineNumber);
|
||||||
|
|
||||||
// printf("%c ", t->Value.Punctuation);
|
printf("%c ", t->Value.Punctuation);
|
||||||
// continue;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// printf("<%d>", t->LineNumber);
|
|
||||||
|
|
||||||
// if (t->Class == LabelClass) {
|
|
||||||
// printf("[L]%s* ", t->Lemexe);
|
|
||||||
// continue;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (t->Class == IdentifierClass) {
|
|
||||||
// printf("[I]%s ", t->Lemexe);
|
|
||||||
// continue;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (t->Class == RegisterClass) {
|
|
||||||
// printf("[R]%d", t->Value.Register);
|
|
||||||
// continue;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (t->Class == NumberClass) {
|
|
||||||
// printf("[N]%d ", t->Value.Number);
|
|
||||||
// continue;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (t->Class == MnemonicClass) {
|
|
||||||
// GetMnemonicText(t->Value.Mnemonic, mnemonic);
|
|
||||||
// printf("[M]%s ", mnemonic);
|
|
||||||
// continue;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (t->Class == DirectiveClass) {
|
|
||||||
// printf("[D]%d ", t->Value.Directive);
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (t->Class == CharacterClass) {
|
|
||||||
// printf("%s ", t->Lemexe);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
IRState* image = ParseTokens(list);
|
|
||||||
char instruction[12];
|
|
||||||
char reg[3];
|
|
||||||
|
|
||||||
for(int i = 0; i < image->Instructions->size; i++) {
|
|
||||||
Instruction* ins = image->Instructions->content[i];
|
|
||||||
|
|
||||||
GetMnemonicText(ins->Mnemonic, instruction);
|
|
||||||
|
|
||||||
printf("%s ", instruction);
|
|
||||||
|
|
||||||
if (!ins->ParameterOne) {
|
|
||||||
printf("\n");
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(ins->ParameterOne->ParameterType) {
|
printf("<%d>", t->LineNumber);
|
||||||
case RegisterParameter:
|
|
||||||
GetRegisterText(ins->ParameterOne->Value.Register, reg);
|
|
||||||
|
|
||||||
if (ins->ParameterOne->InterpretedAs == AddressParameter) printf("[%s]", reg);
|
if (t->Class == LabelClass) {
|
||||||
else printf("%s", reg);
|
printf("[L]%s* ", t->Lemexe);
|
||||||
break;
|
|
||||||
case ConstantParameter:
|
|
||||||
if (ins->ParameterOne->InterpretedAs == AddressParameter) printf("[%d]", ins->ParameterOne->Value.Number);
|
|
||||||
else printf("%d", ins->ParameterOne->Value.Number);
|
|
||||||
break;
|
|
||||||
case AddressParameter:
|
|
||||||
if (ins->ParameterOne->InterpretedAs == AddressParameter) printf("[%s]", ins->ParameterOne->Value.Symbol);
|
|
||||||
else {
|
|
||||||
Symbol* s = TryGetSymbol(ins->ParameterOne->Value.Symbol, image->SymbolsTable);
|
|
||||||
|
|
||||||
switch(s->Type) {
|
|
||||||
case NumericSymbol:
|
|
||||||
printf("%s {%d}", s->Name, s->Value.Number);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
printf("%s", ins->ParameterOne->Value.Symbol);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
printf("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ins->ParameterTwo) {
|
|
||||||
printf("\n");
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(ins->ParameterTwo->ParameterType) {
|
if (t->Class == IdentifierClass) {
|
||||||
case RegisterParameter:
|
printf("[I]%s ", t->Lemexe);
|
||||||
GetRegisterText(ins->ParameterTwo->Value.Register, reg);
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (ins->ParameterTwo->InterpretedAs == AddressParameter) printf(", [%s]\n", reg);
|
if (t->Class == RegisterClass) {
|
||||||
else printf(", %s\n", reg);
|
printf("[R]%d", t->Value.Register);
|
||||||
break;
|
continue;
|
||||||
case ConstantParameter:
|
}
|
||||||
if (ins->ParameterTwo->InterpretedAs == AddressParameter) printf(", [%d]\n", ins->ParameterTwo->Value.Number);
|
|
||||||
else printf(", %d\n", ins->ParameterTwo->Value.Number);
|
|
||||||
break;
|
|
||||||
case AddressParameter:
|
|
||||||
if (ins->ParameterTwo->InterpretedAs == AddressParameter) printf(", [%s]\n", ins->ParameterTwo->Value.Symbol);
|
|
||||||
else {
|
|
||||||
Symbol* s = TryGetSymbol(ins->ParameterTwo->Value.Symbol, image->SymbolsTable);
|
|
||||||
|
|
||||||
switch(s->Type) {
|
if (t->Class == NumberClass) {
|
||||||
case NumericSymbol:
|
printf("[N]%d ", t->Value.Number);
|
||||||
printf(", %s {%d}\n", s->Name, s->Value.Number);
|
continue;
|
||||||
break;
|
}
|
||||||
default:
|
|
||||||
printf(", %s\n", ins->ParameterTwo->Value.Symbol);
|
if (t->Class == MnemonicClass) {
|
||||||
}
|
GetMnemonicText(t->Value.Mnemonic, mnemonic);
|
||||||
}
|
printf("[M]%s ", mnemonic);
|
||||||
break;
|
continue;
|
||||||
default:
|
}
|
||||||
printf("\n");
|
|
||||||
|
if (t->Class == DirectiveClass) {
|
||||||
|
printf("[D]%d ", t->Value.Directive);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t->Class == CharacterClass) {
|
||||||
|
printf("%s ", t->Lemexe);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Setup(image);
|
|
||||||
//free(image);
|
|
||||||
//Disassemble(image);
|
|
||||||
//for(int i = 0; i < image->Opcodes->size; i++) {
|
|
||||||
// printf("%d\n", ((IROpcode*) image->Opcodes->content[i])->Mnemonic);
|
|
||||||
//}
|
|
||||||
|
|
||||||
//FILE* program = fopen("program.bin", "w+b");
|
|
||||||
|
|
||||||
//fwrite(image, 1, image[2] + image[3], program);
|
|
||||||
|
|
||||||
//fclose(program);
|
|
||||||
|
|
||||||
free(source_code);
|
free(source_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Setup(IRState* state) {
|
|
||||||
int start = 4;
|
|
||||||
int end = start;
|
|
||||||
|
|
||||||
for(int i = 0; i < state->SymbolsTable->Size; i++) {
|
|
||||||
Symbol* symbol = state->SymbolsTable->Symbols[i];
|
|
||||||
|
|
||||||
switch(symbol->Type) {
|
|
||||||
case StringSymbol:
|
|
||||||
memccpy(&Memory[end], symbol->Value.String->String, 0, strlen(symbol->Value.String->String));
|
|
||||||
|
|
||||||
end += strlen(symbol->Value.String->String);
|
|
||||||
|
|
||||||
if (symbol->Value.String->Terminated) {
|
|
||||||
Memory[end] = symbol->Value.String->TerminatingByte;
|
|
||||||
end++;
|
|
||||||
}
|
|
||||||
|
|
||||||
//end++;
|
|
||||||
break;
|
|
||||||
case NumericSymbol:
|
|
||||||
Memory[end] = symbol->Value.Number >> 8 & 0xFF;
|
|
||||||
Memory[end + 1] = symbol->Value.Number & 0xFF;
|
|
||||||
end += 2;
|
|
||||||
break;
|
|
||||||
case InstructionPointerSymbol:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for(int i = 0; i < end; i++) {
|
|
||||||
if (i != 0 && i % 8 == 0) printf("\n");
|
|
||||||
printf("%02x ", Memory[i]);
|
|
||||||
}
|
|
||||||
printf("\n");
|
|
||||||
}
|
|
||||||
+3
-3
@@ -15,9 +15,7 @@ struct _instruction instructions[OPCODECOUNT] = {
|
|||||||
{ "add", ADD, RegisterParameter, RegisterParameter },
|
{ "add", ADD, RegisterParameter, RegisterParameter },
|
||||||
{ "sub", SUB, RegisterParameter, RegisterParameter },//, Reg, Reg | Constant },
|
{ "sub", SUB, RegisterParameter, RegisterParameter },//, Reg, Reg | Constant },
|
||||||
{ "jz", JZ, AddressParameter, NoParameter },//, Address, None },
|
{ "jz", JZ, AddressParameter, NoParameter },//, Address, None },
|
||||||
{ "int", INT, ConstantParameter, NoParameter },//, Constant, None },
|
|
||||||
{ "yld", YLD, NoParameter, NoParameter },//, None, None },
|
{ "yld", YLD, NoParameter, NoParameter },//, None, None },
|
||||||
{ "ret", RET, NoParameter, NoParameter },//, None, None },
|
|
||||||
{ "cmp", CMP, RegisterParameter, RegisterParameter },//, Reg, Reg | Constant },
|
{ "cmp", CMP, RegisterParameter, RegisterParameter },//, Reg, Reg | Constant },
|
||||||
{ "cmpi", CMPI, RegisterParameter, ConstantParameter },
|
{ "cmpi", CMPI, RegisterParameter, ConstantParameter },
|
||||||
{ "inc", INC, RegisterParameter, NoParameter },//, Constant | Reg, None},
|
{ "inc", INC, RegisterParameter, NoParameter },//, Constant | Reg, None},
|
||||||
@@ -41,7 +39,9 @@ struct _instruction instructions[OPCODECOUNT] = {
|
|||||||
{ "not", NOT, RegisterParameter, NoParameter },
|
{ "not", NOT, RegisterParameter, NoParameter },
|
||||||
{ "shr", SHR, RegisterParameter, ConstantParameter },
|
{ "shr", SHR, RegisterParameter, ConstantParameter },
|
||||||
{ "shl", SHL, RegisterParameter, ConstantParameter },
|
{ "shl", SHL, RegisterParameter, ConstantParameter },
|
||||||
{ "nop", NOP, NoParameter, NoParameter }
|
{ "nop", NOP, NoParameter, NoParameter },
|
||||||
|
{ "pop", POP, RegisterParameter, NoParameter },
|
||||||
|
{ "push", PUSH, RegisterParameter, NoParameter }
|
||||||
};
|
};
|
||||||
|
|
||||||
void ExpectParameters(Mnemonic mnemonic, OpcodeParameter* paramOne, OpcodeParameter* paramTwo) {
|
void ExpectParameters(Mnemonic mnemonic, OpcodeParameter* paramOne, OpcodeParameter* paramTwo) {
|
||||||
|
|||||||
+6
-7
@@ -67,7 +67,7 @@ List* GenerateTokenList(const char* source) {
|
|||||||
Line++;
|
Line++;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case '.': //directive like ".org" or ".db"
|
case '.': //directive like ".include" or ".db"
|
||||||
token = ParseDirective();
|
token = ParseDirective();
|
||||||
if (token) AddListItem(token, tokens);
|
if (token) AddListItem(token, tokens);
|
||||||
break;
|
break;
|
||||||
@@ -191,17 +191,16 @@ Token* ParseDirective(void) {
|
|||||||
|
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
else if (strcmp(directive, ".org") == 0) {
|
else if (strcmp(directive, ".include") == 0) {
|
||||||
fprintf(stderr, "[Warning] Org is not a supported directive.\n");
|
token->Value.Directive = Include;
|
||||||
free(directive);
|
|
||||||
free(token);
|
return token;
|
||||||
IgnoreLine();
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(stderr, "[Error] Unknown assembler directive '%s'\n", directive);
|
fprintf(stderr, "[Error] Unknown assembler directive '%s'\n", directive);
|
||||||
|
|
||||||
free(directive);
|
free(directive);
|
||||||
|
free(token);
|
||||||
|
|
||||||
IgnoreLine();
|
IgnoreLine();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user