diff --git a/src/compiler.c b/src/compiler.c index 8610b8c..a5132f4 100644 --- a/src/compiler.c +++ b/src/compiler.c @@ -5,71 +5,51 @@ Code *demo_add_compile() { Code *code = (Code *)malloc(sizeof(Code)); - Word memory[MEMORY_SIZE] = {0}; /* Memory array */ + Value memory[MEMORY_SIZE] = {0}; /* Memory array */ code->memory = memory; code->size = MEMORY_SIZE; + code->current.pc = 1; - int i = 1; + uint32_t i = 1; memory[0].c[0] = 0; memory[0].c[1] = 'z'; memory[0].c[2] = 'r'; memory[0].c[3] = 'e'; - memory[i++].u = OP_ADD_REAL; - memory[i++].u = 102; - memory[i++].u = 103; - memory[i++].u = 103; - memory[i++].u = OP_SUB_UINT; - memory[i++].u = 100; - memory[i++].u = 101; - memory[i++].u = 100; - memory[i++].u = OP_JGT_UINT; - memory[i++].u = 100; - memory[i++].u = 99; - memory[i++].u = 1; - memory[i++].u = OP_REAL_TO_STRING; - memory[i++].u = 103; + memory[i++].u = OP(OP_LOADU, 0, 0, 0); + memory[i++].u = 0; + memory[i++].u = OP(OP_LOADU, 1, 0, 0); + memory[i++].u = 5; + memory[i++].u = OP(OP_LOADU, 2, 0, 0); memory[i++].u = 1; + memory[i++].u = OP(OP_LOADF, 3, 0, 0); + memory[i++].f = 5.0f; + memory[i++].u = OP(OP_LOADF, 4, 0, 0); + memory[i++].f = 5.0f; + memory[i++].u = OP(OP_LOADU, 5, 0, 0); memory[i++].u = 200; - memory[i++].u = OP_PRINT_STRING; - memory[i++].u = 201; - memory[i++].u = 1; - memory[i++].u = 1; - memory[i++].u = OP_REAL_TO_UINT; - memory[i++].u = 103; - memory[i++].u = 1; - memory[i++].u = 103; - memory[i++].u = OP_UINT_TO_STRING; - memory[i++].u = 103; - memory[i++].u = 1; - memory[i++].u = 104; - memory[i++].u = OP_PRINT_STRING; - memory[i++].u = 105; - memory[i++].u = 1; - memory[i++].u = 1; - memory[i++].u = OP_READ_STRING; - memory[i++].u = 1; - memory[i++].u = 1; - memory[i++].u = 109; - memory[i++].u = OP_PRINT_STRING; - memory[i++].u = 110; - memory[i++].u = 1; - memory[i++].u = 1; - memory[i++].u = OP_HALT; - memory[i++].u = 0; - memory[i++].u = 0; - memory[i++].u = 0; - memory[99].u = 0; - memory[100].u = 5; - memory[101].u = 1; - memory[102].f = 5.0f; - memory[103].f = 5.0f; + memory[i++].u = OP(OP_LOADU, 6, 0, 0); + memory[i++].u = 250; + memory[i++].u = OP(OP_LOADU, 7, 0, 0); + memory[i++].u = 252; + uint32_t jmp = i; + memory[i++].u = OP(OP_ADD_REAL, 4, 4, 3); + memory[i++].u = OP(OP_SUB_UINT, 1, 1, 2); + memory[i++].u = OP(OP_JGT_UINT, jmp, 1, 0); + memory[i++].u = OP(OP_REAL_TO_STRING, 5, 4, 0); + memory[i++].u = OP(OP_PRINT_STRING, 0, 5, 0); + memory[i++].u = OP(OP_REAL_TO_UINT, 1, 4, 4); + memory[i++].u = OP(OP_UINT_TO_STRING, 6, 1, 0); + memory[i++].u = OP(OP_PRINT_STRING, 0, 6, 0); + memory[i++].u = OP(OP_READ_STRING, 7, 0, 0); + memory[i++].u = OP(OP_PRINT_STRING, 0, 7, 0); + memory[i++].u = OP(OP_HALT, 0, 0, 0); return code; } Code *compile(char *buffer) { Code *code = (Code *)malloc(sizeof(Code)); - Word memory[MEMORY_SIZE] = {0}; /* Memory array */ + Value memory[MEMORY_SIZE] = {0}; /* Memory array */ code->memory = memory; code->size = MEMORY_SIZE; diff --git a/src/compiler.h b/src/compiler.h index 68e36a4..967c2fb 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -5,7 +5,8 @@ typedef struct Code Code; struct Code { - Word *memory; + Value *memory; + VMFrame current; uint32_t size; }; diff --git a/src/debug.c b/src/debug.c index 0c6010c..43d3008 100644 --- a/src/debug.c +++ b/src/debug.c @@ -1,6 +1,6 @@ #include "debug.h" -int core_dump(Word *memory, uint32_t memory_size) { +int core_dump(Value *memory, uint32_t memory_size) { FILE *file = fopen("memory_dump.bin", "wb"); if (!file) { perror("Failed to open file"); diff --git a/src/debug.h b/src/debug.h index d33a20c..aa4290e 100644 --- a/src/debug.h +++ b/src/debug.h @@ -3,6 +3,6 @@ #include "vm.h" -int core_dump(Word *memory, uint32_t memory_size); +int core_dump(Value *memory, uint32_t memory_size); #endif diff --git a/src/hashmap.h b/src/hashmap.h index 66248ac..543b338 100644 --- a/src/hashmap.h +++ b/src/hashmap.h @@ -21,7 +21,7 @@ unsigned int hash_##StructType(char *s) { \ return hashval % HASHSIZE; \ } \ \ -StructType *lookup_##StructType(StructType **map, char *s) { \ +StructType *get_##StructType(StructType **map, char *s) { \ StructType *np; \ for (np = map[hash_##StructType(s)]; np != NULL; np = np->next) \ if (strcmp(s, np->keyword) == 0) \ @@ -32,7 +32,7 @@ StructType *lookup_##StructType(StructType **map, char *s) { \ StructType *put_##StructType(StructType **map, char *keyword, TokenType token) { \ StructType *np; \ unsigned int hashval; \ - if ((np = lookup_##StructType(map, keyword)) == NULL) { \ + if ((np = get_##StructType(map, keyword)) == NULL) { \ np = (StructType *)malloc(sizeof(*np)); \ if (np == NULL || (np->keyword = strdup(keyword)) == NULL) \ return NULL; \ diff --git a/src/main.c b/src/main.c index 97af7e5..4360675 100644 --- a/src/main.c +++ b/src/main.c @@ -21,7 +21,7 @@ uint32_t pc = 1; /* Program counter */ Code *code; void mainloop() { - pc = step_vm(code->memory, code->size, pc); + pc = step_vm(&code->current, code->memory); if (pc == 0) { #ifdef __EMSCRIPTEN__ emscripten_cancel_main_loop(); /* this should "kill" the app. */ diff --git a/src/opcodes.h b/src/opcodes.h index 84962c7..e56206c 100644 --- a/src/opcodes.h +++ b/src/opcodes.h @@ -6,12 +6,25 @@ typedef union { int32_t i; /* Integers */ float f; /* Float */ - uint32_t u; /* Unsigned integers */ + uint32_t u; /* Unsigned integers, also used for pointer address */ char c[4]; /* 4 Byte char array for string packing */ -} Word; +} Value; + +#define MAX_REGS 255 + +typedef struct { + Value registers[MAX_REGS]; /* R0-R255 */ + uint32_t pc; /* Program counter */ +} VMFrame; typedef enum { OP_HALT, /* terminate execution */ + OP_LOADI, /* loads an int from memory */ + OP_LOADU, /* loads a uint from memory */ + OP_LOADF, /* loads a float from memory */ + OP_STOREI, /* stores a int to memory */ + OP_STOREU, /* stores a uint to memory */ + OP_STOREF, /* stores a float to memory */ OP_ADD_INT, /* dest = src1 + src2 */ OP_SUB_INT, /* dest = src1 - src2 */ OP_MUL_INT, /* dest = src1 * src2 */ @@ -53,4 +66,7 @@ typedef enum { OP_CMP_STRING, /* dest = (str == src2) as bool */ } Opcode; +/* defines a uint32 opcode */ +#define OP(opcode, a, b, c) ((opcode << 24) | (a << 16) | (b << 8) | c) + #endif diff --git a/src/parser.c b/src/parser.c index da1eea6..217baf5 100644 --- a/src/parser.c +++ b/src/parser.c @@ -50,14 +50,6 @@ void initTokenMap() { put_TokenMap(tokenMap, "sll", TOKEN_SHIFTLEFT); } -TokenType get_Token(char *s) { - TokenMap *np; - for (np = tokenMap[hash_TokenMap(s)]; np != NULL; np = np->next) - if (strcmp(s, np->keyword) == 0) - return np->token; - return TOKEN_IDENTIFIER; -} - typedef struct Tokenizer Tokenizer; struct Tokenizer { char *start; @@ -144,9 +136,17 @@ static char *currentTokenToS() { return str; } +TokenType getToken(char *s) { + TokenMap *np; + for (np = tokenMap[hash_TokenMap(s)]; np != NULL; np = np->next) + if (strcmp(s, np->keyword) == 0) + return np->token; + return TOKEN_IDENTIFIER; +} + static TokenType identifierType() { char *check = currentTokenToS(); - TokenType t = get_Token(check); + TokenType t = getToken(check); free(check); return t; } diff --git a/src/vm.c b/src/vm.c index 49713da..4bbf238 100644 --- a/src/vm.c +++ b/src/vm.c @@ -2,52 +2,67 @@ #define COMPARE_AND_JUMP(type, accessor, op) \ do { \ - type value = memory[src1_addr].accessor; \ - type value2 = memory[src2_addr].accessor; \ - uint32_t jump_target = dest_addr; \ - pc = (value op value2) ? jump_target : pc; \ - return pc; \ + type value = frame->registers[src1].accessor; \ + type value2 = frame->registers[src2].accessor; \ + frame->pc = (value op value2) ? dest : frame->pc; \ + return frame->pc; \ } while (0) #define MATH_OP(accessor, op) \ do { \ - memory[dest_addr].accessor = \ - memory[src1_addr].accessor op memory[src2_addr].accessor; \ - return pc; \ + frame->registers[dest].accessor = \ + frame->registers[src1].accessor op frame->registers[src2].accessor; \ + return frame->pc; \ } while (0) /** * String copy in data memory. */ -void mem_strcpy(Word *memory, const char *str, uint32_t length, - uint32_t dest_addr) { - memory[dest_addr].u = length; - uint32_t buffer_addr = dest_addr + 1; +void mem_strcpy(Value *memory, const char *str, uint32_t length, + uint32_t dest) { + memory[dest].u = length; + uint32_t buffer = dest + 1; uint32_t i; for (i = 0; i < length; i++) { - memory[buffer_addr + (i / 4)].c[i % 4] = str[i]; + memory[buffer + (i / 4)].c[i % 4] = str[i]; } } /** * Step to the next opcode in the vm. */ -uint32_t step_vm(Word *memory, uint32_t memory_size, uint32_t pc) { - Opcode opcode = memory[pc].u; - uint32_t src1_addr = memory[pc + 1].u; - uint32_t src2_addr = memory[pc + 2].u; - uint32_t dest_addr = memory[pc + 3].u; - pc += 4; /* Advance to next instruction */ +uint32_t step_vm(VMFrame *frame, Value *memory) { + uint32_t instruction = memory[frame->pc].u; - if (src1_addr >= memory_size || src2_addr >= memory_size || - dest_addr >= memory_size) { - printf("Invalid memory address!\n"); - return 0; - } + /* Extract 8-bit register indices from 32-bit instruction */ + uint8_t opcode = (instruction >> 24) & 0xFF; + uint8_t dest = (instruction >> 16) & 0xFF; + uint8_t src1 = (instruction >> 8) & 0xFF; + uint8_t src2 = instruction & 0xFF; + /* Advance to next instruction */ + frame->pc++; switch (opcode) { case OP_HALT: return 0; + case OP_LOADI: + frame->registers[dest].i = memory[frame->pc++].i; + return frame->pc; + case OP_LOADU: + frame->registers[dest].u = memory[frame->pc++].u; + return frame->pc; + case OP_LOADF: + frame->registers[dest].f = memory[frame->pc++].f; + return frame->pc; + case OP_STOREI: + memory[frame->pc++].i = frame->registers[src1].i; + return frame->pc; + case OP_STOREU: + memory[frame->pc++].u = frame->registers[src1].u; + return frame->pc; + case OP_STOREF: + memory[frame->pc++].f = frame->registers[src1].f; + return frame->pc; case OP_ADD_INT: MATH_OP(i, +); case OP_SUB_INT: @@ -73,27 +88,23 @@ uint32_t step_vm(Word *memory, uint32_t memory_size, uint32_t pc) { case OP_DIV_REAL: MATH_OP(f, /); case OP_REAL_TO_INT: - memory[dest_addr].i = (int32_t)(memory[src1_addr].f); - return pc; - + frame->registers[dest].i = (int32_t)(frame->registers[src1].f); + return frame->pc; case OP_INT_TO_REAL: - memory[dest_addr].f = (float)(memory[src1_addr].i); - return pc; - + frame->registers[dest].f = (float)(frame->registers[src1].i); + return frame->pc; case OP_REAL_TO_UINT: - memory[dest_addr].u = (uint32_t)(memory[src1_addr].f); - return pc; - + frame->registers[dest].u = (uint32_t)(frame->registers[src1].f); + return frame->pc; case OP_UINT_TO_REAL: - memory[dest_addr].f = (float)(memory[src1_addr].u); - return pc; - + frame->registers[dest].f = (float)(frame->registers[src1].u); + return frame->pc; case OP_MOV: - memory[dest_addr] = memory[src1_addr]; - return pc; + frame->registers[dest] = frame->registers[src1]; + return frame->pc; case OP_JMP: - pc = src1_addr; /* Jump to address */ - return pc; + frame->pc = frame->registers[src1].u; /* Jump to address */ + return frame->pc; case OP_JEQ_UINT: { COMPARE_AND_JUMP(uint32_t, u, ==); } @@ -140,59 +151,64 @@ uint32_t step_vm(Word *memory, uint32_t memory_size, uint32_t pc) { COMPARE_AND_JUMP(int32_t, u, <=); } case OP_INT_TO_STRING: { - int32_t a = (int32_t)memory[src1_addr].i; + int32_t a = (int32_t)frame->registers[src1].i; + uint32_t str_dest = (uint32_t)frame->registers[dest].u; char buffer[32]; int len = sprintf(buffer, "%d", a); - mem_strcpy(memory, buffer, len, dest_addr); - return pc; + mem_strcpy(memory, buffer, len, str_dest); + return frame->pc; } case OP_UINT_TO_STRING: { - uint32_t a = (uint32_t)memory[src1_addr].u; + uint32_t a = (uint32_t)frame->registers[src1].u; + uint32_t str_dest = (uint32_t)frame->registers[dest].u; char buffer[32]; int len = sprintf(buffer, "%d", a); - mem_strcpy(memory, buffer, len, dest_addr); - return pc; + mem_strcpy(memory, buffer, len, str_dest); + return frame->pc; } case OP_REAL_TO_STRING: { - float a = (float)memory[src1_addr].f; + float a = (float)frame->registers[src1].f; + uint32_t str_dest = (uint32_t)frame->registers[dest].u; char buffer[32]; int len = sprintf(buffer, "%f", a); - mem_strcpy(memory, buffer, len, dest_addr); - return pc; + mem_strcpy(memory, buffer, len, str_dest); + return frame->pc; } case OP_READ_STRING: { - uint32_t buffer_addr = dest_addr + 1; + uint32_t str_dest = (uint32_t)frame->registers[dest].u; + uint32_t buffer = str_dest + 1; uint32_t length = 0; while (1) { int ch = getchar(); if (ch == '\n' || ch == EOF) { - memory[buffer_addr + (length / 4)].c[length % 4] = '\0'; + memory[buffer + (length / 4)].c[length % 4] = '\0'; break; } - memory[buffer_addr + (length / 4)].c[length % 4] = ch; + memory[buffer + (length / 4)].c[length % 4] = ch; length++; } - memory[dest_addr].u = length; - return pc; + memory[str_dest].u = length; + return frame->pc; } case OP_PRINT_STRING: { - uint32_t string_addr = src1_addr; - uint32_t length = memory[src1_addr - 1].u; + uint32_t ptr = (uint32_t)frame->registers[src1].u; + uint32_t length = memory[ptr].u; + uint32_t str_src = ptr + 1; uint32_t i; for (i = 0; i < length; i++) { - uint8_t ch = memory[string_addr + (i / 4)].c[i % 4]; + uint8_t ch = memory[str_src + (i / 4)].c[i % 4]; if (ch == '\0') break; putchar(ch); } putchar('\n'); - return pc; + return frame->pc; } case OP_CMP_STRING: { - uint32_t addr1 = src1_addr; - uint32_t addr2 = src2_addr; - uint32_t length1 = memory[src1_addr - 1].u; - uint32_t length2 = memory[src2_addr - 1].u; + uint32_t addr1 = (uint32_t)frame->registers[src1].u; + uint32_t addr2 = (uint32_t)frame->registers[src2].u; + uint32_t length1 = memory[addr1 - 1].u; + uint32_t length2 = memory[addr2 - 1].u; uint32_t equal = 1; if (length1 != length2) { @@ -207,11 +223,11 @@ uint32_t step_vm(Word *memory, uint32_t memory_size, uint32_t pc) { break; } if ((char1 & 0xFF) == '\0' && (char2 & 0xFF) == '\0') - return pc; + return frame->pc; } } - memory[dest_addr].u = equal; - return pc; + memory[dest].u = equal; + return frame->pc; } } return 0; diff --git a/src/vm.h b/src/vm.h index 6ad51f8..6f39c62 100644 --- a/src/vm.h +++ b/src/vm.h @@ -3,6 +3,6 @@ #include "opcodes.h" -uint32_t step_vm(Word *memory, uint32_t memory_size, uint32_t pc); +uint32_t step_vm(VMFrame *frame, Value *memory); #endif