wip stack oriented VM

This commit is contained in:
zongor 2025-10-12 22:11:54 -07:00
parent 4d82914f3c
commit 4e5ebdb749
7 changed files with 423 additions and 975 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 VM written in freestanding C89, has a CISC like instruction format of one byte opcode and a variable byte operand. 32 general purpose registers. It runs on the =Reality Engine=, a 32 bit stack based VM written in freestanding C89.
* 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-immediate $0 &terminal-namespace) ; load terminal namespace (load &terminal-namespace) ; load terminal namespace
(load-immediate $1 &hello-str) ; load hello string ptr (load &hello-str) ; load hello string ptr
(string-length $2 $1) ; get length to write to stdout (string-length) ; get length to write to stdout
(syscall WRITE $0 $1 $2) ; do the write syscall (syscall WRITE) ; 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

@ -260,79 +260,87 @@ void register_sdl_devices(VM *vm) {
vm_register_device(vm, "/dev/keyboard/0", "keyboard", &keyboard_data, vm_register_device(vm, "/dev/keyboard/0", "keyboard", &keyboard_data,
&keyboard_ops); &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[] = {[OP_HALT] = "halt", static const char *names[] = {
[OP_JMP] = "jump", [OP_HALT] = "halt",
[OP_JMPF] = "jump-if-flag", [OP_JMP] = "jump",
[OP_CALL] = "call", [OP_JMPF] = "jump-if-flag",
[OP_RETURN] = "return", [OP_CALL] = "call",
[OP_LOAD] = "load", [OP_RETURN] = "return",
[OP_LOAD_REG] = "get", [OP_LOAD_8] = "load-8",
[OP_LOAD_REG8] = "get-8", [OP_LOAD_16] = "load-16",
[OP_LOADI8] = "load-i8", [OP_LOAD_32] = "load",
[OP_LOADU8] = "load-u8", [OP_STORE_8] = "store-8",
[OP_LOADI16] = "load-i16", [OP_STORE_16] = "store-16",
[OP_LOADU16] = "load-u16", [OP_STORE_32] = "store",
[OP_LOAD_IMM] = "load-immediate", [OP_MALLOC] = "malloc",
[OP_MALLOC] = "malloc", [OP_MEMSET_8] = "memset-8",
[OP_STORE] = "store", [OP_MEMSET_16] = "memset-16",
[OP_STORE8] = "store-8", [OP_MEMSET_32] = "memset",
[OP_STORE16] = "store-16", [OP_PUSH] = "push",
[OP_PUSH] = "push", [OP_POP] = "pop",
[OP_POP] = "pop", [OP_DUP] = "dup",
[OP_REG_MOV] = "register-move", [OP_EXCH] = "exch",
[OP_SYSCALL] = "syscall", [OP_OVER] = "over",
[OP_SLL] = "bit-shift-left", [OP_PICK] = "pick",
[OP_SRL] = "bit-shift-right", [OP_ROT] = "rot",
[OP_SRE] = "bit-shift-right-extend", [OP_DEPTH] = "depth",
[OP_BAND] = "bit-and", [OP_SYSCALL] = "syscall",
[OP_BOR] = "bit-or", [OP_SLL] = "bit-shift-left",
[OP_BXOR] = "bit-xor", [OP_SRL] = "bit-shift-right",
[OP_ADD_INT] = "add-int", [OP_SRE] = "bit-shift-re",
[OP_SUB_INT] = "sub-int", [OP_BAND] = "bit-and",
[OP_MUL_INT] = "mul-int", [OP_BOR] = "bit-or",
[OP_DIV_INT] = "div-int", [OP_BXOR] = "bit-xor",
[OP_ADD_UINT] = "add-nat", [OP_ADD_INT] = "add-int",
[OP_SUB_UINT] = "sub-nat", [OP_SUB_INT] = "sub-int",
[OP_MUL_UINT] = "mul-nat", [OP_MUL_INT] = "mul-int",
[OP_DIV_UINT] = "div-nat", [OP_DIV_INT] = "div-int",
[OP_ADD_REAL] = "add-real", [OP_ADD_UINT] = "add-nat",
[OP_SUB_REAL] = "sub-real", [OP_SUB_UINT] = "sub-nat",
[OP_MUL_REAL] = "mul-real", [OP_MUL_UINT] = "mul-nat",
[OP_DIV_REAL] = "div-real", [OP_DIV_UINT] = "div-nat",
[OP_INT_TO_REAL] = "int-to-real", [OP_ADD_REAL] = "add-real",
[OP_UINT_TO_REAL] = "nat-to-real", [OP_SUB_REAL] = "sub-real",
[OP_REAL_TO_INT] = "real-to-int", [OP_MUL_REAL] = "mul-real",
[OP_REAL_TO_UINT] = "real-to-nat", [OP_DIV_REAL] = "div-real",
[OP_JEQ_INT] = "jump-eq-int", [OP_INT_TO_REAL] = "int-to-real",
[OP_JGT_INT] = "jump-gt-int", [OP_UINT_TO_REAL] = "nat-to-real",
[OP_JLT_INT] = "jump-lt-int", [OP_REAL_TO_INT] = "real-to-int",
[OP_JLE_INT] = "jump-le-int", [OP_REAL_TO_UINT] = "real-to-nat",
[OP_JGE_INT] = "jump-ge-int", [OP_JEQ_INT] = "jump-eq-int",
[OP_JEQ_UINT] = "jump-eq-nat", [OP_JNEQ_INT] = "jump-neq-int",
[OP_JGT_UINT] = "jump-gt-nat", [OP_JGT_INT] = "jump-gt-int",
[OP_JLT_UINT] = "jump-lt-nat", [OP_JLT_INT] = "jump-lt-int",
[OP_JLE_UINT] = "jump-le-nat", [OP_JLE_INT] = "jump-le-int",
[OP_JGE_UINT] = "jump-ge-nat", [OP_JGE_INT] = "jump-ge-int",
[OP_JEQ_REAL] = "jump-eq-real", [OP_JEQ_UINT] = "jump-eq-nat",
[OP_JGE_REAL] = "jump-ge-real", [OP_JNEQ_UINT] = "jump-neq-nat",
[OP_JGT_REAL] = "jump-gt-real", [OP_JGT_UINT] = "jump-gt-nat",
[OP_JLT_REAL] = "jump-lt-real", [OP_JLT_UINT] = "jump-lt-nat",
[OP_JLE_REAL] = "jump-le-real", [OP_JLE_UINT] = "jump-le-nat",
[OP_STRLEN] = "string-length", [OP_JGE_UINT] = "jump-ge-nat",
[OP_STREQ] = "string-eq", [OP_JEQ_REAL] = "jump-eq-real",
[OP_STRCAT] = "string-concat", [OP_JNEQ_REAL] = "jump-neq-real",
[OP_STR_GET_CHAR] = "string-get-char", [OP_JGE_REAL] = "jump-ge-real",
[OP_STR_FIND_CHAR] = "string-find-char", [OP_JGT_REAL] = "jump-gt-real",
[OP_STR_SLICE] = "string-slice", [OP_JLT_REAL] = "jump-lt-real",
[OP_INT_TO_STRING] = "int-to-string", [OP_JLE_REAL] = "jump-le-real",
[OP_UINT_TO_STRING] = "nat-to-string", [OP_STRLEN] = "string-length",
[OP_REAL_TO_STRING] = "real-to-string", [OP_STREQ] = "string-eq",
[OP_STRING_TO_INT] = "string-to-int", [OP_STRCAT] = "string-concat",
[OP_STRING_TO_UINT] = "string-to-nat", [OP_STR_GET_CHAR] = "string-get-char",
[OP_STRING_TO_REAL] = "string-to-real"}; [OP_STR_FIND_CHAR] = "string-find-char",
[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,59 +70,43 @@ 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 ||
return 1; strcmp(opname, "pop") == 0 || strcmp(opname, "malloc") == 0 ||
} strcmp(opname, "int-to-string") == 0 || strcmp(opname, "dup") == 0 ||
strcmp(opname, "get-8") == 0 || strcmp(opname, "nat-to-string") == 0 ||
// Register-based opcodes (2 bytes: opcode + register) strcmp(opname, "get-16") == 0 || strcmp(opname, "real-to-string") == 0 ||
if (strcmp(opname, "pop") == 0 || strcmp(opname, "jump-if-flag") == 0 || strcmp(opname, "get") == 0 || strcmp(opname, "int-to-real") == 0 ||
strcmp(opname, "jump") == 0 || strcmp(opname, "push") == 0) { strcmp(opname, "put-8") == 0 || strcmp(opname, "nat-to-real") == 0 ||
return 2; strcmp(opname, "put-16") == 0 || strcmp(opname, "real-to-int") == 0 ||
} 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, "malloc") == 0) { strcmp(opname, "register-move") == 0 || strcmp(opname, "add-int") == 0 ||
return 3; strcmp(opname, "sub-int") == 0 || strcmp(opname, "mul-int") == 0 ||
} strcmp(opname, "div-int") == 0 || strcmp(opname, "add-nat") == 0 ||
strcmp(opname, "sub-nat") == 0 || strcmp(opname, "mul-nat") == 0 ||
// Register-register-register opcodes (4 bytes: 1 + 3) strcmp(opname, "div-nat") == 0 || strcmp(opname, "add-real") == 0 ||
if (strcmp(opname, "add-int") == 0 || strcmp(opname, "sub-int") == 0 || strcmp(opname, "sub-real") == 0 || strcmp(opname, "over") == 0 ||
strcmp(opname, "mul-int") == 0 || strcmp(opname, "div-int") == 0 || strcmp(opname, "bit-shift-left") == 0 || strcmp(opname, "exch") == 0 ||
strcmp(opname, "add-nat") == 0 || strcmp(opname, "sub-nat") == 0 || strcmp(opname, "bit-shift-right") == 0 || strcmp(opname, "pick") == 0 ||
strcmp(opname, "mul-nat") == 0 || strcmp(opname, "div-nat") == 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-and") == 0 || strcmp(opname, "bit-or") == 0 ||
strcmp(opname, "bit-xor") == 0 || strcmp(opname, "mul-real") == 0 || strcmp(opname, "bit-xor") == 0 || strcmp(opname, "mul-real") == 0 ||
strcmp(opname, "div-real") == 0) { strcmp(opname, "div-real") == 0 || strcmp(opname, "load") == 0 ||
return 4; 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;
} }
// (5 bytes: 1 + 4) // multibyte opcodes (5 bytes: opcode + u32)
if (strcmp(opname, "call") == 0) { if (strcmp(opname, "call") == 0 ||
return 5; strcmp(opname, "push") == 0 ||
} strcmp(opname, "jump") == 0 ||
strcmp(opname, "jump-if-flag") == 0 ||
// Load, Load-immediate (6 bytes: 1 + 1 + 4) strcmp(opname, "jump-eq-int") == 0 ||
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 ||
@ -140,13 +124,7 @@ 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 7; return 5;
}
// 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);
@ -236,6 +214,11 @@ 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;
@ -243,12 +226,6 @@ 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] == '&') {
@ -434,110 +411,46 @@ 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_8); emit_opcode(vm, OP_LOAD_16);
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_8); emit_opcode(vm, OP_LOAD_32);
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);
int dest = parse_register(node->children[0]->token); u32 addr = resolve_symbol(table, node->children[0]->token);
int src1 = parse_register(node->children[1]->token); emit_u32(vm, addr);
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, "push") == 0) { } else if (strcmp(opname, "push") == 0) {
emit_opcode(vm, OP_PUSH); emit_opcode(vm, OP_PUSH);
int reg = parse_register(node->children[0]->token); u32 value = resolve_symbol(table, node->children[0]->token);
emit_byte(vm, reg); emit_u32(vm, value);
} else if (strcmp(opname, "pop") == 0) { } else if (strcmp(opname, "pop") == 0) {
emit_opcode(vm, OP_POP); emit_opcode(vm, OP_POP);
int reg = parse_register(node->children[0]->token); } else if (strcmp(opname, "dup") == 0) {
emit_byte(vm, reg); emit_opcode(vm, OP_DUP);
} else if (strcmp(opname, "register-move") == 0) { } else if (strcmp(opname, "over") == 0) {
emit_opcode(vm, OP_REG_MOV); emit_opcode(vm, OP_OVER);
int dest = parse_register(node->children[0]->token); } else if (strcmp(opname, "rot") == 0 ) {
int src = parse_register(node->children[1]->token); emit_opcode(vm, OP_ROT);
emit_byte(vm, dest); } else if (strcmp(opname, "depth") == 0) {
emit_byte(vm, src); emit_opcode(vm, OP_DEPTH);
} 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);
@ -559,407 +472,146 @@ 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,90 +4,85 @@
#include "common.h" #include "common.h"
typedef enum { typedef enum {
OP_HALT, /* halt : terminate execution with code [src1] */ OP_HALT, /* [obj1 `halt` - | terminate execution with code ] */
OP_JMP, /* jump : jump to address dest unconditionally */ OP_JMP, /* [dest `jump` - | jump to address dest unconditionally ] */
OP_JMPF, /* jump-if-flag : jump to address dest if flag is ne 0 */ OP_JMPF, /* [dest `jump-if-flag` - | jump to address dest if flag is ne 0 ] */
OP_CALL, /* call : creates a new frame */ OP_CALL, /* [&code_ref `call` - | creates a new frame ] */
OP_RETURN, /* return : returns from a frame to the parent frame */ OP_RETURN, /* [obj1 `return` - | returns from a frame to the parent frame, pushes obj1 on stack ] */
OP_LOAD_IMM, /* load-immediate : dest = constant */ OP_LOAD_8, /* [&dest `load-8` u8 | push memory[obj1] onto stack as u8 ] */
OP_GET_8, /* get-8 : dest = memory[registers[src1]] as u8 */ OP_LOAD_16, /* [&dest `load-16` u16 | push memory[obj1] onto stack as u16 ] */
OP_GET_16, /* get-16 : dest = memory[registers[src1]] as u8 */ OP_LOAD_32, /* [&dest `load` u32 | push memory[obj1] onto stack as u32 ] */
OP_GET_32, /* get : dest = memory[registers[src1]] as u32 */ OP_STORE_8, /* [&dest obj1 `store-8` - | memory[dest] = obj1 << 8 ] */
OP_LOAD_8, /* load-8 : dest = memory[src1 as u32] */ OP_STORE_16, /* [&dest obj1 `store-16`- | memory[dest] = obj1 << 16 ] */
OP_LOAD_16, /* load-16 : dest = memory[src1 as u32] */ OP_STORE_32, /* [&dest obj1 `store` - | memory[dest] = obj1 ] */
OP_LOAD_32, /* load : dest = memory[src1 as u32] */ OP_MALLOC, /* [size `malloc` ptr | allocate 'size + 4' of memory and push ptr to memory on stack ] */
OP_STORE_8, /* store-8 : memory[dest] = src1 << 8 */ OP_MEMSET_8, /* [ `memset-8` | dest <-> dest+count = obj1 as u8 ] */
OP_STORE_16, /* store-16 : memory[dest] = src1 << 16 */ OP_MEMSET_16, /* [ `memset-16` | dest <-> dest+count = obj1 as u8 ] */
OP_STORE_32, /* store : memory[dest] = src1 */ OP_MEMSET_32, /* [ `memset-32` | dest <-> dest+count = obj1 as u32 ] */
OP_PUT_8, /* put-8 : memory[dest] = registers[src1] << 8 */ OP_PUSH, /* [ `push` | push const of ref ] */
OP_PUT_16, /* put-16 : memory[dest] = registers[src1] << 16*/ OP_POP, /* [ `pop` | pop cosnt or ref ] */
OP_PUT_32, /* put : memory[dest] = registers[src1] */ OP_DUP, /* [ obj1 `dup` obj1 obj1 | ] */
OP_MALLOC, /* malloc : dest = fat ptr to memory of ((src1 as size) + 4) */ OP_EXCH, /* [ obj1 obj2 `exch` obj2 obj1 | ] */
OP_MEMSET_8, /* memset-8 : dest <-> dest+count = src1 as u8 */ OP_OVER, /* [ obj1 obj2 `over` obj1 obj2 obj1 | ] */
OP_MEMSET_16, /* memset-16 : dest <-> dest+count = src1 as u8 */ OP_PICK, /* [ N `pick` objN | ] */
OP_MEMSET_32, /* memset-32 : dest <-> dest+count = src1 as u32 */ OP_ROT, /* [ obj1 obj2 obj3 `rot` obj2 obj3 obj1 | ] */
OP_PUSH, /* push : push const of ref */ OP_DEPTH, /* [ - `depth` stack_size | ] */
OP_POP, /* pop : pop cosnt or ref */ OP_SYSCALL, /* [ `syscall` | obj1 obj2 obj3 obj4 more? does a system call based on args ] */
OP_REG_MOV, /* register-move : dest = src1 */ OP_SLL, /* [ `bit-shift-left` | dest = obj1 << obj2 ] */
OP_SYSCALL, /* syscall : src1 src2 src3 src4 more? does a system call based on args */ OP_SRL, /* [ `bit-shift-right` | dest = obj1 >> obj2 ] */
OP_SLL, /* bit-shift-left : dest = src1 << src2 */ OP_SRE, /* [ `bit-shift-re` | dest as i32 = obj1 >> obj2 ] */
OP_SRL, /* bit-shift-right : dest = src1 >> src2 */ OP_BAND, /* [ `bit-and` | dest = obj1 & obj2 ] */
OP_SRE, /* bit-shift-re : dest as i32 = src1 >> src2 */ OP_BOR, /* [ `bit-or` | dest = obj1 | obj2 ] */
OP_BAND, /* bit-and : dest = src1 & src2 */ OP_BXOR, /* [ `bit-xor` | dest = obj1 ^ obj2 ] */
OP_BOR, /* bit-or : dest = src1 | src2 */ OP_ADD_INT, /* [ `add-int` | dest = obj1 + obj2 ] */
OP_BXOR, /* bit-xor : dest = src1 ^ src2 */ OP_SUB_INT, /* [ `sub-int` | dest = obj1 - obj2 ] */
OP_ADD_INT, /* add-int : dest = src1 + src2 */ OP_MUL_INT, /* [ `mul-int` | dest = obj1 * obj2 ] */
OP_SUB_INT, /* sub-int : dest = src1 - src2 */ OP_DIV_INT, /* [ `div-int` | dest = obj1 / obj2 ] */
OP_MUL_INT, /* mul-int : dest = src1 * src2 */ OP_ADD_UINT, /* [ `add-nat` | dest = obj1 + obj2 ] */
OP_DIV_INT, /* div-int : dest = src1 / src2 */ OP_SUB_UINT, /* [ `sub-nat` | dest = obj1 - obj2 ] */
OP_ADD_UINT, /* add-nat : dest = src1 + src2 */ OP_MUL_UINT, /* [ `mul-nat` | dest = obj1 * obj2 ] */
OP_SUB_UINT, /* sub-nat : dest = src1 - src2 */ OP_DIV_UINT, /* [ `div-nat` | dest = obj1 / obj2 ] */
OP_MUL_UINT, /* mul-nat : dest = src1 * src2 */ OP_ADD_REAL, /* [ `add-real` | dest = obj1 + obj2 ] */
OP_DIV_UINT, /* div-nat : dest = src1 / src2 */ OP_SUB_REAL, /* [ `sub-real` | dest = obj1 - obj2 ] */
OP_ADD_REAL, /* add-real : dest = src1 + src2 */ OP_MUL_REAL, /* [ `mul-real` | dest = obj1 * obj2 ] */
OP_SUB_REAL, /* sub-real : dest = src1 - src2 */ OP_DIV_REAL, /* [ `div-real` | dest = obj1 / obj2 ] */
OP_MUL_REAL, /* mul-real : dest = src1 * src2 */ OP_INT_TO_REAL, /* [ `int-to-real` | dest = obj1 as real ] */
OP_DIV_REAL, /* div-real : dest = src1 / src2 */ OP_UINT_TO_REAL, /* [ `nat-to-real` | dest = obj1 as real ] */
OP_INT_TO_REAL, /* int-to-real : dest = src1 as real */ OP_REAL_TO_INT, /* [ `real-to-int` | dest = obj1 as int ] */
OP_UINT_TO_REAL, /* nat-to-real : dest = src1 as real */ OP_REAL_TO_UINT, /* [ `real-to-nat` | dest = obj1 as uint ] */
OP_REAL_TO_INT, /* real-to-int : dest = src1 as int */ OP_JEQ_INT, /* [ `jump-eq-int` | jump to address dest if obj1 as int == obj2 as int ] */
OP_REAL_TO_UINT, /* real-to-nat : dest = src1 as uint */ OP_JNEQ_INT, /* [ `jump-neq-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_JGT_INT, /* [ `jump-gt-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_JLT_INT, /* [ `jump-lt-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_JLE_INT, /* [ `jump-le-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_JGE_INT, /* [ `jump-ge-int` | jump to address dest if obj1 as int >= obj2 as int ] */
OP_JLE_INT, /* jump-le-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_JGE_INT, /* jump-ge-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_JEQ_UINT, /* jump-eq-nat : jump to address dest if src1 as uint == src2 as uint */ OP_JGT_UINT, /* [ `jump-gt-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_JLT_UINT, /* [ `jump-lt-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_JLE_UINT, /* [ `jump-le-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_JGE_UINT, /* [ `jump-ge-nat` | jump to address dest if obj1 as uint >= obj2 as uint ] */
OP_JLE_UINT, /* jump-le-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_JGE_UINT, /* jump-ge-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_JEQ_REAL, /* jump-eq-real : jump to address dest if src1 as real == src2 as real */ OP_JGE_REAL, /* [ `jump-ge-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_JGT_REAL, /* [ `jump-gt-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_JLT_REAL, /* [ `jump-lt-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_JLE_REAL, /* [ `jump-le-real` | jump to address dest if obj1 as real <= obj2 as real ] */
OP_JLT_REAL, /* jump-lt-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_JLE_REAL, /* jump-le-real : jump to address dest if src1 as real <= src2 as real */ OP_STREQ, /* [ `string-eq` | dest = obj1 ptr string == obj2 ptr string ] */
OP_STRLEN, /* string-length : dest = length of str at src1 ptr */ OP_STRCAT, /* [ `string-concat` | dest = ptr of obj1 ptr string + obj2 ptr string ] */
OP_STREQ, /* string-eq : dest = src1 ptr string == src2 ptr string */ OP_STR_GET_CHAR, /* [ `string-get-char` | dest = ptr of obj1 ptr str, obj2 index of str ] */
OP_STRCAT, /* string-concat : dest = ptr of src1 ptr string + src2 ptr string */ OP_STR_FIND_CHAR, /* [ `string-find-char` | dest = ptr of obj1 ptr string, obj2 uint8 char ] */
OP_STR_GET_CHAR, /* string-get-char : dest = ptr of src1 ptr str, src2 index of str */ OP_STR_SLICE, /* [ `string-slice` | dest = ptr of obj1 ptr str, obj2 start index, obj3 end index ] */
OP_STR_FIND_CHAR, /* string-find-char : dest = ptr of src1 ptr string, src2 uint8 char */ OP_INT_TO_STRING, /* [ `int-to-string` | dest = obj1 as str ] */
OP_STR_SLICE, /* string-slice : dest = ptr of src1 ptr str, src2 start index, src3 end index */ OP_UINT_TO_STRING, /* [ `nat-to-string` | dest = obj1 as str ] */
OP_INT_TO_STRING, /* int-to-string : dest = src1 as str */ OP_REAL_TO_STRING, /* [ `real-to-string` | dest = obj1 as str ] */
OP_UINT_TO_STRING, /* nat-to-string : dest = src1 as str */ OP_STRING_TO_INT, /* [ `string-to-int` | dest = obj1 as int ] */
OP_REAL_TO_STRING, /* real-to-string : dest = src1 as str */ OP_STRING_TO_UINT, /* [ `string-to-nat` | dest = obj1 as uint ] */
OP_STRING_TO_INT, /* string-to-int : dest = src1 as int */ OP_STRING_TO_REAL /* [ `string-to-real` | dest = obj1 as real ] */
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;
@ -128,20 +123,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[STACK_SIZE]; /* return stack (for call recursion) */ u32 return_stack[FRAMES_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,17 +7,12 @@
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; \
src1 = read_u8(vm, code, vm->pc); \ value2 = (type)vm->stack[--vm->sp]; \
vm->pc++; \ value = (type)vm->stack[--vm->sp]; \
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); \
@ -26,26 +21,17 @@
#define MATH_OP(type, op) \ #define MATH_OP(type, op) \
do { \ do { \
dest = read_u8(vm, code, vm->pc); \ type b = (type)vm->stack[--vm->sp]; \
vm->pc++; \ type a = (type)vm->stack[--vm->sp]; \
src1 = read_u8(vm, code, vm->pc); \ vm->stack[vm->sp++] = (type)(a op b); \
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 { \
dest = read_u8(vm, code, vm->pc); \ u32 a = vm->stack[--vm->sp]; \
vm->pc++; \ u32 b = vm->stack[--vm->sp]; \
src1 = read_u8(vm, code, vm->pc); \ vm->stack[vm->sp++] = a op b; \
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)
@ -67,14 +53,9 @@ 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 */
opcode = vm->code[vm->pc++]; u8 opcode = vm->code[vm->pc++];
frame = &vm->frames[vm->fp]; Frame *frame = &vm->frames[vm->fp];
switch (opcode) { switch (opcode) {
case OP_HALT: { case OP_HALT: {
@ -90,7 +71,6 @@ 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
@ -98,26 +78,18 @@ bool step_vm(VM *vm) {
return true; return true;
} }
case OP_MALLOC: { case OP_MALLOC: {
u32 size; u32 size = read_u32(vm, code, vm->pc);
dest = read_u8(vm, code, vm->pc);
vm->pc++; vm->pc++;
src1 = read_u8(vm, code, vm->pc); vm->stack[vm->sp++] = vm->mp;
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;
u8 dest_reg = read_u8(vm, code, vm->pc++); u32 dest = vm->stack[--vm->sp];
u8 value_reg = read_u8(vm, code, vm->pc++); u32 value = vm->stack[--vm->sp];
u8 count_reg = read_u8(vm, code, vm->pc++); u32 count = vm->stack[--vm->sp];
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;
@ -127,29 +99,24 @@ bool step_vm(VM *vm) {
start = dest; start = dest;
end = dest + count; end = dest + count;
if (start >= vm->mp || count > vm->mp || if (start >= vm->mp || count > vm->mp || end > 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);
} }
frame->registers[0] = dest; vm->stack[vm->sp++] = 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;
u8 dest_reg = read_u8(vm, code, vm->pc++); u32 dest = vm->stack[--vm->sp];
u8 value_reg = read_u8(vm, code, vm->pc++); u16 value = (u16)(vm->stack[--vm->sp]);
u8 count_reg = read_u8(vm, code, vm->pc++); u32 count = vm->stack[--vm->sp];
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;
@ -159,29 +126,24 @@ bool step_vm(VM *vm) {
start = dest; start = dest;
end = dest + count; end = dest + count;
if (start >= vm->mp || count > vm->mp || if (start >= vm->mp || count > vm->mp || end > 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);
} }
frame->registers[0] = dest; vm->stack[vm->sp++] = 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;
u8 dest_reg = read_u8(vm, code, vm->pc++); u32 dest = vm->stack[--vm->sp];
u8 value_reg = read_u8(vm, code, vm->pc++); u8 value = (u8)(vm->stack[--vm->sp]);
u8 count_reg = read_u8(vm, code, vm->pc++); u32 count = vm->stack[--vm->sp];
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;
@ -191,8 +153,7 @@ bool step_vm(VM *vm) {
start = dest; start = dest;
end = dest + count; end = dest + count;
if (start >= vm->mp || count > vm->mp || if (start >= vm->mp || count > vm->mp || end > vm->mp) {
end > vm->mp) {
vm->flag = 0; vm->flag = 0;
return true; return true;
} }
@ -201,169 +162,94 @@ bool step_vm(VM *vm) {
write_u8(vm, memory, i, value); write_u8(vm, memory, i, value);
} }
frame->registers[0] = dest; vm->stack[vm->sp++] = dest;
vm->flag = 1; vm->flag = 1;
return true; return true;
} }
case OP_LOAD_IMM: { case OP_LOAD_8: {
dest = read_u8(vm, code, vm->pc); u32 addr = vm->stack[--vm->sp];
vm->pc++; vm->stack[vm->sp++] = read_u8(vm, memory, addr);
v = read_u32(vm, code, vm->pc);
vm->pc += 4;
frame->registers[dest] = v;
return true;
}
case OP_LOAD_32: {
dest = read_u8(vm, code, vm->pc);
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_LOAD_16: { case OP_LOAD_16: {
dest = read_u8(vm, code, vm->pc); u32 addr = vm->stack[--vm->sp];
vm->pc++; vm->stack[vm->sp++] = read_u16(vm, memory, addr);
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_LOAD_8: { case OP_LOAD_32: {
dest = read_u8(vm, code, vm->pc); u32 addr = vm->stack[--vm->sp];
vm->pc++; vm->stack[vm->sp++] = read_u32(vm, memory, addr);
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;
}
case OP_STORE_32: {
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_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; return true;
} }
case OP_STORE_8: { case OP_STORE_8: {
dest = read_u8(vm, code, vm->pc); u8 value = vm->stack[--vm->sp];
vm->pc++; u32 addr = vm->stack[--vm->sp];
src1 = read_u8(vm, code, vm->pc); write_u8(vm, memory, addr, value);
vm->pc++;
v = frame->registers[src1];
ptr = frame->registers[dest];
write_u8(vm, memory, ptr, v);
return true; return true;
} }
case OP_PUT_32: { case OP_STORE_16: {
dest = read_u8(vm, code, vm->pc); u16 value = vm->stack[--vm->sp];
vm->pc++; u32 addr = vm->stack[--vm->sp];
src1 = read_u8(vm, code, vm->pc); write_u16(vm, memory, addr, value);
vm->pc++;
ptr = frame->registers[dest];
v = frame->registers[src1];
write_u32(vm, memory, ptr, v);
return true; return true;
} }
case OP_PUT_16: { case OP_STORE_32: {
u16 v16; 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++;
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: {
dest = read_u8(vm, code, vm->pc); u32 val = read_u32(vm, code, vm->pc);
vm->pc++; vm->pc += 4;
vm->stack[++vm->sp] = frame->registers[dest]; vm->stack[vm->sp++] = val;
return true; return true;
} }
case OP_POP: { case OP_POP: {
dest = read_u8(vm, code, vm->pc); vm->sp--;
vm->pc++;
frame->registers[dest] = vm->stack[vm->sp--];
return true; return true;
} }
case OP_REG_MOV: { case OP_DUP: {
dest = read_u8(vm, code, vm->pc); u32 a = vm->stack[--vm->sp];
vm->pc++; vm->stack[vm->sp++] = a;
src1 = read_u8(vm, code, vm->pc); vm->stack[vm->sp++] = a;
vm->pc++; return true;
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: {
dest = read_u8(vm, code, vm->pc); u32 dest = read_u32(vm, code, vm->pc);
vm->pc++; vm->pc += 4;
vm->pc = frame->registers[dest]; /* Jump to address */ vm->pc = 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; u32 mask, dest = read_u32(vm, code, vm->pc);
dest = read_u8(vm, code, vm->pc); vm->pc += 4;
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;
@ -377,15 +263,8 @@ 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, mode; u32 path_ptr = vm->stack[--vm->sp];
u8 path_reg, mode_reg; u32 mode = vm->stack[--vm->sp];
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) {
@ -402,25 +281,15 @@ bool step_vm(VM *vm) {
case SYSCALL_DEVICE_READ: { case SYSCALL_DEVICE_READ: {
Device *dev; Device *dev;
u32 path_ptr, buffer_ptr, size;
u16 path_reg, buffer_reg, size_reg;
path_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++;
path_ptr = frame->registers[path_reg]; /* path pointer */ u32 path_ptr = vm->stack[--vm->sp]; /* path pointer */
size = frame->registers[size_reg]; /* size */ u32 size = vm->stack[--vm->sp]; /* size */
buffer_ptr = frame->registers[dest]; u32 buffer_ptr = vm->stack[--vm->sp];
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 && 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);
frame->registers[buffer_reg] = buffer_ptr; vm->stack[vm->sp++] = buffer_ptr;
} else { } else {
vm->flag = 0; vm->flag = 0;
} }
@ -430,18 +299,9 @@ bool step_vm(VM *vm) {
case SYSCALL_DEVICE_WRITE: { case SYSCALL_DEVICE_WRITE: {
Device *dev; Device *dev;
u32 path_ptr, buffer_ptr, size; u32 path_ptr = vm->stack[--vm->sp]; /* path pointer */
u16 path_reg, buffer_reg, size_reg; u32 size = vm->stack[--vm->sp]; /* size */
path_reg = read_u8(vm, code, vm->pc); u32 buffer_ptr = vm->stack[--vm->sp]; /* buffer pointer */
vm->pc++;
buffer_reg = read_u8(vm, code, vm->pc);
vm->pc++;
size_reg = read_u8(vm, code, vm->pc);
vm->pc++;
path_ptr = frame->registers[path_reg]; /* R0: path pointer */
buffer_ptr = frame->registers[buffer_reg]; /* R1: buffer pointer */
size = frame->registers[size_reg]; /* R2: size */
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 && dev->ops->write) { if (dev && dev->ops->write) {
@ -456,12 +316,7 @@ bool step_vm(VM *vm) {
case SYSCALL_DEVICE_CLOSE: { case SYSCALL_DEVICE_CLOSE: {
Device *dev; Device *dev;
u32 path_ptr; u32 path_ptr = vm->stack[--vm->sp]; /* path pointer */
u8 path_reg;
path_reg = read_u8(vm, code, vm->pc);
vm->pc++;
path_ptr = frame->registers[path_reg]; /* R0: path pointer */
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]);
@ -477,18 +332,9 @@ bool step_vm(VM *vm) {
case SYSCALL_DEVICE_IOCTL: { case SYSCALL_DEVICE_IOCTL: {
Device *dev; Device *dev;
u32 path_ptr, args_ptr, cmd; u32 path_ptr = vm->stack[--vm->sp]; /* device path */
u8 path_reg, cmd_reg, args_ptr_reg; u32 cmd = vm->stack[--vm->sp]; /* ioctl command */
path_reg = read_u8(vm, code, vm->pc); u32 args_ptr = vm->stack[--vm->sp]; /* args pointer */
vm->pc++;
cmd_reg = read_u8(vm, code, vm->pc);
vm->pc++;
args_ptr_reg = read_u8(vm, code, vm->pc);
vm->pc++;
path_ptr = frame->registers[path_reg]; /* R0: device path */
cmd = frame->registers[cmd_reg]; /* R1: ioctl command */
args_ptr = frame->registers[args_ptr_reg]; /* R2: args pointer */
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]);
@ -542,92 +388,55 @@ 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: {
dest = read_u8(vm, code, vm->pc); u32 a = vm->stack[--vm->sp];
vm->pc++; u32 b = (vm->stack[--vm->sp] >> 16);
src1 = read_u8(vm, code, vm->pc); vm->stack[vm->sp++] = a * b;
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: {
dest = read_u8(vm, code, vm->pc); u32 a = vm->stack[--vm->sp] << 16;
vm->pc++; u32 b = vm->stack[--vm->sp];
src1 = read_u8(vm, code, vm->pc); vm->stack[vm->sp++] = a / b;
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: {
dest = read_u8(vm, code, vm->pc); u32 a = vm->stack[--vm->sp];
vm->pc++; u32 b = vm->stack[--vm->sp];
src1 = read_u8(vm, code, vm->pc); vm->stack[vm->sp++] = a + b;
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: {
dest = read_u8(vm, code, vm->pc); u32 a = vm->stack[--vm->sp];
vm->pc++; u32 b = vm->stack[--vm->sp];
src1 = read_u8(vm, code, vm->pc); vm->stack[vm->sp++] = a - b;
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: {
dest = read_u8(vm, code, vm->pc); i32 value = vm->stack[--vm->sp];
vm->pc++;
src1 = read_u8(vm, code, vm->pc);
vm->pc++;
value = frame->registers[src1];
if (value >= 0) { if (value >= 0) {
frame->registers[dest] = value >> 16; vm->stack[vm->sp++] = value >> 16;
} else { } else {
frame->registers[dest] = -((-value) >> 16); vm->stack[vm->sp++] = -((-value) >> 16);
} }
return true; return true;
} }
case OP_INT_TO_REAL: { case OP_INT_TO_REAL: {
dest = read_u8(vm, code, vm->pc); i32 value = (vm->stack[--vm->sp] << 16);
vm->pc++; vm->stack[vm->sp++] = value;
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: {
dest = read_u8(vm, code, vm->pc); i32 value = vm->stack[--vm->sp];
vm->pc++;
src1 = read_u8(vm, code, vm->pc);
vm->pc++;
value = frame->registers[src1];
if (value < 0) { if (value < 0) {
frame->registers[dest] = 0; vm->stack[vm->sp++] = 0;
} else { } else {
frame->registers[dest] = AS_UINT(value >> 16); vm->stack[vm->sp++] = AS_UINT(value >> 16);
} }
return true; return true;
} }
case OP_UINT_TO_REAL: { case OP_UINT_TO_REAL: {
dest = read_u8(vm, code, vm->pc); i32 value = AS_INT(vm->stack[--vm->sp] << 16);
vm->pc++; vm->stack[vm->sp++] = value;
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: {
@ -686,48 +495,27 @@ bool step_vm(VM *vm) {
} }
case OP_INT_TO_STRING: { case OP_INT_TO_STRING: {
char buffer[32]; char buffer[32];
dest = read_u8(vm, code, vm->pc); int_to_string(AS_INT(vm->stack[--vm->sp]), buffer);
vm->pc++; vm->stack[vm->sp++] = str_alloc(vm, frame, buffer, strlength(buffer));
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];
dest = read_u8(vm, code, vm->pc); uint_to_string(vm->stack[--vm->sp], buffer);
vm->pc++; vm->stack[vm->sp++] = str_alloc(vm, frame, buffer, strlength(buffer));
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];
dest = read_u8(vm, code, vm->pc); fixed_to_string(AS_INT(vm->stack[--vm->sp]), buffer);
vm->pc++; vm->stack[vm->sp++] = str_alloc(
src1 = read_u8(vm, code, vm->pc); vm, frame, buffer, strlength(buffer)); /* copy buffer to dest */
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, length; u32 ptr;
dest = read_u8(vm, code, vm->pc); ptr = vm->stack[--vm->sp];
vm->pc++; vm->stack[vm->sp++] = read_u32(vm, memory, ptr);
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,24 +1,27 @@
(module add ((code
(const terminal-namespace "/dev/term/0") (label main
(const new-line "\n") (push 1)
(push 1)
(fn :1 main () (call &add)
(load-immediate $0 1) (int-to-string)
(load-immediate $1 1) (call &pln)
(call &add ($0 $1) $2)
(int-to-string $1 $2)
(call &pln ($1))
(halt)) (halt))
(label add
(add-int)
(return))
(fn :1 add ($0 $1) (label pln
(add-int $2 $1 $0) (dup)
(return $2)) (string-length)
(push &terminal-namespace)
(fn :1 pln ($1) (syscall WRITE)
(load-immediate $0 &terminal-namespace) (push &new-line)
(load-immediate $3 &new-line) (dup)
(string-length $2 $1) (string-length)
(syscall WRITE $0 $1 $2) (push &terminal-namespace)
(string-length $4 $3) (syscall WRITE)
(syscall WRITE $0 $3 $4)
(return))) (return)))
(data
(label terminal-namespace "/dev/term/0")
(label new-line "\n")))

View File

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