From 4e5ebdb7496b159d0e2bd8ef0202ab1fc9af4ab3 Mon Sep 17 00:00:00 2001 From: zongor Date: Sun, 12 Oct 2025 22:11:54 -0700 Subject: [PATCH] wip stack oriented VM --- README.org | 12 +- src/arch/linux/main.c | 150 ++++++------- src/tools/assembler.c | 452 +++++---------------------------------- src/vm/opcodes.h | 183 ++++++++-------- src/vm/vm.c | 476 ++++++++++++------------------------------ test/add.asm.lisp | 45 ++-- test/fib.asm.lisp | 80 +++---- 7 files changed, 423 insertions(+), 975 deletions(-) diff --git a/README.org b/README.org index 56778d8..2261377 100644 --- a/README.org +++ b/README.org @@ -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 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 @@ -58,11 +58,11 @@ The Undâr compiler will be written in Sċieppan, as well as core VM tests. #+BEGIN_SRC lisp ((code (label main - (load-immediate $0 &terminal-namespace) ; load terminal namespace - (load-immediate $1 &hello-str) ; load hello string ptr - (string-length $2 $1) ; get length to write to stdout - (syscall WRITE $0 $1 $2) ; do the write syscall - (halt))) ; done + (load &terminal-namespace) ; load terminal namespace + (load &hello-str) ; load hello string ptr + (string-length) ; get length to write to stdout + (syscall WRITE) ; do the write syscall + (halt))) ; done (data (label terminal-namespace "/dev/term/0") (label hello-str "nuqneH 'u'?\n"))) diff --git a/src/arch/linux/main.c b/src/arch/linux/main.c index 57ffc12..de78fb5 100644 --- a/src/arch/linux/main.c +++ b/src/arch/linux/main.c @@ -260,79 +260,87 @@ void register_sdl_devices(VM *vm) { vm_register_device(vm, "/dev/keyboard/0", "keyboard", &keyboard_data, &keyboard_ops); } - +#define ASM_DEBUG #ifdef ASM_DEBUG const char *opcode_to_string(Opcode op) { - static const char *names[] = {[OP_HALT] = "halt", - [OP_JMP] = "jump", - [OP_JMPF] = "jump-if-flag", - [OP_CALL] = "call", - [OP_RETURN] = "return", - [OP_LOAD] = "load", - [OP_LOAD_REG] = "get", - [OP_LOAD_REG8] = "get-8", - [OP_LOADI8] = "load-i8", - [OP_LOADU8] = "load-u8", - [OP_LOADI16] = "load-i16", - [OP_LOADU16] = "load-u16", - [OP_LOAD_IMM] = "load-immediate", - [OP_MALLOC] = "malloc", - [OP_STORE] = "store", - [OP_STORE8] = "store-8", - [OP_STORE16] = "store-16", - [OP_PUSH] = "push", - [OP_POP] = "pop", - [OP_REG_MOV] = "register-move", - [OP_SYSCALL] = "syscall", - [OP_SLL] = "bit-shift-left", - [OP_SRL] = "bit-shift-right", - [OP_SRE] = "bit-shift-right-extend", - [OP_BAND] = "bit-and", - [OP_BOR] = "bit-or", - [OP_BXOR] = "bit-xor", - [OP_ADD_INT] = "add-int", - [OP_SUB_INT] = "sub-int", - [OP_MUL_INT] = "mul-int", - [OP_DIV_INT] = "div-int", - [OP_ADD_UINT] = "add-nat", - [OP_SUB_UINT] = "sub-nat", - [OP_MUL_UINT] = "mul-nat", - [OP_DIV_UINT] = "div-nat", - [OP_ADD_REAL] = "add-real", - [OP_SUB_REAL] = "sub-real", - [OP_MUL_REAL] = "mul-real", - [OP_DIV_REAL] = "div-real", - [OP_INT_TO_REAL] = "int-to-real", - [OP_UINT_TO_REAL] = "nat-to-real", - [OP_REAL_TO_INT] = "real-to-int", - [OP_REAL_TO_UINT] = "real-to-nat", - [OP_JEQ_INT] = "jump-eq-int", - [OP_JGT_INT] = "jump-gt-int", - [OP_JLT_INT] = "jump-lt-int", - [OP_JLE_INT] = "jump-le-int", - [OP_JGE_INT] = "jump-ge-int", - [OP_JEQ_UINT] = "jump-eq-nat", - [OP_JGT_UINT] = "jump-gt-nat", - [OP_JLT_UINT] = "jump-lt-nat", - [OP_JLE_UINT] = "jump-le-nat", - [OP_JGE_UINT] = "jump-ge-nat", - [OP_JEQ_REAL] = "jump-eq-real", - [OP_JGE_REAL] = "jump-ge-real", - [OP_JGT_REAL] = "jump-gt-real", - [OP_JLT_REAL] = "jump-lt-real", - [OP_JLE_REAL] = "jump-le-real", - [OP_STRLEN] = "string-length", - [OP_STREQ] = "string-eq", - [OP_STRCAT] = "string-concat", - [OP_STR_GET_CHAR] = "string-get-char", - [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"}; + static const char *names[] = { + [OP_HALT] = "halt", + [OP_JMP] = "jump", + [OP_JMPF] = "jump-if-flag", + [OP_CALL] = "call", + [OP_RETURN] = "return", + [OP_LOAD_8] = "load-8", + [OP_LOAD_16] = "load-16", + [OP_LOAD_32] = "load", + [OP_STORE_8] = "store-8", + [OP_STORE_16] = "store-16", + [OP_STORE_32] = "store", + [OP_MALLOC] = "malloc", + [OP_MEMSET_8] = "memset-8", + [OP_MEMSET_16] = "memset-16", + [OP_MEMSET_32] = "memset", + [OP_PUSH] = "push", + [OP_POP] = "pop", + [OP_DUP] = "dup", + [OP_EXCH] = "exch", + [OP_OVER] = "over", + [OP_PICK] = "pick", + [OP_ROT] = "rot", + [OP_DEPTH] = "depth", + [OP_SYSCALL] = "syscall", + [OP_SLL] = "bit-shift-left", + [OP_SRL] = "bit-shift-right", + [OP_SRE] = "bit-shift-re", + [OP_BAND] = "bit-and", + [OP_BOR] = "bit-or", + [OP_BXOR] = "bit-xor", + [OP_ADD_INT] = "add-int", + [OP_SUB_INT] = "sub-int", + [OP_MUL_INT] = "mul-int", + [OP_DIV_INT] = "div-int", + [OP_ADD_UINT] = "add-nat", + [OP_SUB_UINT] = "sub-nat", + [OP_MUL_UINT] = "mul-nat", + [OP_DIV_UINT] = "div-nat", + [OP_ADD_REAL] = "add-real", + [OP_SUB_REAL] = "sub-real", + [OP_MUL_REAL] = "mul-real", + [OP_DIV_REAL] = "div-real", + [OP_INT_TO_REAL] = "int-to-real", + [OP_UINT_TO_REAL] = "nat-to-real", + [OP_REAL_TO_INT] = "real-to-int", + [OP_REAL_TO_UINT] = "real-to-nat", + [OP_JEQ_INT] = "jump-eq-int", + [OP_JNEQ_INT] = "jump-neq-int", + [OP_JGT_INT] = "jump-gt-int", + [OP_JLT_INT] = "jump-lt-int", + [OP_JLE_INT] = "jump-le-int", + [OP_JGE_INT] = "jump-ge-int", + [OP_JEQ_UINT] = "jump-eq-nat", + [OP_JNEQ_UINT] = "jump-neq-nat", + [OP_JGT_UINT] = "jump-gt-nat", + [OP_JLT_UINT] = "jump-lt-nat", + [OP_JLE_UINT] = "jump-le-nat", + [OP_JGE_UINT] = "jump-ge-nat", + [OP_JEQ_REAL] = "jump-eq-real", + [OP_JNEQ_REAL] = "jump-neq-real", + [OP_JGE_REAL] = "jump-ge-real", + [OP_JGT_REAL] = "jump-gt-real", + [OP_JLT_REAL] = "jump-lt-real", + [OP_JLE_REAL] = "jump-le-real", + [OP_STRLEN] = "string-length", + [OP_STREQ] = "string-eq", + [OP_STRCAT] = "string-concat", + [OP_STR_GET_CHAR] = "string-get-char", + [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]))) { return ""; diff --git a/src/tools/assembler.c b/src/tools/assembler.c index 5bb1a38..1733915 100644 --- a/src/tools/assembler.c +++ b/src/tools/assembler.c @@ -70,59 +70,43 @@ int get_instruction_byte_size(ExprNode *node) { const char *opname = node->token; // Simple opcodes (1 byte) - if (strcmp(opname, "halt") == 0 || strcmp(opname, "return") == 0) { - return 1; - } - - // Register-based opcodes (2 bytes: opcode + register) - if (strcmp(opname, "pop") == 0 || strcmp(opname, "jump-if-flag") == 0 || - strcmp(opname, "jump") == 0 || strcmp(opname, "push") == 0) { - return 2; - } - - 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 || + if (strcmp(opname, "halt") == 0 || strcmp(opname, "return") == 0 || + 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 || + 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, "string-length") == 0 || strcmp(opname, "store") == 0 || strcmp(opname, "store-8") == 0 || strcmp(opname, "store-16") == 0 || strcmp(opname, "memset") == 0 || strcmp(opname, "memset") == 0 || strcmp(opname, "memset-8") == 0 || strcmp(opname, "memset-16") == 0 || - strcmp(opname, "register-move") == 0 || strcmp(opname, "malloc") == 0) { - return 3; - } - - // Register-register-register opcodes (4 bytes: 1 + 3) - if (strcmp(opname, "add-int") == 0 || 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 || 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, "register-move") == 0 || strcmp(opname, "add-int") == 0 || + 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 || + 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) { - return 4; + 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; } - // (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 || + // multibyte opcodes (5 bytes: opcode + u32) + if (strcmp(opname, "call") == 0 || + strcmp(opname, "push") == 0 || + strcmp(opname, "jump") == 0 || + strcmp(opname, "jump-if-flag") == 0 || + strcmp(opname, "jump-eq-int") == 0 || strcmp(opname, "jump-neq-int") == 0 || strcmp(opname, "jump-gt-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-le-real") == 0 || strcmp(opname, "jump-ge-real") == 0) { - 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); + return 5; } 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_u16(VM *vm, u16 value) { + write_u16(vm, code, vm->cp, value); + vm->cp += 4; +} + void emit_u32(VM *vm, u32 value) { write_u32(vm, code, vm->cp, value); 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); } -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) { // Handle symbol references (e.g., &label) if (ref[0] == '&') { @@ -434,110 +411,46 @@ void process_code_expr(VM *vm, SymbolTable *table, ExprNode *node) { emit_u32(vm, addr); } else if (strcmp(opname, "return") == 0) { 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) { 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) { - 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); + emit_opcode(vm, OP_LOAD_16); } else if (strcmp(opname, "load") == 0) { - 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); + emit_opcode(vm, OP_LOAD_32); } else if (strcmp(opname, "malloc") == 0) { emit_opcode(vm, OP_MALLOC); - int dest = parse_register(node->children[0]->token); - int src1 = parse_register(node->children[1]->token); - emit_byte(vm, dest); - emit_byte(vm, src1); + u32 addr = resolve_symbol(table, node->children[0]->token); + emit_u32(vm, addr); } else if (strcmp(opname, "memset-8") == 0) { 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) { 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) { 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) { 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) { 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) { 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) { emit_opcode(vm, OP_PUSH); - int reg = parse_register(node->children[0]->token); - emit_byte(vm, reg); + u32 value = resolve_symbol(table, node->children[0]->token); + emit_u32(vm, value); } else if (strcmp(opname, "pop") == 0) { emit_opcode(vm, OP_POP); - int reg = parse_register(node->children[0]->token); - emit_byte(vm, reg); - } else if (strcmp(opname, "register-move") == 0) { - emit_opcode(vm, OP_REG_MOV); - 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, "dup") == 0) { + emit_opcode(vm, OP_DUP); + } else if (strcmp(opname, "over") == 0) { + emit_opcode(vm, OP_OVER); + } else if (strcmp(opname, "rot") == 0 ) { + emit_opcode(vm, OP_ROT); + } else if (strcmp(opname, "depth") == 0) { + 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) { 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 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { emit_opcode(vm, OP_JEQ_INT); 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_byte(vm, src1); - emit_byte(vm, src2); } else if (strcmp(opname, "jump-neq-int") == 0) { emit_opcode(vm, OP_JNEQ_INT); 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_byte(vm, src1); - emit_byte(vm, src2); } else if (strcmp(opname, "jump-gt-int") == 0) { emit_opcode(vm, OP_JGT_INT); 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_byte(vm, src1); - emit_byte(vm, src2); } else if (strcmp(opname, "jump-lt-int") == 0) { emit_opcode(vm, OP_JLT_INT); 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_byte(vm, src1); - emit_byte(vm, src2); } else if (strcmp(opname, "jump-le-int") == 0) { emit_opcode(vm, OP_JLE_INT); 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_byte(vm, src1); - emit_byte(vm, src2); } else if (strcmp(opname, "jump-ge-int") == 0) { emit_opcode(vm, OP_JGE_INT); 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_byte(vm, src1); - emit_byte(vm, src2); } else if (strcmp(opname, "jump-eq-nat") == 0) { emit_opcode(vm, OP_JEQ_UINT); 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_byte(vm, src1); - emit_byte(vm, src2); } else if (strcmp(opname, "jump-neq-nat") == 0) { emit_opcode(vm, OP_JNEQ_UINT); 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_byte(vm, src1); - emit_byte(vm, src2); } else if (strcmp(opname, "jump-gt-nat") == 0) { emit_opcode(vm, OP_JGT_UINT); 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_byte(vm, src1); - emit_byte(vm, src2); } else if (strcmp(opname, "jump-lt-nat") == 0) { emit_opcode(vm, OP_JLT_UINT); 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_byte(vm, src1); - emit_byte(vm, src2); } else if (strcmp(opname, "jump-le-nat") == 0) { emit_opcode(vm, OP_JLE_UINT); 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_byte(vm, src1); - emit_byte(vm, src2); } else if (strcmp(opname, "jump-ge-nat") == 0) { emit_opcode(vm, OP_JGE_UINT); 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_byte(vm, src1); - emit_byte(vm, src2); } else if (strcmp(opname, "jump-eq-real") == 0) { emit_opcode(vm, OP_JEQ_REAL); 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_byte(vm, src1); - emit_byte(vm, src2); } else if (strcmp(opname, "jump-neq-real") == 0) { emit_opcode(vm, OP_JNEQ_REAL); 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_byte(vm, src1); - emit_byte(vm, src2); } else if (strcmp(opname, "jump-gt-real") == 0) { emit_opcode(vm, OP_JGT_REAL); 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_byte(vm, src1); - emit_byte(vm, src2); } else if (strcmp(opname, "jump-lt-real") == 0) { emit_opcode(vm, OP_JLT_REAL); 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_byte(vm, src1); - emit_byte(vm, src2); } else if (strcmp(opname, "jump-le-real") == 0) { emit_opcode(vm, OP_JLE_REAL); 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_byte(vm, src1); - emit_byte(vm, src2); } else if (strcmp(opname, "jump-ge-real") == 0) { emit_opcode(vm, OP_JGE_REAL); 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_byte(vm, src1); - emit_byte(vm, src2); } else if (strcmp(opname, "string-length") == 0) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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 { fprintf(stderr, "Unknown opcode: %s\n", opname); } diff --git a/src/vm/opcodes.h b/src/vm/opcodes.h index 332fec7..04aa1bf 100644 --- a/src/vm/opcodes.h +++ b/src/vm/opcodes.h @@ -4,90 +4,85 @@ #include "common.h" typedef enum { - OP_HALT, /* halt : terminate execution with code [src1] */ - OP_JMP, /* jump : jump to address dest unconditionally */ - OP_JMPF, /* jump-if-flag : jump to address dest if flag is ne 0 */ - OP_CALL, /* call : creates a new frame */ - OP_RETURN, /* return : returns from a frame to the parent frame */ - OP_LOAD_IMM, /* load-immediate : dest = constant */ - OP_GET_8, /* get-8 : dest = memory[registers[src1]] as u8 */ - OP_GET_16, /* get-16 : dest = memory[registers[src1]] as u8 */ - OP_GET_32, /* get : dest = memory[registers[src1]] as u32 */ - OP_LOAD_8, /* load-8 : dest = memory[src1 as u32] */ - OP_LOAD_16, /* load-16 : dest = memory[src1 as u32] */ - OP_LOAD_32, /* load : dest = memory[src1 as u32] */ - OP_STORE_8, /* store-8 : memory[dest] = src1 << 8 */ - OP_STORE_16, /* store-16 : memory[dest] = src1 << 16 */ - OP_STORE_32, /* store : memory[dest] = src1 */ - OP_PUT_8, /* put-8 : memory[dest] = registers[src1] << 8 */ - OP_PUT_16, /* put-16 : memory[dest] = registers[src1] << 16*/ - OP_PUT_32, /* put : memory[dest] = registers[src1] */ - OP_MALLOC, /* malloc : dest = fat ptr to memory of ((src1 as size) + 4) */ - OP_MEMSET_8, /* memset-8 : dest <-> dest+count = src1 as u8 */ - OP_MEMSET_16, /* memset-16 : dest <-> dest+count = src1 as u8 */ - OP_MEMSET_32, /* memset-32 : dest <-> dest+count = src1 as u32 */ - OP_PUSH, /* push : push const of ref */ - OP_POP, /* pop : pop cosnt or ref */ - OP_REG_MOV, /* register-move : dest = src1 */ - OP_SYSCALL, /* syscall : src1 src2 src3 src4 more? does a system call based on args */ - OP_SLL, /* bit-shift-left : dest = src1 << src2 */ - OP_SRL, /* bit-shift-right : dest = src1 >> src2 */ - OP_SRE, /* bit-shift-re : dest as i32 = src1 >> src2 */ - OP_BAND, /* bit-and : dest = src1 & src2 */ - OP_BOR, /* bit-or : dest = src1 | src2 */ - OP_BXOR, /* bit-xor : dest = src1 ^ src2 */ - OP_ADD_INT, /* add-int : dest = src1 + src2 */ - OP_SUB_INT, /* sub-int : dest = src1 - src2 */ - OP_MUL_INT, /* mul-int : dest = src1 * src2 */ - OP_DIV_INT, /* div-int : dest = src1 / src2 */ - OP_ADD_UINT, /* add-nat : dest = src1 + src2 */ - OP_SUB_UINT, /* sub-nat : dest = src1 - src2 */ - OP_MUL_UINT, /* mul-nat : dest = src1 * src2 */ - OP_DIV_UINT, /* div-nat : dest = src1 / src2 */ - OP_ADD_REAL, /* add-real : dest = src1 + src2 */ - OP_SUB_REAL, /* sub-real : dest = src1 - src2 */ - OP_MUL_REAL, /* mul-real : dest = src1 * src2 */ - OP_DIV_REAL, /* div-real : dest = src1 / src2 */ - OP_INT_TO_REAL, /* int-to-real : dest = src1 as real */ - OP_UINT_TO_REAL, /* nat-to-real : dest = src1 as real */ - OP_REAL_TO_INT, /* real-to-int : dest = src1 as int */ - OP_REAL_TO_UINT, /* real-to-nat : dest = src1 as uint */ - OP_JEQ_INT, /* jump-eq-int : jump to address dest if src1 as int == src2 as int */ - OP_JNEQ_INT, /* jump-neq-int : jump to address dest if src1 as int != src2 as int */ - OP_JGT_INT, /* jump-gt-int : jump to address dest if src1 as int > src2 as int */ - OP_JLT_INT, /* jump-lt-int : jump to address dest if src1 as int < src2 as int */ - OP_JLE_INT, /* jump-le-int : jump to address dest if src1 as int <= src2 as int */ - OP_JGE_INT, /* jump-ge-int : jump to address dest if src1 as int >= src2 as int */ - OP_JEQ_UINT, /* jump-eq-nat : jump to address dest if src1 as uint == src2 as uint */ - OP_JNEQ_UINT, /* jump-neq-nat : jump to address dest if src1 as uint != src2 as uint */ - OP_JGT_UINT, /* jump-gt-nat : jump to address dest if src1 as uint > src2 as uint */ - OP_JLT_UINT, /* jump-lt-nat : jump to address dest if src1 as uint < src2 as uint */ - OP_JLE_UINT, /* jump-le-nat : jump to address dest if src1 as uint <= src2 as uint */ - OP_JGE_UINT, /* jump-ge-nat : jump to address dest if src1 as uint >= src2 as uint */ - OP_JEQ_REAL, /* jump-eq-real : jump to address dest if src1 as real == src2 as real */ - OP_JNEQ_REAL, /* jump-neq-real : jump to address dest if src1 as real != src2 as real */ - OP_JGE_REAL, /* jump-ge-real : jump to address dest if src1 as real >= src2 as real */ - OP_JGT_REAL, /* jump-gt-real : jump to address dest if src1 as real > src2 as real */ - OP_JLT_REAL, /* jump-lt-real : jump to address dest if src1 as real < src2 as real */ - OP_JLE_REAL, /* jump-le-real : jump to address dest if src1 as real <= src2 as real */ - OP_STRLEN, /* string-length : dest = length of str at src1 ptr */ - OP_STREQ, /* string-eq : dest = src1 ptr string == src2 ptr string */ - OP_STRCAT, /* string-concat : dest = ptr of src1 ptr string + src2 ptr string */ - OP_STR_GET_CHAR, /* string-get-char : dest = ptr of src1 ptr str, src2 index of str */ - OP_STR_FIND_CHAR, /* string-find-char : dest = ptr of src1 ptr string, src2 uint8 char */ - OP_STR_SLICE, /* string-slice : dest = ptr of src1 ptr str, src2 start index, src3 end index */ - OP_INT_TO_STRING, /* int-to-string : dest = src1 as str */ - OP_UINT_TO_STRING, /* nat-to-string : dest = src1 as str */ - OP_REAL_TO_STRING, /* real-to-string : dest = src1 as str */ - 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 */ + OP_HALT, /* [obj1 `halt` - | terminate execution with code ] */ + OP_JMP, /* [dest `jump` - | jump to address dest unconditionally ] */ + OP_JMPF, /* [dest `jump-if-flag` - | jump to address dest if flag is ne 0 ] */ + OP_CALL, /* [&code_ref `call` - | creates a new frame ] */ + OP_RETURN, /* [obj1 `return` - | returns from a frame to the parent frame, pushes obj1 on stack ] */ + OP_LOAD_8, /* [&dest `load-8` u8 | push memory[obj1] onto stack as u8 ] */ + OP_LOAD_16, /* [&dest `load-16` u16 | push memory[obj1] onto stack as u16 ] */ + OP_LOAD_32, /* [&dest `load` u32 | push memory[obj1] onto stack as u32 ] */ + OP_STORE_8, /* [&dest obj1 `store-8` - | memory[dest] = obj1 << 8 ] */ + OP_STORE_16, /* [&dest obj1 `store-16`- | memory[dest] = obj1 << 16 ] */ + OP_STORE_32, /* [&dest obj1 `store` - | memory[dest] = obj1 ] */ + OP_MALLOC, /* [size `malloc` ptr | allocate 'size + 4' of memory and push ptr to memory on stack ] */ + OP_MEMSET_8, /* [ `memset-8` | dest <-> dest+count = obj1 as u8 ] */ + OP_MEMSET_16, /* [ `memset-16` | dest <-> dest+count = obj1 as u8 ] */ + OP_MEMSET_32, /* [ `memset-32` | dest <-> dest+count = obj1 as u32 ] */ + OP_PUSH, /* [ `push` | push const of ref ] */ + OP_POP, /* [ `pop` | pop cosnt or ref ] */ + OP_DUP, /* [ obj1 `dup` obj1 obj1 | ] */ + OP_EXCH, /* [ obj1 obj2 `exch` obj2 obj1 | ] */ + OP_OVER, /* [ obj1 obj2 `over` obj1 obj2 obj1 | ] */ + OP_PICK, /* [ N `pick` objN | ] */ + OP_ROT, /* [ obj1 obj2 obj3 `rot` obj2 obj3 obj1 | ] */ + OP_DEPTH, /* [ - `depth` stack_size | ] */ + OP_SYSCALL, /* [ `syscall` | obj1 obj2 obj3 obj4 more? does a system call based on args ] */ + OP_SLL, /* [ `bit-shift-left` | dest = obj1 << obj2 ] */ + OP_SRL, /* [ `bit-shift-right` | dest = obj1 >> obj2 ] */ + OP_SRE, /* [ `bit-shift-re` | dest as i32 = obj1 >> obj2 ] */ + OP_BAND, /* [ `bit-and` | dest = obj1 & obj2 ] */ + OP_BOR, /* [ `bit-or` | dest = obj1 | obj2 ] */ + OP_BXOR, /* [ `bit-xor` | dest = obj1 ^ obj2 ] */ + OP_ADD_INT, /* [ `add-int` | dest = obj1 + obj2 ] */ + OP_SUB_INT, /* [ `sub-int` | dest = obj1 - obj2 ] */ + OP_MUL_INT, /* [ `mul-int` | dest = obj1 * obj2 ] */ + OP_DIV_INT, /* [ `div-int` | dest = obj1 / obj2 ] */ + OP_ADD_UINT, /* [ `add-nat` | dest = obj1 + obj2 ] */ + OP_SUB_UINT, /* [ `sub-nat` | dest = obj1 - obj2 ] */ + OP_MUL_UINT, /* [ `mul-nat` | dest = obj1 * obj2 ] */ + OP_DIV_UINT, /* [ `div-nat` | dest = obj1 / obj2 ] */ + OP_ADD_REAL, /* [ `add-real` | dest = obj1 + obj2 ] */ + OP_SUB_REAL, /* [ `sub-real` | dest = obj1 - obj2 ] */ + OP_MUL_REAL, /* [ `mul-real` | dest = obj1 * obj2 ] */ + OP_DIV_REAL, /* [ `div-real` | dest = obj1 / obj2 ] */ + OP_INT_TO_REAL, /* [ `int-to-real` | dest = obj1 as real ] */ + OP_UINT_TO_REAL, /* [ `nat-to-real` | dest = obj1 as real ] */ + OP_REAL_TO_INT, /* [ `real-to-int` | dest = obj1 as int ] */ + OP_REAL_TO_UINT, /* [ `real-to-nat` | dest = obj1 as uint ] */ + OP_JEQ_INT, /* [ `jump-eq-int` | jump to address dest if obj1 as int == obj2 as int ] */ + OP_JNEQ_INT, /* [ `jump-neq-int` | jump to address dest if obj1 as int != obj2 as int ] */ + OP_JGT_INT, /* [ `jump-gt-int` | jump to address dest if obj1 as int > obj2 as int ] */ + OP_JLT_INT, /* [ `jump-lt-int` | jump to address dest if obj1 as int < obj2 as int ] */ + OP_JLE_INT, /* [ `jump-le-int` | jump to address dest if obj1 as int <= obj2 as int ] */ + OP_JGE_INT, /* [ `jump-ge-int` | jump to address dest if obj1 as int >= obj2 as int ] */ + OP_JEQ_UINT, /* [ `jump-eq-nat` | jump to address dest if obj1 as uint == obj2 as uint ] */ + OP_JNEQ_UINT, /* [ `jump-neq-nat` | jump to address dest if obj1 as uint != obj2 as uint ] */ + OP_JGT_UINT, /* [ `jump-gt-nat` | jump to address dest if obj1 as uint > obj2 as uint ] */ + OP_JLT_UINT, /* [ `jump-lt-nat` | jump to address dest if obj1 as uint < obj2 as uint ] */ + OP_JLE_UINT, /* [ `jump-le-nat` | jump to address dest if obj1 as uint <= obj2 as uint ] */ + OP_JGE_UINT, /* [ `jump-ge-nat` | jump to address dest if obj1 as uint >= obj2 as uint ] */ + OP_JEQ_REAL, /* [ `jump-eq-real` | jump to address dest if obj1 as real == obj2 as real ] */ + OP_JNEQ_REAL, /* [ `jump-neq-real` | jump to address dest if obj1 as real != obj2 as real ] */ + OP_JGE_REAL, /* [ `jump-ge-real` | jump to address dest if obj1 as real >= obj2 as real ] */ + OP_JGT_REAL, /* [ `jump-gt-real` | jump to address dest if obj1 as real > obj2 as real ] */ + OP_JLT_REAL, /* [ `jump-lt-real` | jump to address dest if obj1 as real < obj2 as real ] */ + OP_JLE_REAL, /* [ `jump-le-real` | jump to address dest if obj1 as real <= obj2 as real ] */ + OP_STRLEN, /* [&str `string-length` len &str | length of string from str ptr ] */ + OP_STREQ, /* [ `string-eq` | dest = obj1 ptr string == obj2 ptr string ] */ + OP_STRCAT, /* [ `string-concat` | dest = ptr of obj1 ptr string + obj2 ptr string ] */ + OP_STR_GET_CHAR, /* [ `string-get-char` | dest = ptr of obj1 ptr str, obj2 index of str ] */ + OP_STR_FIND_CHAR, /* [ `string-find-char` | dest = ptr of obj1 ptr string, obj2 uint8 char ] */ + OP_STR_SLICE, /* [ `string-slice` | dest = ptr of obj1 ptr str, obj2 start index, obj3 end index ] */ + OP_INT_TO_STRING, /* [ `int-to-string` | dest = obj1 as str ] */ + OP_UINT_TO_STRING, /* [ `nat-to-string` | dest = obj1 as str ] */ + OP_REAL_TO_STRING, /* [ `real-to-string` | dest = obj1 as str ] */ + OP_STRING_TO_INT, /* [ `string-to-int` | dest = obj1 as int ] */ + OP_STRING_TO_UINT, /* [ `string-to-nat` | dest = obj1 as uint ] */ + OP_STRING_TO_REAL /* [ `string-to-real` | dest = obj1 as real ] */ } Opcode; -#define MAX_REGS 32 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 end; } Frame; @@ -128,20 +123,20 @@ typedef struct device_s { #define STACK_SIZE 256 #define DEVICES_SIZE 8 typedef struct vm_s { - u32 pc; /* program counter */ - u32 cp; /* code pointer (last allocated opcode) */ - u32 fp; /* frame pointer (current frame) */ - u32 sp; /* stack pointer (top of stack) */ - u32 rp; /* return stack pointer (top of stack) */ - u32 mp; /* memory pointer (last allocated value) */ - u32 dc; /* device count */ - i32 flag; /* flag (temporary results like SYSCALL status) */ - Frame frames[FRAMES_SIZE]; /* function call frames */ - u32 stack[STACK_SIZE]; /* main stack */ - u32 return_stack[STACK_SIZE]; /* return stack (for call recursion) */ + u32 pc; /* program counter */ + u32 cp; /* code pointer (last allocated opcode) */ + u32 fp; /* frame pointer (current frame) */ + u32 sp; /* stack pointer (top of stack) */ + u32 rp; /* return stack pointer (top of stack) */ + u32 mp; /* memory pointer (last allocated value) */ + u32 dc; /* device count */ + i32 flag; /* flag (temporary results like SYSCALL status) */ + Frame frames[FRAMES_SIZE]; /* function call frames */ + u32 stack[STACK_SIZE]; /* main stack */ + u32 return_stack[FRAMES_SIZE]; /* return stack (for call recursion) */ Device devices[DEVICES_SIZE]; /* device definitions */ - u8 code[CODE_SIZE]; /* code block */ - u8 memory[MEMORY_SIZE]; /* memory block */ + u8 code[CODE_SIZE]; /* code block */ + u8 memory[MEMORY_SIZE]; /* memory block */ } VM; #define read_u8(vm, location, addr) ((vm)->location[addr]) diff --git a/src/vm/vm.c b/src/vm/vm.c index 13b7cc2..8b244e7 100644 --- a/src/vm/vm.c +++ b/src/vm/vm.c @@ -7,17 +7,12 @@ do { \ i32 cond; \ u32 mask, target; \ - u8 src1, src2; \ type value; \ type value2; \ target = read_u32(vm, code, vm->pc); \ vm->pc += 4; \ - src1 = read_u8(vm, code, vm->pc); \ - vm->pc++; \ - src2 = read_u8(vm, code, vm->pc); \ - vm->pc++; \ - value = (type)frame->registers[src1]; \ - value2 = (type)frame->registers[src2]; \ + value2 = (type)vm->stack[--vm->sp]; \ + value = (type)vm->stack[--vm->sp]; \ cond = !!(value op value2); \ mask = -(u32)cond; \ vm->pc = (target & mask) | (vm->pc & ~mask); \ @@ -26,26 +21,17 @@ #define MATH_OP(type, op) \ do { \ - dest = read_u8(vm, code, vm->pc); \ - vm->pc++; \ - 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]; \ + type b = (type)vm->stack[--vm->sp]; \ + type a = (type)vm->stack[--vm->sp]; \ + vm->stack[vm->sp++] = (type)(a op b); \ return true; \ } while (0) #define BIT_OP(op) \ do { \ - dest = read_u8(vm, code, vm->pc); \ - vm->pc++; \ - 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]; \ + u32 a = vm->stack[--vm->sp]; \ + u32 b = vm->stack[--vm->sp]; \ + vm->stack[vm->sp++] = a op b; \ return true; \ } 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. */ bool step_vm(VM *vm) { - u16 opcode, dest, src1, src2; - u32 v, ptr; - i32 value; - Frame *frame; - /* Get current instruction & Advance to next instruction */ - opcode = vm->code[vm->pc++]; - frame = &vm->frames[vm->fp]; + u8 opcode = vm->code[vm->pc++]; + Frame *frame = &vm->frames[vm->fp]; switch (opcode) { case OP_HALT: { @@ -90,7 +71,6 @@ bool step_vm(VM *vm) { return true; } case OP_RETURN: { - frame->rp = 0; /* reset register ptr */ vm->pc = vm->return_stack[--vm->rp]; /* set pc to return address */ vm->mp = vm->frames[vm->fp--].start; /* reset memory pointer to start @@ -98,26 +78,18 @@ bool step_vm(VM *vm) { return true; } case OP_MALLOC: { - u32 size; - dest = read_u8(vm, code, vm->pc); + u32 size = read_u32(vm, code, vm->pc); vm->pc++; - src1 = read_u8(vm, code, vm->pc); - vm->pc++; - frame->registers[dest] = vm->mp; - size = frame->registers[src1]; + vm->stack[vm->sp++] = vm->mp; write_u32(vm, memory, vm->mp, size); vm->mp += (size + 4); return true; } case OP_MEMSET_32: { u32 i, start, end; - u8 dest_reg = read_u8(vm, code, vm->pc++); - u8 value_reg = read_u8(vm, code, vm->pc++); - 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]; + u32 dest = vm->stack[--vm->sp]; + u32 value = vm->stack[--vm->sp]; + u32 count = vm->stack[--vm->sp]; if (count == 0) { vm->flag = 1; @@ -127,29 +99,24 @@ bool step_vm(VM *vm) { start = dest; 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; return true; } - for (i = start; i < end; i+=4) { + for (i = start; i < end; i += 4) { write_u32(vm, memory, i, value); } - frame->registers[0] = dest; + vm->stack[vm->sp++] = dest; vm->flag = 1; return true; } case OP_MEMSET_16: { u32 i, start, end; - u8 dest_reg = read_u8(vm, code, vm->pc++); - u8 value_reg = read_u8(vm, code, vm->pc++); - 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]; + u32 dest = vm->stack[--vm->sp]; + u16 value = (u16)(vm->stack[--vm->sp]); + u32 count = vm->stack[--vm->sp]; if (count == 0) { vm->flag = 1; @@ -159,29 +126,24 @@ bool step_vm(VM *vm) { start = dest; 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; return true; } - for (i = start; i < end; i+=2) { + for (i = start; i < end; i += 2) { write_u16(vm, memory, i, value); } - frame->registers[0] = dest; + vm->stack[vm->sp++] = dest; vm->flag = 1; return true; } case OP_MEMSET_8: { u32 i, start, end; - u8 dest_reg = read_u8(vm, code, vm->pc++); - u8 value_reg = read_u8(vm, code, vm->pc++); - 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]; + u32 dest = vm->stack[--vm->sp]; + u8 value = (u8)(vm->stack[--vm->sp]); + u32 count = vm->stack[--vm->sp]; if (count == 0) { vm->flag = 1; @@ -191,8 +153,7 @@ bool step_vm(VM *vm) { start = dest; 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; return true; } @@ -201,169 +162,94 @@ bool step_vm(VM *vm) { write_u8(vm, memory, i, value); } - frame->registers[0] = dest; + vm->stack[vm->sp++] = dest; vm->flag = 1; return true; } - case OP_LOAD_IMM: { - dest = read_u8(vm, code, vm->pc); - vm->pc++; - 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; + case OP_LOAD_8: { + u32 addr = vm->stack[--vm->sp]; + vm->stack[vm->sp++] = read_u8(vm, memory, addr); return true; } case OP_LOAD_16: { - dest = read_u8(vm, code, vm->pc); - vm->pc++; - ptr = read_u32(vm, code, vm->pc); - vm->pc += 4; - v = read_u16(vm, memory, ptr); - frame->registers[dest] = v; + u32 addr = vm->stack[--vm->sp]; + vm->stack[vm->sp++] = read_u16(vm, memory, addr); return true; } - case OP_LOAD_8: { - dest = read_u8(vm, code, vm->pc); - vm->pc++; - 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); + case OP_LOAD_32: { + u32 addr = vm->stack[--vm->sp]; + vm->stack[vm->sp++] = read_u32(vm, memory, addr); 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); + u8 value = vm->stack[--vm->sp]; + u32 addr = vm->stack[--vm->sp]; + write_u8(vm, memory, addr, value); 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); + case OP_STORE_16: { + u16 value = vm->stack[--vm->sp]; + u32 addr = vm->stack[--vm->sp]; + write_u16(vm, memory, addr, value); 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); + case OP_STORE_32: { + u32 value = vm->stack[--vm->sp]; + u32 addr = vm->stack[--vm->sp]; + write_u32(vm, memory, addr, value); return true; } case OP_PUSH: { - dest = read_u8(vm, code, vm->pc); - vm->pc++; - vm->stack[++vm->sp] = frame->registers[dest]; + u32 val = read_u32(vm, code, vm->pc); + vm->pc += 4; + vm->stack[vm->sp++] = val; return true; } case OP_POP: { - dest = read_u8(vm, code, vm->pc); - vm->pc++; - frame->registers[dest] = vm->stack[vm->sp--]; + vm->sp--; return true; } - case OP_REG_MOV: { - dest = read_u8(vm, code, vm->pc); - vm->pc++; - src1 = read_u8(vm, code, vm->pc); - vm->pc++; - frame->registers[dest] = frame->registers[src1]; + case OP_DUP: { + u32 a = vm->stack[--vm->sp]; + vm->stack[vm->sp++] = a; + vm->stack[vm->sp++] = a; + return true; + } + 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; } case OP_JMP: { - dest = read_u8(vm, code, vm->pc); - vm->pc++; - vm->pc = frame->registers[dest]; /* Jump to address */ + u32 dest = read_u32(vm, code, vm->pc); + vm->pc += 4; + vm->pc = dest; /* Jump to address */ return true; } case OP_JMPF: { /* error handling for syscall, jump if flag == 0 */ - u32 mask; - dest = read_u8(vm, code, vm->pc); - vm->pc++; + u32 mask, dest = read_u32(vm, code, vm->pc); + vm->pc += 4; mask = -(u32)(vm->flag == 0); vm->pc = (dest & mask) | (vm->pc & ~mask); return true; @@ -377,15 +263,8 @@ bool step_vm(VM *vm) { switch (syscall_id) { case SYSCALL_DEVICE_OPEN: { Device *dev; - u32 path_ptr, mode; - u8 path_reg, mode_reg; - 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]; + u32 path_ptr = vm->stack[--vm->sp]; + u32 mode = vm->stack[--vm->sp]; dev = find_device_by_path(vm, (const char *)&vm->memory[path_ptr + 4]); if (dev) { if (dev->ops->open) { @@ -402,25 +281,15 @@ bool step_vm(VM *vm) { case SYSCALL_DEVICE_READ: { 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 */ - size = frame->registers[size_reg]; /* size */ - buffer_ptr = frame->registers[dest]; + u32 path_ptr = vm->stack[--vm->sp]; /* path pointer */ + u32 size = vm->stack[--vm->sp]; /* size */ + u32 buffer_ptr = vm->stack[--vm->sp]; dev = find_device_by_path(vm, (const char *)&vm->memory[path_ptr + 4]); if (dev && dev->ops->read) { 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 { vm->flag = 0; } @@ -430,18 +299,9 @@ bool step_vm(VM *vm) { case SYSCALL_DEVICE_WRITE: { 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++; - - 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 */ + u32 path_ptr = vm->stack[--vm->sp]; /* path pointer */ + u32 size = vm->stack[--vm->sp]; /* size */ + u32 buffer_ptr = vm->stack[--vm->sp]; /* buffer pointer */ dev = find_device_by_path(vm, (const char *)&vm->memory[path_ptr + 4]); if (dev && dev->ops->write) { @@ -456,12 +316,7 @@ bool step_vm(VM *vm) { case SYSCALL_DEVICE_CLOSE: { Device *dev; - u32 path_ptr; - u8 path_reg; - path_reg = read_u8(vm, code, vm->pc); - vm->pc++; - - path_ptr = frame->registers[path_reg]; /* R0: path pointer */ + u32 path_ptr = vm->stack[--vm->sp]; /* path pointer */ 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: { Device *dev; - u32 path_ptr, args_ptr, cmd; - u8 path_reg, cmd_reg, args_ptr_reg; - path_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++; - - 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 */ + u32 path_ptr = vm->stack[--vm->sp]; /* device path */ + u32 cmd = vm->stack[--vm->sp]; /* ioctl command */ + u32 args_ptr = vm->stack[--vm->sp]; /* args pointer */ 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: MATH_OP(u32, /); case OP_MUL_REAL: { - dest = read_u8(vm, code, vm->pc); - vm->pc++; - 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; + u32 a = vm->stack[--vm->sp]; + u32 b = (vm->stack[--vm->sp] >> 16); + vm->stack[vm->sp++] = a * b; return true; } - case OP_DIV_REAL: { - dest = read_u8(vm, code, vm->pc); - vm->pc++; - 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]; + u32 a = vm->stack[--vm->sp] << 16; + u32 b = vm->stack[--vm->sp]; + vm->stack[vm->sp++] = a / b; return true; } - case OP_ADD_REAL: { - dest = read_u8(vm, code, vm->pc); - vm->pc++; - 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]; + u32 a = vm->stack[--vm->sp]; + u32 b = vm->stack[--vm->sp]; + vm->stack[vm->sp++] = a + b; return true; } - case OP_SUB_REAL: { - dest = read_u8(vm, code, vm->pc); - vm->pc++; - 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]; + u32 a = vm->stack[--vm->sp]; + u32 b = vm->stack[--vm->sp]; + vm->stack[vm->sp++] = a - b; return true; } case OP_REAL_TO_INT: { - dest = read_u8(vm, code, vm->pc); - vm->pc++; - src1 = read_u8(vm, code, vm->pc); - vm->pc++; - value = frame->registers[src1]; - + i32 value = vm->stack[--vm->sp]; if (value >= 0) { - frame->registers[dest] = value >> 16; + vm->stack[vm->sp++] = value >> 16; } else { - frame->registers[dest] = -((-value) >> 16); + vm->stack[vm->sp++] = -((-value) >> 16); } - return true; } case OP_INT_TO_REAL: { - dest = read_u8(vm, code, vm->pc); - vm->pc++; - src1 = read_u8(vm, code, vm->pc); - vm->pc++; - frame->registers[dest] = (frame->registers[src1] << 16); + i32 value = (vm->stack[--vm->sp] << 16); + vm->stack[vm->sp++] = value; return true; } case OP_REAL_TO_UINT: { - dest = read_u8(vm, code, vm->pc); - vm->pc++; - src1 = read_u8(vm, code, vm->pc); - vm->pc++; - value = frame->registers[src1]; + i32 value = vm->stack[--vm->sp]; if (value < 0) { - frame->registers[dest] = 0; + vm->stack[vm->sp++] = 0; } else { - frame->registers[dest] = AS_UINT(value >> 16); + vm->stack[vm->sp++] = AS_UINT(value >> 16); } return true; } case OP_UINT_TO_REAL: { - dest = read_u8(vm, code, vm->pc); - vm->pc++; - src1 = read_u8(vm, code, vm->pc); - vm->pc++; - frame->registers[dest] = AS_INT(frame->registers[src1] << 16); + i32 value = AS_INT(vm->stack[--vm->sp] << 16); + vm->stack[vm->sp++] = value; return true; } case OP_JEQ_UINT: { @@ -686,48 +495,27 @@ bool step_vm(VM *vm) { } case OP_INT_TO_STRING: { char buffer[32]; - dest = read_u8(vm, code, vm->pc); - 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; + int_to_string(AS_INT(vm->stack[--vm->sp]), buffer); + vm->stack[vm->sp++] = str_alloc(vm, frame, buffer, strlength(buffer)); return true; } case OP_UINT_TO_STRING: { char buffer[32]; - dest = read_u8(vm, code, vm->pc); - 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; + uint_to_string(vm->stack[--vm->sp], buffer); + vm->stack[vm->sp++] = str_alloc(vm, frame, buffer, strlength(buffer)); return true; } case OP_REAL_TO_STRING: { char buffer[32]; - dest = read_u8(vm, code, vm->pc); - vm->pc++; - 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; + fixed_to_string(AS_INT(vm->stack[--vm->sp]), buffer); + vm->stack[vm->sp++] = str_alloc( + vm, frame, buffer, strlength(buffer)); /* copy buffer to dest */ return true; } case OP_STRLEN: { - u32 ptr, length; - dest = read_u8(vm, code, vm->pc); - 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; + u32 ptr; + ptr = vm->stack[--vm->sp]; + vm->stack[vm->sp++] = read_u32(vm, memory, ptr); return true; } case OP_STRCAT: { diff --git a/test/add.asm.lisp b/test/add.asm.lisp index 68c4d93..ea016d7 100644 --- a/test/add.asm.lisp +++ b/test/add.asm.lisp @@ -1,24 +1,27 @@ -(module add - (const terminal-namespace "/dev/term/0") - (const new-line "\n") - - (fn :1 main () - (load-immediate $0 1) - (load-immediate $1 1) - (call &add ($0 $1) $2) - (int-to-string $1 $2) - (call &pln ($1)) +((code + (label main + (push 1) + (push 1) + (call &add) + (int-to-string) + (call &pln) (halt)) + + (label add + (add-int) + (return)) - (fn :1 add ($0 $1) - (add-int $2 $1 $0) - (return $2)) - - (fn :1 pln ($1) - (load-immediate $0 &terminal-namespace) - (load-immediate $3 &new-line) - (string-length $2 $1) - (syscall WRITE $0 $1 $2) - (string-length $4 $3) - (syscall WRITE $0 $3 $4) + (label pln + (dup) + (string-length) + (push &terminal-namespace) + (syscall WRITE) + (push &new-line) + (dup) + (string-length) + (push &terminal-namespace) + (syscall WRITE) (return))) +(data + (label terminal-namespace "/dev/term/0") + (label new-line "\n"))) diff --git a/test/fib.asm.lisp b/test/fib.asm.lisp index 3c5fffd..bf8c516 100644 --- a/test/fib.asm.lisp +++ b/test/fib.asm.lisp @@ -1,42 +1,44 @@ ((code - (label main - (load-immediate $0 35) - (push $0) - (call &fib) - (pop $0) - (int-to-string $1 $0) - (push $1) - (call &pln) - (halt)) - (label fib - (pop $0) - (load-immediate $1 2) - (jump-lt-int &base-case $0 $1) - (load-immediate $3 2) - (sub-int $4 $0 $3) - (push $4) - (call &fib) - (load-immediate $3 1) - (sub-int $4 $0 $3) - (push $4) - (call &fib) - (pop $4) - (pop $5) - (add-int $6 $5 $4) - (push $6) - (return) - (label base-case - (push $0) - (return))) - (label pln - (load-immediate $0 &terminal-namespace) - (load-immediate $3 &new-line) - (pop $1) - (string-length $2 $1) - (syscall WRITE $0 $1 $2) - (string-length $4 $3) - (syscall WRITE $0 $3 $4) + (label main + (push 35) + (call &fib) + (int-to-string) + (call &pln) + (halt)) + + (label fib + (dup) ; dup num + (push 2) ; Base case: n < 2 + (jump-lt-int &base-case) + + (dup) + (push 2) ; First call: fib(n-2) + (sub-int) ; n - 2 + (call &fib) + + (over) ; get n over the previous answer + (push 1) ; Second call: fib(n-1) + (sub-int) ; n-1 (using saved n) + (call &fib) ; Result in $2 + + ; Combine results + (add-int) ; fib(n-2) + fib(n-1) + (return) ; Return result + + (label base-case + (return))) ; Return n directly + + (label pln + (dup) + (string-length) + (push &terminal-namespace) + (syscall WRITE) + (push &new-line) + (dup) + (string-length) + (push &terminal-namespace) + (syscall WRITE) (return))) (data - (label terminal-namespace "/dev/term/0") - (label new-line "\n"))) + (label terminal-namespace "/dev/term/0") + (label new-line "\n")))