Compare commits

...

1 Commits

Author SHA1 Message Date
zongor 4e5ebdb749 wip stack oriented VM 2025-10-12 22:11:54 -07:00
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 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")))

View File

@ -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 "<invalid-opcode>";

View File

@ -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);
}

View File

@ -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])

View File

@ -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: {

View File

@ -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")))

View File

@ -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")))