wip stack oriented VM
This commit is contained in:
parent
4d82914f3c
commit
4e5ebdb749
12
README.org
12
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 has an internal REPL that allows for quick development as well as the ability to dump the program to a binary rom for preserving that program/game/etc.
|
||||||
|
|
||||||
It runs on the =Reality Engine=, a VM written in freestanding C89, has a CISC like instruction format of one byte opcode and a variable byte operand. 32 general purpose registers.
|
It runs on the =Reality Engine=, a 32 bit stack based VM written in freestanding C89.
|
||||||
|
|
||||||
* Philosophy
|
* Philosophy
|
||||||
|
|
||||||
|
@ -58,11 +58,11 @@ The Undâr compiler will be written in Sċieppan, as well as core VM tests.
|
||||||
#+BEGIN_SRC lisp
|
#+BEGIN_SRC lisp
|
||||||
((code
|
((code
|
||||||
(label main
|
(label main
|
||||||
(load-immediate $0 &terminal-namespace) ; load terminal namespace
|
(load &terminal-namespace) ; load terminal namespace
|
||||||
(load-immediate $1 &hello-str) ; load hello string ptr
|
(load &hello-str) ; load hello string ptr
|
||||||
(string-length $2 $1) ; get length to write to stdout
|
(string-length) ; get length to write to stdout
|
||||||
(syscall WRITE $0 $1 $2) ; do the write syscall
|
(syscall WRITE) ; do the write syscall
|
||||||
(halt))) ; done
|
(halt))) ; done
|
||||||
(data
|
(data
|
||||||
(label terminal-namespace "/dev/term/0")
|
(label terminal-namespace "/dev/term/0")
|
||||||
(label hello-str "nuqneH 'u'?\n")))
|
(label hello-str "nuqneH 'u'?\n")))
|
||||||
|
|
|
@ -260,79 +260,87 @@ void register_sdl_devices(VM *vm) {
|
||||||
vm_register_device(vm, "/dev/keyboard/0", "keyboard", &keyboard_data,
|
vm_register_device(vm, "/dev/keyboard/0", "keyboard", &keyboard_data,
|
||||||
&keyboard_ops);
|
&keyboard_ops);
|
||||||
}
|
}
|
||||||
|
#define ASM_DEBUG
|
||||||
#ifdef ASM_DEBUG
|
#ifdef ASM_DEBUG
|
||||||
const char *opcode_to_string(Opcode op) {
|
const char *opcode_to_string(Opcode op) {
|
||||||
static const char *names[] = {[OP_HALT] = "halt",
|
static const char *names[] = {
|
||||||
[OP_JMP] = "jump",
|
[OP_HALT] = "halt",
|
||||||
[OP_JMPF] = "jump-if-flag",
|
[OP_JMP] = "jump",
|
||||||
[OP_CALL] = "call",
|
[OP_JMPF] = "jump-if-flag",
|
||||||
[OP_RETURN] = "return",
|
[OP_CALL] = "call",
|
||||||
[OP_LOAD] = "load",
|
[OP_RETURN] = "return",
|
||||||
[OP_LOAD_REG] = "get",
|
[OP_LOAD_8] = "load-8",
|
||||||
[OP_LOAD_REG8] = "get-8",
|
[OP_LOAD_16] = "load-16",
|
||||||
[OP_LOADI8] = "load-i8",
|
[OP_LOAD_32] = "load",
|
||||||
[OP_LOADU8] = "load-u8",
|
[OP_STORE_8] = "store-8",
|
||||||
[OP_LOADI16] = "load-i16",
|
[OP_STORE_16] = "store-16",
|
||||||
[OP_LOADU16] = "load-u16",
|
[OP_STORE_32] = "store",
|
||||||
[OP_LOAD_IMM] = "load-immediate",
|
[OP_MALLOC] = "malloc",
|
||||||
[OP_MALLOC] = "malloc",
|
[OP_MEMSET_8] = "memset-8",
|
||||||
[OP_STORE] = "store",
|
[OP_MEMSET_16] = "memset-16",
|
||||||
[OP_STORE8] = "store-8",
|
[OP_MEMSET_32] = "memset",
|
||||||
[OP_STORE16] = "store-16",
|
[OP_PUSH] = "push",
|
||||||
[OP_PUSH] = "push",
|
[OP_POP] = "pop",
|
||||||
[OP_POP] = "pop",
|
[OP_DUP] = "dup",
|
||||||
[OP_REG_MOV] = "register-move",
|
[OP_EXCH] = "exch",
|
||||||
[OP_SYSCALL] = "syscall",
|
[OP_OVER] = "over",
|
||||||
[OP_SLL] = "bit-shift-left",
|
[OP_PICK] = "pick",
|
||||||
[OP_SRL] = "bit-shift-right",
|
[OP_ROT] = "rot",
|
||||||
[OP_SRE] = "bit-shift-right-extend",
|
[OP_DEPTH] = "depth",
|
||||||
[OP_BAND] = "bit-and",
|
[OP_SYSCALL] = "syscall",
|
||||||
[OP_BOR] = "bit-or",
|
[OP_SLL] = "bit-shift-left",
|
||||||
[OP_BXOR] = "bit-xor",
|
[OP_SRL] = "bit-shift-right",
|
||||||
[OP_ADD_INT] = "add-int",
|
[OP_SRE] = "bit-shift-re",
|
||||||
[OP_SUB_INT] = "sub-int",
|
[OP_BAND] = "bit-and",
|
||||||
[OP_MUL_INT] = "mul-int",
|
[OP_BOR] = "bit-or",
|
||||||
[OP_DIV_INT] = "div-int",
|
[OP_BXOR] = "bit-xor",
|
||||||
[OP_ADD_UINT] = "add-nat",
|
[OP_ADD_INT] = "add-int",
|
||||||
[OP_SUB_UINT] = "sub-nat",
|
[OP_SUB_INT] = "sub-int",
|
||||||
[OP_MUL_UINT] = "mul-nat",
|
[OP_MUL_INT] = "mul-int",
|
||||||
[OP_DIV_UINT] = "div-nat",
|
[OP_DIV_INT] = "div-int",
|
||||||
[OP_ADD_REAL] = "add-real",
|
[OP_ADD_UINT] = "add-nat",
|
||||||
[OP_SUB_REAL] = "sub-real",
|
[OP_SUB_UINT] = "sub-nat",
|
||||||
[OP_MUL_REAL] = "mul-real",
|
[OP_MUL_UINT] = "mul-nat",
|
||||||
[OP_DIV_REAL] = "div-real",
|
[OP_DIV_UINT] = "div-nat",
|
||||||
[OP_INT_TO_REAL] = "int-to-real",
|
[OP_ADD_REAL] = "add-real",
|
||||||
[OP_UINT_TO_REAL] = "nat-to-real",
|
[OP_SUB_REAL] = "sub-real",
|
||||||
[OP_REAL_TO_INT] = "real-to-int",
|
[OP_MUL_REAL] = "mul-real",
|
||||||
[OP_REAL_TO_UINT] = "real-to-nat",
|
[OP_DIV_REAL] = "div-real",
|
||||||
[OP_JEQ_INT] = "jump-eq-int",
|
[OP_INT_TO_REAL] = "int-to-real",
|
||||||
[OP_JGT_INT] = "jump-gt-int",
|
[OP_UINT_TO_REAL] = "nat-to-real",
|
||||||
[OP_JLT_INT] = "jump-lt-int",
|
[OP_REAL_TO_INT] = "real-to-int",
|
||||||
[OP_JLE_INT] = "jump-le-int",
|
[OP_REAL_TO_UINT] = "real-to-nat",
|
||||||
[OP_JGE_INT] = "jump-ge-int",
|
[OP_JEQ_INT] = "jump-eq-int",
|
||||||
[OP_JEQ_UINT] = "jump-eq-nat",
|
[OP_JNEQ_INT] = "jump-neq-int",
|
||||||
[OP_JGT_UINT] = "jump-gt-nat",
|
[OP_JGT_INT] = "jump-gt-int",
|
||||||
[OP_JLT_UINT] = "jump-lt-nat",
|
[OP_JLT_INT] = "jump-lt-int",
|
||||||
[OP_JLE_UINT] = "jump-le-nat",
|
[OP_JLE_INT] = "jump-le-int",
|
||||||
[OP_JGE_UINT] = "jump-ge-nat",
|
[OP_JGE_INT] = "jump-ge-int",
|
||||||
[OP_JEQ_REAL] = "jump-eq-real",
|
[OP_JEQ_UINT] = "jump-eq-nat",
|
||||||
[OP_JGE_REAL] = "jump-ge-real",
|
[OP_JNEQ_UINT] = "jump-neq-nat",
|
||||||
[OP_JGT_REAL] = "jump-gt-real",
|
[OP_JGT_UINT] = "jump-gt-nat",
|
||||||
[OP_JLT_REAL] = "jump-lt-real",
|
[OP_JLT_UINT] = "jump-lt-nat",
|
||||||
[OP_JLE_REAL] = "jump-le-real",
|
[OP_JLE_UINT] = "jump-le-nat",
|
||||||
[OP_STRLEN] = "string-length",
|
[OP_JGE_UINT] = "jump-ge-nat",
|
||||||
[OP_STREQ] = "string-eq",
|
[OP_JEQ_REAL] = "jump-eq-real",
|
||||||
[OP_STRCAT] = "string-concat",
|
[OP_JNEQ_REAL] = "jump-neq-real",
|
||||||
[OP_STR_GET_CHAR] = "string-get-char",
|
[OP_JGE_REAL] = "jump-ge-real",
|
||||||
[OP_STR_FIND_CHAR] = "string-find-char",
|
[OP_JGT_REAL] = "jump-gt-real",
|
||||||
[OP_STR_SLICE] = "string-slice",
|
[OP_JLT_REAL] = "jump-lt-real",
|
||||||
[OP_INT_TO_STRING] = "int-to-string",
|
[OP_JLE_REAL] = "jump-le-real",
|
||||||
[OP_UINT_TO_STRING] = "nat-to-string",
|
[OP_STRLEN] = "string-length",
|
||||||
[OP_REAL_TO_STRING] = "real-to-string",
|
[OP_STREQ] = "string-eq",
|
||||||
[OP_STRING_TO_INT] = "string-to-int",
|
[OP_STRCAT] = "string-concat",
|
||||||
[OP_STRING_TO_UINT] = "string-to-nat",
|
[OP_STR_GET_CHAR] = "string-get-char",
|
||||||
[OP_STRING_TO_REAL] = "string-to-real"};
|
[OP_STR_FIND_CHAR] = "string-find-char",
|
||||||
|
[OP_STR_SLICE] = "string-slice",
|
||||||
|
[OP_INT_TO_STRING] = "int-to-string",
|
||||||
|
[OP_UINT_TO_STRING] = "nat-to-string",
|
||||||
|
[OP_REAL_TO_STRING] = "real-to-string",
|
||||||
|
[OP_STRING_TO_INT] = "string-to-int",
|
||||||
|
[OP_STRING_TO_UINT] = "string-to-nat",
|
||||||
|
[OP_STRING_TO_REAL] = "string-to-real",
|
||||||
|
};
|
||||||
|
|
||||||
if (op < 0 || op >= (int)(sizeof(names) / sizeof(names[0]))) {
|
if (op < 0 || op >= (int)(sizeof(names) / sizeof(names[0]))) {
|
||||||
return "<invalid-opcode>";
|
return "<invalid-opcode>";
|
||||||
|
|
|
@ -70,59 +70,43 @@ int get_instruction_byte_size(ExprNode *node) {
|
||||||
const char *opname = node->token;
|
const char *opname = node->token;
|
||||||
|
|
||||||
// Simple opcodes (1 byte)
|
// Simple opcodes (1 byte)
|
||||||
if (strcmp(opname, "halt") == 0 || strcmp(opname, "return") == 0) {
|
if (strcmp(opname, "halt") == 0 || strcmp(opname, "return") == 0 ||
|
||||||
return 1;
|
strcmp(opname, "pop") == 0 || strcmp(opname, "malloc") == 0 ||
|
||||||
}
|
strcmp(opname, "int-to-string") == 0 || strcmp(opname, "dup") == 0 ||
|
||||||
|
strcmp(opname, "get-8") == 0 || strcmp(opname, "nat-to-string") == 0 ||
|
||||||
// Register-based opcodes (2 bytes: opcode + register)
|
strcmp(opname, "get-16") == 0 || strcmp(opname, "real-to-string") == 0 ||
|
||||||
if (strcmp(opname, "pop") == 0 || strcmp(opname, "jump-if-flag") == 0 ||
|
strcmp(opname, "get") == 0 || strcmp(opname, "int-to-real") == 0 ||
|
||||||
strcmp(opname, "jump") == 0 || strcmp(opname, "push") == 0) {
|
strcmp(opname, "put-8") == 0 || strcmp(opname, "nat-to-real") == 0 ||
|
||||||
return 2;
|
strcmp(opname, "put-16") == 0 || strcmp(opname, "real-to-int") == 0 ||
|
||||||
}
|
strcmp(opname, "put") == 0 || strcmp(opname, "real-to-nat") == 0 ||
|
||||||
|
|
||||||
if (strcmp(opname, "int-to-string") == 0 || strcmp(opname, "get-8") == 0 ||
|
|
||||||
strcmp(opname, "nat-to-string") == 0 || strcmp(opname, "get-16") == 0 ||
|
|
||||||
strcmp(opname, "real-to-string") == 0 || strcmp(opname, "get") == 0 ||
|
|
||||||
strcmp(opname, "int-to-real") == 0 || strcmp(opname, "put-8") == 0 ||
|
|
||||||
strcmp(opname, "nat-to-real") == 0 || strcmp(opname, "put-16") == 0 ||
|
|
||||||
strcmp(opname, "real-to-int") == 0 || strcmp(opname, "put") == 0 ||
|
|
||||||
strcmp(opname, "real-to-nat") == 0 ||
|
|
||||||
strcmp(opname, "nat-to-int") == 0 || strcmp(opname, "int-to-nat") == 0 ||
|
strcmp(opname, "nat-to-int") == 0 || strcmp(opname, "int-to-nat") == 0 ||
|
||||||
strcmp(opname, "string-length") == 0 || strcmp(opname, "store") == 0 ||
|
strcmp(opname, "string-length") == 0 || strcmp(opname, "store") == 0 ||
|
||||||
strcmp(opname, "store-8") == 0 || strcmp(opname, "store-16") == 0 ||
|
strcmp(opname, "store-8") == 0 || strcmp(opname, "store-16") == 0 ||
|
||||||
strcmp(opname, "memset") == 0 || strcmp(opname, "memset") == 0 ||
|
strcmp(opname, "memset") == 0 || strcmp(opname, "memset") == 0 ||
|
||||||
strcmp(opname, "memset-8") == 0 || strcmp(opname, "memset-16") == 0 ||
|
strcmp(opname, "memset-8") == 0 || strcmp(opname, "memset-16") == 0 ||
|
||||||
strcmp(opname, "register-move") == 0 || strcmp(opname, "malloc") == 0) {
|
strcmp(opname, "register-move") == 0 || strcmp(opname, "add-int") == 0 ||
|
||||||
return 3;
|
strcmp(opname, "sub-int") == 0 || strcmp(opname, "mul-int") == 0 ||
|
||||||
}
|
strcmp(opname, "div-int") == 0 || strcmp(opname, "add-nat") == 0 ||
|
||||||
|
strcmp(opname, "sub-nat") == 0 || strcmp(opname, "mul-nat") == 0 ||
|
||||||
// Register-register-register opcodes (4 bytes: 1 + 3)
|
strcmp(opname, "div-nat") == 0 || strcmp(opname, "add-real") == 0 ||
|
||||||
if (strcmp(opname, "add-int") == 0 || strcmp(opname, "sub-int") == 0 ||
|
strcmp(opname, "sub-real") == 0 || strcmp(opname, "over") == 0 ||
|
||||||
strcmp(opname, "mul-int") == 0 || strcmp(opname, "div-int") == 0 ||
|
strcmp(opname, "bit-shift-left") == 0 || strcmp(opname, "exch") == 0 ||
|
||||||
strcmp(opname, "add-nat") == 0 || strcmp(opname, "sub-nat") == 0 ||
|
strcmp(opname, "bit-shift-right") == 0 || strcmp(opname, "pick") == 0 ||
|
||||||
strcmp(opname, "mul-nat") == 0 || strcmp(opname, "div-nat") == 0 ||
|
|
||||||
strcmp(opname, "add-real") == 0 || strcmp(opname, "sub-real") == 0 ||
|
|
||||||
strcmp(opname, "bit-shift-left") == 0 ||
|
|
||||||
strcmp(opname, "bit-shift-right") == 0 ||
|
|
||||||
strcmp(opname, "bit-and") == 0 || strcmp(opname, "bit-or") == 0 ||
|
strcmp(opname, "bit-and") == 0 || strcmp(opname, "bit-or") == 0 ||
|
||||||
strcmp(opname, "bit-xor") == 0 || strcmp(opname, "mul-real") == 0 ||
|
strcmp(opname, "bit-xor") == 0 || strcmp(opname, "mul-real") == 0 ||
|
||||||
strcmp(opname, "div-real") == 0) {
|
strcmp(opname, "div-real") == 0 || strcmp(opname, "load") == 0 ||
|
||||||
return 4;
|
strcmp(opname, "load-immediate") == 0 || strcmp(opname, "load-16") == 0 ||
|
||||||
|
strcmp(opname, "load-8") == 0 || strcmp(opname, "syscall") == 0 ||
|
||||||
|
strcmp(opname, "rot") == 0 || strcmp(opname, "depth") == 0) {
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// (5 bytes: 1 + 4)
|
// multibyte opcodes (5 bytes: opcode + u32)
|
||||||
if (strcmp(opname, "call") == 0) {
|
if (strcmp(opname, "call") == 0 ||
|
||||||
return 5;
|
strcmp(opname, "push") == 0 ||
|
||||||
}
|
strcmp(opname, "jump") == 0 ||
|
||||||
|
strcmp(opname, "jump-if-flag") == 0 ||
|
||||||
// Load, Load-immediate (6 bytes: 1 + 1 + 4)
|
strcmp(opname, "jump-eq-int") == 0 ||
|
||||||
if (strcmp(opname, "load") == 0 || strcmp(opname, "load-immediate") == 0 ||
|
|
||||||
strcmp(opname, "load-16") == 0 || strcmp(opname, "load-8") == 0) {
|
|
||||||
return 6;
|
|
||||||
}
|
|
||||||
|
|
||||||
// jump compare (7 bytes: 1 + 4 + 1 + 1)
|
|
||||||
if (strcmp(opname, "jump-eq-int") == 0 ||
|
|
||||||
strcmp(opname, "jump-neq-int") == 0 ||
|
strcmp(opname, "jump-neq-int") == 0 ||
|
||||||
strcmp(opname, "jump-gt-int") == 0 ||
|
strcmp(opname, "jump-gt-int") == 0 ||
|
||||||
strcmp(opname, "jump-lt-int") == 0 ||
|
strcmp(opname, "jump-lt-int") == 0 ||
|
||||||
|
@ -140,13 +124,7 @@ int get_instruction_byte_size(ExprNode *node) {
|
||||||
strcmp(opname, "jump-lt-real") == 0 ||
|
strcmp(opname, "jump-lt-real") == 0 ||
|
||||||
strcmp(opname, "jump-le-real") == 0 ||
|
strcmp(opname, "jump-le-real") == 0 ||
|
||||||
strcmp(opname, "jump-ge-real") == 0) {
|
strcmp(opname, "jump-ge-real") == 0) {
|
||||||
return 7;
|
return 5;
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Syscall (1 + syscall_id (4) + args)
|
|
||||||
if (strcmp(opname, "syscall") == 0) {
|
|
||||||
return 1 + 4 + (node->child_count > 0 ? node->child_count - 1 : 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(stderr, "Unknown opcode for sizing: %s\n", opname);
|
fprintf(stderr, "Unknown opcode for sizing: %s\n", opname);
|
||||||
|
@ -236,6 +214,11 @@ u32 allocate_data(VM *vm, SymbolTable *table, const char *name, u32 size) {
|
||||||
|
|
||||||
void emit_byte(VM *vm, u8 byte) { vm->code[vm->cp++] = byte; }
|
void emit_byte(VM *vm, u8 byte) { vm->code[vm->cp++] = byte; }
|
||||||
|
|
||||||
|
void emit_u16(VM *vm, u16 value) {
|
||||||
|
write_u16(vm, code, vm->cp, value);
|
||||||
|
vm->cp += 4;
|
||||||
|
}
|
||||||
|
|
||||||
void emit_u32(VM *vm, u32 value) {
|
void emit_u32(VM *vm, u32 value) {
|
||||||
write_u32(vm, code, vm->cp, value);
|
write_u32(vm, code, vm->cp, value);
|
||||||
vm->cp += 4;
|
vm->cp += 4;
|
||||||
|
@ -243,12 +226,6 @@ void emit_u32(VM *vm, u32 value) {
|
||||||
|
|
||||||
void emit_opcode(VM *vm, Opcode op) { emit_byte(vm, op); }
|
void emit_opcode(VM *vm, Opcode op) { emit_byte(vm, op); }
|
||||||
|
|
||||||
int parse_register(const char *reg_str) {
|
|
||||||
if (reg_str[0] != '$')
|
|
||||||
return -1;
|
|
||||||
return atoi(reg_str + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 resolve_symbol(SymbolTable *table, const char *ref) {
|
u32 resolve_symbol(SymbolTable *table, const char *ref) {
|
||||||
// Handle symbol references (e.g., &label)
|
// Handle symbol references (e.g., &label)
|
||||||
if (ref[0] == '&') {
|
if (ref[0] == '&') {
|
||||||
|
@ -434,110 +411,46 @@ void process_code_expr(VM *vm, SymbolTable *table, ExprNode *node) {
|
||||||
emit_u32(vm, addr);
|
emit_u32(vm, addr);
|
||||||
} else if (strcmp(opname, "return") == 0) {
|
} else if (strcmp(opname, "return") == 0) {
|
||||||
emit_opcode(vm, OP_RETURN);
|
emit_opcode(vm, OP_RETURN);
|
||||||
} else if (strcmp(opname, "load-immediate") == 0) {
|
|
||||||
emit_opcode(vm, OP_LOAD_IMM);
|
|
||||||
int reg = parse_register(node->children[0]->token);
|
|
||||||
u32 addr = resolve_symbol(table, node->children[1]->token);
|
|
||||||
emit_byte(vm, reg);
|
|
||||||
emit_u32(vm, addr);
|
|
||||||
} else if (strcmp(opname, "load-8") == 0) {
|
} else if (strcmp(opname, "load-8") == 0) {
|
||||||
emit_opcode(vm, OP_LOAD_8);
|
emit_opcode(vm, OP_LOAD_8);
|
||||||
int dest = parse_register(node->children[0]->token);
|
|
||||||
u32 addr = resolve_symbol(table, node->children[1]->token);
|
|
||||||
emit_byte(vm, dest);
|
|
||||||
emit_u32(vm, addr);
|
|
||||||
} else if (strcmp(opname, "load-16") == 0) {
|
} else if (strcmp(opname, "load-16") == 0) {
|
||||||
emit_opcode(vm, OP_LOAD_8);
|
emit_opcode(vm, OP_LOAD_16);
|
||||||
int dest = parse_register(node->children[0]->token);
|
|
||||||
u32 addr = resolve_symbol(table, node->children[1]->token);
|
|
||||||
emit_byte(vm, dest);
|
|
||||||
emit_u32(vm, addr);
|
|
||||||
} else if (strcmp(opname, "load") == 0) {
|
} else if (strcmp(opname, "load") == 0) {
|
||||||
emit_opcode(vm, OP_LOAD_8);
|
emit_opcode(vm, OP_LOAD_32);
|
||||||
int dest = parse_register(node->children[0]->token);
|
|
||||||
u32 addr = resolve_symbol(table, node->children[1]->token);
|
|
||||||
emit_byte(vm, dest);
|
|
||||||
emit_u32(vm, addr);
|
|
||||||
} else if (strcmp(opname, "get-8") == 0) {
|
|
||||||
emit_opcode(vm, OP_GET_8);
|
|
||||||
int dest = parse_register(node->children[0]->token);
|
|
||||||
int src1 = parse_register(node->children[1]->token);
|
|
||||||
emit_byte(vm, dest);
|
|
||||||
emit_byte(vm, src1);
|
|
||||||
} else if (strcmp(opname, "get-16") == 0) {
|
|
||||||
emit_opcode(vm, OP_GET_16);
|
|
||||||
int dest = parse_register(node->children[0]->token);
|
|
||||||
int src1 = parse_register(node->children[1]->token);
|
|
||||||
emit_byte(vm, dest);
|
|
||||||
emit_byte(vm, src1);
|
|
||||||
} else if (strcmp(opname, "get") == 0) {
|
|
||||||
emit_opcode(vm, OP_GET_32);
|
|
||||||
int dest = parse_register(node->children[0]->token);
|
|
||||||
int src1 = parse_register(node->children[1]->token);
|
|
||||||
emit_byte(vm, dest);
|
|
||||||
emit_byte(vm, src1);
|
|
||||||
} else if (strcmp(opname, "malloc") == 0) {
|
} else if (strcmp(opname, "malloc") == 0) {
|
||||||
emit_opcode(vm, OP_MALLOC);
|
emit_opcode(vm, OP_MALLOC);
|
||||||
int dest = parse_register(node->children[0]->token);
|
u32 addr = resolve_symbol(table, node->children[0]->token);
|
||||||
int src1 = parse_register(node->children[1]->token);
|
emit_u32(vm, addr);
|
||||||
emit_byte(vm, dest);
|
|
||||||
emit_byte(vm, src1);
|
|
||||||
} else if (strcmp(opname, "memset-8") == 0) {
|
} else if (strcmp(opname, "memset-8") == 0) {
|
||||||
emit_opcode(vm, OP_MEMSET_8);
|
emit_opcode(vm, OP_MEMSET_8);
|
||||||
int dest = parse_register(node->children[0]->token);
|
|
||||||
int value = parse_register(node->children[1]->token);
|
|
||||||
int count = parse_register(node->children[2]->token);
|
|
||||||
emit_byte(vm, dest);
|
|
||||||
emit_byte(vm, value);
|
|
||||||
emit_byte(vm, count);
|
|
||||||
} else if (strcmp(opname, "memset-16") == 0) {
|
} else if (strcmp(opname, "memset-16") == 0) {
|
||||||
emit_opcode(vm, OP_MEMSET_16);
|
emit_opcode(vm, OP_MEMSET_16);
|
||||||
int dest = parse_register(node->children[0]->token);
|
|
||||||
int value = parse_register(node->children[1]->token);
|
|
||||||
int count = parse_register(node->children[2]->token);
|
|
||||||
emit_byte(vm, dest);
|
|
||||||
emit_byte(vm, value);
|
|
||||||
emit_byte(vm, count);
|
|
||||||
} else if (strcmp(opname, "memset") == 0) {
|
} else if (strcmp(opname, "memset") == 0) {
|
||||||
emit_opcode(vm, OP_MEMSET_32);
|
emit_opcode(vm, OP_MEMSET_32);
|
||||||
int dest = parse_register(node->children[0]->token);
|
|
||||||
int value = parse_register(node->children[1]->token);
|
|
||||||
int count = parse_register(node->children[2]->token);
|
|
||||||
emit_byte(vm, dest);
|
|
||||||
emit_byte(vm, value);
|
|
||||||
emit_byte(vm, count);
|
|
||||||
} else if (strcmp(opname, "store-8") == 0) {
|
} else if (strcmp(opname, "store-8") == 0) {
|
||||||
emit_opcode(vm, OP_STORE_8);
|
emit_opcode(vm, OP_STORE_8);
|
||||||
int dest = parse_register(node->children[0]->token);
|
|
||||||
int src1 = parse_register(node->children[1]->token);
|
|
||||||
emit_byte(vm, dest);
|
|
||||||
emit_byte(vm, src1);
|
|
||||||
} else if (strcmp(opname, "store-16") == 0) {
|
} else if (strcmp(opname, "store-16") == 0) {
|
||||||
emit_opcode(vm, OP_STORE_16);
|
emit_opcode(vm, OP_STORE_16);
|
||||||
int dest = parse_register(node->children[0]->token);
|
|
||||||
int src1 = parse_register(node->children[1]->token);
|
|
||||||
emit_byte(vm, dest);
|
|
||||||
emit_byte(vm, src1);
|
|
||||||
} else if (strcmp(opname, "store") == 0) {
|
} else if (strcmp(opname, "store") == 0) {
|
||||||
emit_opcode(vm, OP_STORE_32);
|
emit_opcode(vm, OP_STORE_32);
|
||||||
int dest = parse_register(node->children[0]->token);
|
|
||||||
int src1 = parse_register(node->children[1]->token);
|
|
||||||
emit_byte(vm, dest);
|
|
||||||
emit_byte(vm, src1);
|
|
||||||
} else if (strcmp(opname, "push") == 0) {
|
} else if (strcmp(opname, "push") == 0) {
|
||||||
emit_opcode(vm, OP_PUSH);
|
emit_opcode(vm, OP_PUSH);
|
||||||
int reg = parse_register(node->children[0]->token);
|
u32 value = resolve_symbol(table, node->children[0]->token);
|
||||||
emit_byte(vm, reg);
|
emit_u32(vm, value);
|
||||||
} else if (strcmp(opname, "pop") == 0) {
|
} else if (strcmp(opname, "pop") == 0) {
|
||||||
emit_opcode(vm, OP_POP);
|
emit_opcode(vm, OP_POP);
|
||||||
int reg = parse_register(node->children[0]->token);
|
} else if (strcmp(opname, "dup") == 0) {
|
||||||
emit_byte(vm, reg);
|
emit_opcode(vm, OP_DUP);
|
||||||
} else if (strcmp(opname, "register-move") == 0) {
|
} else if (strcmp(opname, "over") == 0) {
|
||||||
emit_opcode(vm, OP_REG_MOV);
|
emit_opcode(vm, OP_OVER);
|
||||||
int dest = parse_register(node->children[0]->token);
|
} else if (strcmp(opname, "rot") == 0 ) {
|
||||||
int src = parse_register(node->children[1]->token);
|
emit_opcode(vm, OP_ROT);
|
||||||
emit_byte(vm, dest);
|
} else if (strcmp(opname, "depth") == 0) {
|
||||||
emit_byte(vm, src);
|
emit_opcode(vm, OP_DEPTH);
|
||||||
|
} else if (strcmp(opname, "exch") == 0) {
|
||||||
|
emit_opcode(vm, OP_EXCH);
|
||||||
|
} else if (strcmp(opname, "pick") == 0) {
|
||||||
|
emit_opcode(vm, OP_PICK);
|
||||||
} else if (strcmp(opname, "syscall") == 0) {
|
} else if (strcmp(opname, "syscall") == 0) {
|
||||||
emit_opcode(vm, OP_SYSCALL);
|
emit_opcode(vm, OP_SYSCALL);
|
||||||
|
|
||||||
|
@ -559,407 +472,146 @@ void process_code_expr(VM *vm, SymbolTable *table, ExprNode *node) {
|
||||||
|
|
||||||
emit_u32(vm, syscall_id);
|
emit_u32(vm, syscall_id);
|
||||||
|
|
||||||
// Emit register arguments
|
|
||||||
for (size_t i = 1; i < node->child_count; ++i) {
|
|
||||||
int reg = parse_register(node->children[i]->token);
|
|
||||||
emit_byte(vm, reg);
|
|
||||||
}
|
|
||||||
} else if (strcmp(opname, "bit-shift-left") == 0) {
|
} else if (strcmp(opname, "bit-shift-left") == 0) {
|
||||||
emit_opcode(vm, OP_SLL);
|
emit_opcode(vm, OP_SLL);
|
||||||
int dest = parse_register(node->children[0]->token);
|
|
||||||
int src1 = parse_register(node->children[1]->token);
|
|
||||||
int src2 = parse_register(node->children[2]->token);
|
|
||||||
emit_byte(vm, dest);
|
|
||||||
emit_byte(vm, src1);
|
|
||||||
emit_byte(vm, src2);
|
|
||||||
} else if (strcmp(opname, "bit-shift-right") == 0) {
|
} else if (strcmp(opname, "bit-shift-right") == 0) {
|
||||||
emit_opcode(vm, OP_SRL);
|
emit_opcode(vm, OP_SRL);
|
||||||
int dest = parse_register(node->children[0]->token);
|
|
||||||
int src1 = parse_register(node->children[1]->token);
|
|
||||||
int src2 = parse_register(node->children[2]->token);
|
|
||||||
emit_byte(vm, dest);
|
|
||||||
emit_byte(vm, src1);
|
|
||||||
emit_byte(vm, src2);
|
|
||||||
} else if (strcmp(opname, "bit-shift-re") == 0) {
|
} else if (strcmp(opname, "bit-shift-re") == 0) {
|
||||||
emit_opcode(vm, OP_SRE);
|
emit_opcode(vm, OP_SRE);
|
||||||
int dest = parse_register(node->children[0]->token);
|
|
||||||
int src1 = parse_register(node->children[1]->token);
|
|
||||||
int src2 = parse_register(node->children[2]->token);
|
|
||||||
emit_byte(vm, dest);
|
|
||||||
emit_byte(vm, src1);
|
|
||||||
emit_byte(vm, src2);
|
|
||||||
} else if (strcmp(opname, "bit-and") == 0) {
|
} else if (strcmp(opname, "bit-and") == 0) {
|
||||||
emit_opcode(vm, OP_BAND);
|
emit_opcode(vm, OP_BAND);
|
||||||
int dest = parse_register(node->children[0]->token);
|
|
||||||
int src1 = parse_register(node->children[1]->token);
|
|
||||||
int src2 = parse_register(node->children[2]->token);
|
|
||||||
emit_byte(vm, dest);
|
|
||||||
emit_byte(vm, src1);
|
|
||||||
emit_byte(vm, src2);
|
|
||||||
} else if (strcmp(opname, "bit-or") == 0) {
|
} else if (strcmp(opname, "bit-or") == 0) {
|
||||||
emit_opcode(vm, OP_BOR);
|
emit_opcode(vm, OP_BOR);
|
||||||
int dest = parse_register(node->children[0]->token);
|
|
||||||
int src1 = parse_register(node->children[1]->token);
|
|
||||||
int src2 = parse_register(node->children[2]->token);
|
|
||||||
emit_byte(vm, dest);
|
|
||||||
emit_byte(vm, src1);
|
|
||||||
emit_byte(vm, src2);
|
|
||||||
} else if (strcmp(opname, "bit-xor") == 0) {
|
} else if (strcmp(opname, "bit-xor") == 0) {
|
||||||
emit_opcode(vm, OP_BXOR);
|
emit_opcode(vm, OP_BXOR);
|
||||||
int dest = parse_register(node->children[0]->token);
|
|
||||||
int src1 = parse_register(node->children[1]->token);
|
|
||||||
int src2 = parse_register(node->children[2]->token);
|
|
||||||
emit_byte(vm, dest);
|
|
||||||
emit_byte(vm, src1);
|
|
||||||
emit_byte(vm, src2);
|
|
||||||
} else if (strcmp(opname, "add-int") == 0) {
|
} else if (strcmp(opname, "add-int") == 0) {
|
||||||
emit_opcode(vm, OP_ADD_INT);
|
emit_opcode(vm, OP_ADD_INT);
|
||||||
int dest = parse_register(node->children[0]->token);
|
|
||||||
int src1 = parse_register(node->children[1]->token);
|
|
||||||
int src2 = parse_register(node->children[2]->token);
|
|
||||||
emit_byte(vm, dest);
|
|
||||||
emit_byte(vm, src1);
|
|
||||||
emit_byte(vm, src2);
|
|
||||||
} else if (strcmp(opname, "sub-int") == 0) {
|
} else if (strcmp(opname, "sub-int") == 0) {
|
||||||
emit_opcode(vm, OP_SUB_INT);
|
emit_opcode(vm, OP_SUB_INT);
|
||||||
int dest = parse_register(node->children[0]->token);
|
|
||||||
int src1 = parse_register(node->children[1]->token);
|
|
||||||
int src2 = parse_register(node->children[2]->token);
|
|
||||||
emit_byte(vm, dest);
|
|
||||||
emit_byte(vm, src1);
|
|
||||||
emit_byte(vm, src2);
|
|
||||||
} else if (strcmp(opname, "mul-int") == 0) {
|
} else if (strcmp(opname, "mul-int") == 0) {
|
||||||
emit_opcode(vm, OP_MUL_INT);
|
emit_opcode(vm, OP_MUL_INT);
|
||||||
int dest = parse_register(node->children[0]->token);
|
|
||||||
int src1 = parse_register(node->children[1]->token);
|
|
||||||
int src2 = parse_register(node->children[2]->token);
|
|
||||||
emit_byte(vm, dest);
|
|
||||||
emit_byte(vm, src1);
|
|
||||||
emit_byte(vm, src2);
|
|
||||||
} else if (strcmp(opname, "div-int") == 0) {
|
} else if (strcmp(opname, "div-int") == 0) {
|
||||||
emit_opcode(vm, OP_DIV_INT);
|
emit_opcode(vm, OP_DIV_INT);
|
||||||
int dest = parse_register(node->children[0]->token);
|
|
||||||
int src1 = parse_register(node->children[1]->token);
|
|
||||||
int src2 = parse_register(node->children[2]->token);
|
|
||||||
emit_byte(vm, dest);
|
|
||||||
emit_byte(vm, src1);
|
|
||||||
emit_byte(vm, src2);
|
|
||||||
} else if (strcmp(opname, "add-nat") == 0) {
|
} else if (strcmp(opname, "add-nat") == 0) {
|
||||||
emit_opcode(vm, OP_ADD_UINT);
|
emit_opcode(vm, OP_ADD_UINT);
|
||||||
int dest = parse_register(node->children[0]->token);
|
|
||||||
int src1 = parse_register(node->children[1]->token);
|
|
||||||
int src2 = parse_register(node->children[2]->token);
|
|
||||||
emit_byte(vm, dest);
|
|
||||||
emit_byte(vm, src1);
|
|
||||||
emit_byte(vm, src2);
|
|
||||||
} else if (strcmp(opname, "sub-nat") == 0) {
|
} else if (strcmp(opname, "sub-nat") == 0) {
|
||||||
emit_opcode(vm, OP_SUB_UINT);
|
emit_opcode(vm, OP_SUB_UINT);
|
||||||
int dest = parse_register(node->children[0]->token);
|
|
||||||
int src1 = parse_register(node->children[1]->token);
|
|
||||||
int src2 = parse_register(node->children[2]->token);
|
|
||||||
emit_byte(vm, dest);
|
|
||||||
emit_byte(vm, src1);
|
|
||||||
emit_byte(vm, src2);
|
|
||||||
} else if (strcmp(opname, "mul-nat") == 0) {
|
} else if (strcmp(opname, "mul-nat") == 0) {
|
||||||
emit_opcode(vm, OP_MUL_UINT);
|
emit_opcode(vm, OP_MUL_UINT);
|
||||||
int dest = parse_register(node->children[0]->token);
|
|
||||||
int src1 = parse_register(node->children[1]->token);
|
|
||||||
int src2 = parse_register(node->children[2]->token);
|
|
||||||
emit_byte(vm, dest);
|
|
||||||
emit_byte(vm, src1);
|
|
||||||
emit_byte(vm, src2);
|
|
||||||
} else if (strcmp(opname, "div-nat") == 0) {
|
} else if (strcmp(opname, "div-nat") == 0) {
|
||||||
emit_opcode(vm, OP_DIV_UINT);
|
emit_opcode(vm, OP_DIV_UINT);
|
||||||
int dest = parse_register(node->children[0]->token);
|
|
||||||
int src1 = parse_register(node->children[1]->token);
|
|
||||||
int src2 = parse_register(node->children[2]->token);
|
|
||||||
emit_byte(vm, dest);
|
|
||||||
emit_byte(vm, src1);
|
|
||||||
emit_byte(vm, src2);
|
|
||||||
} else if (strcmp(opname, "add-real") == 0) {
|
} else if (strcmp(opname, "add-real") == 0) {
|
||||||
emit_opcode(vm, OP_ADD_REAL);
|
emit_opcode(vm, OP_ADD_REAL);
|
||||||
int dest = parse_register(node->children[0]->token);
|
|
||||||
int src1 = parse_register(node->children[1]->token);
|
|
||||||
int src2 = parse_register(node->children[2]->token);
|
|
||||||
emit_byte(vm, dest);
|
|
||||||
emit_byte(vm, src1);
|
|
||||||
emit_byte(vm, src2);
|
|
||||||
} else if (strcmp(opname, "sub-real") == 0) {
|
} else if (strcmp(opname, "sub-real") == 0) {
|
||||||
emit_opcode(vm, OP_SUB_REAL);
|
emit_opcode(vm, OP_SUB_REAL);
|
||||||
int dest = parse_register(node->children[0]->token);
|
|
||||||
int src1 = parse_register(node->children[1]->token);
|
|
||||||
int src2 = parse_register(node->children[2]->token);
|
|
||||||
emit_byte(vm, dest);
|
|
||||||
emit_byte(vm, src1);
|
|
||||||
emit_byte(vm, src2);
|
|
||||||
} else if (strcmp(opname, "mul-real") == 0) {
|
} else if (strcmp(opname, "mul-real") == 0) {
|
||||||
emit_opcode(vm, OP_MUL_REAL);
|
emit_opcode(vm, OP_MUL_REAL);
|
||||||
int dest = parse_register(node->children[0]->token);
|
|
||||||
int src1 = parse_register(node->children[1]->token);
|
|
||||||
int src2 = parse_register(node->children[2]->token);
|
|
||||||
emit_byte(vm, dest);
|
|
||||||
emit_byte(vm, src1);
|
|
||||||
emit_byte(vm, src2);
|
|
||||||
} else if (strcmp(opname, "div-real") == 0) {
|
} else if (strcmp(opname, "div-real") == 0) {
|
||||||
emit_opcode(vm, OP_DIV_REAL);
|
emit_opcode(vm, OP_DIV_REAL);
|
||||||
int dest = parse_register(node->children[0]->token);
|
|
||||||
int src1 = parse_register(node->children[1]->token);
|
|
||||||
int src2 = parse_register(node->children[2]->token);
|
|
||||||
emit_byte(vm, dest);
|
|
||||||
emit_byte(vm, src1);
|
|
||||||
emit_byte(vm, src2);
|
|
||||||
} else if (strcmp(opname, "int-to-real") == 0) {
|
} else if (strcmp(opname, "int-to-real") == 0) {
|
||||||
emit_opcode(vm, OP_INT_TO_REAL);
|
emit_opcode(vm, OP_INT_TO_REAL);
|
||||||
int dest = parse_register(node->children[0]->token);
|
|
||||||
int src = parse_register(node->children[1]->token);
|
|
||||||
emit_byte(vm, dest);
|
|
||||||
emit_byte(vm, src);
|
|
||||||
} else if (strcmp(opname, "nat-to-real") == 0) {
|
} else if (strcmp(opname, "nat-to-real") == 0) {
|
||||||
emit_opcode(vm, OP_UINT_TO_REAL);
|
emit_opcode(vm, OP_UINT_TO_REAL);
|
||||||
int dest = parse_register(node->children[0]->token);
|
|
||||||
int src = parse_register(node->children[1]->token);
|
|
||||||
emit_byte(vm, dest);
|
|
||||||
emit_byte(vm, src);
|
|
||||||
} else if (strcmp(opname, "real-to-int") == 0) {
|
} else if (strcmp(opname, "real-to-int") == 0) {
|
||||||
emit_opcode(vm, OP_REAL_TO_INT);
|
emit_opcode(vm, OP_REAL_TO_INT);
|
||||||
int dest = parse_register(node->children[0]->token);
|
|
||||||
int src = parse_register(node->children[1]->token);
|
|
||||||
emit_byte(vm, dest);
|
|
||||||
emit_byte(vm, src);
|
|
||||||
} else if (strcmp(opname, "real-to-nat") == 0) {
|
} else if (strcmp(opname, "real-to-nat") == 0) {
|
||||||
emit_opcode(vm, OP_REAL_TO_UINT);
|
emit_opcode(vm, OP_REAL_TO_UINT);
|
||||||
int dest = parse_register(node->children[0]->token);
|
|
||||||
int src = parse_register(node->children[1]->token);
|
|
||||||
emit_byte(vm, dest);
|
|
||||||
emit_byte(vm, src);
|
|
||||||
} else if (strcmp(opname, "jump-eq-int") == 0) {
|
} else if (strcmp(opname, "jump-eq-int") == 0) {
|
||||||
emit_opcode(vm, OP_JEQ_INT);
|
emit_opcode(vm, OP_JEQ_INT);
|
||||||
u32 addr = resolve_symbol(table, node->children[0]->token);
|
u32 addr = resolve_symbol(table, node->children[0]->token);
|
||||||
int src1 = parse_register(node->children[1]->token);
|
|
||||||
int src2 = parse_register(node->children[2]->token);
|
|
||||||
emit_u32(vm, addr);
|
emit_u32(vm, addr);
|
||||||
emit_byte(vm, src1);
|
|
||||||
emit_byte(vm, src2);
|
|
||||||
} else if (strcmp(opname, "jump-neq-int") == 0) {
|
} else if (strcmp(opname, "jump-neq-int") == 0) {
|
||||||
emit_opcode(vm, OP_JNEQ_INT);
|
emit_opcode(vm, OP_JNEQ_INT);
|
||||||
u32 addr = resolve_symbol(table, node->children[0]->token);
|
u32 addr = resolve_symbol(table, node->children[0]->token);
|
||||||
int src1 = parse_register(node->children[1]->token);
|
|
||||||
int src2 = parse_register(node->children[2]->token);
|
|
||||||
emit_u32(vm, addr);
|
emit_u32(vm, addr);
|
||||||
emit_byte(vm, src1);
|
|
||||||
emit_byte(vm, src2);
|
|
||||||
} else if (strcmp(opname, "jump-gt-int") == 0) {
|
} else if (strcmp(opname, "jump-gt-int") == 0) {
|
||||||
emit_opcode(vm, OP_JGT_INT);
|
emit_opcode(vm, OP_JGT_INT);
|
||||||
u32 addr = resolve_symbol(table, node->children[0]->token);
|
u32 addr = resolve_symbol(table, node->children[0]->token);
|
||||||
int src1 = parse_register(node->children[1]->token);
|
|
||||||
int src2 = parse_register(node->children[2]->token);
|
|
||||||
emit_u32(vm, addr);
|
emit_u32(vm, addr);
|
||||||
emit_byte(vm, src1);
|
|
||||||
emit_byte(vm, src2);
|
|
||||||
} else if (strcmp(opname, "jump-lt-int") == 0) {
|
} else if (strcmp(opname, "jump-lt-int") == 0) {
|
||||||
emit_opcode(vm, OP_JLT_INT);
|
emit_opcode(vm, OP_JLT_INT);
|
||||||
u32 addr = resolve_symbol(table, node->children[0]->token);
|
u32 addr = resolve_symbol(table, node->children[0]->token);
|
||||||
int src1 = parse_register(node->children[1]->token);
|
|
||||||
int src2 = parse_register(node->children[2]->token);
|
|
||||||
emit_u32(vm, addr);
|
emit_u32(vm, addr);
|
||||||
emit_byte(vm, src1);
|
|
||||||
emit_byte(vm, src2);
|
|
||||||
} else if (strcmp(opname, "jump-le-int") == 0) {
|
} else if (strcmp(opname, "jump-le-int") == 0) {
|
||||||
emit_opcode(vm, OP_JLE_INT);
|
emit_opcode(vm, OP_JLE_INT);
|
||||||
u32 addr = resolve_symbol(table, node->children[0]->token);
|
u32 addr = resolve_symbol(table, node->children[0]->token);
|
||||||
int src1 = parse_register(node->children[1]->token);
|
|
||||||
int src2 = parse_register(node->children[2]->token);
|
|
||||||
emit_u32(vm, addr);
|
emit_u32(vm, addr);
|
||||||
emit_byte(vm, src1);
|
|
||||||
emit_byte(vm, src2);
|
|
||||||
} else if (strcmp(opname, "jump-ge-int") == 0) {
|
} else if (strcmp(opname, "jump-ge-int") == 0) {
|
||||||
emit_opcode(vm, OP_JGE_INT);
|
emit_opcode(vm, OP_JGE_INT);
|
||||||
u32 addr = resolve_symbol(table, node->children[0]->token);
|
u32 addr = resolve_symbol(table, node->children[0]->token);
|
||||||
int src1 = parse_register(node->children[1]->token);
|
|
||||||
int src2 = parse_register(node->children[2]->token);
|
|
||||||
emit_u32(vm, addr);
|
emit_u32(vm, addr);
|
||||||
emit_byte(vm, src1);
|
|
||||||
emit_byte(vm, src2);
|
|
||||||
} else if (strcmp(opname, "jump-eq-nat") == 0) {
|
} else if (strcmp(opname, "jump-eq-nat") == 0) {
|
||||||
emit_opcode(vm, OP_JEQ_UINT);
|
emit_opcode(vm, OP_JEQ_UINT);
|
||||||
u32 addr = resolve_symbol(table, node->children[0]->token);
|
u32 addr = resolve_symbol(table, node->children[0]->token);
|
||||||
int src1 = parse_register(node->children[1]->token);
|
|
||||||
int src2 = parse_register(node->children[2]->token);
|
|
||||||
emit_u32(vm, addr);
|
emit_u32(vm, addr);
|
||||||
emit_byte(vm, src1);
|
|
||||||
emit_byte(vm, src2);
|
|
||||||
} else if (strcmp(opname, "jump-neq-nat") == 0) {
|
} else if (strcmp(opname, "jump-neq-nat") == 0) {
|
||||||
emit_opcode(vm, OP_JNEQ_UINT);
|
emit_opcode(vm, OP_JNEQ_UINT);
|
||||||
u32 addr = resolve_symbol(table, node->children[0]->token);
|
u32 addr = resolve_symbol(table, node->children[0]->token);
|
||||||
int src1 = parse_register(node->children[1]->token);
|
|
||||||
int src2 = parse_register(node->children[2]->token);
|
|
||||||
emit_u32(vm, addr);
|
emit_u32(vm, addr);
|
||||||
emit_byte(vm, src1);
|
|
||||||
emit_byte(vm, src2);
|
|
||||||
} else if (strcmp(opname, "jump-gt-nat") == 0) {
|
} else if (strcmp(opname, "jump-gt-nat") == 0) {
|
||||||
emit_opcode(vm, OP_JGT_UINT);
|
emit_opcode(vm, OP_JGT_UINT);
|
||||||
u32 addr = resolve_symbol(table, node->children[0]->token);
|
u32 addr = resolve_symbol(table, node->children[0]->token);
|
||||||
int src1 = parse_register(node->children[1]->token);
|
|
||||||
int src2 = parse_register(node->children[2]->token);
|
|
||||||
emit_u32(vm, addr);
|
emit_u32(vm, addr);
|
||||||
emit_byte(vm, src1);
|
|
||||||
emit_byte(vm, src2);
|
|
||||||
} else if (strcmp(opname, "jump-lt-nat") == 0) {
|
} else if (strcmp(opname, "jump-lt-nat") == 0) {
|
||||||
emit_opcode(vm, OP_JLT_UINT);
|
emit_opcode(vm, OP_JLT_UINT);
|
||||||
u32 addr = resolve_symbol(table, node->children[0]->token);
|
u32 addr = resolve_symbol(table, node->children[0]->token);
|
||||||
int src1 = parse_register(node->children[1]->token);
|
|
||||||
int src2 = parse_register(node->children[2]->token);
|
|
||||||
emit_u32(vm, addr);
|
emit_u32(vm, addr);
|
||||||
emit_byte(vm, src1);
|
|
||||||
emit_byte(vm, src2);
|
|
||||||
} else if (strcmp(opname, "jump-le-nat") == 0) {
|
} else if (strcmp(opname, "jump-le-nat") == 0) {
|
||||||
emit_opcode(vm, OP_JLE_UINT);
|
emit_opcode(vm, OP_JLE_UINT);
|
||||||
u32 addr = resolve_symbol(table, node->children[0]->token);
|
u32 addr = resolve_symbol(table, node->children[0]->token);
|
||||||
int src1 = parse_register(node->children[1]->token);
|
|
||||||
int src2 = parse_register(node->children[2]->token);
|
|
||||||
emit_u32(vm, addr);
|
emit_u32(vm, addr);
|
||||||
emit_byte(vm, src1);
|
|
||||||
emit_byte(vm, src2);
|
|
||||||
} else if (strcmp(opname, "jump-ge-nat") == 0) {
|
} else if (strcmp(opname, "jump-ge-nat") == 0) {
|
||||||
emit_opcode(vm, OP_JGE_UINT);
|
emit_opcode(vm, OP_JGE_UINT);
|
||||||
u32 addr = resolve_symbol(table, node->children[0]->token);
|
u32 addr = resolve_symbol(table, node->children[0]->token);
|
||||||
int src1 = parse_register(node->children[1]->token);
|
|
||||||
int src2 = parse_register(node->children[2]->token);
|
|
||||||
emit_u32(vm, addr);
|
emit_u32(vm, addr);
|
||||||
emit_byte(vm, src1);
|
|
||||||
emit_byte(vm, src2);
|
|
||||||
} else if (strcmp(opname, "jump-eq-real") == 0) {
|
} else if (strcmp(opname, "jump-eq-real") == 0) {
|
||||||
emit_opcode(vm, OP_JEQ_REAL);
|
emit_opcode(vm, OP_JEQ_REAL);
|
||||||
u32 addr = resolve_symbol(table, node->children[0]->token);
|
u32 addr = resolve_symbol(table, node->children[0]->token);
|
||||||
int src1 = parse_register(node->children[1]->token);
|
|
||||||
int src2 = parse_register(node->children[2]->token);
|
|
||||||
emit_u32(vm, addr);
|
emit_u32(vm, addr);
|
||||||
emit_byte(vm, src1);
|
|
||||||
emit_byte(vm, src2);
|
|
||||||
} else if (strcmp(opname, "jump-neq-real") == 0) {
|
} else if (strcmp(opname, "jump-neq-real") == 0) {
|
||||||
emit_opcode(vm, OP_JNEQ_REAL);
|
emit_opcode(vm, OP_JNEQ_REAL);
|
||||||
u32 addr = resolve_symbol(table, node->children[0]->token);
|
u32 addr = resolve_symbol(table, node->children[0]->token);
|
||||||
int src1 = parse_register(node->children[1]->token);
|
|
||||||
int src2 = parse_register(node->children[2]->token);
|
|
||||||
emit_u32(vm, addr);
|
emit_u32(vm, addr);
|
||||||
emit_byte(vm, src1);
|
|
||||||
emit_byte(vm, src2);
|
|
||||||
} else if (strcmp(opname, "jump-gt-real") == 0) {
|
} else if (strcmp(opname, "jump-gt-real") == 0) {
|
||||||
emit_opcode(vm, OP_JGT_REAL);
|
emit_opcode(vm, OP_JGT_REAL);
|
||||||
u32 addr = resolve_symbol(table, node->children[0]->token);
|
u32 addr = resolve_symbol(table, node->children[0]->token);
|
||||||
int src1 = parse_register(node->children[1]->token);
|
|
||||||
int src2 = parse_register(node->children[2]->token);
|
|
||||||
emit_u32(vm, addr);
|
emit_u32(vm, addr);
|
||||||
emit_byte(vm, src1);
|
|
||||||
emit_byte(vm, src2);
|
|
||||||
} else if (strcmp(opname, "jump-lt-real") == 0) {
|
} else if (strcmp(opname, "jump-lt-real") == 0) {
|
||||||
emit_opcode(vm, OP_JLT_REAL);
|
emit_opcode(vm, OP_JLT_REAL);
|
||||||
u32 addr = resolve_symbol(table, node->children[0]->token);
|
u32 addr = resolve_symbol(table, node->children[0]->token);
|
||||||
int src1 = parse_register(node->children[1]->token);
|
|
||||||
int src2 = parse_register(node->children[2]->token);
|
|
||||||
emit_u32(vm, addr);
|
emit_u32(vm, addr);
|
||||||
emit_byte(vm, src1);
|
|
||||||
emit_byte(vm, src2);
|
|
||||||
} else if (strcmp(opname, "jump-le-real") == 0) {
|
} else if (strcmp(opname, "jump-le-real") == 0) {
|
||||||
emit_opcode(vm, OP_JLE_REAL);
|
emit_opcode(vm, OP_JLE_REAL);
|
||||||
u32 addr = resolve_symbol(table, node->children[0]->token);
|
u32 addr = resolve_symbol(table, node->children[0]->token);
|
||||||
int src1 = parse_register(node->children[1]->token);
|
|
||||||
int src2 = parse_register(node->children[2]->token);
|
|
||||||
emit_u32(vm, addr);
|
emit_u32(vm, addr);
|
||||||
emit_byte(vm, src1);
|
|
||||||
emit_byte(vm, src2);
|
|
||||||
} else if (strcmp(opname, "jump-ge-real") == 0) {
|
} else if (strcmp(opname, "jump-ge-real") == 0) {
|
||||||
emit_opcode(vm, OP_JGE_REAL);
|
emit_opcode(vm, OP_JGE_REAL);
|
||||||
u32 addr = resolve_symbol(table, node->children[0]->token);
|
u32 addr = resolve_symbol(table, node->children[0]->token);
|
||||||
int src1 = parse_register(node->children[1]->token);
|
|
||||||
int src2 = parse_register(node->children[2]->token);
|
|
||||||
emit_u32(vm, addr);
|
emit_u32(vm, addr);
|
||||||
emit_byte(vm, src1);
|
|
||||||
emit_byte(vm, src2);
|
|
||||||
} else if (strcmp(opname, "string-length") == 0) {
|
} else if (strcmp(opname, "string-length") == 0) {
|
||||||
emit_opcode(vm, OP_STRLEN);
|
emit_opcode(vm, OP_STRLEN);
|
||||||
int dest = parse_register(node->children[0]->token);
|
|
||||||
int src = parse_register(node->children[1]->token);
|
|
||||||
emit_byte(vm, dest);
|
|
||||||
emit_byte(vm, src);
|
|
||||||
} else if (strcmp(opname, "string-eq") == 0) {
|
} else if (strcmp(opname, "string-eq") == 0) {
|
||||||
emit_opcode(vm, OP_STREQ);
|
emit_opcode(vm, OP_STREQ);
|
||||||
int dest = parse_register(node->children[0]->token);
|
|
||||||
int src1 = parse_register(node->children[1]->token);
|
|
||||||
int src2 = parse_register(node->children[2]->token);
|
|
||||||
emit_byte(vm, dest);
|
|
||||||
emit_byte(vm, src1);
|
|
||||||
emit_byte(vm, src2);
|
|
||||||
} else if (strcmp(opname, "string-concat") == 0) {
|
} else if (strcmp(opname, "string-concat") == 0) {
|
||||||
emit_opcode(vm, OP_STRCAT);
|
emit_opcode(vm, OP_STRCAT);
|
||||||
int dest = parse_register(node->children[0]->token);
|
|
||||||
int src1 = parse_register(node->children[1]->token);
|
|
||||||
int src2 = parse_register(node->children[2]->token);
|
|
||||||
emit_byte(vm, dest);
|
|
||||||
emit_byte(vm, src1);
|
|
||||||
emit_byte(vm, src2);
|
|
||||||
} else if (strcmp(opname, "string-get-char") == 0) {
|
} else if (strcmp(opname, "string-get-char") == 0) {
|
||||||
emit_opcode(vm, OP_STR_GET_CHAR);
|
emit_opcode(vm, OP_STR_GET_CHAR);
|
||||||
int dest = parse_register(node->children[0]->token);
|
|
||||||
int src1 = parse_register(node->children[1]->token);
|
|
||||||
int src2 = parse_register(node->children[2]->token);
|
|
||||||
emit_byte(vm, dest);
|
|
||||||
emit_byte(vm, src1);
|
|
||||||
emit_byte(vm, src2);
|
|
||||||
} else if (strcmp(opname, "string-find-char") == 0) {
|
} else if (strcmp(opname, "string-find-char") == 0) {
|
||||||
emit_opcode(vm, OP_STR_FIND_CHAR);
|
emit_opcode(vm, OP_STR_FIND_CHAR);
|
||||||
int dest = parse_register(node->children[0]->token);
|
|
||||||
int src1 = parse_register(node->children[1]->token);
|
|
||||||
int src2 = parse_register(node->children[2]->token);
|
|
||||||
emit_byte(vm, dest);
|
|
||||||
emit_byte(vm, src1);
|
|
||||||
emit_byte(vm, src2);
|
|
||||||
} else if (strcmp(opname, "string-slice") == 0) {
|
} else if (strcmp(opname, "string-slice") == 0) {
|
||||||
emit_opcode(vm, OP_STR_SLICE);
|
emit_opcode(vm, OP_STR_SLICE);
|
||||||
int dest = parse_register(node->children[0]->token);
|
|
||||||
int src1 = parse_register(node->children[1]->token);
|
|
||||||
int src2 = parse_register(node->children[2]->token);
|
|
||||||
int src3 = parse_register(node->children[3]->token);
|
|
||||||
emit_byte(vm, dest);
|
|
||||||
emit_byte(vm, src1);
|
|
||||||
emit_byte(vm, src2);
|
|
||||||
emit_byte(vm, src3);
|
|
||||||
} else if (strcmp(opname, "int-to-string") == 0) {
|
} else if (strcmp(opname, "int-to-string") == 0) {
|
||||||
emit_opcode(vm, OP_INT_TO_STRING);
|
emit_opcode(vm, OP_INT_TO_STRING);
|
||||||
int dest = parse_register(node->children[0]->token);
|
|
||||||
int src = parse_register(node->children[1]->token);
|
|
||||||
emit_byte(vm, dest);
|
|
||||||
emit_byte(vm, src);
|
|
||||||
} else if (strcmp(opname, "nat-to-string") == 0) {
|
} else if (strcmp(opname, "nat-to-string") == 0) {
|
||||||
emit_opcode(vm, OP_UINT_TO_STRING);
|
emit_opcode(vm, OP_UINT_TO_STRING);
|
||||||
int dest = parse_register(node->children[0]->token);
|
|
||||||
int src = parse_register(node->children[1]->token);
|
|
||||||
emit_byte(vm, dest);
|
|
||||||
emit_byte(vm, src);
|
|
||||||
} else if (strcmp(opname, "real-to-string") == 0) {
|
} else if (strcmp(opname, "real-to-string") == 0) {
|
||||||
emit_opcode(vm, OP_REAL_TO_STRING);
|
emit_opcode(vm, OP_REAL_TO_STRING);
|
||||||
int dest = parse_register(node->children[0]->token);
|
|
||||||
int src = parse_register(node->children[1]->token);
|
|
||||||
emit_byte(vm, dest);
|
|
||||||
emit_byte(vm, src);
|
|
||||||
} else if (strcmp(opname, "string-to-int") == 0) {
|
} else if (strcmp(opname, "string-to-int") == 0) {
|
||||||
emit_opcode(vm, OP_STRING_TO_INT);
|
emit_opcode(vm, OP_STRING_TO_INT);
|
||||||
int dest = parse_register(node->children[0]->token);
|
|
||||||
int src = parse_register(node->children[1]->token);
|
|
||||||
emit_byte(vm, dest);
|
|
||||||
emit_byte(vm, src);
|
|
||||||
} else if (strcmp(opname, "string-to-nat") == 0) {
|
} else if (strcmp(opname, "string-to-nat") == 0) {
|
||||||
emit_opcode(vm, OP_STRING_TO_UINT);
|
emit_opcode(vm, OP_STRING_TO_UINT);
|
||||||
int dest = parse_register(node->children[0]->token);
|
|
||||||
int src = parse_register(node->children[1]->token);
|
|
||||||
emit_byte(vm, dest);
|
|
||||||
emit_byte(vm, src);
|
|
||||||
} else if (strcmp(opname, "string-to-real") == 0) {
|
} else if (strcmp(opname, "string-to-real") == 0) {
|
||||||
emit_opcode(vm, OP_STRING_TO_REAL);
|
emit_opcode(vm, OP_STRING_TO_REAL);
|
||||||
int dest = parse_register(node->children[0]->token);
|
|
||||||
int src = parse_register(node->children[1]->token);
|
|
||||||
emit_byte(vm, dest);
|
|
||||||
emit_byte(vm, src);
|
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "Unknown opcode: %s\n", opname);
|
fprintf(stderr, "Unknown opcode: %s\n", opname);
|
||||||
}
|
}
|
||||||
|
|
183
src/vm/opcodes.h
183
src/vm/opcodes.h
|
@ -4,90 +4,85 @@
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
OP_HALT, /* halt : terminate execution with code [src1] */
|
OP_HALT, /* [obj1 `halt` - | terminate execution with code ] */
|
||||||
OP_JMP, /* jump : jump to address dest unconditionally */
|
OP_JMP, /* [dest `jump` - | jump to address dest unconditionally ] */
|
||||||
OP_JMPF, /* jump-if-flag : jump to address dest if flag is ne 0 */
|
OP_JMPF, /* [dest `jump-if-flag` - | jump to address dest if flag is ne 0 ] */
|
||||||
OP_CALL, /* call : creates a new frame */
|
OP_CALL, /* [&code_ref `call` - | creates a new frame ] */
|
||||||
OP_RETURN, /* return : returns from a frame to the parent frame */
|
OP_RETURN, /* [obj1 `return` - | returns from a frame to the parent frame, pushes obj1 on stack ] */
|
||||||
OP_LOAD_IMM, /* load-immediate : dest = constant */
|
OP_LOAD_8, /* [&dest `load-8` u8 | push memory[obj1] onto stack as u8 ] */
|
||||||
OP_GET_8, /* get-8 : dest = memory[registers[src1]] as u8 */
|
OP_LOAD_16, /* [&dest `load-16` u16 | push memory[obj1] onto stack as u16 ] */
|
||||||
OP_GET_16, /* get-16 : dest = memory[registers[src1]] as u8 */
|
OP_LOAD_32, /* [&dest `load` u32 | push memory[obj1] onto stack as u32 ] */
|
||||||
OP_GET_32, /* get : dest = memory[registers[src1]] as u32 */
|
OP_STORE_8, /* [&dest obj1 `store-8` - | memory[dest] = obj1 << 8 ] */
|
||||||
OP_LOAD_8, /* load-8 : dest = memory[src1 as u32] */
|
OP_STORE_16, /* [&dest obj1 `store-16`- | memory[dest] = obj1 << 16 ] */
|
||||||
OP_LOAD_16, /* load-16 : dest = memory[src1 as u32] */
|
OP_STORE_32, /* [&dest obj1 `store` - | memory[dest] = obj1 ] */
|
||||||
OP_LOAD_32, /* load : dest = memory[src1 as u32] */
|
OP_MALLOC, /* [size `malloc` ptr | allocate 'size + 4' of memory and push ptr to memory on stack ] */
|
||||||
OP_STORE_8, /* store-8 : memory[dest] = src1 << 8 */
|
OP_MEMSET_8, /* [ `memset-8` | dest <-> dest+count = obj1 as u8 ] */
|
||||||
OP_STORE_16, /* store-16 : memory[dest] = src1 << 16 */
|
OP_MEMSET_16, /* [ `memset-16` | dest <-> dest+count = obj1 as u8 ] */
|
||||||
OP_STORE_32, /* store : memory[dest] = src1 */
|
OP_MEMSET_32, /* [ `memset-32` | dest <-> dest+count = obj1 as u32 ] */
|
||||||
OP_PUT_8, /* put-8 : memory[dest] = registers[src1] << 8 */
|
OP_PUSH, /* [ `push` | push const of ref ] */
|
||||||
OP_PUT_16, /* put-16 : memory[dest] = registers[src1] << 16*/
|
OP_POP, /* [ `pop` | pop cosnt or ref ] */
|
||||||
OP_PUT_32, /* put : memory[dest] = registers[src1] */
|
OP_DUP, /* [ obj1 `dup` obj1 obj1 | ] */
|
||||||
OP_MALLOC, /* malloc : dest = fat ptr to memory of ((src1 as size) + 4) */
|
OP_EXCH, /* [ obj1 obj2 `exch` obj2 obj1 | ] */
|
||||||
OP_MEMSET_8, /* memset-8 : dest <-> dest+count = src1 as u8 */
|
OP_OVER, /* [ obj1 obj2 `over` obj1 obj2 obj1 | ] */
|
||||||
OP_MEMSET_16, /* memset-16 : dest <-> dest+count = src1 as u8 */
|
OP_PICK, /* [ N `pick` objN | ] */
|
||||||
OP_MEMSET_32, /* memset-32 : dest <-> dest+count = src1 as u32 */
|
OP_ROT, /* [ obj1 obj2 obj3 `rot` obj2 obj3 obj1 | ] */
|
||||||
OP_PUSH, /* push : push const of ref */
|
OP_DEPTH, /* [ - `depth` stack_size | ] */
|
||||||
OP_POP, /* pop : pop cosnt or ref */
|
OP_SYSCALL, /* [ `syscall` | obj1 obj2 obj3 obj4 more? does a system call based on args ] */
|
||||||
OP_REG_MOV, /* register-move : dest = src1 */
|
OP_SLL, /* [ `bit-shift-left` | dest = obj1 << obj2 ] */
|
||||||
OP_SYSCALL, /* syscall : src1 src2 src3 src4 more? does a system call based on args */
|
OP_SRL, /* [ `bit-shift-right` | dest = obj1 >> obj2 ] */
|
||||||
OP_SLL, /* bit-shift-left : dest = src1 << src2 */
|
OP_SRE, /* [ `bit-shift-re` | dest as i32 = obj1 >> obj2 ] */
|
||||||
OP_SRL, /* bit-shift-right : dest = src1 >> src2 */
|
OP_BAND, /* [ `bit-and` | dest = obj1 & obj2 ] */
|
||||||
OP_SRE, /* bit-shift-re : dest as i32 = src1 >> src2 */
|
OP_BOR, /* [ `bit-or` | dest = obj1 | obj2 ] */
|
||||||
OP_BAND, /* bit-and : dest = src1 & src2 */
|
OP_BXOR, /* [ `bit-xor` | dest = obj1 ^ obj2 ] */
|
||||||
OP_BOR, /* bit-or : dest = src1 | src2 */
|
OP_ADD_INT, /* [ `add-int` | dest = obj1 + obj2 ] */
|
||||||
OP_BXOR, /* bit-xor : dest = src1 ^ src2 */
|
OP_SUB_INT, /* [ `sub-int` | dest = obj1 - obj2 ] */
|
||||||
OP_ADD_INT, /* add-int : dest = src1 + src2 */
|
OP_MUL_INT, /* [ `mul-int` | dest = obj1 * obj2 ] */
|
||||||
OP_SUB_INT, /* sub-int : dest = src1 - src2 */
|
OP_DIV_INT, /* [ `div-int` | dest = obj1 / obj2 ] */
|
||||||
OP_MUL_INT, /* mul-int : dest = src1 * src2 */
|
OP_ADD_UINT, /* [ `add-nat` | dest = obj1 + obj2 ] */
|
||||||
OP_DIV_INT, /* div-int : dest = src1 / src2 */
|
OP_SUB_UINT, /* [ `sub-nat` | dest = obj1 - obj2 ] */
|
||||||
OP_ADD_UINT, /* add-nat : dest = src1 + src2 */
|
OP_MUL_UINT, /* [ `mul-nat` | dest = obj1 * obj2 ] */
|
||||||
OP_SUB_UINT, /* sub-nat : dest = src1 - src2 */
|
OP_DIV_UINT, /* [ `div-nat` | dest = obj1 / obj2 ] */
|
||||||
OP_MUL_UINT, /* mul-nat : dest = src1 * src2 */
|
OP_ADD_REAL, /* [ `add-real` | dest = obj1 + obj2 ] */
|
||||||
OP_DIV_UINT, /* div-nat : dest = src1 / src2 */
|
OP_SUB_REAL, /* [ `sub-real` | dest = obj1 - obj2 ] */
|
||||||
OP_ADD_REAL, /* add-real : dest = src1 + src2 */
|
OP_MUL_REAL, /* [ `mul-real` | dest = obj1 * obj2 ] */
|
||||||
OP_SUB_REAL, /* sub-real : dest = src1 - src2 */
|
OP_DIV_REAL, /* [ `div-real` | dest = obj1 / obj2 ] */
|
||||||
OP_MUL_REAL, /* mul-real : dest = src1 * src2 */
|
OP_INT_TO_REAL, /* [ `int-to-real` | dest = obj1 as real ] */
|
||||||
OP_DIV_REAL, /* div-real : dest = src1 / src2 */
|
OP_UINT_TO_REAL, /* [ `nat-to-real` | dest = obj1 as real ] */
|
||||||
OP_INT_TO_REAL, /* int-to-real : dest = src1 as real */
|
OP_REAL_TO_INT, /* [ `real-to-int` | dest = obj1 as int ] */
|
||||||
OP_UINT_TO_REAL, /* nat-to-real : dest = src1 as real */
|
OP_REAL_TO_UINT, /* [ `real-to-nat` | dest = obj1 as uint ] */
|
||||||
OP_REAL_TO_INT, /* real-to-int : dest = src1 as int */
|
OP_JEQ_INT, /* [ `jump-eq-int` | jump to address dest if obj1 as int == obj2 as int ] */
|
||||||
OP_REAL_TO_UINT, /* real-to-nat : dest = src1 as uint */
|
OP_JNEQ_INT, /* [ `jump-neq-int` | jump to address dest if obj1 as int != obj2 as int ] */
|
||||||
OP_JEQ_INT, /* jump-eq-int : jump to address dest if src1 as int == src2 as int */
|
OP_JGT_INT, /* [ `jump-gt-int` | jump to address dest if obj1 as int > obj2 as int ] */
|
||||||
OP_JNEQ_INT, /* jump-neq-int : jump to address dest if src1 as int != src2 as int */
|
OP_JLT_INT, /* [ `jump-lt-int` | jump to address dest if obj1 as int < obj2 as int ] */
|
||||||
OP_JGT_INT, /* jump-gt-int : jump to address dest if src1 as int > src2 as int */
|
OP_JLE_INT, /* [ `jump-le-int` | jump to address dest if obj1 as int <= obj2 as int ] */
|
||||||
OP_JLT_INT, /* jump-lt-int : jump to address dest if src1 as int < src2 as int */
|
OP_JGE_INT, /* [ `jump-ge-int` | jump to address dest if obj1 as int >= obj2 as int ] */
|
||||||
OP_JLE_INT, /* jump-le-int : jump to address dest if src1 as int <= src2 as int */
|
OP_JEQ_UINT, /* [ `jump-eq-nat` | jump to address dest if obj1 as uint == obj2 as uint ] */
|
||||||
OP_JGE_INT, /* jump-ge-int : jump to address dest if src1 as int >= src2 as int */
|
OP_JNEQ_UINT, /* [ `jump-neq-nat` | jump to address dest if obj1 as uint != obj2 as uint ] */
|
||||||
OP_JEQ_UINT, /* jump-eq-nat : jump to address dest if src1 as uint == src2 as uint */
|
OP_JGT_UINT, /* [ `jump-gt-nat` | jump to address dest if obj1 as uint > obj2 as uint ] */
|
||||||
OP_JNEQ_UINT, /* jump-neq-nat : jump to address dest if src1 as uint != src2 as uint */
|
OP_JLT_UINT, /* [ `jump-lt-nat` | jump to address dest if obj1 as uint < obj2 as uint ] */
|
||||||
OP_JGT_UINT, /* jump-gt-nat : jump to address dest if src1 as uint > src2 as uint */
|
OP_JLE_UINT, /* [ `jump-le-nat` | jump to address dest if obj1 as uint <= obj2 as uint ] */
|
||||||
OP_JLT_UINT, /* jump-lt-nat : jump to address dest if src1 as uint < src2 as uint */
|
OP_JGE_UINT, /* [ `jump-ge-nat` | jump to address dest if obj1 as uint >= obj2 as uint ] */
|
||||||
OP_JLE_UINT, /* jump-le-nat : jump to address dest if src1 as uint <= src2 as uint */
|
OP_JEQ_REAL, /* [ `jump-eq-real` | jump to address dest if obj1 as real == obj2 as real ] */
|
||||||
OP_JGE_UINT, /* jump-ge-nat : jump to address dest if src1 as uint >= src2 as uint */
|
OP_JNEQ_REAL, /* [ `jump-neq-real` | jump to address dest if obj1 as real != obj2 as real ] */
|
||||||
OP_JEQ_REAL, /* jump-eq-real : jump to address dest if src1 as real == src2 as real */
|
OP_JGE_REAL, /* [ `jump-ge-real` | jump to address dest if obj1 as real >= obj2 as real ] */
|
||||||
OP_JNEQ_REAL, /* jump-neq-real : jump to address dest if src1 as real != src2 as real */
|
OP_JGT_REAL, /* [ `jump-gt-real` | jump to address dest if obj1 as real > obj2 as real ] */
|
||||||
OP_JGE_REAL, /* jump-ge-real : jump to address dest if src1 as real >= src2 as real */
|
OP_JLT_REAL, /* [ `jump-lt-real` | jump to address dest if obj1 as real < obj2 as real ] */
|
||||||
OP_JGT_REAL, /* jump-gt-real : jump to address dest if src1 as real > src2 as real */
|
OP_JLE_REAL, /* [ `jump-le-real` | jump to address dest if obj1 as real <= obj2 as real ] */
|
||||||
OP_JLT_REAL, /* jump-lt-real : jump to address dest if src1 as real < src2 as real */
|
OP_STRLEN, /* [&str `string-length` len &str | length of string from str ptr ] */
|
||||||
OP_JLE_REAL, /* jump-le-real : jump to address dest if src1 as real <= src2 as real */
|
OP_STREQ, /* [ `string-eq` | dest = obj1 ptr string == obj2 ptr string ] */
|
||||||
OP_STRLEN, /* string-length : dest = length of str at src1 ptr */
|
OP_STRCAT, /* [ `string-concat` | dest = ptr of obj1 ptr string + obj2 ptr string ] */
|
||||||
OP_STREQ, /* string-eq : dest = src1 ptr string == src2 ptr string */
|
OP_STR_GET_CHAR, /* [ `string-get-char` | dest = ptr of obj1 ptr str, obj2 index of str ] */
|
||||||
OP_STRCAT, /* string-concat : dest = ptr of src1 ptr string + src2 ptr string */
|
OP_STR_FIND_CHAR, /* [ `string-find-char` | dest = ptr of obj1 ptr string, obj2 uint8 char ] */
|
||||||
OP_STR_GET_CHAR, /* string-get-char : dest = ptr of src1 ptr str, src2 index of str */
|
OP_STR_SLICE, /* [ `string-slice` | dest = ptr of obj1 ptr str, obj2 start index, obj3 end index ] */
|
||||||
OP_STR_FIND_CHAR, /* string-find-char : dest = ptr of src1 ptr string, src2 uint8 char */
|
OP_INT_TO_STRING, /* [ `int-to-string` | dest = obj1 as str ] */
|
||||||
OP_STR_SLICE, /* string-slice : dest = ptr of src1 ptr str, src2 start index, src3 end index */
|
OP_UINT_TO_STRING, /* [ `nat-to-string` | dest = obj1 as str ] */
|
||||||
OP_INT_TO_STRING, /* int-to-string : dest = src1 as str */
|
OP_REAL_TO_STRING, /* [ `real-to-string` | dest = obj1 as str ] */
|
||||||
OP_UINT_TO_STRING, /* nat-to-string : dest = src1 as str */
|
OP_STRING_TO_INT, /* [ `string-to-int` | dest = obj1 as int ] */
|
||||||
OP_REAL_TO_STRING, /* real-to-string : dest = src1 as str */
|
OP_STRING_TO_UINT, /* [ `string-to-nat` | dest = obj1 as uint ] */
|
||||||
OP_STRING_TO_INT, /* string-to-int : dest = src1 as int */
|
OP_STRING_TO_REAL /* [ `string-to-real` | dest = obj1 as real ] */
|
||||||
OP_STRING_TO_UINT, /* string-to-nat : dest = src1 as uint */
|
|
||||||
OP_STRING_TO_REAL /* string-to-real : dest = src1 as real */
|
|
||||||
} Opcode;
|
} Opcode;
|
||||||
|
|
||||||
#define MAX_REGS 32
|
|
||||||
typedef struct frame_s {
|
typedef struct frame_s {
|
||||||
u32 registers[MAX_REGS]; /* R0-R31 */
|
|
||||||
u32 rp; /* register pointer (last unused) */
|
|
||||||
u32 start; /* start and end of global allocated block */
|
u32 start; /* start and end of global allocated block */
|
||||||
u32 end;
|
u32 end;
|
||||||
} Frame;
|
} Frame;
|
||||||
|
@ -128,20 +123,20 @@ typedef struct device_s {
|
||||||
#define STACK_SIZE 256
|
#define STACK_SIZE 256
|
||||||
#define DEVICES_SIZE 8
|
#define DEVICES_SIZE 8
|
||||||
typedef struct vm_s {
|
typedef struct vm_s {
|
||||||
u32 pc; /* program counter */
|
u32 pc; /* program counter */
|
||||||
u32 cp; /* code pointer (last allocated opcode) */
|
u32 cp; /* code pointer (last allocated opcode) */
|
||||||
u32 fp; /* frame pointer (current frame) */
|
u32 fp; /* frame pointer (current frame) */
|
||||||
u32 sp; /* stack pointer (top of stack) */
|
u32 sp; /* stack pointer (top of stack) */
|
||||||
u32 rp; /* return stack pointer (top of stack) */
|
u32 rp; /* return stack pointer (top of stack) */
|
||||||
u32 mp; /* memory pointer (last allocated value) */
|
u32 mp; /* memory pointer (last allocated value) */
|
||||||
u32 dc; /* device count */
|
u32 dc; /* device count */
|
||||||
i32 flag; /* flag (temporary results like SYSCALL status) */
|
i32 flag; /* flag (temporary results like SYSCALL status) */
|
||||||
Frame frames[FRAMES_SIZE]; /* function call frames */
|
Frame frames[FRAMES_SIZE]; /* function call frames */
|
||||||
u32 stack[STACK_SIZE]; /* main stack */
|
u32 stack[STACK_SIZE]; /* main stack */
|
||||||
u32 return_stack[STACK_SIZE]; /* return stack (for call recursion) */
|
u32 return_stack[FRAMES_SIZE]; /* return stack (for call recursion) */
|
||||||
Device devices[DEVICES_SIZE]; /* device definitions */
|
Device devices[DEVICES_SIZE]; /* device definitions */
|
||||||
u8 code[CODE_SIZE]; /* code block */
|
u8 code[CODE_SIZE]; /* code block */
|
||||||
u8 memory[MEMORY_SIZE]; /* memory block */
|
u8 memory[MEMORY_SIZE]; /* memory block */
|
||||||
} VM;
|
} VM;
|
||||||
|
|
||||||
#define read_u8(vm, location, addr) ((vm)->location[addr])
|
#define read_u8(vm, location, addr) ((vm)->location[addr])
|
||||||
|
|
476
src/vm/vm.c
476
src/vm/vm.c
|
@ -7,17 +7,12 @@
|
||||||
do { \
|
do { \
|
||||||
i32 cond; \
|
i32 cond; \
|
||||||
u32 mask, target; \
|
u32 mask, target; \
|
||||||
u8 src1, src2; \
|
|
||||||
type value; \
|
type value; \
|
||||||
type value2; \
|
type value2; \
|
||||||
target = read_u32(vm, code, vm->pc); \
|
target = read_u32(vm, code, vm->pc); \
|
||||||
vm->pc += 4; \
|
vm->pc += 4; \
|
||||||
src1 = read_u8(vm, code, vm->pc); \
|
value2 = (type)vm->stack[--vm->sp]; \
|
||||||
vm->pc++; \
|
value = (type)vm->stack[--vm->sp]; \
|
||||||
src2 = read_u8(vm, code, vm->pc); \
|
|
||||||
vm->pc++; \
|
|
||||||
value = (type)frame->registers[src1]; \
|
|
||||||
value2 = (type)frame->registers[src2]; \
|
|
||||||
cond = !!(value op value2); \
|
cond = !!(value op value2); \
|
||||||
mask = -(u32)cond; \
|
mask = -(u32)cond; \
|
||||||
vm->pc = (target & mask) | (vm->pc & ~mask); \
|
vm->pc = (target & mask) | (vm->pc & ~mask); \
|
||||||
|
@ -26,26 +21,17 @@
|
||||||
|
|
||||||
#define MATH_OP(type, op) \
|
#define MATH_OP(type, op) \
|
||||||
do { \
|
do { \
|
||||||
dest = read_u8(vm, code, vm->pc); \
|
type b = (type)vm->stack[--vm->sp]; \
|
||||||
vm->pc++; \
|
type a = (type)vm->stack[--vm->sp]; \
|
||||||
src1 = read_u8(vm, code, vm->pc); \
|
vm->stack[vm->sp++] = (type)(a op b); \
|
||||||
vm->pc++; \
|
|
||||||
src2 = read_u8(vm, code, vm->pc); \
|
|
||||||
vm->pc++; \
|
|
||||||
frame->registers[dest] = \
|
|
||||||
(type)frame->registers[src1] op(type) frame->registers[src2]; \
|
|
||||||
return true; \
|
return true; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define BIT_OP(op) \
|
#define BIT_OP(op) \
|
||||||
do { \
|
do { \
|
||||||
dest = read_u8(vm, code, vm->pc); \
|
u32 a = vm->stack[--vm->sp]; \
|
||||||
vm->pc++; \
|
u32 b = vm->stack[--vm->sp]; \
|
||||||
src1 = read_u8(vm, code, vm->pc); \
|
vm->stack[vm->sp++] = a op b; \
|
||||||
vm->pc++; \
|
|
||||||
src2 = read_u8(vm, code, vm->pc); \
|
|
||||||
vm->pc++; \
|
|
||||||
frame->registers[dest] = frame->registers[src1] op frame->registers[src2]; \
|
|
||||||
return true; \
|
return true; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
@ -67,14 +53,9 @@ u32 str_alloc(VM *vm, Frame *frame, const char *str, u32 length) {
|
||||||
* Step to the next opcode in the vm.
|
* Step to the next opcode in the vm.
|
||||||
*/
|
*/
|
||||||
bool step_vm(VM *vm) {
|
bool step_vm(VM *vm) {
|
||||||
u16 opcode, dest, src1, src2;
|
|
||||||
u32 v, ptr;
|
|
||||||
i32 value;
|
|
||||||
Frame *frame;
|
|
||||||
|
|
||||||
/* Get current instruction & Advance to next instruction */
|
/* Get current instruction & Advance to next instruction */
|
||||||
opcode = vm->code[vm->pc++];
|
u8 opcode = vm->code[vm->pc++];
|
||||||
frame = &vm->frames[vm->fp];
|
Frame *frame = &vm->frames[vm->fp];
|
||||||
|
|
||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
case OP_HALT: {
|
case OP_HALT: {
|
||||||
|
@ -90,7 +71,6 @@ bool step_vm(VM *vm) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case OP_RETURN: {
|
case OP_RETURN: {
|
||||||
frame->rp = 0; /* reset register ptr */
|
|
||||||
vm->pc = vm->return_stack[--vm->rp]; /* set pc to return address */
|
vm->pc = vm->return_stack[--vm->rp]; /* set pc to return address */
|
||||||
vm->mp =
|
vm->mp =
|
||||||
vm->frames[vm->fp--].start; /* reset memory pointer to start
|
vm->frames[vm->fp--].start; /* reset memory pointer to start
|
||||||
|
@ -98,26 +78,18 @@ bool step_vm(VM *vm) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case OP_MALLOC: {
|
case OP_MALLOC: {
|
||||||
u32 size;
|
u32 size = read_u32(vm, code, vm->pc);
|
||||||
dest = read_u8(vm, code, vm->pc);
|
|
||||||
vm->pc++;
|
vm->pc++;
|
||||||
src1 = read_u8(vm, code, vm->pc);
|
vm->stack[vm->sp++] = vm->mp;
|
||||||
vm->pc++;
|
|
||||||
frame->registers[dest] = vm->mp;
|
|
||||||
size = frame->registers[src1];
|
|
||||||
write_u32(vm, memory, vm->mp, size);
|
write_u32(vm, memory, vm->mp, size);
|
||||||
vm->mp += (size + 4);
|
vm->mp += (size + 4);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case OP_MEMSET_32: {
|
case OP_MEMSET_32: {
|
||||||
u32 i, start, end;
|
u32 i, start, end;
|
||||||
u8 dest_reg = read_u8(vm, code, vm->pc++);
|
u32 dest = vm->stack[--vm->sp];
|
||||||
u8 value_reg = read_u8(vm, code, vm->pc++);
|
u32 value = vm->stack[--vm->sp];
|
||||||
u8 count_reg = read_u8(vm, code, vm->pc++);
|
u32 count = vm->stack[--vm->sp];
|
||||||
|
|
||||||
u32 dest = frame->registers[dest_reg];
|
|
||||||
u32 value = frame->registers[value_reg];
|
|
||||||
u32 count = frame->registers[count_reg];
|
|
||||||
|
|
||||||
if (count == 0) {
|
if (count == 0) {
|
||||||
vm->flag = 1;
|
vm->flag = 1;
|
||||||
|
@ -127,29 +99,24 @@ bool step_vm(VM *vm) {
|
||||||
start = dest;
|
start = dest;
|
||||||
end = dest + count;
|
end = dest + count;
|
||||||
|
|
||||||
if (start >= vm->mp || count > vm->mp ||
|
if (start >= vm->mp || count > vm->mp || end > vm->mp) {
|
||||||
end > vm->mp) {
|
|
||||||
vm->flag = 0;
|
vm->flag = 0;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = start; i < end; i+=4) {
|
for (i = start; i < end; i += 4) {
|
||||||
write_u32(vm, memory, i, value);
|
write_u32(vm, memory, i, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
frame->registers[0] = dest;
|
vm->stack[vm->sp++] = dest;
|
||||||
vm->flag = 1;
|
vm->flag = 1;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case OP_MEMSET_16: {
|
case OP_MEMSET_16: {
|
||||||
u32 i, start, end;
|
u32 i, start, end;
|
||||||
u8 dest_reg = read_u8(vm, code, vm->pc++);
|
u32 dest = vm->stack[--vm->sp];
|
||||||
u8 value_reg = read_u8(vm, code, vm->pc++);
|
u16 value = (u16)(vm->stack[--vm->sp]);
|
||||||
u8 count_reg = read_u8(vm, code, vm->pc++);
|
u32 count = vm->stack[--vm->sp];
|
||||||
|
|
||||||
u32 dest = frame->registers[dest_reg];
|
|
||||||
u16 value = (u16)(frame->registers[value_reg]);
|
|
||||||
u32 count = frame->registers[count_reg];
|
|
||||||
|
|
||||||
if (count == 0) {
|
if (count == 0) {
|
||||||
vm->flag = 1;
|
vm->flag = 1;
|
||||||
|
@ -159,29 +126,24 @@ bool step_vm(VM *vm) {
|
||||||
start = dest;
|
start = dest;
|
||||||
end = dest + count;
|
end = dest + count;
|
||||||
|
|
||||||
if (start >= vm->mp || count > vm->mp ||
|
if (start >= vm->mp || count > vm->mp || end > vm->mp) {
|
||||||
end > vm->mp) {
|
|
||||||
vm->flag = 0;
|
vm->flag = 0;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = start; i < end; i+=2) {
|
for (i = start; i < end; i += 2) {
|
||||||
write_u16(vm, memory, i, value);
|
write_u16(vm, memory, i, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
frame->registers[0] = dest;
|
vm->stack[vm->sp++] = dest;
|
||||||
vm->flag = 1;
|
vm->flag = 1;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case OP_MEMSET_8: {
|
case OP_MEMSET_8: {
|
||||||
u32 i, start, end;
|
u32 i, start, end;
|
||||||
u8 dest_reg = read_u8(vm, code, vm->pc++);
|
u32 dest = vm->stack[--vm->sp];
|
||||||
u8 value_reg = read_u8(vm, code, vm->pc++);
|
u8 value = (u8)(vm->stack[--vm->sp]);
|
||||||
u8 count_reg = read_u8(vm, code, vm->pc++);
|
u32 count = vm->stack[--vm->sp];
|
||||||
|
|
||||||
u32 dest = frame->registers[dest_reg];
|
|
||||||
u8 value = (u8)(frame->registers[value_reg]);
|
|
||||||
u32 count = frame->registers[count_reg];
|
|
||||||
|
|
||||||
if (count == 0) {
|
if (count == 0) {
|
||||||
vm->flag = 1;
|
vm->flag = 1;
|
||||||
|
@ -191,8 +153,7 @@ bool step_vm(VM *vm) {
|
||||||
start = dest;
|
start = dest;
|
||||||
end = dest + count;
|
end = dest + count;
|
||||||
|
|
||||||
if (start >= vm->mp || count > vm->mp ||
|
if (start >= vm->mp || count > vm->mp || end > vm->mp) {
|
||||||
end > vm->mp) {
|
|
||||||
vm->flag = 0;
|
vm->flag = 0;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -201,169 +162,94 @@ bool step_vm(VM *vm) {
|
||||||
write_u8(vm, memory, i, value);
|
write_u8(vm, memory, i, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
frame->registers[0] = dest;
|
vm->stack[vm->sp++] = dest;
|
||||||
vm->flag = 1;
|
vm->flag = 1;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case OP_LOAD_IMM: {
|
case OP_LOAD_8: {
|
||||||
dest = read_u8(vm, code, vm->pc);
|
u32 addr = vm->stack[--vm->sp];
|
||||||
vm->pc++;
|
vm->stack[vm->sp++] = read_u8(vm, memory, addr);
|
||||||
v = read_u32(vm, code, vm->pc);
|
|
||||||
vm->pc += 4;
|
|
||||||
frame->registers[dest] = v;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
case OP_LOAD_32: {
|
|
||||||
dest = read_u8(vm, code, vm->pc);
|
|
||||||
vm->pc++;
|
|
||||||
ptr = read_u32(vm, code, vm->pc);
|
|
||||||
vm->pc += 4;
|
|
||||||
v = read_u32(vm, memory, ptr);
|
|
||||||
frame->registers[dest] = v;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case OP_LOAD_16: {
|
case OP_LOAD_16: {
|
||||||
dest = read_u8(vm, code, vm->pc);
|
u32 addr = vm->stack[--vm->sp];
|
||||||
vm->pc++;
|
vm->stack[vm->sp++] = read_u16(vm, memory, addr);
|
||||||
ptr = read_u32(vm, code, vm->pc);
|
|
||||||
vm->pc += 4;
|
|
||||||
v = read_u16(vm, memory, ptr);
|
|
||||||
frame->registers[dest] = v;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case OP_LOAD_8: {
|
case OP_LOAD_32: {
|
||||||
dest = read_u8(vm, code, vm->pc);
|
u32 addr = vm->stack[--vm->sp];
|
||||||
vm->pc++;
|
vm->stack[vm->sp++] = read_u32(vm, memory, addr);
|
||||||
ptr = read_u32(vm, code, vm->pc);
|
|
||||||
vm->pc += 4;
|
|
||||||
v = read_u8(vm, memory, ptr);
|
|
||||||
frame->registers[dest] = v;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
case OP_GET_32: {
|
|
||||||
dest = read_u8(vm, code, vm->pc);
|
|
||||||
vm->pc++;
|
|
||||||
src1 = read_u8(vm, code, vm->pc);
|
|
||||||
vm->pc++;
|
|
||||||
v = frame->registers[src1];
|
|
||||||
ptr = read_u32(vm, memory, v);
|
|
||||||
frame->registers[dest] = ptr;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
case OP_GET_16: {
|
|
||||||
u16 v16;
|
|
||||||
dest = read_u8(vm, code, vm->pc);
|
|
||||||
vm->pc++;
|
|
||||||
src1 = read_u8(vm, code, vm->pc);
|
|
||||||
vm->pc++;
|
|
||||||
v = frame->registers[src1];
|
|
||||||
v16 = read_u16(vm, memory, v);
|
|
||||||
frame->registers[dest] = v16;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
case OP_GET_8: {
|
|
||||||
u8 v8;
|
|
||||||
dest = read_u8(vm, code, vm->pc);
|
|
||||||
vm->pc++;
|
|
||||||
src1 = read_u8(vm, code, vm->pc);
|
|
||||||
vm->pc++;
|
|
||||||
v = frame->registers[src1];
|
|
||||||
v8 = read_u8(vm, memory, v);
|
|
||||||
frame->registers[dest] = v8;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
case OP_STORE_32: {
|
|
||||||
dest = read_u8(vm, code, vm->pc);
|
|
||||||
vm->pc++;
|
|
||||||
src1 = read_u8(vm, code, vm->pc);
|
|
||||||
vm->pc++;
|
|
||||||
v = frame->registers[src1];
|
|
||||||
ptr = frame->registers[dest];
|
|
||||||
write_u32(vm, memory, ptr, v);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
case OP_STORE_16: {
|
|
||||||
dest = read_u8(vm, code, vm->pc);
|
|
||||||
vm->pc++;
|
|
||||||
src1 = read_u8(vm, code, vm->pc);
|
|
||||||
vm->pc++;
|
|
||||||
v = frame->registers[src1];
|
|
||||||
ptr = frame->registers[dest];
|
|
||||||
write_u16(vm, memory, ptr, v);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case OP_STORE_8: {
|
case OP_STORE_8: {
|
||||||
dest = read_u8(vm, code, vm->pc);
|
u8 value = vm->stack[--vm->sp];
|
||||||
vm->pc++;
|
u32 addr = vm->stack[--vm->sp];
|
||||||
src1 = read_u8(vm, code, vm->pc);
|
write_u8(vm, memory, addr, value);
|
||||||
vm->pc++;
|
|
||||||
v = frame->registers[src1];
|
|
||||||
ptr = frame->registers[dest];
|
|
||||||
write_u8(vm, memory, ptr, v);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case OP_PUT_32: {
|
case OP_STORE_16: {
|
||||||
dest = read_u8(vm, code, vm->pc);
|
u16 value = vm->stack[--vm->sp];
|
||||||
vm->pc++;
|
u32 addr = vm->stack[--vm->sp];
|
||||||
src1 = read_u8(vm, code, vm->pc);
|
write_u16(vm, memory, addr, value);
|
||||||
vm->pc++;
|
|
||||||
ptr = frame->registers[dest];
|
|
||||||
v = frame->registers[src1];
|
|
||||||
write_u32(vm, memory, ptr, v);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case OP_PUT_16: {
|
case OP_STORE_32: {
|
||||||
u16 v16;
|
u32 value = vm->stack[--vm->sp];
|
||||||
dest = read_u8(vm, code, vm->pc);
|
u32 addr = vm->stack[--vm->sp];
|
||||||
vm->pc++;
|
write_u32(vm, memory, addr, value);
|
||||||
src1 = read_u8(vm, code, vm->pc);
|
|
||||||
vm->pc++;
|
|
||||||
ptr = frame->registers[dest];
|
|
||||||
v16 = frame->registers[src1];
|
|
||||||
write_u16(vm, memory, ptr, v16);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
case OP_PUT_8: {
|
|
||||||
u8 v8;
|
|
||||||
dest = read_u8(vm, code, vm->pc);
|
|
||||||
vm->pc++;
|
|
||||||
src1 = read_u8(vm, code, vm->pc);
|
|
||||||
vm->pc++;
|
|
||||||
ptr = frame->registers[dest];
|
|
||||||
v8 = frame->registers[src1];
|
|
||||||
write_u8(vm, memory, ptr, v8);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case OP_PUSH: {
|
case OP_PUSH: {
|
||||||
dest = read_u8(vm, code, vm->pc);
|
u32 val = read_u32(vm, code, vm->pc);
|
||||||
vm->pc++;
|
vm->pc += 4;
|
||||||
vm->stack[++vm->sp] = frame->registers[dest];
|
vm->stack[vm->sp++] = val;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case OP_POP: {
|
case OP_POP: {
|
||||||
dest = read_u8(vm, code, vm->pc);
|
vm->sp--;
|
||||||
vm->pc++;
|
|
||||||
frame->registers[dest] = vm->stack[vm->sp--];
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case OP_REG_MOV: {
|
case OP_DUP: {
|
||||||
dest = read_u8(vm, code, vm->pc);
|
u32 a = vm->stack[--vm->sp];
|
||||||
vm->pc++;
|
vm->stack[vm->sp++] = a;
|
||||||
src1 = read_u8(vm, code, vm->pc);
|
vm->stack[vm->sp++] = a;
|
||||||
vm->pc++;
|
return true;
|
||||||
frame->registers[dest] = frame->registers[src1];
|
}
|
||||||
|
case OP_EXCH: {
|
||||||
|
u32 a = vm->stack[--vm->sp];
|
||||||
|
u32 b = vm->stack[--vm->sp];
|
||||||
|
vm->stack[vm->sp++] = b;
|
||||||
|
vm->stack[vm->sp++] = a;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case OP_OVER: {
|
||||||
|
u32 a = vm->stack[vm->sp - 1];
|
||||||
|
vm->stack[vm->sp++] = a;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case OP_PICK: {
|
||||||
|
u32 n = vm->stack[--vm->sp];
|
||||||
|
u32 b = vm->stack[vm->sp - n];
|
||||||
|
vm->stack[vm->sp++] = b;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case OP_ROT: {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
case OP_DEPTH: {
|
||||||
|
u32 a = vm->sp;
|
||||||
|
vm->stack[vm->sp++] = a;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case OP_JMP: {
|
case OP_JMP: {
|
||||||
dest = read_u8(vm, code, vm->pc);
|
u32 dest = read_u32(vm, code, vm->pc);
|
||||||
vm->pc++;
|
vm->pc += 4;
|
||||||
vm->pc = frame->registers[dest]; /* Jump to address */
|
vm->pc = dest; /* Jump to address */
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case OP_JMPF: { /* error handling for syscall, jump if flag == 0 */
|
case OP_JMPF: { /* error handling for syscall, jump if flag == 0 */
|
||||||
u32 mask;
|
u32 mask, dest = read_u32(vm, code, vm->pc);
|
||||||
dest = read_u8(vm, code, vm->pc);
|
vm->pc += 4;
|
||||||
vm->pc++;
|
|
||||||
mask = -(u32)(vm->flag == 0);
|
mask = -(u32)(vm->flag == 0);
|
||||||
vm->pc = (dest & mask) | (vm->pc & ~mask);
|
vm->pc = (dest & mask) | (vm->pc & ~mask);
|
||||||
return true;
|
return true;
|
||||||
|
@ -377,15 +263,8 @@ bool step_vm(VM *vm) {
|
||||||
switch (syscall_id) {
|
switch (syscall_id) {
|
||||||
case SYSCALL_DEVICE_OPEN: {
|
case SYSCALL_DEVICE_OPEN: {
|
||||||
Device *dev;
|
Device *dev;
|
||||||
u32 path_ptr, mode;
|
u32 path_ptr = vm->stack[--vm->sp];
|
||||||
u8 path_reg, mode_reg;
|
u32 mode = vm->stack[--vm->sp];
|
||||||
path_reg = read_u8(vm, code, vm->pc);
|
|
||||||
vm->pc++;
|
|
||||||
mode_reg = read_u8(vm, code, vm->pc);
|
|
||||||
vm->pc++;
|
|
||||||
|
|
||||||
path_ptr = frame->registers[path_reg];
|
|
||||||
mode = frame->registers[mode_reg];
|
|
||||||
dev = find_device_by_path(vm, (const char *)&vm->memory[path_ptr + 4]);
|
dev = find_device_by_path(vm, (const char *)&vm->memory[path_ptr + 4]);
|
||||||
if (dev) {
|
if (dev) {
|
||||||
if (dev->ops->open) {
|
if (dev->ops->open) {
|
||||||
|
@ -402,25 +281,15 @@ bool step_vm(VM *vm) {
|
||||||
|
|
||||||
case SYSCALL_DEVICE_READ: {
|
case SYSCALL_DEVICE_READ: {
|
||||||
Device *dev;
|
Device *dev;
|
||||||
u32 path_ptr, buffer_ptr, size;
|
|
||||||
u16 path_reg, buffer_reg, size_reg;
|
|
||||||
path_reg = read_u8(vm, code, vm->pc);
|
|
||||||
vm->pc++;
|
|
||||||
buffer_reg = read_u8(vm, code, vm->pc);
|
|
||||||
vm->pc++;
|
|
||||||
size_reg = read_u8(vm, code, vm->pc);
|
|
||||||
vm->pc++;
|
|
||||||
dest = read_u8(vm, code, vm->pc);
|
|
||||||
vm->pc++;
|
|
||||||
|
|
||||||
path_ptr = frame->registers[path_reg]; /* path pointer */
|
u32 path_ptr = vm->stack[--vm->sp]; /* path pointer */
|
||||||
size = frame->registers[size_reg]; /* size */
|
u32 size = vm->stack[--vm->sp]; /* size */
|
||||||
buffer_ptr = frame->registers[dest];
|
u32 buffer_ptr = vm->stack[--vm->sp];
|
||||||
|
|
||||||
dev = find_device_by_path(vm, (const char *)&vm->memory[path_ptr + 4]);
|
dev = find_device_by_path(vm, (const char *)&vm->memory[path_ptr + 4]);
|
||||||
if (dev && dev->ops->read) {
|
if (dev && dev->ops->read) {
|
||||||
vm->flag = dev->ops->read(dev->data, &vm->memory[buffer_ptr + 4], size);
|
vm->flag = dev->ops->read(dev->data, &vm->memory[buffer_ptr + 4], size);
|
||||||
frame->registers[buffer_reg] = buffer_ptr;
|
vm->stack[vm->sp++] = buffer_ptr;
|
||||||
} else {
|
} else {
|
||||||
vm->flag = 0;
|
vm->flag = 0;
|
||||||
}
|
}
|
||||||
|
@ -430,18 +299,9 @@ bool step_vm(VM *vm) {
|
||||||
|
|
||||||
case SYSCALL_DEVICE_WRITE: {
|
case SYSCALL_DEVICE_WRITE: {
|
||||||
Device *dev;
|
Device *dev;
|
||||||
u32 path_ptr, buffer_ptr, size;
|
u32 path_ptr = vm->stack[--vm->sp]; /* path pointer */
|
||||||
u16 path_reg, buffer_reg, size_reg;
|
u32 size = vm->stack[--vm->sp]; /* size */
|
||||||
path_reg = read_u8(vm, code, vm->pc);
|
u32 buffer_ptr = vm->stack[--vm->sp]; /* buffer pointer */
|
||||||
vm->pc++;
|
|
||||||
buffer_reg = read_u8(vm, code, vm->pc);
|
|
||||||
vm->pc++;
|
|
||||||
size_reg = read_u8(vm, code, vm->pc);
|
|
||||||
vm->pc++;
|
|
||||||
|
|
||||||
path_ptr = frame->registers[path_reg]; /* R0: path pointer */
|
|
||||||
buffer_ptr = frame->registers[buffer_reg]; /* R1: buffer pointer */
|
|
||||||
size = frame->registers[size_reg]; /* R2: size */
|
|
||||||
|
|
||||||
dev = find_device_by_path(vm, (const char *)&vm->memory[path_ptr + 4]);
|
dev = find_device_by_path(vm, (const char *)&vm->memory[path_ptr + 4]);
|
||||||
if (dev && dev->ops->write) {
|
if (dev && dev->ops->write) {
|
||||||
|
@ -456,12 +316,7 @@ bool step_vm(VM *vm) {
|
||||||
|
|
||||||
case SYSCALL_DEVICE_CLOSE: {
|
case SYSCALL_DEVICE_CLOSE: {
|
||||||
Device *dev;
|
Device *dev;
|
||||||
u32 path_ptr;
|
u32 path_ptr = vm->stack[--vm->sp]; /* path pointer */
|
||||||
u8 path_reg;
|
|
||||||
path_reg = read_u8(vm, code, vm->pc);
|
|
||||||
vm->pc++;
|
|
||||||
|
|
||||||
path_ptr = frame->registers[path_reg]; /* R0: path pointer */
|
|
||||||
|
|
||||||
dev = find_device_by_path(vm, (const char *)&vm->memory[path_ptr + 4]);
|
dev = find_device_by_path(vm, (const char *)&vm->memory[path_ptr + 4]);
|
||||||
|
|
||||||
|
@ -477,18 +332,9 @@ bool step_vm(VM *vm) {
|
||||||
|
|
||||||
case SYSCALL_DEVICE_IOCTL: {
|
case SYSCALL_DEVICE_IOCTL: {
|
||||||
Device *dev;
|
Device *dev;
|
||||||
u32 path_ptr, args_ptr, cmd;
|
u32 path_ptr = vm->stack[--vm->sp]; /* device path */
|
||||||
u8 path_reg, cmd_reg, args_ptr_reg;
|
u32 cmd = vm->stack[--vm->sp]; /* ioctl command */
|
||||||
path_reg = read_u8(vm, code, vm->pc);
|
u32 args_ptr = vm->stack[--vm->sp]; /* args pointer */
|
||||||
vm->pc++;
|
|
||||||
cmd_reg = read_u8(vm, code, vm->pc);
|
|
||||||
vm->pc++;
|
|
||||||
args_ptr_reg = read_u8(vm, code, vm->pc);
|
|
||||||
vm->pc++;
|
|
||||||
|
|
||||||
path_ptr = frame->registers[path_reg]; /* R0: device path */
|
|
||||||
cmd = frame->registers[cmd_reg]; /* R1: ioctl command */
|
|
||||||
args_ptr = frame->registers[args_ptr_reg]; /* R2: args pointer */
|
|
||||||
|
|
||||||
dev = find_device_by_path(vm, (const char *)&vm->memory[path_ptr + 4]);
|
dev = find_device_by_path(vm, (const char *)&vm->memory[path_ptr + 4]);
|
||||||
|
|
||||||
|
@ -542,92 +388,55 @@ bool step_vm(VM *vm) {
|
||||||
case OP_DIV_UINT:
|
case OP_DIV_UINT:
|
||||||
MATH_OP(u32, /);
|
MATH_OP(u32, /);
|
||||||
case OP_MUL_REAL: {
|
case OP_MUL_REAL: {
|
||||||
dest = read_u8(vm, code, vm->pc);
|
u32 a = vm->stack[--vm->sp];
|
||||||
vm->pc++;
|
u32 b = (vm->stack[--vm->sp] >> 16);
|
||||||
src1 = read_u8(vm, code, vm->pc);
|
vm->stack[vm->sp++] = a * b;
|
||||||
vm->pc++;
|
|
||||||
src2 = read_u8(vm, code, vm->pc);
|
|
||||||
vm->pc++;
|
|
||||||
frame->registers[dest] =
|
|
||||||
(frame->registers[src1] * frame->registers[src2]) >> 16;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
case OP_DIV_REAL: {
|
case OP_DIV_REAL: {
|
||||||
dest = read_u8(vm, code, vm->pc);
|
u32 a = vm->stack[--vm->sp] << 16;
|
||||||
vm->pc++;
|
u32 b = vm->stack[--vm->sp];
|
||||||
src1 = read_u8(vm, code, vm->pc);
|
vm->stack[vm->sp++] = a / b;
|
||||||
vm->pc++;
|
|
||||||
src2 = read_u8(vm, code, vm->pc);
|
|
||||||
vm->pc++;
|
|
||||||
frame->registers[dest] =
|
|
||||||
(frame->registers[src1] << 16) / frame->registers[src2];
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
case OP_ADD_REAL: {
|
case OP_ADD_REAL: {
|
||||||
dest = read_u8(vm, code, vm->pc);
|
u32 a = vm->stack[--vm->sp];
|
||||||
vm->pc++;
|
u32 b = vm->stack[--vm->sp];
|
||||||
src1 = read_u8(vm, code, vm->pc);
|
vm->stack[vm->sp++] = a + b;
|
||||||
vm->pc++;
|
|
||||||
src2 = read_u8(vm, code, vm->pc);
|
|
||||||
vm->pc++;
|
|
||||||
frame->registers[dest] = frame->registers[src1] + frame->registers[src2];
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
case OP_SUB_REAL: {
|
case OP_SUB_REAL: {
|
||||||
dest = read_u8(vm, code, vm->pc);
|
u32 a = vm->stack[--vm->sp];
|
||||||
vm->pc++;
|
u32 b = vm->stack[--vm->sp];
|
||||||
src1 = read_u8(vm, code, vm->pc);
|
vm->stack[vm->sp++] = a - b;
|
||||||
vm->pc++;
|
|
||||||
src2 = read_u8(vm, code, vm->pc);
|
|
||||||
vm->pc++;
|
|
||||||
frame->registers[dest] = frame->registers[src1] - frame->registers[src2];
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case OP_REAL_TO_INT: {
|
case OP_REAL_TO_INT: {
|
||||||
dest = read_u8(vm, code, vm->pc);
|
i32 value = vm->stack[--vm->sp];
|
||||||
vm->pc++;
|
|
||||||
src1 = read_u8(vm, code, vm->pc);
|
|
||||||
vm->pc++;
|
|
||||||
value = frame->registers[src1];
|
|
||||||
|
|
||||||
if (value >= 0) {
|
if (value >= 0) {
|
||||||
frame->registers[dest] = value >> 16;
|
vm->stack[vm->sp++] = value >> 16;
|
||||||
} else {
|
} else {
|
||||||
frame->registers[dest] = -((-value) >> 16);
|
vm->stack[vm->sp++] = -((-value) >> 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case OP_INT_TO_REAL: {
|
case OP_INT_TO_REAL: {
|
||||||
dest = read_u8(vm, code, vm->pc);
|
i32 value = (vm->stack[--vm->sp] << 16);
|
||||||
vm->pc++;
|
vm->stack[vm->sp++] = value;
|
||||||
src1 = read_u8(vm, code, vm->pc);
|
|
||||||
vm->pc++;
|
|
||||||
frame->registers[dest] = (frame->registers[src1] << 16);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case OP_REAL_TO_UINT: {
|
case OP_REAL_TO_UINT: {
|
||||||
dest = read_u8(vm, code, vm->pc);
|
i32 value = vm->stack[--vm->sp];
|
||||||
vm->pc++;
|
|
||||||
src1 = read_u8(vm, code, vm->pc);
|
|
||||||
vm->pc++;
|
|
||||||
value = frame->registers[src1];
|
|
||||||
if (value < 0) {
|
if (value < 0) {
|
||||||
frame->registers[dest] = 0;
|
vm->stack[vm->sp++] = 0;
|
||||||
} else {
|
} else {
|
||||||
frame->registers[dest] = AS_UINT(value >> 16);
|
vm->stack[vm->sp++] = AS_UINT(value >> 16);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case OP_UINT_TO_REAL: {
|
case OP_UINT_TO_REAL: {
|
||||||
dest = read_u8(vm, code, vm->pc);
|
i32 value = AS_INT(vm->stack[--vm->sp] << 16);
|
||||||
vm->pc++;
|
vm->stack[vm->sp++] = value;
|
||||||
src1 = read_u8(vm, code, vm->pc);
|
|
||||||
vm->pc++;
|
|
||||||
frame->registers[dest] = AS_INT(frame->registers[src1] << 16);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case OP_JEQ_UINT: {
|
case OP_JEQ_UINT: {
|
||||||
|
@ -686,48 +495,27 @@ bool step_vm(VM *vm) {
|
||||||
}
|
}
|
||||||
case OP_INT_TO_STRING: {
|
case OP_INT_TO_STRING: {
|
||||||
char buffer[32];
|
char buffer[32];
|
||||||
dest = read_u8(vm, code, vm->pc);
|
int_to_string(AS_INT(vm->stack[--vm->sp]), buffer);
|
||||||
vm->pc++;
|
vm->stack[vm->sp++] = str_alloc(vm, frame, buffer, strlength(buffer));
|
||||||
src1 = read_u8(vm, code, vm->pc);
|
|
||||||
vm->pc++;
|
|
||||||
int_to_string(AS_INT(frame->registers[src1]), buffer);
|
|
||||||
ptr = str_alloc(vm, frame, buffer, strlength(buffer));
|
|
||||||
frame->registers[dest] = ptr;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case OP_UINT_TO_STRING: {
|
case OP_UINT_TO_STRING: {
|
||||||
char buffer[32];
|
char buffer[32];
|
||||||
dest = read_u8(vm, code, vm->pc);
|
uint_to_string(vm->stack[--vm->sp], buffer);
|
||||||
vm->pc++;
|
vm->stack[vm->sp++] = str_alloc(vm, frame, buffer, strlength(buffer));
|
||||||
src1 = read_u8(vm, code, vm->pc);
|
|
||||||
vm->pc++;
|
|
||||||
uint_to_string(frame->registers[src1], buffer);
|
|
||||||
ptr = str_alloc(vm, frame, buffer, strlength(buffer));
|
|
||||||
frame->registers[dest] = ptr;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case OP_REAL_TO_STRING: {
|
case OP_REAL_TO_STRING: {
|
||||||
char buffer[32];
|
char buffer[32];
|
||||||
dest = read_u8(vm, code, vm->pc);
|
fixed_to_string(AS_INT(vm->stack[--vm->sp]), buffer);
|
||||||
vm->pc++;
|
vm->stack[vm->sp++] = str_alloc(
|
||||||
src1 = read_u8(vm, code, vm->pc);
|
vm, frame, buffer, strlength(buffer)); /* copy buffer to dest */
|
||||||
vm->pc++;
|
|
||||||
fixed_to_string(AS_INT(frame->registers[src1]), buffer);
|
|
||||||
ptr = str_alloc(vm, frame, buffer,
|
|
||||||
strlength(buffer)); /* copy buffer to dest */
|
|
||||||
frame->registers[dest] = ptr;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case OP_STRLEN: {
|
case OP_STRLEN: {
|
||||||
u32 ptr, length;
|
u32 ptr;
|
||||||
dest = read_u8(vm, code, vm->pc);
|
ptr = vm->stack[--vm->sp];
|
||||||
vm->pc++;
|
vm->stack[vm->sp++] = read_u32(vm, memory, ptr);
|
||||||
src1 = read_u8(vm, code, vm->pc);
|
|
||||||
vm->pc++;
|
|
||||||
|
|
||||||
ptr = frame->registers[src1];
|
|
||||||
length = read_u32(vm, memory, ptr);
|
|
||||||
frame->registers[dest] = length;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case OP_STRCAT: {
|
case OP_STRCAT: {
|
||||||
|
|
|
@ -1,24 +1,27 @@
|
||||||
(module add
|
((code
|
||||||
(const terminal-namespace "/dev/term/0")
|
(label main
|
||||||
(const new-line "\n")
|
(push 1)
|
||||||
|
(push 1)
|
||||||
(fn :1 main ()
|
(call &add)
|
||||||
(load-immediate $0 1)
|
(int-to-string)
|
||||||
(load-immediate $1 1)
|
(call &pln)
|
||||||
(call &add ($0 $1) $2)
|
|
||||||
(int-to-string $1 $2)
|
|
||||||
(call &pln ($1))
|
|
||||||
(halt))
|
(halt))
|
||||||
|
|
||||||
|
(label add
|
||||||
|
(add-int)
|
||||||
|
(return))
|
||||||
|
|
||||||
(fn :1 add ($0 $1)
|
(label pln
|
||||||
(add-int $2 $1 $0)
|
(dup)
|
||||||
(return $2))
|
(string-length)
|
||||||
|
(push &terminal-namespace)
|
||||||
(fn :1 pln ($1)
|
(syscall WRITE)
|
||||||
(load-immediate $0 &terminal-namespace)
|
(push &new-line)
|
||||||
(load-immediate $3 &new-line)
|
(dup)
|
||||||
(string-length $2 $1)
|
(string-length)
|
||||||
(syscall WRITE $0 $1 $2)
|
(push &terminal-namespace)
|
||||||
(string-length $4 $3)
|
(syscall WRITE)
|
||||||
(syscall WRITE $0 $3 $4)
|
|
||||||
(return)))
|
(return)))
|
||||||
|
(data
|
||||||
|
(label terminal-namespace "/dev/term/0")
|
||||||
|
(label new-line "\n")))
|
||||||
|
|
|
@ -1,42 +1,44 @@
|
||||||
((code
|
((code
|
||||||
(label main
|
(label main
|
||||||
(load-immediate $0 35)
|
(push 35)
|
||||||
(push $0)
|
(call &fib)
|
||||||
(call &fib)
|
(int-to-string)
|
||||||
(pop $0)
|
(call &pln)
|
||||||
(int-to-string $1 $0)
|
(halt))
|
||||||
(push $1)
|
|
||||||
(call &pln)
|
(label fib
|
||||||
(halt))
|
(dup) ; dup num
|
||||||
(label fib
|
(push 2) ; Base case: n < 2
|
||||||
(pop $0)
|
(jump-lt-int &base-case)
|
||||||
(load-immediate $1 2)
|
|
||||||
(jump-lt-int &base-case $0 $1)
|
(dup)
|
||||||
(load-immediate $3 2)
|
(push 2) ; First call: fib(n-2)
|
||||||
(sub-int $4 $0 $3)
|
(sub-int) ; n - 2
|
||||||
(push $4)
|
(call &fib)
|
||||||
(call &fib)
|
|
||||||
(load-immediate $3 1)
|
(over) ; get n over the previous answer
|
||||||
(sub-int $4 $0 $3)
|
(push 1) ; Second call: fib(n-1)
|
||||||
(push $4)
|
(sub-int) ; n-1 (using saved n)
|
||||||
(call &fib)
|
(call &fib) ; Result in $2
|
||||||
(pop $4)
|
|
||||||
(pop $5)
|
; Combine results
|
||||||
(add-int $6 $5 $4)
|
(add-int) ; fib(n-2) + fib(n-1)
|
||||||
(push $6)
|
(return) ; Return result
|
||||||
(return)
|
|
||||||
(label base-case
|
(label base-case
|
||||||
(push $0)
|
(return))) ; Return n directly
|
||||||
(return)))
|
|
||||||
(label pln
|
(label pln
|
||||||
(load-immediate $0 &terminal-namespace)
|
(dup)
|
||||||
(load-immediate $3 &new-line)
|
(string-length)
|
||||||
(pop $1)
|
(push &terminal-namespace)
|
||||||
(string-length $2 $1)
|
(syscall WRITE)
|
||||||
(syscall WRITE $0 $1 $2)
|
(push &new-line)
|
||||||
(string-length $4 $3)
|
(dup)
|
||||||
(syscall WRITE $0 $3 $4)
|
(string-length)
|
||||||
|
(push &terminal-namespace)
|
||||||
|
(syscall WRITE)
|
||||||
(return)))
|
(return)))
|
||||||
(data
|
(data
|
||||||
(label terminal-namespace "/dev/term/0")
|
(label terminal-namespace "/dev/term/0")
|
||||||
(label new-line "\n")))
|
(label new-line "\n")))
|
||||||
|
|
Loading…
Reference in New Issue