Compare commits

..

1 Commits

Author SHA1 Message Date
zongor dcf348f577 remove string lookup for devices use handles instead 2025-10-14 00:02:12 -07:00
7 changed files with 1000 additions and 443 deletions

View File

@ -21,7 +21,7 @@ Undâr is a programming language for the purpose of creating three dimensional v
It has an internal REPL that allows for quick development as well as the ability to dump the program to a binary rom for preserving that program/game/etc. It has an internal REPL that allows for quick development as well as the ability to dump the program to a binary rom for preserving that program/game/etc.
It runs on the =Reality Engine=, a 32 bit stack based VM written in freestanding C89. It runs on the =Reality Engine=, a VM written in freestanding C89, has a CISC like instruction format of one byte opcode and a variable byte operand. 32 general purpose registers.
* Philosophy * Philosophy
@ -58,11 +58,11 @@ The Undâr compiler will be written in Sċieppan, as well as core VM tests.
#+BEGIN_SRC lisp #+BEGIN_SRC lisp
((code ((code
(label main (label main
(load &terminal-namespace) ; load terminal namespace (load-immediate $0 &terminal-namespace) ; load terminal namespace
(load &hello-str) ; load hello string ptr (load-immediate $1 &hello-str) ; load hello string ptr
(string-length) ; get length to write to stdout (string-length $2 $1) ; get length to write to stdout
(syscall WRITE) ; do the write syscall (syscall WRITE $0 $1 $2) ; do the write syscall
(halt))) ; done (halt))) ; done
(data (data
(label terminal-namespace "/dev/term/0") (label terminal-namespace "/dev/term/0")
(label hello-str "nuqneH 'u'?\n"))) (label hello-str "nuqneH 'u'?\n")))

View File

@ -236,111 +236,78 @@ void repl(VM *vm) {
exit(0); exit(0);
} }
/*
* This needs to be done dynamically eventually
*/
void register_sdl_devices(VM *vm) {
screen_data.width = 640;
screen_data.height = 480;
screen_data.size = screen_data.width * screen_data.height;
vm_register_device(vm, "/dev/screen/0", "screen", &screen_data, &screen_ops);
mouse_data.x = 0;
mouse_data.y = 0;
mouse_data.btn1 = 0;
mouse_data.btn2 = 0;
mouse_data.btn3 = 0;
mouse_data.btn4 = 0;
mouse_data.size = 12;
vm_register_device(vm, "/dev/mouse/0", "mouse", &mouse_data, &mouse_ops);
keyboard_data.keys = SDL_GetKeyboardState(&keyboard_data.key_count);
vm_register_device(vm, "/dev/keyboard/0", "keyboard", &keyboard_data,
&keyboard_ops);
}
#define ASM_DEBUG
#ifdef ASM_DEBUG #ifdef ASM_DEBUG
const char *opcode_to_string(Opcode op) { const char *opcode_to_string(Opcode op) {
static const char *names[] = { static const char *names[] = {[OP_HALT] = "halt",
[OP_HALT] = "halt", [OP_JMP] = "jump",
[OP_JMP] = "jump", [OP_JMPF] = "jump-if-flag",
[OP_JMPF] = "jump-if-flag", [OP_CALL] = "call",
[OP_CALL] = "call", [OP_RETURN] = "return",
[OP_RETURN] = "return", [OP_LOAD] = "load",
[OP_LOAD_8] = "load-8", [OP_LOAD_REG] = "get",
[OP_LOAD_16] = "load-16", [OP_LOAD_REG8] = "get-8",
[OP_LOAD_32] = "load", [OP_LOADI8] = "load-i8",
[OP_STORE_8] = "store-8", [OP_LOADU8] = "load-u8",
[OP_STORE_16] = "store-16", [OP_LOADI16] = "load-i16",
[OP_STORE_32] = "store", [OP_LOADU16] = "load-u16",
[OP_MALLOC] = "malloc", [OP_LOAD_IMM] = "load-immediate",
[OP_MEMSET_8] = "memset-8", [OP_MALLOC] = "malloc",
[OP_MEMSET_16] = "memset-16", [OP_STORE] = "store",
[OP_MEMSET_32] = "memset", [OP_STORE8] = "store-8",
[OP_PUSH] = "push", [OP_STORE16] = "store-16",
[OP_POP] = "pop", [OP_PUSH] = "push",
[OP_DUP] = "dup", [OP_POP] = "pop",
[OP_EXCH] = "exch", [OP_REG_MOV] = "register-move",
[OP_OVER] = "over", [OP_SYSCALL] = "syscall",
[OP_PICK] = "pick", [OP_SLL] = "bit-shift-left",
[OP_ROT] = "rot", [OP_SRL] = "bit-shift-right",
[OP_DEPTH] = "depth", [OP_SRE] = "bit-shift-right-extend",
[OP_SYSCALL] = "syscall", [OP_BAND] = "bit-and",
[OP_SLL] = "bit-shift-left", [OP_BOR] = "bit-or",
[OP_SRL] = "bit-shift-right", [OP_BXOR] = "bit-xor",
[OP_SRE] = "bit-shift-re", [OP_ADD_INT] = "add-int",
[OP_BAND] = "bit-and", [OP_SUB_INT] = "sub-int",
[OP_BOR] = "bit-or", [OP_MUL_INT] = "mul-int",
[OP_BXOR] = "bit-xor", [OP_DIV_INT] = "div-int",
[OP_ADD_INT] = "add-int", [OP_ADD_UINT] = "add-nat",
[OP_SUB_INT] = "sub-int", [OP_SUB_UINT] = "sub-nat",
[OP_MUL_INT] = "mul-int", [OP_MUL_UINT] = "mul-nat",
[OP_DIV_INT] = "div-int", [OP_DIV_UINT] = "div-nat",
[OP_ADD_UINT] = "add-nat", [OP_ADD_REAL] = "add-real",
[OP_SUB_UINT] = "sub-nat", [OP_SUB_REAL] = "sub-real",
[OP_MUL_UINT] = "mul-nat", [OP_MUL_REAL] = "mul-real",
[OP_DIV_UINT] = "div-nat", [OP_DIV_REAL] = "div-real",
[OP_ADD_REAL] = "add-real", [OP_INT_TO_REAL] = "int-to-real",
[OP_SUB_REAL] = "sub-real", [OP_UINT_TO_REAL] = "nat-to-real",
[OP_MUL_REAL] = "mul-real", [OP_REAL_TO_INT] = "real-to-int",
[OP_DIV_REAL] = "div-real", [OP_REAL_TO_UINT] = "real-to-nat",
[OP_INT_TO_REAL] = "int-to-real", [OP_JEQ_INT] = "jump-eq-int",
[OP_UINT_TO_REAL] = "nat-to-real", [OP_JGT_INT] = "jump-gt-int",
[OP_REAL_TO_INT] = "real-to-int", [OP_JLT_INT] = "jump-lt-int",
[OP_REAL_TO_UINT] = "real-to-nat", [OP_JLE_INT] = "jump-le-int",
[OP_JEQ_INT] = "jump-eq-int", [OP_JGE_INT] = "jump-ge-int",
[OP_JNEQ_INT] = "jump-neq-int", [OP_JEQ_UINT] = "jump-eq-nat",
[OP_JGT_INT] = "jump-gt-int", [OP_JGT_UINT] = "jump-gt-nat",
[OP_JLT_INT] = "jump-lt-int", [OP_JLT_UINT] = "jump-lt-nat",
[OP_JLE_INT] = "jump-le-int", [OP_JLE_UINT] = "jump-le-nat",
[OP_JGE_INT] = "jump-ge-int", [OP_JGE_UINT] = "jump-ge-nat",
[OP_JEQ_UINT] = "jump-eq-nat", [OP_JEQ_REAL] = "jump-eq-real",
[OP_JNEQ_UINT] = "jump-neq-nat", [OP_JGE_REAL] = "jump-ge-real",
[OP_JGT_UINT] = "jump-gt-nat", [OP_JGT_REAL] = "jump-gt-real",
[OP_JLT_UINT] = "jump-lt-nat", [OP_JLT_REAL] = "jump-lt-real",
[OP_JLE_UINT] = "jump-le-nat", [OP_JLE_REAL] = "jump-le-real",
[OP_JGE_UINT] = "jump-ge-nat", [OP_STRLEN] = "string-length",
[OP_JEQ_REAL] = "jump-eq-real", [OP_STREQ] = "string-eq",
[OP_JNEQ_REAL] = "jump-neq-real", [OP_STRCAT] = "string-concat",
[OP_JGE_REAL] = "jump-ge-real", [OP_STR_GET_CHAR] = "string-get-char",
[OP_JGT_REAL] = "jump-gt-real", [OP_STR_FIND_CHAR] = "string-find-char",
[OP_JLT_REAL] = "jump-lt-real", [OP_STR_SLICE] = "string-slice",
[OP_JLE_REAL] = "jump-le-real", [OP_INT_TO_STRING] = "int-to-string",
[OP_STRLEN] = "string-length", [OP_UINT_TO_STRING] = "nat-to-string",
[OP_STREQ] = "string-eq", [OP_REAL_TO_STRING] = "real-to-string",
[OP_STRCAT] = "string-concat", [OP_STRING_TO_INT] = "string-to-int",
[OP_STR_GET_CHAR] = "string-get-char", [OP_STRING_TO_UINT] = "string-to-nat",
[OP_STR_FIND_CHAR] = "string-find-char", [OP_STRING_TO_REAL] = "string-to-real"};
[OP_STR_SLICE] = "string-slice",
[OP_INT_TO_STRING] = "int-to-string",
[OP_UINT_TO_STRING] = "nat-to-string",
[OP_REAL_TO_STRING] = "real-to-string",
[OP_STRING_TO_INT] = "string-to-int",
[OP_STRING_TO_UINT] = "string-to-nat",
[OP_STRING_TO_REAL] = "string-to-real",
};
if (op < 0 || op >= (int)(sizeof(names) / sizeof(names[0]))) { if (op < 0 || op >= (int)(sizeof(names) / sizeof(names[0]))) {
return "<invalid-opcode>"; return "<invalid-opcode>";

View File

@ -70,43 +70,59 @@ int get_instruction_byte_size(ExprNode *node) {
const char *opname = node->token; const char *opname = node->token;
// Simple opcodes (1 byte) // Simple opcodes (1 byte)
if (strcmp(opname, "halt") == 0 || strcmp(opname, "return") == 0 || if (strcmp(opname, "halt") == 0 || strcmp(opname, "return") == 0) {
strcmp(opname, "pop") == 0 || strcmp(opname, "malloc") == 0 || return 1;
strcmp(opname, "int-to-string") == 0 || strcmp(opname, "dup") == 0 || }
strcmp(opname, "get-8") == 0 || strcmp(opname, "nat-to-string") == 0 ||
strcmp(opname, "get-16") == 0 || strcmp(opname, "real-to-string") == 0 || // Register-based opcodes (2 bytes: opcode + register)
strcmp(opname, "get") == 0 || strcmp(opname, "int-to-real") == 0 || if (strcmp(opname, "pop") == 0 || strcmp(opname, "jump-if-flag") == 0 ||
strcmp(opname, "put-8") == 0 || strcmp(opname, "nat-to-real") == 0 || strcmp(opname, "jump") == 0 || strcmp(opname, "push") == 0) {
strcmp(opname, "put-16") == 0 || strcmp(opname, "real-to-int") == 0 || return 2;
strcmp(opname, "put") == 0 || strcmp(opname, "real-to-nat") == 0 || }
if (strcmp(opname, "int-to-string") == 0 || strcmp(opname, "get-8") == 0 ||
strcmp(opname, "nat-to-string") == 0 || strcmp(opname, "get-16") == 0 ||
strcmp(opname, "real-to-string") == 0 || strcmp(opname, "get") == 0 ||
strcmp(opname, "int-to-real") == 0 || strcmp(opname, "put-8") == 0 ||
strcmp(opname, "nat-to-real") == 0 || strcmp(opname, "put-16") == 0 ||
strcmp(opname, "real-to-int") == 0 || strcmp(opname, "put") == 0 ||
strcmp(opname, "real-to-nat") == 0 ||
strcmp(opname, "nat-to-int") == 0 || strcmp(opname, "int-to-nat") == 0 || strcmp(opname, "nat-to-int") == 0 || strcmp(opname, "int-to-nat") == 0 ||
strcmp(opname, "string-length") == 0 || strcmp(opname, "store") == 0 || strcmp(opname, "string-length") == 0 || strcmp(opname, "store") == 0 ||
strcmp(opname, "store-8") == 0 || strcmp(opname, "store-16") == 0 || strcmp(opname, "store-8") == 0 || strcmp(opname, "store-16") == 0 ||
strcmp(opname, "memset") == 0 || strcmp(opname, "memset") == 0 || strcmp(opname, "memset") == 0 || strcmp(opname, "memset") == 0 ||
strcmp(opname, "memset-8") == 0 || strcmp(opname, "memset-16") == 0 || strcmp(opname, "memset-8") == 0 || strcmp(opname, "memset-16") == 0 ||
strcmp(opname, "register-move") == 0 || strcmp(opname, "add-int") == 0 || strcmp(opname, "register-move") == 0 || strcmp(opname, "malloc") == 0) {
strcmp(opname, "sub-int") == 0 || strcmp(opname, "mul-int") == 0 || return 3;
strcmp(opname, "div-int") == 0 || strcmp(opname, "add-nat") == 0 ||
strcmp(opname, "sub-nat") == 0 || strcmp(opname, "mul-nat") == 0 ||
strcmp(opname, "div-nat") == 0 || strcmp(opname, "add-real") == 0 ||
strcmp(opname, "sub-real") == 0 || strcmp(opname, "over") == 0 ||
strcmp(opname, "bit-shift-left") == 0 || strcmp(opname, "exch") == 0 ||
strcmp(opname, "bit-shift-right") == 0 || strcmp(opname, "pick") == 0 ||
strcmp(opname, "bit-and") == 0 || strcmp(opname, "bit-or") == 0 ||
strcmp(opname, "bit-xor") == 0 || strcmp(opname, "mul-real") == 0 ||
strcmp(opname, "div-real") == 0 || strcmp(opname, "load") == 0 ||
strcmp(opname, "load-immediate") == 0 || strcmp(opname, "load-16") == 0 ||
strcmp(opname, "load-8") == 0 || strcmp(opname, "syscall") == 0 ||
strcmp(opname, "rot") == 0 || strcmp(opname, "depth") == 0) {
return 1;
} }
// multibyte opcodes (5 bytes: opcode + u32) // Register-register-register opcodes (4 bytes: 1 + 3)
if (strcmp(opname, "call") == 0 || if (strcmp(opname, "add-int") == 0 || strcmp(opname, "sub-int") == 0 ||
strcmp(opname, "push") == 0 || strcmp(opname, "mul-int") == 0 || strcmp(opname, "div-int") == 0 ||
strcmp(opname, "jump") == 0 || strcmp(opname, "add-nat") == 0 || strcmp(opname, "sub-nat") == 0 ||
strcmp(opname, "jump-if-flag") == 0 || strcmp(opname, "mul-nat") == 0 || strcmp(opname, "div-nat") == 0 ||
strcmp(opname, "jump-eq-int") == 0 || strcmp(opname, "add-real") == 0 || strcmp(opname, "sub-real") == 0 ||
strcmp(opname, "bit-shift-left") == 0 ||
strcmp(opname, "bit-shift-right") == 0 ||
strcmp(opname, "bit-and") == 0 || strcmp(opname, "bit-or") == 0 ||
strcmp(opname, "bit-xor") == 0 || strcmp(opname, "mul-real") == 0 ||
strcmp(opname, "div-real") == 0) {
return 4;
}
// (5 bytes: 1 + 4)
if (strcmp(opname, "call") == 0) {
return 5;
}
// Load, Load-immediate (6 bytes: 1 + 1 + 4)
if (strcmp(opname, "load") == 0 || strcmp(opname, "load-immediate") == 0 ||
strcmp(opname, "load-16") == 0 || strcmp(opname, "load-8") == 0) {
return 6;
}
// jump compare (7 bytes: 1 + 4 + 1 + 1)
if (strcmp(opname, "jump-eq-int") == 0 ||
strcmp(opname, "jump-neq-int") == 0 || strcmp(opname, "jump-neq-int") == 0 ||
strcmp(opname, "jump-gt-int") == 0 || strcmp(opname, "jump-gt-int") == 0 ||
strcmp(opname, "jump-lt-int") == 0 || strcmp(opname, "jump-lt-int") == 0 ||
@ -124,7 +140,13 @@ int get_instruction_byte_size(ExprNode *node) {
strcmp(opname, "jump-lt-real") == 0 || strcmp(opname, "jump-lt-real") == 0 ||
strcmp(opname, "jump-le-real") == 0 || strcmp(opname, "jump-le-real") == 0 ||
strcmp(opname, "jump-ge-real") == 0) { strcmp(opname, "jump-ge-real") == 0) {
return 5; return 7;
}
// Syscall (1 + syscall_id (4) + args)
if (strcmp(opname, "syscall") == 0) {
return 1 + 4 + (node->child_count > 0 ? node->child_count - 1 : 0);
} }
fprintf(stderr, "Unknown opcode for sizing: %s\n", opname); fprintf(stderr, "Unknown opcode for sizing: %s\n", opname);
@ -214,11 +236,6 @@ u32 allocate_data(VM *vm, SymbolTable *table, const char *name, u32 size) {
void emit_byte(VM *vm, u8 byte) { vm->code[vm->cp++] = byte; } void emit_byte(VM *vm, u8 byte) { vm->code[vm->cp++] = byte; }
void emit_u16(VM *vm, u16 value) {
write_u16(vm, code, vm->cp, value);
vm->cp += 4;
}
void emit_u32(VM *vm, u32 value) { void emit_u32(VM *vm, u32 value) {
write_u32(vm, code, vm->cp, value); write_u32(vm, code, vm->cp, value);
vm->cp += 4; vm->cp += 4;
@ -226,6 +243,12 @@ void emit_u32(VM *vm, u32 value) {
void emit_opcode(VM *vm, Opcode op) { emit_byte(vm, op); } void emit_opcode(VM *vm, Opcode op) { emit_byte(vm, op); }
int parse_register(const char *reg_str) {
if (reg_str[0] != '$')
return -1;
return atoi(reg_str + 1);
}
u32 resolve_symbol(SymbolTable *table, const char *ref) { u32 resolve_symbol(SymbolTable *table, const char *ref) {
// Handle symbol references (e.g., &label) // Handle symbol references (e.g., &label)
if (ref[0] == '&') { if (ref[0] == '&') {
@ -411,46 +434,128 @@ void process_code_expr(VM *vm, SymbolTable *table, ExprNode *node) {
emit_u32(vm, addr); emit_u32(vm, addr);
} else if (strcmp(opname, "return") == 0) { } else if (strcmp(opname, "return") == 0) {
emit_opcode(vm, OP_RETURN); emit_opcode(vm, OP_RETURN);
} else if (strcmp(opname, "load-immediate") == 0) {
emit_opcode(vm, OP_LOAD_IMM);
int reg = parse_register(node->children[0]->token);
u32 addr = resolve_symbol(table, node->children[1]->token);
emit_byte(vm, reg);
emit_u32(vm, addr);
} else if (strcmp(opname, "load-8") == 0) { } else if (strcmp(opname, "load-8") == 0) {
emit_opcode(vm, OP_LOAD_8); emit_opcode(vm, OP_LOAD_8);
int dest = parse_register(node->children[0]->token);
u32 addr = resolve_symbol(table, node->children[1]->token);
emit_byte(vm, dest);
emit_u32(vm, addr);
} else if (strcmp(opname, "load-16") == 0) { } else if (strcmp(opname, "load-16") == 0) {
emit_opcode(vm, OP_LOAD_16); emit_opcode(vm, OP_LOAD_8);
int dest = parse_register(node->children[0]->token);
u32 addr = resolve_symbol(table, node->children[1]->token);
emit_byte(vm, dest);
emit_u32(vm, addr);
} else if (strcmp(opname, "load") == 0) { } else if (strcmp(opname, "load") == 0) {
emit_opcode(vm, OP_LOAD_32); emit_opcode(vm, OP_LOAD_8);
int dest = parse_register(node->children[0]->token);
u32 addr = resolve_symbol(table, node->children[1]->token);
emit_byte(vm, dest);
emit_u32(vm, addr);
} else if (strcmp(opname, "get-8") == 0) {
emit_opcode(vm, OP_GET_8);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
} else if (strcmp(opname, "get-16") == 0) {
emit_opcode(vm, OP_GET_16);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
} else if (strcmp(opname, "get") == 0) {
emit_opcode(vm, OP_GET_32);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
} else if (strcmp(opname, "malloc") == 0) { } else if (strcmp(opname, "malloc") == 0) {
emit_opcode(vm, OP_MALLOC); emit_opcode(vm, OP_MALLOC);
u32 addr = resolve_symbol(table, node->children[0]->token); int dest = parse_register(node->children[0]->token);
emit_u32(vm, addr); int src1 = parse_register(node->children[1]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
} else if (strcmp(opname, "memset-8") == 0) { } else if (strcmp(opname, "memset-8") == 0) {
emit_opcode(vm, OP_MEMSET_8); emit_opcode(vm, OP_MEMSET_8);
int dest = parse_register(node->children[0]->token);
int value = parse_register(node->children[1]->token);
int count = parse_register(node->children[2]->token);
emit_byte(vm, dest);
emit_byte(vm, value);
emit_byte(vm, count);
} else if (strcmp(opname, "memset-16") == 0) { } else if (strcmp(opname, "memset-16") == 0) {
emit_opcode(vm, OP_MEMSET_16); emit_opcode(vm, OP_MEMSET_16);
int dest = parse_register(node->children[0]->token);
int value = parse_register(node->children[1]->token);
int count = parse_register(node->children[2]->token);
emit_byte(vm, dest);
emit_byte(vm, value);
emit_byte(vm, count);
} else if (strcmp(opname, "memset") == 0) { } else if (strcmp(opname, "memset") == 0) {
emit_opcode(vm, OP_MEMSET_32); emit_opcode(vm, OP_MEMSET_32);
int dest = parse_register(node->children[0]->token);
int value = parse_register(node->children[1]->token);
int count = parse_register(node->children[2]->token);
emit_byte(vm, dest);
emit_byte(vm, value);
emit_byte(vm, count);
} else if (strcmp(opname, "store-8") == 0) { } else if (strcmp(opname, "store-8") == 0) {
emit_opcode(vm, OP_STORE_8); emit_opcode(vm, OP_STORE_8);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
} else if (strcmp(opname, "store-16") == 0) { } else if (strcmp(opname, "store-16") == 0) {
emit_opcode(vm, OP_STORE_16); emit_opcode(vm, OP_STORE_16);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
} else if (strcmp(opname, "store") == 0) { } else if (strcmp(opname, "store") == 0) {
emit_opcode(vm, OP_STORE_32); emit_opcode(vm, OP_STORE_32);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
} else if (strcmp(opname, "put-8") == 0) {
emit_opcode(vm, OP_PUT_8);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
} else if (strcmp(opname, "put-16") == 0) {
emit_opcode(vm, OP_PUT_16);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
} else if (strcmp(opname, "put") == 0) {
emit_opcode(vm, OP_PUT_32);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
} else if (strcmp(opname, "push") == 0) { } else if (strcmp(opname, "push") == 0) {
emit_opcode(vm, OP_PUSH); emit_opcode(vm, OP_PUSH);
u32 value = resolve_symbol(table, node->children[0]->token); int reg = parse_register(node->children[0]->token);
emit_u32(vm, value); emit_byte(vm, reg);
} else if (strcmp(opname, "pop") == 0) { } else if (strcmp(opname, "pop") == 0) {
emit_opcode(vm, OP_POP); emit_opcode(vm, OP_POP);
} else if (strcmp(opname, "dup") == 0) { int reg = parse_register(node->children[0]->token);
emit_opcode(vm, OP_DUP); emit_byte(vm, reg);
} else if (strcmp(opname, "over") == 0) { } else if (strcmp(opname, "register-move") == 0) {
emit_opcode(vm, OP_OVER); emit_opcode(vm, OP_REG_MOV);
} else if (strcmp(opname, "rot") == 0 ) { int dest = parse_register(node->children[0]->token);
emit_opcode(vm, OP_ROT); int src = parse_register(node->children[1]->token);
} else if (strcmp(opname, "depth") == 0) { emit_byte(vm, dest);
emit_opcode(vm, OP_DEPTH); emit_byte(vm, src);
} else if (strcmp(opname, "exch") == 0) {
emit_opcode(vm, OP_EXCH);
} else if (strcmp(opname, "pick") == 0) {
emit_opcode(vm, OP_PICK);
} else if (strcmp(opname, "syscall") == 0) { } else if (strcmp(opname, "syscall") == 0) {
emit_opcode(vm, OP_SYSCALL); emit_opcode(vm, OP_SYSCALL);
@ -472,146 +577,407 @@ void process_code_expr(VM *vm, SymbolTable *table, ExprNode *node) {
emit_u32(vm, syscall_id); emit_u32(vm, syscall_id);
// Emit register arguments
for (size_t i = 1; i < node->child_count; ++i) {
int reg = parse_register(node->children[i]->token);
emit_byte(vm, reg);
}
} else if (strcmp(opname, "bit-shift-left") == 0) { } else if (strcmp(opname, "bit-shift-left") == 0) {
emit_opcode(vm, OP_SLL); emit_opcode(vm, OP_SLL);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "bit-shift-right") == 0) { } else if (strcmp(opname, "bit-shift-right") == 0) {
emit_opcode(vm, OP_SRL); emit_opcode(vm, OP_SRL);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "bit-shift-re") == 0) { } else if (strcmp(opname, "bit-shift-re") == 0) {
emit_opcode(vm, OP_SRE); emit_opcode(vm, OP_SRE);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "bit-and") == 0) { } else if (strcmp(opname, "bit-and") == 0) {
emit_opcode(vm, OP_BAND); emit_opcode(vm, OP_BAND);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "bit-or") == 0) { } else if (strcmp(opname, "bit-or") == 0) {
emit_opcode(vm, OP_BOR); emit_opcode(vm, OP_BOR);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "bit-xor") == 0) { } else if (strcmp(opname, "bit-xor") == 0) {
emit_opcode(vm, OP_BXOR); emit_opcode(vm, OP_BXOR);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "add-int") == 0) { } else if (strcmp(opname, "add-int") == 0) {
emit_opcode(vm, OP_ADD_INT); emit_opcode(vm, OP_ADD_INT);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "sub-int") == 0) { } else if (strcmp(opname, "sub-int") == 0) {
emit_opcode(vm, OP_SUB_INT); emit_opcode(vm, OP_SUB_INT);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "mul-int") == 0) { } else if (strcmp(opname, "mul-int") == 0) {
emit_opcode(vm, OP_MUL_INT); emit_opcode(vm, OP_MUL_INT);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "div-int") == 0) { } else if (strcmp(opname, "div-int") == 0) {
emit_opcode(vm, OP_DIV_INT); emit_opcode(vm, OP_DIV_INT);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "add-nat") == 0) { } else if (strcmp(opname, "add-nat") == 0) {
emit_opcode(vm, OP_ADD_UINT); emit_opcode(vm, OP_ADD_UINT);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "sub-nat") == 0) { } else if (strcmp(opname, "sub-nat") == 0) {
emit_opcode(vm, OP_SUB_UINT); emit_opcode(vm, OP_SUB_UINT);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "mul-nat") == 0) { } else if (strcmp(opname, "mul-nat") == 0) {
emit_opcode(vm, OP_MUL_UINT); emit_opcode(vm, OP_MUL_UINT);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "div-nat") == 0) { } else if (strcmp(opname, "div-nat") == 0) {
emit_opcode(vm, OP_DIV_UINT); emit_opcode(vm, OP_DIV_UINT);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "add-real") == 0) { } else if (strcmp(opname, "add-real") == 0) {
emit_opcode(vm, OP_ADD_REAL); emit_opcode(vm, OP_ADD_REAL);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "sub-real") == 0) { } else if (strcmp(opname, "sub-real") == 0) {
emit_opcode(vm, OP_SUB_REAL); emit_opcode(vm, OP_SUB_REAL);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "mul-real") == 0) { } else if (strcmp(opname, "mul-real") == 0) {
emit_opcode(vm, OP_MUL_REAL); emit_opcode(vm, OP_MUL_REAL);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "div-real") == 0) { } else if (strcmp(opname, "div-real") == 0) {
emit_opcode(vm, OP_DIV_REAL); emit_opcode(vm, OP_DIV_REAL);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "int-to-real") == 0) { } else if (strcmp(opname, "int-to-real") == 0) {
emit_opcode(vm, OP_INT_TO_REAL); emit_opcode(vm, OP_INT_TO_REAL);
int dest = parse_register(node->children[0]->token);
int src = parse_register(node->children[1]->token);
emit_byte(vm, dest);
emit_byte(vm, src);
} else if (strcmp(opname, "nat-to-real") == 0) { } else if (strcmp(opname, "nat-to-real") == 0) {
emit_opcode(vm, OP_UINT_TO_REAL); emit_opcode(vm, OP_UINT_TO_REAL);
int dest = parse_register(node->children[0]->token);
int src = parse_register(node->children[1]->token);
emit_byte(vm, dest);
emit_byte(vm, src);
} else if (strcmp(opname, "real-to-int") == 0) { } else if (strcmp(opname, "real-to-int") == 0) {
emit_opcode(vm, OP_REAL_TO_INT); emit_opcode(vm, OP_REAL_TO_INT);
int dest = parse_register(node->children[0]->token);
int src = parse_register(node->children[1]->token);
emit_byte(vm, dest);
emit_byte(vm, src);
} else if (strcmp(opname, "real-to-nat") == 0) { } else if (strcmp(opname, "real-to-nat") == 0) {
emit_opcode(vm, OP_REAL_TO_UINT); emit_opcode(vm, OP_REAL_TO_UINT);
int dest = parse_register(node->children[0]->token);
int src = parse_register(node->children[1]->token);
emit_byte(vm, dest);
emit_byte(vm, src);
} else if (strcmp(opname, "jump-eq-int") == 0) { } else if (strcmp(opname, "jump-eq-int") == 0) {
emit_opcode(vm, OP_JEQ_INT); emit_opcode(vm, OP_JEQ_INT);
u32 addr = resolve_symbol(table, node->children[0]->token); u32 addr = resolve_symbol(table, node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_u32(vm, addr); emit_u32(vm, addr);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "jump-neq-int") == 0) { } else if (strcmp(opname, "jump-neq-int") == 0) {
emit_opcode(vm, OP_JNEQ_INT); emit_opcode(vm, OP_JNEQ_INT);
u32 addr = resolve_symbol(table, node->children[0]->token); u32 addr = resolve_symbol(table, node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_u32(vm, addr); emit_u32(vm, addr);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "jump-gt-int") == 0) { } else if (strcmp(opname, "jump-gt-int") == 0) {
emit_opcode(vm, OP_JGT_INT); emit_opcode(vm, OP_JGT_INT);
u32 addr = resolve_symbol(table, node->children[0]->token); u32 addr = resolve_symbol(table, node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_u32(vm, addr); emit_u32(vm, addr);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "jump-lt-int") == 0) { } else if (strcmp(opname, "jump-lt-int") == 0) {
emit_opcode(vm, OP_JLT_INT); emit_opcode(vm, OP_JLT_INT);
u32 addr = resolve_symbol(table, node->children[0]->token); u32 addr = resolve_symbol(table, node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_u32(vm, addr); emit_u32(vm, addr);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "jump-le-int") == 0) { } else if (strcmp(opname, "jump-le-int") == 0) {
emit_opcode(vm, OP_JLE_INT); emit_opcode(vm, OP_JLE_INT);
u32 addr = resolve_symbol(table, node->children[0]->token); u32 addr = resolve_symbol(table, node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_u32(vm, addr); emit_u32(vm, addr);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "jump-ge-int") == 0) { } else if (strcmp(opname, "jump-ge-int") == 0) {
emit_opcode(vm, OP_JGE_INT); emit_opcode(vm, OP_JGE_INT);
u32 addr = resolve_symbol(table, node->children[0]->token); u32 addr = resolve_symbol(table, node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_u32(vm, addr); emit_u32(vm, addr);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "jump-eq-nat") == 0) { } else if (strcmp(opname, "jump-eq-nat") == 0) {
emit_opcode(vm, OP_JEQ_UINT); emit_opcode(vm, OP_JEQ_UINT);
u32 addr = resolve_symbol(table, node->children[0]->token); u32 addr = resolve_symbol(table, node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_u32(vm, addr); emit_u32(vm, addr);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "jump-neq-nat") == 0) { } else if (strcmp(opname, "jump-neq-nat") == 0) {
emit_opcode(vm, OP_JNEQ_UINT); emit_opcode(vm, OP_JNEQ_UINT);
u32 addr = resolve_symbol(table, node->children[0]->token); u32 addr = resolve_symbol(table, node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_u32(vm, addr); emit_u32(vm, addr);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "jump-gt-nat") == 0) { } else if (strcmp(opname, "jump-gt-nat") == 0) {
emit_opcode(vm, OP_JGT_UINT); emit_opcode(vm, OP_JGT_UINT);
u32 addr = resolve_symbol(table, node->children[0]->token); u32 addr = resolve_symbol(table, node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_u32(vm, addr); emit_u32(vm, addr);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "jump-lt-nat") == 0) { } else if (strcmp(opname, "jump-lt-nat") == 0) {
emit_opcode(vm, OP_JLT_UINT); emit_opcode(vm, OP_JLT_UINT);
u32 addr = resolve_symbol(table, node->children[0]->token); u32 addr = resolve_symbol(table, node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_u32(vm, addr); emit_u32(vm, addr);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "jump-le-nat") == 0) { } else if (strcmp(opname, "jump-le-nat") == 0) {
emit_opcode(vm, OP_JLE_UINT); emit_opcode(vm, OP_JLE_UINT);
u32 addr = resolve_symbol(table, node->children[0]->token); u32 addr = resolve_symbol(table, node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_u32(vm, addr); emit_u32(vm, addr);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "jump-ge-nat") == 0) { } else if (strcmp(opname, "jump-ge-nat") == 0) {
emit_opcode(vm, OP_JGE_UINT); emit_opcode(vm, OP_JGE_UINT);
u32 addr = resolve_symbol(table, node->children[0]->token); u32 addr = resolve_symbol(table, node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_u32(vm, addr); emit_u32(vm, addr);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "jump-eq-real") == 0) { } else if (strcmp(opname, "jump-eq-real") == 0) {
emit_opcode(vm, OP_JEQ_REAL); emit_opcode(vm, OP_JEQ_REAL);
u32 addr = resolve_symbol(table, node->children[0]->token); u32 addr = resolve_symbol(table, node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_u32(vm, addr); emit_u32(vm, addr);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "jump-neq-real") == 0) { } else if (strcmp(opname, "jump-neq-real") == 0) {
emit_opcode(vm, OP_JNEQ_REAL); emit_opcode(vm, OP_JNEQ_REAL);
u32 addr = resolve_symbol(table, node->children[0]->token); u32 addr = resolve_symbol(table, node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_u32(vm, addr); emit_u32(vm, addr);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "jump-gt-real") == 0) { } else if (strcmp(opname, "jump-gt-real") == 0) {
emit_opcode(vm, OP_JGT_REAL); emit_opcode(vm, OP_JGT_REAL);
u32 addr = resolve_symbol(table, node->children[0]->token); u32 addr = resolve_symbol(table, node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_u32(vm, addr); emit_u32(vm, addr);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "jump-lt-real") == 0) { } else if (strcmp(opname, "jump-lt-real") == 0) {
emit_opcode(vm, OP_JLT_REAL); emit_opcode(vm, OP_JLT_REAL);
u32 addr = resolve_symbol(table, node->children[0]->token); u32 addr = resolve_symbol(table, node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_u32(vm, addr); emit_u32(vm, addr);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "jump-le-real") == 0) { } else if (strcmp(opname, "jump-le-real") == 0) {
emit_opcode(vm, OP_JLE_REAL); emit_opcode(vm, OP_JLE_REAL);
u32 addr = resolve_symbol(table, node->children[0]->token); u32 addr = resolve_symbol(table, node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_u32(vm, addr); emit_u32(vm, addr);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "jump-ge-real") == 0) { } else if (strcmp(opname, "jump-ge-real") == 0) {
emit_opcode(vm, OP_JGE_REAL); emit_opcode(vm, OP_JGE_REAL);
u32 addr = resolve_symbol(table, node->children[0]->token); u32 addr = resolve_symbol(table, node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_u32(vm, addr); emit_u32(vm, addr);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "string-length") == 0) { } else if (strcmp(opname, "string-length") == 0) {
emit_opcode(vm, OP_STRLEN); emit_opcode(vm, OP_STRLEN);
int dest = parse_register(node->children[0]->token);
int src = parse_register(node->children[1]->token);
emit_byte(vm, dest);
emit_byte(vm, src);
} else if (strcmp(opname, "string-eq") == 0) { } else if (strcmp(opname, "string-eq") == 0) {
emit_opcode(vm, OP_STREQ); emit_opcode(vm, OP_STREQ);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "string-concat") == 0) { } else if (strcmp(opname, "string-concat") == 0) {
emit_opcode(vm, OP_STRCAT); emit_opcode(vm, OP_STRCAT);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "string-get-char") == 0) { } else if (strcmp(opname, "string-get-char") == 0) {
emit_opcode(vm, OP_STR_GET_CHAR); emit_opcode(vm, OP_STR_GET_CHAR);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "string-find-char") == 0) { } else if (strcmp(opname, "string-find-char") == 0) {
emit_opcode(vm, OP_STR_FIND_CHAR); emit_opcode(vm, OP_STR_FIND_CHAR);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "string-slice") == 0) { } else if (strcmp(opname, "string-slice") == 0) {
emit_opcode(vm, OP_STR_SLICE); emit_opcode(vm, OP_STR_SLICE);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
int src3 = parse_register(node->children[3]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
emit_byte(vm, src2);
emit_byte(vm, src3);
} else if (strcmp(opname, "int-to-string") == 0) { } else if (strcmp(opname, "int-to-string") == 0) {
emit_opcode(vm, OP_INT_TO_STRING); emit_opcode(vm, OP_INT_TO_STRING);
int dest = parse_register(node->children[0]->token);
int src = parse_register(node->children[1]->token);
emit_byte(vm, dest);
emit_byte(vm, src);
} else if (strcmp(opname, "nat-to-string") == 0) { } else if (strcmp(opname, "nat-to-string") == 0) {
emit_opcode(vm, OP_UINT_TO_STRING); emit_opcode(vm, OP_UINT_TO_STRING);
int dest = parse_register(node->children[0]->token);
int src = parse_register(node->children[1]->token);
emit_byte(vm, dest);
emit_byte(vm, src);
} else if (strcmp(opname, "real-to-string") == 0) { } else if (strcmp(opname, "real-to-string") == 0) {
emit_opcode(vm, OP_REAL_TO_STRING); emit_opcode(vm, OP_REAL_TO_STRING);
int dest = parse_register(node->children[0]->token);
int src = parse_register(node->children[1]->token);
emit_byte(vm, dest);
emit_byte(vm, src);
} else if (strcmp(opname, "string-to-int") == 0) { } else if (strcmp(opname, "string-to-int") == 0) {
emit_opcode(vm, OP_STRING_TO_INT); emit_opcode(vm, OP_STRING_TO_INT);
int dest = parse_register(node->children[0]->token);
int src = parse_register(node->children[1]->token);
emit_byte(vm, dest);
emit_byte(vm, src);
} else if (strcmp(opname, "string-to-nat") == 0) { } else if (strcmp(opname, "string-to-nat") == 0) {
emit_opcode(vm, OP_STRING_TO_UINT); emit_opcode(vm, OP_STRING_TO_UINT);
int dest = parse_register(node->children[0]->token);
int src = parse_register(node->children[1]->token);
emit_byte(vm, dest);
emit_byte(vm, src);
} else if (strcmp(opname, "string-to-real") == 0) { } else if (strcmp(opname, "string-to-real") == 0) {
emit_opcode(vm, OP_STRING_TO_REAL); emit_opcode(vm, OP_STRING_TO_REAL);
int dest = parse_register(node->children[0]->token);
int src = parse_register(node->children[1]->token);
emit_byte(vm, dest);
emit_byte(vm, src);
} else { } else {
fprintf(stderr, "Unknown opcode: %s\n", opname); fprintf(stderr, "Unknown opcode: %s\n", opname);
} }

View File

@ -4,85 +4,90 @@
#include "common.h" #include "common.h"
typedef enum { typedef enum {
OP_HALT, /* [obj1 `halt` - | terminate execution with code ] */ OP_HALT, /* halt : terminate execution with code [src1] */
OP_JMP, /* [dest `jump` - | jump to address dest unconditionally ] */ OP_JMP, /* jump : jump to address dest unconditionally */
OP_JMPF, /* [dest `jump-if-flag` - | jump to address dest if flag is ne 0 ] */ OP_JMPF, /* jump-if-flag : jump to address dest if flag is ne 0 */
OP_CALL, /* [&code_ref `call` - | creates a new frame ] */ OP_CALL, /* call : creates a new frame */
OP_RETURN, /* [obj1 `return` - | returns from a frame to the parent frame, pushes obj1 on stack ] */ OP_RETURN, /* return : returns from a frame to the parent frame */
OP_LOAD_8, /* [&dest `load-8` u8 | push memory[obj1] onto stack as u8 ] */ OP_LOAD_IMM, /* load-immediate : dest = constant */
OP_LOAD_16, /* [&dest `load-16` u16 | push memory[obj1] onto stack as u16 ] */ OP_GET_8, /* get-8 : dest = memory[registers[src1]] as u8 */
OP_LOAD_32, /* [&dest `load` u32 | push memory[obj1] onto stack as u32 ] */ OP_GET_16, /* get-16 : dest = memory[registers[src1]] as u8 */
OP_STORE_8, /* [&dest obj1 `store-8` - | memory[dest] = obj1 << 8 ] */ OP_GET_32, /* get : dest = memory[registers[src1]] as u32 */
OP_STORE_16, /* [&dest obj1 `store-16`- | memory[dest] = obj1 << 16 ] */ OP_LOAD_8, /* load-8 : dest = memory[src1 as u32] */
OP_STORE_32, /* [&dest obj1 `store` - | memory[dest] = obj1 ] */ OP_LOAD_16, /* load-16 : dest = memory[src1 as u32] */
OP_MALLOC, /* [size `malloc` ptr | allocate 'size + 4' of memory and push ptr to memory on stack ] */ OP_LOAD_32, /* load : dest = memory[src1 as u32] */
OP_MEMSET_8, /* [ `memset-8` | dest <-> dest+count = obj1 as u8 ] */ OP_STORE_8, /* store-8 : memory[dest] = src1 << 8 */
OP_MEMSET_16, /* [ `memset-16` | dest <-> dest+count = obj1 as u8 ] */ OP_STORE_16, /* store-16 : memory[dest] = src1 << 16 */
OP_MEMSET_32, /* [ `memset-32` | dest <-> dest+count = obj1 as u32 ] */ OP_STORE_32, /* store : memory[dest] = src1 */
OP_PUSH, /* [ `push` | push const of ref ] */ OP_PUT_8, /* put-8 : memory[dest] = registers[src1] << 8 */
OP_POP, /* [ `pop` | pop cosnt or ref ] */ OP_PUT_16, /* put-16 : memory[dest] = registers[src1] << 16*/
OP_DUP, /* [ obj1 `dup` obj1 obj1 | ] */ OP_PUT_32, /* put : memory[dest] = registers[src1] */
OP_EXCH, /* [ obj1 obj2 `exch` obj2 obj1 | ] */ OP_MALLOC, /* malloc : dest = fat ptr to memory of ((src1 as size) + 4) */
OP_OVER, /* [ obj1 obj2 `over` obj1 obj2 obj1 | ] */ OP_MEMSET_8, /* memset-8 : dest <-> dest+count = src1 as u8 */
OP_PICK, /* [ N `pick` objN | ] */ OP_MEMSET_16, /* memset-16 : dest <-> dest+count = src1 as u8 */
OP_ROT, /* [ obj1 obj2 obj3 `rot` obj2 obj3 obj1 | ] */ OP_MEMSET_32, /* memset-32 : dest <-> dest+count = src1 as u32 */
OP_DEPTH, /* [ - `depth` stack_size | ] */ OP_PUSH, /* push : push const of ref */
OP_SYSCALL, /* [ `syscall` | obj1 obj2 obj3 obj4 more? does a system call based on args ] */ OP_POP, /* pop : pop cosnt or ref */
OP_SLL, /* [ `bit-shift-left` | dest = obj1 << obj2 ] */ OP_REG_MOV, /* register-move : dest = src1 */
OP_SRL, /* [ `bit-shift-right` | dest = obj1 >> obj2 ] */ OP_SYSCALL, /* syscall : src1 src2 src3 src4 more? does a system call based on args */
OP_SRE, /* [ `bit-shift-re` | dest as i32 = obj1 >> obj2 ] */ OP_SLL, /* bit-shift-left : dest = src1 << src2 */
OP_BAND, /* [ `bit-and` | dest = obj1 & obj2 ] */ OP_SRL, /* bit-shift-right : dest = src1 >> src2 */
OP_BOR, /* [ `bit-or` | dest = obj1 | obj2 ] */ OP_SRE, /* bit-shift-re : dest as i32 = src1 >> src2 */
OP_BXOR, /* [ `bit-xor` | dest = obj1 ^ obj2 ] */ OP_BAND, /* bit-and : dest = src1 & src2 */
OP_ADD_INT, /* [ `add-int` | dest = obj1 + obj2 ] */ OP_BOR, /* bit-or : dest = src1 | src2 */
OP_SUB_INT, /* [ `sub-int` | dest = obj1 - obj2 ] */ OP_BXOR, /* bit-xor : dest = src1 ^ src2 */
OP_MUL_INT, /* [ `mul-int` | dest = obj1 * obj2 ] */ OP_ADD_INT, /* add-int : dest = src1 + src2 */
OP_DIV_INT, /* [ `div-int` | dest = obj1 / obj2 ] */ OP_SUB_INT, /* sub-int : dest = src1 - src2 */
OP_ADD_UINT, /* [ `add-nat` | dest = obj1 + obj2 ] */ OP_MUL_INT, /* mul-int : dest = src1 * src2 */
OP_SUB_UINT, /* [ `sub-nat` | dest = obj1 - obj2 ] */ OP_DIV_INT, /* div-int : dest = src1 / src2 */
OP_MUL_UINT, /* [ `mul-nat` | dest = obj1 * obj2 ] */ OP_ADD_UINT, /* add-nat : dest = src1 + src2 */
OP_DIV_UINT, /* [ `div-nat` | dest = obj1 / obj2 ] */ OP_SUB_UINT, /* sub-nat : dest = src1 - src2 */
OP_ADD_REAL, /* [ `add-real` | dest = obj1 + obj2 ] */ OP_MUL_UINT, /* mul-nat : dest = src1 * src2 */
OP_SUB_REAL, /* [ `sub-real` | dest = obj1 - obj2 ] */ OP_DIV_UINT, /* div-nat : dest = src1 / src2 */
OP_MUL_REAL, /* [ `mul-real` | dest = obj1 * obj2 ] */ OP_ADD_REAL, /* add-real : dest = src1 + src2 */
OP_DIV_REAL, /* [ `div-real` | dest = obj1 / obj2 ] */ OP_SUB_REAL, /* sub-real : dest = src1 - src2 */
OP_INT_TO_REAL, /* [ `int-to-real` | dest = obj1 as real ] */ OP_MUL_REAL, /* mul-real : dest = src1 * src2 */
OP_UINT_TO_REAL, /* [ `nat-to-real` | dest = obj1 as real ] */ OP_DIV_REAL, /* div-real : dest = src1 / src2 */
OP_REAL_TO_INT, /* [ `real-to-int` | dest = obj1 as int ] */ OP_INT_TO_REAL, /* int-to-real : dest = src1 as real */
OP_REAL_TO_UINT, /* [ `real-to-nat` | dest = obj1 as uint ] */ OP_UINT_TO_REAL, /* nat-to-real : dest = src1 as real */
OP_JEQ_INT, /* [ `jump-eq-int` | jump to address dest if obj1 as int == obj2 as int ] */ OP_REAL_TO_INT, /* real-to-int : dest = src1 as int */
OP_JNEQ_INT, /* [ `jump-neq-int` | jump to address dest if obj1 as int != obj2 as int ] */ OP_REAL_TO_UINT, /* real-to-nat : dest = src1 as uint */
OP_JGT_INT, /* [ `jump-gt-int` | jump to address dest if obj1 as int > obj2 as int ] */ OP_JEQ_INT, /* jump-eq-int : jump to address dest if src1 as int == src2 as int */
OP_JLT_INT, /* [ `jump-lt-int` | jump to address dest if obj1 as int < obj2 as int ] */ OP_JNEQ_INT, /* jump-neq-int : jump to address dest if src1 as int != src2 as int */
OP_JLE_INT, /* [ `jump-le-int` | jump to address dest if obj1 as int <= obj2 as int ] */ OP_JGT_INT, /* jump-gt-int : jump to address dest if src1 as int > src2 as int */
OP_JGE_INT, /* [ `jump-ge-int` | jump to address dest if obj1 as int >= obj2 as int ] */ OP_JLT_INT, /* jump-lt-int : jump to address dest if src1 as int < src2 as int */
OP_JEQ_UINT, /* [ `jump-eq-nat` | jump to address dest if obj1 as uint == obj2 as uint ] */ OP_JLE_INT, /* jump-le-int : jump to address dest if src1 as int <= src2 as int */
OP_JNEQ_UINT, /* [ `jump-neq-nat` | jump to address dest if obj1 as uint != obj2 as uint ] */ OP_JGE_INT, /* jump-ge-int : jump to address dest if src1 as int >= src2 as int */
OP_JGT_UINT, /* [ `jump-gt-nat` | jump to address dest if obj1 as uint > obj2 as uint ] */ OP_JEQ_UINT, /* jump-eq-nat : jump to address dest if src1 as uint == src2 as uint */
OP_JLT_UINT, /* [ `jump-lt-nat` | jump to address dest if obj1 as uint < obj2 as uint ] */ OP_JNEQ_UINT, /* jump-neq-nat : jump to address dest if src1 as uint != src2 as uint */
OP_JLE_UINT, /* [ `jump-le-nat` | jump to address dest if obj1 as uint <= obj2 as uint ] */ OP_JGT_UINT, /* jump-gt-nat : jump to address dest if src1 as uint > src2 as uint */
OP_JGE_UINT, /* [ `jump-ge-nat` | jump to address dest if obj1 as uint >= obj2 as uint ] */ OP_JLT_UINT, /* jump-lt-nat : jump to address dest if src1 as uint < src2 as uint */
OP_JEQ_REAL, /* [ `jump-eq-real` | jump to address dest if obj1 as real == obj2 as real ] */ OP_JLE_UINT, /* jump-le-nat : jump to address dest if src1 as uint <= src2 as uint */
OP_JNEQ_REAL, /* [ `jump-neq-real` | jump to address dest if obj1 as real != obj2 as real ] */ OP_JGE_UINT, /* jump-ge-nat : jump to address dest if src1 as uint >= src2 as uint */
OP_JGE_REAL, /* [ `jump-ge-real` | jump to address dest if obj1 as real >= obj2 as real ] */ OP_JEQ_REAL, /* jump-eq-real : jump to address dest if src1 as real == src2 as real */
OP_JGT_REAL, /* [ `jump-gt-real` | jump to address dest if obj1 as real > obj2 as real ] */ OP_JNEQ_REAL, /* jump-neq-real : jump to address dest if src1 as real != src2 as real */
OP_JLT_REAL, /* [ `jump-lt-real` | jump to address dest if obj1 as real < obj2 as real ] */ OP_JGE_REAL, /* jump-ge-real : jump to address dest if src1 as real >= src2 as real */
OP_JLE_REAL, /* [ `jump-le-real` | jump to address dest if obj1 as real <= obj2 as real ] */ OP_JGT_REAL, /* jump-gt-real : jump to address dest if src1 as real > src2 as real */
OP_STRLEN, /* [&str `string-length` len &str | length of string from str ptr ] */ OP_JLT_REAL, /* jump-lt-real : jump to address dest if src1 as real < src2 as real */
OP_STREQ, /* [ `string-eq` | dest = obj1 ptr string == obj2 ptr string ] */ OP_JLE_REAL, /* jump-le-real : jump to address dest if src1 as real <= src2 as real */
OP_STRCAT, /* [ `string-concat` | dest = ptr of obj1 ptr string + obj2 ptr string ] */ OP_STRLEN, /* string-length : dest = length of str at src1 ptr */
OP_STR_GET_CHAR, /* [ `string-get-char` | dest = ptr of obj1 ptr str, obj2 index of str ] */ OP_STREQ, /* string-eq : dest = src1 ptr string == src2 ptr string */
OP_STR_FIND_CHAR, /* [ `string-find-char` | dest = ptr of obj1 ptr string, obj2 uint8 char ] */ OP_STRCAT, /* string-concat : dest = ptr of src1 ptr string + src2 ptr string */
OP_STR_SLICE, /* [ `string-slice` | dest = ptr of obj1 ptr str, obj2 start index, obj3 end index ] */ OP_STR_GET_CHAR, /* string-get-char : dest = ptr of src1 ptr str, src2 index of str */
OP_INT_TO_STRING, /* [ `int-to-string` | dest = obj1 as str ] */ OP_STR_FIND_CHAR, /* string-find-char : dest = ptr of src1 ptr string, src2 uint8 char */
OP_UINT_TO_STRING, /* [ `nat-to-string` | dest = obj1 as str ] */ OP_STR_SLICE, /* string-slice : dest = ptr of src1 ptr str, src2 start index, src3 end index */
OP_REAL_TO_STRING, /* [ `real-to-string` | dest = obj1 as str ] */ OP_INT_TO_STRING, /* int-to-string : dest = src1 as str */
OP_STRING_TO_INT, /* [ `string-to-int` | dest = obj1 as int ] */ OP_UINT_TO_STRING, /* nat-to-string : dest = src1 as str */
OP_STRING_TO_UINT, /* [ `string-to-nat` | dest = obj1 as uint ] */ OP_REAL_TO_STRING, /* real-to-string : dest = src1 as str */
OP_STRING_TO_REAL /* [ `string-to-real` | dest = obj1 as real ] */ OP_STRING_TO_INT, /* string-to-int : dest = src1 as int */
OP_STRING_TO_UINT, /* string-to-nat : dest = src1 as uint */
OP_STRING_TO_REAL /* string-to-real : dest = src1 as real */
} Opcode; } Opcode;
#define MAX_REGS 32
typedef struct frame_s { typedef struct frame_s {
u32 registers[MAX_REGS]; /* R0-R31 */
u32 rp; /* register pointer (last unused) */
u32 start; /* start and end of global allocated block */ u32 start; /* start and end of global allocated block */
u32 end; u32 end;
} Frame; } Frame;
@ -124,20 +129,20 @@ typedef struct device_s {
#define STACK_SIZE 256 #define STACK_SIZE 256
#define DEVICES_SIZE 8 #define DEVICES_SIZE 8
typedef struct vm_s { typedef struct vm_s {
u32 pc; /* program counter */ u32 pc; /* program counter */
u32 cp; /* code pointer (last allocated opcode) */ u32 cp; /* code pointer (last allocated opcode) */
u32 fp; /* frame pointer (current frame) */ u32 fp; /* frame pointer (current frame) */
u32 sp; /* stack pointer (top of stack) */ u32 sp; /* stack pointer (top of stack) */
u32 rp; /* return stack pointer (top of stack) */ u32 rp; /* return stack pointer (top of stack) */
u32 mp; /* memory pointer (last allocated value) */ u32 mp; /* memory pointer (last allocated value) */
u32 dc; /* device count */ u32 dc; /* device count */
i32 flag; /* flag (temporary results like SYSCALL status) */ i32 flag; /* flag (temporary results like SYSCALL status) */
Frame frames[FRAMES_SIZE]; /* function call frames */ Frame frames[FRAMES_SIZE]; /* function call frames */
u32 stack[STACK_SIZE]; /* main stack */ u32 stack[STACK_SIZE]; /* main stack */
u32 return_stack[FRAMES_SIZE]; /* return stack (for call recursion) */ u32 return_stack[STACK_SIZE]; /* return stack (for call recursion) */
Device devices[DEVICES_SIZE]; /* device definitions */ Device devices[DEVICES_SIZE]; /* device definitions */
u8 code[CODE_SIZE]; /* code block */ u8 code[CODE_SIZE]; /* code block */
u8 memory[MEMORY_SIZE]; /* memory block */ u8 memory[MEMORY_SIZE]; /* memory block */
} VM; } VM;
#define read_u8(vm, location, addr) ((vm)->location[addr]) #define read_u8(vm, location, addr) ((vm)->location[addr])

View File

@ -7,12 +7,17 @@
do { \ do { \
i32 cond; \ i32 cond; \
u32 mask, target; \ u32 mask, target; \
u8 src1, src2; \
type value; \ type value; \
type value2; \ type value2; \
target = read_u32(vm, code, vm->pc); \ target = read_u32(vm, code, vm->pc); \
vm->pc += 4; \ vm->pc += 4; \
value2 = (type)vm->stack[--vm->sp]; \ src1 = read_u8(vm, code, vm->pc); \
value = (type)vm->stack[--vm->sp]; \ vm->pc++; \
src2 = read_u8(vm, code, vm->pc); \
vm->pc++; \
value = (type)frame->registers[src1]; \
value2 = (type)frame->registers[src2]; \
cond = !!(value op value2); \ cond = !!(value op value2); \
mask = -(u32)cond; \ mask = -(u32)cond; \
vm->pc = (target & mask) | (vm->pc & ~mask); \ vm->pc = (target & mask) | (vm->pc & ~mask); \
@ -21,17 +26,26 @@
#define MATH_OP(type, op) \ #define MATH_OP(type, op) \
do { \ do { \
type b = (type)vm->stack[--vm->sp]; \ dest = read_u8(vm, code, vm->pc); \
type a = (type)vm->stack[--vm->sp]; \ vm->pc++; \
vm->stack[vm->sp++] = (type)(a op b); \ src1 = read_u8(vm, code, vm->pc); \
vm->pc++; \
src2 = read_u8(vm, code, vm->pc); \
vm->pc++; \
frame->registers[dest] = \
(type)frame->registers[src1] op(type) frame->registers[src2]; \
return true; \ return true; \
} while (0) } while (0)
#define BIT_OP(op) \ #define BIT_OP(op) \
do { \ do { \
u32 a = vm->stack[--vm->sp]; \ dest = read_u8(vm, code, vm->pc); \
u32 b = vm->stack[--vm->sp]; \ vm->pc++; \
vm->stack[vm->sp++] = a op b; \ src1 = read_u8(vm, code, vm->pc); \
vm->pc++; \
src2 = read_u8(vm, code, vm->pc); \
vm->pc++; \
frame->registers[dest] = frame->registers[src1] op frame->registers[src2]; \
return true; \ return true; \
} while (0) } while (0)
@ -53,9 +67,14 @@ u32 str_alloc(VM *vm, Frame *frame, const char *str, u32 length) {
* Step to the next opcode in the vm. * Step to the next opcode in the vm.
*/ */
bool step_vm(VM *vm) { bool step_vm(VM *vm) {
u16 opcode, dest, src1, src2;
u32 v, ptr;
i32 value;
Frame *frame;
/* Get current instruction & Advance to next instruction */ /* Get current instruction & Advance to next instruction */
u8 opcode = vm->code[vm->pc++]; opcode = vm->code[vm->pc++];
Frame *frame = &vm->frames[vm->fp]; frame = &vm->frames[vm->fp];
switch (opcode) { switch (opcode) {
case OP_HALT: { case OP_HALT: {
@ -71,6 +90,7 @@ bool step_vm(VM *vm) {
return true; return true;
} }
case OP_RETURN: { case OP_RETURN: {
frame->rp = 0; /* reset register ptr */
vm->pc = vm->return_stack[--vm->rp]; /* set pc to return address */ vm->pc = vm->return_stack[--vm->rp]; /* set pc to return address */
vm->mp = vm->mp =
vm->frames[vm->fp--].start; /* reset memory pointer to start vm->frames[vm->fp--].start; /* reset memory pointer to start
@ -78,18 +98,26 @@ bool step_vm(VM *vm) {
return true; return true;
} }
case OP_MALLOC: { case OP_MALLOC: {
u32 size = read_u32(vm, code, vm->pc); u32 size;
dest = read_u8(vm, code, vm->pc);
vm->pc++; vm->pc++;
vm->stack[vm->sp++] = vm->mp; src1 = read_u8(vm, code, vm->pc);
vm->pc++;
frame->registers[dest] = vm->mp;
size = frame->registers[src1];
write_u32(vm, memory, vm->mp, size); write_u32(vm, memory, vm->mp, size);
vm->mp += (size + 4); vm->mp += (size + 4);
return true; return true;
} }
case OP_MEMSET_32: { case OP_MEMSET_32: {
u32 i, start, end; u32 i, start, end;
u32 dest = vm->stack[--vm->sp]; u8 dest_reg = read_u8(vm, code, vm->pc++);
u32 value = vm->stack[--vm->sp]; u8 value_reg = read_u8(vm, code, vm->pc++);
u32 count = vm->stack[--vm->sp]; u8 count_reg = read_u8(vm, code, vm->pc++);
u32 dest = frame->registers[dest_reg];
u32 value = frame->registers[value_reg];
u32 count = frame->registers[count_reg];
if (count == 0) { if (count == 0) {
vm->flag = 1; vm->flag = 1;
@ -99,24 +127,29 @@ bool step_vm(VM *vm) {
start = dest; start = dest;
end = dest + count; end = dest + count;
if (start >= vm->mp || count > vm->mp || end > vm->mp) { if (start >= vm->mp || count > vm->mp ||
end > vm->mp) {
vm->flag = 0; vm->flag = 0;
return true; return true;
} }
for (i = start; i < end; i += 4) { for (i = start; i < end; i+=4) {
write_u32(vm, memory, i, value); write_u32(vm, memory, i, value);
} }
vm->stack[vm->sp++] = dest; frame->registers[0] = dest;
vm->flag = 1; vm->flag = 1;
return true; return true;
} }
case OP_MEMSET_16: { case OP_MEMSET_16: {
u32 i, start, end; u32 i, start, end;
u32 dest = vm->stack[--vm->sp]; u8 dest_reg = read_u8(vm, code, vm->pc++);
u16 value = (u16)(vm->stack[--vm->sp]); u8 value_reg = read_u8(vm, code, vm->pc++);
u32 count = vm->stack[--vm->sp]; u8 count_reg = read_u8(vm, code, vm->pc++);
u32 dest = frame->registers[dest_reg];
u16 value = (u16)(frame->registers[value_reg]);
u32 count = frame->registers[count_reg];
if (count == 0) { if (count == 0) {
vm->flag = 1; vm->flag = 1;
@ -126,24 +159,29 @@ bool step_vm(VM *vm) {
start = dest; start = dest;
end = dest + count; end = dest + count;
if (start >= vm->mp || count > vm->mp || end > vm->mp) { if (start >= vm->mp || count > vm->mp ||
end > vm->mp) {
vm->flag = 0; vm->flag = 0;
return true; return true;
} }
for (i = start; i < end; i += 2) { for (i = start; i < end; i+=2) {
write_u16(vm, memory, i, value); write_u16(vm, memory, i, value);
} }
vm->stack[vm->sp++] = dest; frame->registers[0] = dest;
vm->flag = 1; vm->flag = 1;
return true; return true;
} }
case OP_MEMSET_8: { case OP_MEMSET_8: {
u32 i, start, end; u32 i, start, end;
u32 dest = vm->stack[--vm->sp]; u8 dest_reg = read_u8(vm, code, vm->pc++);
u8 value = (u8)(vm->stack[--vm->sp]); u8 value_reg = read_u8(vm, code, vm->pc++);
u32 count = vm->stack[--vm->sp]; u8 count_reg = read_u8(vm, code, vm->pc++);
u32 dest = frame->registers[dest_reg];
u8 value = (u8)(frame->registers[value_reg]);
u32 count = frame->registers[count_reg];
if (count == 0) { if (count == 0) {
vm->flag = 1; vm->flag = 1;
@ -153,7 +191,8 @@ bool step_vm(VM *vm) {
start = dest; start = dest;
end = dest + count; end = dest + count;
if (start >= vm->mp || count > vm->mp || end > vm->mp) { if (start >= vm->mp || count > vm->mp ||
end > vm->mp) {
vm->flag = 0; vm->flag = 0;
return true; return true;
} }
@ -162,94 +201,169 @@ bool step_vm(VM *vm) {
write_u8(vm, memory, i, value); write_u8(vm, memory, i, value);
} }
vm->stack[vm->sp++] = dest; frame->registers[0] = dest;
vm->flag = 1; vm->flag = 1;
return true; return true;
} }
case OP_LOAD_8: { case OP_LOAD_IMM: {
u32 addr = vm->stack[--vm->sp]; dest = read_u8(vm, code, vm->pc);
vm->stack[vm->sp++] = read_u8(vm, memory, addr); vm->pc++;
return true; v = read_u32(vm, code, vm->pc);
} vm->pc += 4;
case OP_LOAD_16: { frame->registers[dest] = v;
u32 addr = vm->stack[--vm->sp];
vm->stack[vm->sp++] = read_u16(vm, memory, addr);
return true; return true;
} }
case OP_LOAD_32: { case OP_LOAD_32: {
u32 addr = vm->stack[--vm->sp]; dest = read_u8(vm, code, vm->pc);
vm->stack[vm->sp++] = read_u32(vm, memory, addr); vm->pc++;
ptr = read_u32(vm, code, vm->pc);
vm->pc += 4;
v = read_u32(vm, memory, ptr);
frame->registers[dest] = v;
return true; return true;
} }
case OP_STORE_8: { case OP_LOAD_16: {
u8 value = vm->stack[--vm->sp]; dest = read_u8(vm, code, vm->pc);
u32 addr = vm->stack[--vm->sp]; vm->pc++;
write_u8(vm, memory, addr, value); ptr = read_u32(vm, code, vm->pc);
vm->pc += 4;
v = read_u16(vm, memory, ptr);
frame->registers[dest] = v;
return true; return true;
} }
case OP_STORE_16: { case OP_LOAD_8: {
u16 value = vm->stack[--vm->sp]; dest = read_u8(vm, code, vm->pc);
u32 addr = vm->stack[--vm->sp]; vm->pc++;
write_u16(vm, memory, addr, value); ptr = read_u32(vm, code, vm->pc);
vm->pc += 4;
v = read_u8(vm, memory, ptr);
frame->registers[dest] = v;
return true;
}
case OP_GET_32: {
dest = read_u8(vm, code, vm->pc);
vm->pc++;
src1 = read_u8(vm, code, vm->pc);
vm->pc++;
v = frame->registers[src1];
ptr = read_u32(vm, memory, v);
frame->registers[dest] = ptr;
return true;
}
case OP_GET_16: {
u16 v16;
dest = read_u8(vm, code, vm->pc);
vm->pc++;
src1 = read_u8(vm, code, vm->pc);
vm->pc++;
v = frame->registers[src1];
v16 = read_u16(vm, memory, v);
frame->registers[dest] = v16;
return true;
}
case OP_GET_8: {
u8 v8;
dest = read_u8(vm, code, vm->pc);
vm->pc++;
src1 = read_u8(vm, code, vm->pc);
vm->pc++;
v = frame->registers[src1];
v8 = read_u8(vm, memory, v);
frame->registers[dest] = v8;
return true; return true;
} }
case OP_STORE_32: { case OP_STORE_32: {
u32 value = vm->stack[--vm->sp]; dest = read_u8(vm, code, vm->pc);
u32 addr = vm->stack[--vm->sp]; vm->pc++;
write_u32(vm, memory, addr, value); src1 = read_u8(vm, code, vm->pc);
vm->pc++;
v = frame->registers[src1];
ptr = frame->registers[dest];
write_u32(vm, memory, ptr, v);
return true;
}
case OP_STORE_16: {
dest = read_u8(vm, code, vm->pc);
vm->pc++;
src1 = read_u8(vm, code, vm->pc);
vm->pc++;
v = frame->registers[src1];
ptr = frame->registers[dest];
write_u16(vm, memory, ptr, v);
return true;
}
case OP_STORE_8: {
dest = read_u8(vm, code, vm->pc);
vm->pc++;
src1 = read_u8(vm, code, vm->pc);
vm->pc++;
v = frame->registers[src1];
ptr = frame->registers[dest];
write_u8(vm, memory, ptr, v);
return true;
}
case OP_PUT_32: {
dest = read_u8(vm, code, vm->pc);
vm->pc++;
src1 = read_u8(vm, code, vm->pc);
vm->pc++;
ptr = frame->registers[dest];
v = frame->registers[src1];
write_u32(vm, memory, ptr, v);
return true;
}
case OP_PUT_16: {
u16 v16;
dest = read_u8(vm, code, vm->pc);
vm->pc++;
src1 = read_u8(vm, code, vm->pc);
vm->pc++;
ptr = frame->registers[dest];
v16 = frame->registers[src1];
write_u16(vm, memory, ptr, v16);
return true;
}
case OP_PUT_8: {
u8 v8;
dest = read_u8(vm, code, vm->pc);
vm->pc++;
src1 = read_u8(vm, code, vm->pc);
vm->pc++;
ptr = frame->registers[dest];
v8 = frame->registers[src1];
write_u8(vm, memory, ptr, v8);
return true; return true;
} }
case OP_PUSH: { case OP_PUSH: {
u32 val = read_u32(vm, code, vm->pc); dest = read_u8(vm, code, vm->pc);
vm->pc += 4; vm->pc++;
vm->stack[vm->sp++] = val; vm->stack[++vm->sp] = frame->registers[dest];
return true; return true;
} }
case OP_POP: { case OP_POP: {
vm->sp--; dest = read_u8(vm, code, vm->pc);
vm->pc++;
frame->registers[dest] = vm->stack[vm->sp--];
return true; return true;
} }
case OP_DUP: { case OP_REG_MOV: {
u32 a = vm->stack[--vm->sp]; dest = read_u8(vm, code, vm->pc);
vm->stack[vm->sp++] = a; vm->pc++;
vm->stack[vm->sp++] = a; src1 = read_u8(vm, code, vm->pc);
return true; vm->pc++;
} frame->registers[dest] = frame->registers[src1];
case OP_EXCH: {
u32 a = vm->stack[--vm->sp];
u32 b = vm->stack[--vm->sp];
vm->stack[vm->sp++] = b;
vm->stack[vm->sp++] = a;
return true;
}
case OP_OVER: {
u32 a = vm->stack[vm->sp - 1];
vm->stack[vm->sp++] = a;
return true;
}
case OP_PICK: {
u32 n = vm->stack[--vm->sp];
u32 b = vm->stack[vm->sp - n];
vm->stack[vm->sp++] = b;
return true;
}
case OP_ROT: {
return false;
}
case OP_DEPTH: {
u32 a = vm->sp;
vm->stack[vm->sp++] = a;
return true; return true;
} }
case OP_JMP: { case OP_JMP: {
u32 dest = read_u32(vm, code, vm->pc); dest = read_u8(vm, code, vm->pc);
vm->pc += 4; vm->pc++;
vm->pc = dest; /* Jump to address */ vm->pc = frame->registers[dest]; /* Jump to address */
return true; return true;
} }
case OP_JMPF: { /* error handling for syscall, jump if flag == 0 */ case OP_JMPF: { /* error handling for syscall, jump if flag == 0 */
u32 mask, dest = read_u32(vm, code, vm->pc); u32 mask;
vm->pc += 4; dest = read_u8(vm, code, vm->pc);
vm->pc++;
mask = -(u32)(vm->flag == 0); mask = -(u32)(vm->flag == 0);
vm->pc = (dest & mask) | (vm->pc & ~mask); vm->pc = (dest & mask) | (vm->pc & ~mask);
return true; return true;
@ -263,13 +377,22 @@ bool step_vm(VM *vm) {
switch (syscall_id) { switch (syscall_id) {
case SYSCALL_DEVICE_OPEN: { case SYSCALL_DEVICE_OPEN: {
Device *dev; Device *dev;
u32 path_ptr = vm->stack[--vm->sp]; u32 path_ptr, mode;
u32 mode = vm->stack[--vm->sp]; u8 path_reg, mode_reg, dest_reg;
dest_reg = read_u8(vm, code, vm->pc);
vm->pc++;
path_reg = read_u8(vm, code, vm->pc);
vm->pc++;
mode_reg = read_u8(vm, code, vm->pc);
vm->pc++;
path_ptr = frame->registers[path_reg];
mode = frame->registers[mode_reg];
dev = find_device_by_path(vm, (const char *)&vm->memory[path_ptr + 4]); dev = find_device_by_path(vm, (const char *)&vm->memory[path_ptr + 4]);
if (dev) { if (dev) {
if (dev->ops->open) { if (dev->ops->open) {
vm->flag = dev->ops->open(dev->data, mode); vm->flag = dev->ops->open(dev->data, mode);
vm->stack[vm->sp++] = dev->handle; frame->registers[dest_reg] = dev->handle;
} else { } else {
vm->flag = 1; /* success, no open needed */ vm->flag = 1; /* success, no open needed */
} }
@ -282,15 +405,25 @@ bool step_vm(VM *vm) {
case SYSCALL_DEVICE_READ: { case SYSCALL_DEVICE_READ: {
Device *dev; Device *dev;
u32 handle, buffer_ptr, size;
u16 handle_reg, buffer_reg, size_reg;
handle_reg = read_u8(vm, code, vm->pc);
vm->pc++;
buffer_reg = read_u8(vm, code, vm->pc);
vm->pc++;
size_reg = read_u8(vm, code, vm->pc);
vm->pc++;
dest = read_u8(vm, code, vm->pc);
vm->pc++;
u32 handle = vm->stack[--vm->sp]; /* path pointer */ handle = frame->registers[handle_reg]; /* path pointer */
u32 size = vm->stack[--vm->sp]; /* size */ size = frame->registers[size_reg]; /* size */
u32 buffer_ptr = vm->stack[--vm->sp]; buffer_ptr = frame->registers[dest];
dev = &vm->devices[handle]; dev = &vm->devices[handle];
if (dev && dev->ops->read) { if (dev && dev->ops->read) {
vm->flag = dev->ops->read(dev->data, &vm->memory[buffer_ptr + 4], size); vm->flag = dev->ops->read(dev->data, &vm->memory[buffer_ptr + 4], size);
vm->stack[vm->sp++] = buffer_ptr; frame->registers[buffer_reg] = buffer_ptr;
} else { } else {
vm->flag = 0; vm->flag = 0;
} }
@ -300,9 +433,18 @@ bool step_vm(VM *vm) {
case SYSCALL_DEVICE_WRITE: { case SYSCALL_DEVICE_WRITE: {
Device *dev; Device *dev;
u32 handle = vm->stack[--vm->sp]; /* path pointer */ u32 handle, buffer_ptr, size;
u32 size = vm->stack[--vm->sp]; /* size */ u16 handle_reg, buffer_reg, size_reg;
u32 buffer_ptr = vm->stack[--vm->sp]; /* buffer pointer */ handle_reg = read_u8(vm, code, vm->pc);
vm->pc++;
buffer_reg = read_u8(vm, code, vm->pc);
vm->pc++;
size_reg = read_u8(vm, code, vm->pc);
vm->pc++;
handle = frame->registers[handle_reg]; /* R0: path pointer */
buffer_ptr = frame->registers[buffer_reg]; /* R1: buffer pointer */
size = frame->registers[size_reg]; /* R2: size */
dev = &vm->devices[handle]; dev = &vm->devices[handle];
if (dev && dev->ops->write) { if (dev && dev->ops->write) {
@ -317,7 +459,12 @@ bool step_vm(VM *vm) {
case SYSCALL_DEVICE_CLOSE: { case SYSCALL_DEVICE_CLOSE: {
Device *dev; Device *dev;
u32 handle = vm->stack[--vm->sp]; /* path pointer */ u32 handle;
u8 handle_reg;
handle_reg = read_u8(vm, code, vm->pc);
vm->pc++;
handle = frame->registers[handle_reg]; /* R0: path pointer */
dev = &vm->devices[handle]; dev = &vm->devices[handle];
if (dev && dev->ops->close) { if (dev && dev->ops->close) {
@ -332,9 +479,18 @@ bool step_vm(VM *vm) {
case SYSCALL_DEVICE_IOCTL: { case SYSCALL_DEVICE_IOCTL: {
Device *dev; Device *dev;
u32 handle = vm->stack[--vm->sp]; /* device path */ u32 handle, args_ptr, cmd;
u32 cmd = vm->stack[--vm->sp]; /* ioctl command */ u8 handle_reg, cmd_reg, args_ptr_reg;
u32 args_ptr = vm->stack[--vm->sp]; /* args pointer */ handle_reg = read_u8(vm, code, vm->pc);
vm->pc++;
cmd_reg = read_u8(vm, code, vm->pc);
vm->pc++;
args_ptr_reg = read_u8(vm, code, vm->pc);
vm->pc++;
handle = frame->registers[handle_reg]; /* R0: device path */
cmd = frame->registers[cmd_reg]; /* R1: ioctl command */
args_ptr = frame->registers[args_ptr_reg]; /* R2: args pointer */
dev = &vm->devices[handle]; dev = &vm->devices[handle];
if (dev && dev->ops && dev->ops->ioctl) { if (dev && dev->ops && dev->ops->ioctl) {
@ -387,55 +543,92 @@ bool step_vm(VM *vm) {
case OP_DIV_UINT: case OP_DIV_UINT:
MATH_OP(u32, /); MATH_OP(u32, /);
case OP_MUL_REAL: { case OP_MUL_REAL: {
u32 a = vm->stack[--vm->sp]; dest = read_u8(vm, code, vm->pc);
u32 b = (vm->stack[--vm->sp] >> 16); vm->pc++;
vm->stack[vm->sp++] = a * b; src1 = read_u8(vm, code, vm->pc);
vm->pc++;
src2 = read_u8(vm, code, vm->pc);
vm->pc++;
frame->registers[dest] =
(frame->registers[src1] * frame->registers[src2]) >> 16;
return true; return true;
} }
case OP_DIV_REAL: { case OP_DIV_REAL: {
u32 a = vm->stack[--vm->sp] << 16; dest = read_u8(vm, code, vm->pc);
u32 b = vm->stack[--vm->sp]; vm->pc++;
vm->stack[vm->sp++] = a / b; src1 = read_u8(vm, code, vm->pc);
vm->pc++;
src2 = read_u8(vm, code, vm->pc);
vm->pc++;
frame->registers[dest] =
(frame->registers[src1] << 16) / frame->registers[src2];
return true; return true;
} }
case OP_ADD_REAL: { case OP_ADD_REAL: {
u32 a = vm->stack[--vm->sp]; dest = read_u8(vm, code, vm->pc);
u32 b = vm->stack[--vm->sp]; vm->pc++;
vm->stack[vm->sp++] = a + b; src1 = read_u8(vm, code, vm->pc);
vm->pc++;
src2 = read_u8(vm, code, vm->pc);
vm->pc++;
frame->registers[dest] = frame->registers[src1] + frame->registers[src2];
return true; return true;
} }
case OP_SUB_REAL: { case OP_SUB_REAL: {
u32 a = vm->stack[--vm->sp]; dest = read_u8(vm, code, vm->pc);
u32 b = vm->stack[--vm->sp]; vm->pc++;
vm->stack[vm->sp++] = a - b; src1 = read_u8(vm, code, vm->pc);
vm->pc++;
src2 = read_u8(vm, code, vm->pc);
vm->pc++;
frame->registers[dest] = frame->registers[src1] - frame->registers[src2];
return true; return true;
} }
case OP_REAL_TO_INT: { case OP_REAL_TO_INT: {
i32 value = vm->stack[--vm->sp]; dest = read_u8(vm, code, vm->pc);
vm->pc++;
src1 = read_u8(vm, code, vm->pc);
vm->pc++;
value = frame->registers[src1];
if (value >= 0) { if (value >= 0) {
vm->stack[vm->sp++] = value >> 16; frame->registers[dest] = value >> 16;
} else { } else {
vm->stack[vm->sp++] = -((-value) >> 16); frame->registers[dest] = -((-value) >> 16);
} }
return true; return true;
} }
case OP_INT_TO_REAL: { case OP_INT_TO_REAL: {
i32 value = (vm->stack[--vm->sp] << 16); dest = read_u8(vm, code, vm->pc);
vm->stack[vm->sp++] = value; vm->pc++;
src1 = read_u8(vm, code, vm->pc);
vm->pc++;
frame->registers[dest] = (frame->registers[src1] << 16);
return true; return true;
} }
case OP_REAL_TO_UINT: { case OP_REAL_TO_UINT: {
i32 value = vm->stack[--vm->sp]; dest = read_u8(vm, code, vm->pc);
vm->pc++;
src1 = read_u8(vm, code, vm->pc);
vm->pc++;
value = frame->registers[src1];
if (value < 0) { if (value < 0) {
vm->stack[vm->sp++] = 0; frame->registers[dest] = 0;
} else { } else {
vm->stack[vm->sp++] = AS_UINT(value >> 16); frame->registers[dest] = AS_UINT(value >> 16);
} }
return true; return true;
} }
case OP_UINT_TO_REAL: { case OP_UINT_TO_REAL: {
i32 value = AS_INT(vm->stack[--vm->sp] << 16); dest = read_u8(vm, code, vm->pc);
vm->stack[vm->sp++] = value; vm->pc++;
src1 = read_u8(vm, code, vm->pc);
vm->pc++;
frame->registers[dest] = AS_INT(frame->registers[src1] << 16);
return true; return true;
} }
case OP_JEQ_UINT: { case OP_JEQ_UINT: {
@ -494,27 +687,48 @@ bool step_vm(VM *vm) {
} }
case OP_INT_TO_STRING: { case OP_INT_TO_STRING: {
char buffer[32]; char buffer[32];
int_to_string(AS_INT(vm->stack[--vm->sp]), buffer); dest = read_u8(vm, code, vm->pc);
vm->stack[vm->sp++] = str_alloc(vm, frame, buffer, strlength(buffer)); vm->pc++;
src1 = read_u8(vm, code, vm->pc);
vm->pc++;
int_to_string(AS_INT(frame->registers[src1]), buffer);
ptr = str_alloc(vm, frame, buffer, strlength(buffer));
frame->registers[dest] = ptr;
return true; return true;
} }
case OP_UINT_TO_STRING: { case OP_UINT_TO_STRING: {
char buffer[32]; char buffer[32];
uint_to_string(vm->stack[--vm->sp], buffer); dest = read_u8(vm, code, vm->pc);
vm->stack[vm->sp++] = str_alloc(vm, frame, buffer, strlength(buffer)); vm->pc++;
src1 = read_u8(vm, code, vm->pc);
vm->pc++;
uint_to_string(frame->registers[src1], buffer);
ptr = str_alloc(vm, frame, buffer, strlength(buffer));
frame->registers[dest] = ptr;
return true; return true;
} }
case OP_REAL_TO_STRING: { case OP_REAL_TO_STRING: {
char buffer[32]; char buffer[32];
fixed_to_string(AS_INT(vm->stack[--vm->sp]), buffer); dest = read_u8(vm, code, vm->pc);
vm->stack[vm->sp++] = str_alloc( vm->pc++;
vm, frame, buffer, strlength(buffer)); /* copy buffer to dest */ src1 = read_u8(vm, code, vm->pc);
vm->pc++;
fixed_to_string(AS_INT(frame->registers[src1]), buffer);
ptr = str_alloc(vm, frame, buffer,
strlength(buffer)); /* copy buffer to dest */
frame->registers[dest] = ptr;
return true; return true;
} }
case OP_STRLEN: { case OP_STRLEN: {
u32 ptr; u32 ptr, length;
ptr = vm->stack[--vm->sp]; dest = read_u8(vm, code, vm->pc);
vm->stack[vm->sp++] = read_u32(vm, memory, ptr); vm->pc++;
src1 = read_u8(vm, code, vm->pc);
vm->pc++;
ptr = frame->registers[src1];
length = read_u32(vm, memory, ptr);
frame->registers[dest] = length;
return true; return true;
} }
case OP_STRCAT: { case OP_STRCAT: {

View File

@ -1,26 +1,32 @@
((code ((code
(label main (label main
(push 1) (load-immediate $0 1)
(push 1) (push $0)
(load-immediate $0 1)
(push $0)
(call &add) (call &add)
(int-to-string) (pop $0)
(call &pln) (int-to-string $1 $0)
(push $1)
(call &println)
(halt)) (halt))
(label add (label add
(add-int) (pop $0)
(pop $1)
(add-int $2 $1 $0)
(push $2)
(return)) (return))
(label pln (label println
(dup) (load-immediate $0 &terminal-namespace)
(string-length) (syscall OPEN $0 $0 $0)
(push &terminal-namespace) (load-immediate $3 &new-line)
(syscall WRITE) (pop $1)
(push &new-line) (string-length $2 $1)
(dup) (syscall WRITE $0 $1 $2)
(string-length) (string-length $4 $3)
(push &terminal-namespace) (syscall WRITE $0 $3 $4)
(syscall WRITE)
(return))) (return)))
(data (data
(label terminal-namespace "/dev/term/0") (label terminal-namespace "/dev/term/0")

View File

@ -1,44 +1,43 @@
((code ((code
(label main (label main
(push 35) (load-immediate $0 35)
(call &fib) (push $0)
(int-to-string) (call &fib)
(call &pln) (pop $0)
(halt)) (int-to-string $1 $0)
(push $1)
(label fib (call &pln)
(dup) ; dup num (halt))
(push 2) ; Base case: n < 2 (label fib
(jump-lt-int &base-case) (pop $0)
(load-immediate $1 2)
(dup) (jump-lt-int &base-case $0 $1)
(push 2) ; First call: fib(n-2) (load-immediate $3 2)
(sub-int) ; n - 2 (sub-int $4 $0 $3)
(call &fib) (push $4)
(call &fib)
(over) ; get n over the previous answer (load-immediate $3 1)
(push 1) ; Second call: fib(n-1) (sub-int $4 $0 $3)
(sub-int) ; n-1 (using saved n) (push $4)
(call &fib) ; Result in $2 (call &fib)
(pop $4)
; Combine results (pop $5)
(add-int) ; fib(n-2) + fib(n-1) (add-int $6 $5 $4)
(return) ; Return result (push $6)
(return)
(label base-case (label base-case
(return))) ; Return n directly (push $0)
(return)))
(label pln (label pln
(dup) (load-immediate $0 &terminal-namespace)
(string-length) (syscall OPEN $0 $0 $0)
(push &terminal-namespace) (load-immediate $3 &new-line)
(syscall WRITE) (pop $1)
(push &new-line) (string-length $2 $1)
(dup) (syscall WRITE $0 $1 $2)
(string-length) (string-length $4 $3)
(push &terminal-namespace) (syscall WRITE $0 $3 $4)
(syscall WRITE)
(return))) (return)))
(data (data
(label terminal-namespace "/dev/term/0") (label terminal-namespace "/dev/term/0")
(label new-line "\n"))) (label new-line "\n")))