convert to register based instead of mem2mem

This commit is contained in:
zongor 2025-06-21 23:20:29 -04:00
parent 16117b9a3a
commit d27d4259aa
10 changed files with 146 additions and 133 deletions

View File

@ -5,71 +5,51 @@
Code *demo_add_compile() { Code *demo_add_compile() {
Code *code = (Code *)malloc(sizeof(Code)); Code *code = (Code *)malloc(sizeof(Code));
Word memory[MEMORY_SIZE] = {0}; /* Memory array */ Value memory[MEMORY_SIZE] = {0}; /* Memory array */
code->memory = memory; code->memory = memory;
code->size = MEMORY_SIZE; code->size = MEMORY_SIZE;
code->current.pc = 1;
int i = 1; uint32_t i = 1;
memory[0].c[0] = 0; memory[0].c[0] = 0;
memory[0].c[1] = 'z'; memory[0].c[1] = 'z';
memory[0].c[2] = 'r'; memory[0].c[2] = 'r';
memory[0].c[3] = 'e'; memory[0].c[3] = 'e';
memory[i++].u = OP_ADD_REAL; memory[i++].u = OP(OP_LOADU, 0, 0, 0);
memory[i++].u = 102; memory[i++].u = 0;
memory[i++].u = 103; memory[i++].u = OP(OP_LOADU, 1, 0, 0);
memory[i++].u = 103; memory[i++].u = 5;
memory[i++].u = OP_SUB_UINT; memory[i++].u = OP(OP_LOADU, 2, 0, 0);
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 = 1; 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 = 200;
memory[i++].u = OP_PRINT_STRING; memory[i++].u = OP(OP_LOADU, 6, 0, 0);
memory[i++].u = 201; memory[i++].u = 250;
memory[i++].u = 1; memory[i++].u = OP(OP_LOADU, 7, 0, 0);
memory[i++].u = 1; memory[i++].u = 252;
memory[i++].u = OP_REAL_TO_UINT; uint32_t jmp = i;
memory[i++].u = 103; memory[i++].u = OP(OP_ADD_REAL, 4, 4, 3);
memory[i++].u = 1; memory[i++].u = OP(OP_SUB_UINT, 1, 1, 2);
memory[i++].u = 103; memory[i++].u = OP(OP_JGT_UINT, jmp, 1, 0);
memory[i++].u = OP_UINT_TO_STRING; memory[i++].u = OP(OP_REAL_TO_STRING, 5, 4, 0);
memory[i++].u = 103; memory[i++].u = OP(OP_PRINT_STRING, 0, 5, 0);
memory[i++].u = 1; memory[i++].u = OP(OP_REAL_TO_UINT, 1, 4, 4);
memory[i++].u = 104; memory[i++].u = OP(OP_UINT_TO_STRING, 6, 1, 0);
memory[i++].u = OP_PRINT_STRING; memory[i++].u = OP(OP_PRINT_STRING, 0, 6, 0);
memory[i++].u = 105; memory[i++].u = OP(OP_READ_STRING, 7, 0, 0);
memory[i++].u = 1; memory[i++].u = OP(OP_PRINT_STRING, 0, 7, 0);
memory[i++].u = 1; memory[i++].u = OP(OP_HALT, 0, 0, 0);
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;
return code; return code;
} }
Code *compile(char *buffer) { Code *compile(char *buffer) {
Code *code = (Code *)malloc(sizeof(Code)); Code *code = (Code *)malloc(sizeof(Code));
Word memory[MEMORY_SIZE] = {0}; /* Memory array */ Value memory[MEMORY_SIZE] = {0}; /* Memory array */
code->memory = memory; code->memory = memory;
code->size = MEMORY_SIZE; code->size = MEMORY_SIZE;

View File

@ -5,7 +5,8 @@
typedef struct Code Code; typedef struct Code Code;
struct Code { struct Code {
Word *memory; Value *memory;
VMFrame current;
uint32_t size; uint32_t size;
}; };

View File

@ -1,6 +1,6 @@
#include "debug.h" #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"); FILE *file = fopen("memory_dump.bin", "wb");
if (!file) { if (!file) {
perror("Failed to open file"); perror("Failed to open file");

View File

@ -3,6 +3,6 @@
#include "vm.h" #include "vm.h"
int core_dump(Word *memory, uint32_t memory_size); int core_dump(Value *memory, uint32_t memory_size);
#endif #endif

View File

@ -21,7 +21,7 @@ unsigned int hash_##StructType(char *s) { \
return hashval % HASHSIZE; \ return hashval % HASHSIZE; \
} \ } \
\ \
StructType *lookup_##StructType(StructType **map, char *s) { \ StructType *get_##StructType(StructType **map, char *s) { \
StructType *np; \ StructType *np; \
for (np = map[hash_##StructType(s)]; np != NULL; np = np->next) \ for (np = map[hash_##StructType(s)]; np != NULL; np = np->next) \
if (strcmp(s, np->keyword) == 0) \ 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 *put_##StructType(StructType **map, char *keyword, TokenType token) { \
StructType *np; \ StructType *np; \
unsigned int hashval; \ unsigned int hashval; \
if ((np = lookup_##StructType(map, keyword)) == NULL) { \ if ((np = get_##StructType(map, keyword)) == NULL) { \
np = (StructType *)malloc(sizeof(*np)); \ np = (StructType *)malloc(sizeof(*np)); \
if (np == NULL || (np->keyword = strdup(keyword)) == NULL) \ if (np == NULL || (np->keyword = strdup(keyword)) == NULL) \
return NULL; \ return NULL; \

View File

@ -21,7 +21,7 @@ uint32_t pc = 1; /* Program counter */
Code *code; Code *code;
void mainloop() { void mainloop() {
pc = step_vm(code->memory, code->size, pc); pc = step_vm(&code->current, code->memory);
if (pc == 0) { if (pc == 0) {
#ifdef __EMSCRIPTEN__ #ifdef __EMSCRIPTEN__
emscripten_cancel_main_loop(); /* this should "kill" the app. */ emscripten_cancel_main_loop(); /* this should "kill" the app. */

View File

@ -6,12 +6,25 @@
typedef union { typedef union {
int32_t i; /* Integers */ int32_t i; /* Integers */
float f; /* Float */ 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 */ 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 { typedef enum {
OP_HALT, /* terminate execution */ 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_ADD_INT, /* dest = src1 + src2 */
OP_SUB_INT, /* dest = src1 - src2 */ OP_SUB_INT, /* dest = src1 - src2 */
OP_MUL_INT, /* dest = src1 * src2 */ OP_MUL_INT, /* dest = src1 * src2 */
@ -53,4 +66,7 @@ typedef enum {
OP_CMP_STRING, /* dest = (str == src2) as bool */ OP_CMP_STRING, /* dest = (str == src2) as bool */
} Opcode; } Opcode;
/* defines a uint32 opcode */
#define OP(opcode, a, b, c) ((opcode << 24) | (a << 16) | (b << 8) | c)
#endif #endif

View File

@ -50,14 +50,6 @@ void initTokenMap() {
put_TokenMap(tokenMap, "sll", TOKEN_SHIFTLEFT); 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; typedef struct Tokenizer Tokenizer;
struct Tokenizer { struct Tokenizer {
char *start; char *start;
@ -144,9 +136,17 @@ static char *currentTokenToS() {
return str; 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() { static TokenType identifierType() {
char *check = currentTokenToS(); char *check = currentTokenToS();
TokenType t = get_Token(check); TokenType t = getToken(check);
free(check); free(check);
return t; return t;
} }

146
src/vm.c
View File

@ -2,52 +2,67 @@
#define COMPARE_AND_JUMP(type, accessor, op) \ #define COMPARE_AND_JUMP(type, accessor, op) \
do { \ do { \
type value = memory[src1_addr].accessor; \ type value = frame->registers[src1].accessor; \
type value2 = memory[src2_addr].accessor; \ type value2 = frame->registers[src2].accessor; \
uint32_t jump_target = dest_addr; \ frame->pc = (value op value2) ? dest : frame->pc; \
pc = (value op value2) ? jump_target : pc; \ return frame->pc; \
return pc; \
} while (0) } while (0)
#define MATH_OP(accessor, op) \ #define MATH_OP(accessor, op) \
do { \ do { \
memory[dest_addr].accessor = \ frame->registers[dest].accessor = \
memory[src1_addr].accessor op memory[src2_addr].accessor; \ frame->registers[src1].accessor op frame->registers[src2].accessor; \
return pc; \ return frame->pc; \
} while (0) } while (0)
/** /**
* String copy in data memory. * String copy in data memory.
*/ */
void mem_strcpy(Word *memory, const char *str, uint32_t length, void mem_strcpy(Value *memory, const char *str, uint32_t length,
uint32_t dest_addr) { uint32_t dest) {
memory[dest_addr].u = length; memory[dest].u = length;
uint32_t buffer_addr = dest_addr + 1; uint32_t buffer = dest + 1;
uint32_t i; uint32_t i;
for (i = 0; i < length; 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. * Step to the next opcode in the vm.
*/ */
uint32_t step_vm(Word *memory, uint32_t memory_size, uint32_t pc) { uint32_t step_vm(VMFrame *frame, Value *memory) {
Opcode opcode = memory[pc].u; uint32_t instruction = memory[frame->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 */
if (src1_addr >= memory_size || src2_addr >= memory_size || /* Extract 8-bit register indices from 32-bit instruction */
dest_addr >= memory_size) { uint8_t opcode = (instruction >> 24) & 0xFF;
printf("Invalid memory address!\n"); uint8_t dest = (instruction >> 16) & 0xFF;
return 0; uint8_t src1 = (instruction >> 8) & 0xFF;
} uint8_t src2 = instruction & 0xFF;
/* Advance to next instruction */
frame->pc++;
switch (opcode) { switch (opcode) {
case OP_HALT: case OP_HALT:
return 0; 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: case OP_ADD_INT:
MATH_OP(i, +); MATH_OP(i, +);
case OP_SUB_INT: 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: case OP_DIV_REAL:
MATH_OP(f, /); MATH_OP(f, /);
case OP_REAL_TO_INT: case OP_REAL_TO_INT:
memory[dest_addr].i = (int32_t)(memory[src1_addr].f); frame->registers[dest].i = (int32_t)(frame->registers[src1].f);
return pc; return frame->pc;
case OP_INT_TO_REAL: case OP_INT_TO_REAL:
memory[dest_addr].f = (float)(memory[src1_addr].i); frame->registers[dest].f = (float)(frame->registers[src1].i);
return pc; return frame->pc;
case OP_REAL_TO_UINT: case OP_REAL_TO_UINT:
memory[dest_addr].u = (uint32_t)(memory[src1_addr].f); frame->registers[dest].u = (uint32_t)(frame->registers[src1].f);
return pc; return frame->pc;
case OP_UINT_TO_REAL: case OP_UINT_TO_REAL:
memory[dest_addr].f = (float)(memory[src1_addr].u); frame->registers[dest].f = (float)(frame->registers[src1].u);
return pc; return frame->pc;
case OP_MOV: case OP_MOV:
memory[dest_addr] = memory[src1_addr]; frame->registers[dest] = frame->registers[src1];
return pc; return frame->pc;
case OP_JMP: case OP_JMP:
pc = src1_addr; /* Jump to address */ frame->pc = frame->registers[src1].u; /* Jump to address */
return pc; return frame->pc;
case OP_JEQ_UINT: { case OP_JEQ_UINT: {
COMPARE_AND_JUMP(uint32_t, u, ==); 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, <=); COMPARE_AND_JUMP(int32_t, u, <=);
} }
case OP_INT_TO_STRING: { 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]; char buffer[32];
int len = sprintf(buffer, "%d", a); int len = sprintf(buffer, "%d", a);
mem_strcpy(memory, buffer, len, dest_addr); mem_strcpy(memory, buffer, len, str_dest);
return pc; return frame->pc;
} }
case OP_UINT_TO_STRING: { 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]; char buffer[32];
int len = sprintf(buffer, "%d", a); int len = sprintf(buffer, "%d", a);
mem_strcpy(memory, buffer, len, dest_addr); mem_strcpy(memory, buffer, len, str_dest);
return pc; return frame->pc;
} }
case OP_REAL_TO_STRING: { 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]; char buffer[32];
int len = sprintf(buffer, "%f", a); int len = sprintf(buffer, "%f", a);
mem_strcpy(memory, buffer, len, dest_addr); mem_strcpy(memory, buffer, len, str_dest);
return pc; return frame->pc;
} }
case OP_READ_STRING: { 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; uint32_t length = 0;
while (1) { while (1) {
int ch = getchar(); int ch = getchar();
if (ch == '\n' || ch == EOF) { if (ch == '\n' || ch == EOF) {
memory[buffer_addr + (length / 4)].c[length % 4] = '\0'; memory[buffer + (length / 4)].c[length % 4] = '\0';
break; break;
} }
memory[buffer_addr + (length / 4)].c[length % 4] = ch; memory[buffer + (length / 4)].c[length % 4] = ch;
length++; length++;
} }
memory[dest_addr].u = length; memory[str_dest].u = length;
return pc; return frame->pc;
} }
case OP_PRINT_STRING: { case OP_PRINT_STRING: {
uint32_t string_addr = src1_addr; uint32_t ptr = (uint32_t)frame->registers[src1].u;
uint32_t length = memory[src1_addr - 1].u; uint32_t length = memory[ptr].u;
uint32_t str_src = ptr + 1;
uint32_t i; uint32_t i;
for (i = 0; i < length; 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') if (ch == '\0')
break; break;
putchar(ch); putchar(ch);
} }
putchar('\n'); putchar('\n');
return pc; return frame->pc;
} }
case OP_CMP_STRING: { case OP_CMP_STRING: {
uint32_t addr1 = src1_addr; uint32_t addr1 = (uint32_t)frame->registers[src1].u;
uint32_t addr2 = src2_addr; uint32_t addr2 = (uint32_t)frame->registers[src2].u;
uint32_t length1 = memory[src1_addr - 1].u; uint32_t length1 = memory[addr1 - 1].u;
uint32_t length2 = memory[src2_addr - 1].u; uint32_t length2 = memory[addr2 - 1].u;
uint32_t equal = 1; uint32_t equal = 1;
if (length1 != length2) { if (length1 != length2) {
@ -207,11 +223,11 @@ uint32_t step_vm(Word *memory, uint32_t memory_size, uint32_t pc) {
break; break;
} }
if ((char1 & 0xFF) == '\0' && (char2 & 0xFF) == '\0') if ((char1 & 0xFF) == '\0' && (char2 & 0xFF) == '\0')
return pc; return frame->pc;
} }
} }
memory[dest_addr].u = equal; memory[dest].u = equal;
return pc; return frame->pc;
} }
} }
return 0; return 0;

View File

@ -3,6 +3,6 @@
#include "opcodes.h" #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 #endif