From 9fe4f970163851496de5f2c6e5d4676991833b1a Mon Sep 17 00:00:00 2001 From: zongor Date: Wed, 7 Jan 2026 23:35:57 -0800 Subject: [PATCH] Add test works, WIP fibonacci test --- arch/linux/tui/main.c | 89 +++++++ vm/vm.c | 603 ++++++++++++++++++++++++++++++++++++++++++ vm/vm.h | 212 +++++++++++++++ 3 files changed, 904 insertions(+) create mode 100644 arch/linux/tui/main.c create mode 100644 vm/vm.c create mode 100644 vm/vm.h diff --git a/arch/linux/tui/main.c b/arch/linux/tui/main.c new file mode 100644 index 0000000..26ddc0b --- /dev/null +++ b/arch/linux/tui/main.c @@ -0,0 +1,89 @@ +#include "../../../vm/vm.h" +#include +#include + +#define CODE_SIZE 8192 +#define MEMORY_SIZE 65536 +u8 lmem[MEMORY_SIZE] = {0}; +u32 lcode[CODE_SIZE] = {0}; + +bool init_vm() { + mem = lmem; + memset(mem, 0, MEMORY_SIZE*sizeof(u8)); + code = lcode; + sp = 0; + mp = 0; + cp = 0; + pc = 0; + interrupt = 0; + return true; +} + +u32 syscall(u32 id, u32 args, u32 mem_ptr) { + USED(args); + switch(id) { + case SYSCALL_DBG_PRINT: { + printf("%d\n", mem[mem_ptr]); + return 0; + } + } + + return 1; // generic error +} + +void test_add_two_num() { + i32 main_local_count = 4; + mp += (4 * main_local_count); + code[cp++] = ENCODE_B(OP_LOAD_IMM, 0, 1); + code[cp++] = ENCODE_B(OP_PUSH, 0, 0); + code[cp++] = ENCODE_B(OP_LOAD_IMM, 1, 1); + code[cp++] = ENCODE_B(OP_PUSH, 1, 0); + i32 add = cp + 4; + code[cp++] = ENCODE_B(OP_LOAD_IMM, 2, add); + code[cp++] = ENCODE_A(OP_CALL, 2, 3, 3); + code[cp++] = ENCODE_A(OP_SYSCALL, SYSCALL_DBG_PRINT, 1, 3); + code[cp++] = ENCODE_A(OP_HALT, 0, 0, 0); + + /* add */ + code[cp++] = ENCODE_A(OP_ADD_INT, 2, 1, 0); + code[cp++] = ENCODE_B(OP_RETURN, 2, 0); +} + +void test_fibonacci() { + /* fn main() */ + i32 main_local_count = 3; + mp += (4 * main_local_count); + code[cp++] = ENCODE_B(OP_LOAD_IMM, 0, 35); + code[cp++] = ENCODE_B(OP_PUSH, 0, 0); + i32 fib = cp + 4; + code[cp++] = ENCODE_B(OP_LOAD_IMM, 1, fib); + code[cp++] = ENCODE_A(OP_CALL, 1, 3, 2); + code[cp++] = ENCODE_A(OP_SYSCALL, SYSCALL_DBG_PRINT, 1, 2); + code[cp++] = ENCODE_A(OP_HALT, 0, 0, 0); + + /* fn fib */ + code[cp++] = ENCODE_B(OP_LOAD_IMM, 1, 2); + code[cp++] = ENCODE_B(OP_LOAD_IMM, 2, fib); + code[cp++] = ENCODE_A(OP_JLT_INT, 2, 0, 1); + code[cp++] = ENCODE_B(OP_LOAD_IMM, 3, 2); + code[cp++] = ENCODE_A(OP_SUB_INT, 4, 0, 3); + code[cp++] = ENCODE_B(OP_PUSH, 4, 0); + code[cp++] = ENCODE_A(OP_CALL, 2, 3, 2); + + + + code[cp++] = ENCODE_B(OP_RETURN, 0, 0); +} + +i32 main() { + init_vm(); + + test_add_two_num(); + + while(step_vm()) { + // do stuff + } + return 0; +} + + diff --git a/vm/vm.c b/vm/vm.c new file mode 100644 index 0000000..4d21035 --- /dev/null +++ b/vm/vm.c @@ -0,0 +1,603 @@ +#include "vm.h" +#define FRAME_HEADER_SIZE 12 + +u32 pc; /* program counter */ +u32 cp; /* code pointer */ +u32 mp; /* memory pointer */ +u32 fp; /* frame pointer */ +u8 sp; /* child local count */ +u32 flag; /* flag */ +u8 interrupt; /* device interrupt */ +u32 *code; /* code */ +u8 *mem; /* memory */ + +bool step_vm() { + + u32 instruction = code[pc++]; + u8 opcode = DECODE_OP(instruction); + + switch (opcode) { + case OP_HALT: { + /* no need to decode, all are zeros */ + return false; + } + case OP_CALL: { + DECODE_A(instruction) + u32 fn_ptr; + + u32 rd = fp + (dest * 4); + u32 r1 = src1; + u32 r2 = fp + src2; + + fn_ptr = READ_U32(rd); + + /* push parents frame value to reset the heap to */ + WRITE_U32(mp, fp); + mp += 4; + /* push return address to child frame */ + WRITE_U32(mp, pc); + mp += 4; + /* push local address to return the value to */ + WRITE_U32(mp, r2); + mp += 4; + /* now set the frame pointer, where the locals start */ + fp = mp; + /* move mp by count many locals */ + mp += (4 * r1); + /* jump to dest_ptr */ + pc = fn_ptr; + return true; + } + case OP_RETURN: { + DECODE_B(instruction) + u32 i, size = 0; + u32 return_local = fp + (dest * 4); + u32 return_value = READ_U32(return_local); + bool is_ptr = (((u32)(1)) << 15) & imm; + bool replaces_value = (((u32)(1)) << 14) & imm; + + /* reset mp to saved mp, use header size to get "real" start of frame */ + u32 frame_start = fp - FRAME_HEADER_SIZE; + u32 parent_fp = READ_U32(frame_start); + u32 return_address = READ_U32(frame_start + 4); + u32 parent_local_return_address = 4 * READ_U32(frame_start + 8); + + USED(replaces_value); + /* reset memory to parents end of memory */ + mp = fp - FRAME_HEADER_SIZE; + /* reset the frame pointer */ + fp = parent_fp; + + /* copy value to end of mp if it is a pointer */ + if (is_ptr) { + WRITE_U32(parent_local_return_address, mp); + size = READ_U32(return_value); + WRITE_U32(mp, size); + mp += 4; + for (i = 0; i < size; i++) { + u8 value = READ_U8(return_value + i); + WRITE_U8(mp, value); + mp++; + } + } else { + /* otherwise just write the return value to its location */ + WRITE_U32(parent_local_return_address, return_value); + } + + /* jump to parent frame */ + pc = return_address; + return true; + } + case OP_SYSCALL: { + DECODE_A(instruction) + u32 id = dest; + u32 args = src1; + u32 rd = fp + (src2 * 4); + flag = syscall(id, args, rd); + return true; + } + case OP_LOAD_IMM: { + DECODE_B(instruction) + u32 rd = fp + (dest * 4); + WRITE_U32(rd, imm); + return true; + } + case OP_LOAD_UPPER_IMM: { + DECODE_B(instruction) + u32 rd = fp + (dest * 4); + u32 value = READ_U32(rd); + WRITE_U32(rd, (value | (((u32)(imm)) << 16))); + return true; + } + case OP_LOAD_IND_8: { + } + case OP_LOAD_IND_16: { + } + case OP_LOAD_IND_32: { + } + case OP_LOAD_ABS_8: { + } + case OP_LOAD_ABS_16: { + } + case OP_LOAD_ABS_32: { + } + case OP_LOAD_OFF_8: { + } + case OP_LOAD_OFF_16: { + } + case OP_LOAD_OFF_32: { + } + case OP_STORE_ABS_8: { + } + case OP_STORE_ABS_16: { + } + case OP_STORE_ABS_32: { + } + case OP_STORE_IND_8: { + } + case OP_STORE_IND_16: { + } + case OP_STORE_IND_32: { + } + case OP_STORE_OFF_8: { + } + case OP_STORE_OFF_16: { + } + case OP_STORE_OFF_32: { + } + case OP_MEM_ALLOC: { + DECODE_A(instruction) + u32 size, ldest; + u32 rd = fp + (dest * 4); + u32 r1 = fp + (src1 * 4); + USED(src2); + ldest = READ_U32(rd); + WRITE_U32(ldest, mp); + size = READ_U32(r1); + WRITE_U32(mp, size); + mp += (size + 4); + return true; + } + case OP_MEM_CPY_8: { + DECODE_A(instruction) + u32 i, count, mdest, msrc; + + u32 rd = fp + (dest * 4); + u32 r1 = fp + (src1 * 4); + u32 r2 = fp + (src2 * 4); + + mdest = READ_U32(rd); + msrc = READ_U32(r1); + count = READ_U32(r2); + + if (mdest + count >= mp) { + flag = 1; + return true; + } + + for (i = 0; i < count; i++) { + u8 value = READ_U8(mdest + i); + WRITE_U8(msrc + i, value); + } + + flag = 0; + return true; + } + case OP_MEM_CPY_16: { + DECODE_A(instruction) + u32 i, count, mdest, msrc; + + u32 rd = fp + (dest * 4); + u32 r1 = fp + (src1 * 4); + u32 r2 = fp + (src2 * 4); + + mdest = READ_U32(rd); + msrc = READ_U32(r1); + count = READ_U32(r2); + + if (mdest + count >= mp) { + flag = 1; + return true; + } + + for (i = 0; i < count; i++) { + u16 value = READ_U16(mdest + i); + WRITE_U16(msrc + i, value); + } + + flag = 0; + return true; + } + case OP_MEM_CPY_32: { + DECODE_A(instruction) + u32 i, count, mdest, msrc; + + u32 rd = fp + (dest * 4); + u32 r1 = fp + (src1 * 4); + u32 r2 = fp + (src2 * 4); + + mdest = READ_U32(rd); + msrc = READ_U32(r1); + count = READ_U32(r2); + + if (mdest + count >= mp) { + flag = 1; + return true; + } + + for (i = 0; i < count; i++) { + u32 value = READ_U32(mdest + i); + WRITE_U32(msrc + i, value); + } + + flag = 0; + return true; + } + case OP_MEM_SET_8: { + DECODE_A(instruction) + u32 i, start, end; + + u32 rd = fp + (dest * 4); + u32 r1 = fp + (src1 * 4); + u32 r2 = fp + (src2 * 4); + + u8 value = (u8)READ_U32(r1); + u32 count = READ_U32(r2); + + if (r2 == 0) { + flag = 1; + return true; + } + + start = READ_U32(rd); + end = start + count; + + if (start >= mp || r2 > mp || end > mp) { + flag = 1; + return true; + } + + for (i = start; i < end; i++) { + WRITE_U8(i, value); + } + + flag = 0; + return true; + } + case OP_MEM_SET_16: { + DECODE_A(instruction) + u32 i, start, end; + + u32 rd = fp + (dest * 4); + u32 r1 = fp + (src1 * 4); + u32 r2 = fp + (src2 * 4); + + u16 value = (u16)READ_U32(r1); + u32 count = READ_U32(r2); + + if (r2 == 0) { + flag = 1; + return true; + } + + start = READ_U32(rd); + end = start + count; + + if (start >= mp || r2 > mp || end > mp) { + flag = 1; + return true; + } + + for (i = start; i < end; i += 2) { + WRITE_U16(i, value); + } + + flag = 0; + return true; + } + case OP_MEM_SET_32: { + DECODE_A(instruction) + u32 i, start, end; + + u32 rd = fp + (dest * 4); + u32 r1 = fp + (src1 * 4); + u32 r2 = fp + (src2 * 4); + + u32 value = READ_U32(r1); + u32 count = READ_U32(r2); + + if (r2 == 0) { + flag = 1; + return true; + } + + start = READ_U32(rd); + end = start + count; + + if (start >= mp || r2 > mp || end > mp) { + flag = 1; + return true; + } + + for (i = start; i < end; i += 4) { + WRITE_U32(i, value); + } + + flag = 0; + return true; + } + case OP_MOV: { + DECODE_A(instruction) + u32 rd = fp + (dest * 4); + u32 r1 = fp + (src1 * 4); + u32 value = READ_U32(r1); + USED(src2); + WRITE_U32(rd, value); + return true; + } + case OP_PUSH: { + DECODE_B(instruction) + u32 rd = fp + (dest * 4); + u32 val = READ_U32(rd); + USED(imm); + WRITE_U32((mp + (4 * (sp + 3))), val); + sp++; + return true; + } + case OP_POP: { + DECODE_C(instruction) + USED(imm); + mp -= 4; + return true; + } + case OP_ADD_INT: { + MATH_OP(i32, +); + } + case OP_SUB_INT: { + MATH_OP(i32, -); + } + case OP_MUL_INT: { + MATH_OP(i32, *); + } + case OP_DIV_INT: { + MATH_OP(i32, /); + } + case OP_ADD_NAT: { + MATH_OP(u32, +); + } + case OP_SUB_NAT: { + MATH_OP(u32, -); + } + case OP_MUL_NAT: { + MATH_OP(u32, *); + } + case OP_DIV_NAT: { + MATH_OP(u32, /); + } + case OP_ADD_REAL: { + MATH_OP(i32, +); + } + case OP_SUB_REAL: { + MATH_OP(i32, -); + } + case OP_MUL_REAL: { + DECODE_A(instruction) + u32 rd = fp + (dest * 4); + u32 r1 = fp + (src1 * 4); + u32 r2 = fp + (src2 * 4); + + i32 src1_whole = (i32)READ_U32(r1) >> 16; + i32 src2_whole = (i32)READ_U32(r2) >> 16; + + i32 src1_decimal = (i32)READ_U32(r1) & 16; + i32 src2_decimal = (i32)READ_U32(r2) & 16; + + i32 result = 0; + result += (src1_whole * src2_whole) << 16; + result += (src1_whole * src2_decimal); + result += (src1_decimal * src2_whole); + result += ((src1_decimal * src2_decimal) >> 16) & 16; + WRITE_U32(rd, result); + return true; + } + case OP_DIV_REAL: { + DECODE_A(instruction) + i32 result; + u32 rd = fp + (dest * 4); + u32 r1 = fp + (src1 * 4); + u32 r2 = fp + (src2 * 4); + + i32 src1_val = (i32)READ_U32(r1); + i32 src2_val = (i32)READ_U32(r2); + + u32 src2_reciprocal = 1; + src2_reciprocal <<= 31; + src2_reciprocal = (u32)(src2_reciprocal / src2_val); + + result = src1_val * src2_reciprocal; + result <<= 1; + WRITE_U32(rd, result); + return true; + } + case OP_INT_TO_REAL: { + DECODE_A(instruction) + u32 rd = fp + (dest * 4); + u32 r1 = fp + (src1 * 4); + i32 result = (i32)READ_U32(r1) << 16; + USED(src2); + WRITE_U32(rd, result); + return true; + } + case OP_INT_TO_NAT: { + DECODE_A(instruction) + u32 rd = fp + (dest * 4); + u32 r1 = fp + (src1 * 4); + u32 result = (u32)READ_U32(r1); + USED(src2); + WRITE_U32(rd, result); + return true; + } + case OP_NAT_TO_REAL: { + DECODE_A(instruction) + u32 rd = fp + (dest * 4); + u32 r1 = fp + (src1 * 4); + i32 result = ((i32)READ_U32(r1) << 16); + USED(src2); + WRITE_U32(rd, result); + return true; + } + case OP_NAT_TO_INT: { + DECODE_A(instruction) + u32 rd = fp + (dest * 4); + u32 r1 = fp + (src1 * 4); + i32 result = ((i32)READ_U32(r1)); + USED(src2); + WRITE_U32(rd, result); + return true; + } + case OP_REAL_TO_INT: { + DECODE_A(instruction) + u32 rd = fp + (dest * 4); + u32 r1 = fp + (src1 * 4); + i32 result = ((i32)READ_U32(r1) >> 16); + USED(src2); + WRITE_U32(rd, result); + return true; + } + case OP_REAL_TO_NAT: { + DECODE_A(instruction) + u32 rd = fp + (dest * 4); + u32 r1 = fp + (src1 * 4); + u32 result = ((u32)READ_U32(r1) >> 16); + USED(src2); + WRITE_U32(rd, result); + return true; + } + case OP_BIT_SHIFT_LEFT: { + MATH_OP_NO_CAST(<<); + } + case OP_BIT_SHIFT_RIGHT: { + MATH_OP_NO_CAST(>>); + } + case OP_BIT_SHIFT_R_EXT: { + MATH_OP(i32, >>); + } + case OP_BIT_AND: { + MATH_OP_NO_CAST(&); + } + case OP_BIT_OR: { + MATH_OP_NO_CAST(|); + } + case OP_BIT_XOR: { + MATH_OP_NO_CAST(^); + } + case OP_JMP_IMM: { + DECODE_C(instruction) + pc = imm; + return true; + } + case OP_JMP_ABS: { + DECODE_A(instruction) + u32 rd = fp + (dest * 4); + u32 jmp_dest = READ_U32(rd); + if (jmp_dest > cp) { + flag = 1; + return true; + } + USED(src1); + USED(src2); + + pc = jmp_dest; + return true; + } + case OP_JMP_OFF: { + DECODE_A(instruction) + u32 rd = fp + (dest * 4); + u32 r1 = fp + (src1 * 4); + + u32 jmp_dest = READ_U32(rd) + READ_U32(r1); + if (jmp_dest > cp) { + flag = 1; + return true; + } + USED(src2); + + pc = jmp_dest; + return true; + } + case OP_JMP_FLAG: { + DECODE_A(instruction) + u32 mask; + u32 rd = fp + (dest * 4); + u32 jmp_dest = READ_U32(rd); + if (jmp_dest > cp) { + flag = 1; + return true; + } + USED(src1); + USED(src2); + + mask = -(u32)(flag == 0); + pc = (jmp_dest & mask) | (pc & ~mask); + return true; + } + case OP_JEQ_INT: { + COMPARE_AND_JUMP(i32, ==); + } + case OP_JNE_INT: { + COMPARE_AND_JUMP(i32, !=); + } + case OP_JGT_INT: { + COMPARE_AND_JUMP(i32, >); + } + case OP_JLT_INT: { + COMPARE_AND_JUMP(i32, <); + } + case OP_JLE_INT: { + COMPARE_AND_JUMP(i32, <=); + } + case OP_JGE_INT: { + COMPARE_AND_JUMP(i32, >=); + } + case OP_JEQ_NAT: { + COMPARE_AND_JUMP(u32, ==); + } + case OP_JNE_NAT: { + COMPARE_AND_JUMP(u32, !=); + } + case OP_JGT_NAT: { + COMPARE_AND_JUMP(u32, >); + } + case OP_JLT_NAT: { + COMPARE_AND_JUMP(u32, <); + } + case OP_JLE_NAT: { + COMPARE_AND_JUMP(u32, <=); + } + case OP_JGE_NAT: { + COMPARE_AND_JUMP(u32, >=); + } + case OP_JEQ_REAL: { + COMPARE_AND_JUMP(i32, ==); + } + case OP_JNE_REAL: { + COMPARE_AND_JUMP(i32, !=); + } + case OP_JGE_REAL: { + COMPARE_AND_JUMP(i32, >=); + } + case OP_JGT_REAL: { + COMPARE_AND_JUMP(i32, >); + } + case OP_JLT_REAL: { + COMPARE_AND_JUMP(i32, <); + } + case OP_JLE_REAL: { + COMPARE_AND_JUMP(i32, <=); + } + } + + /* something went very wrong */ + flag = 255; + return false; +} diff --git a/vm/vm.h b/vm/vm.h new file mode 100644 index 0000000..daf6e6e --- /dev/null +++ b/vm/vm.h @@ -0,0 +1,212 @@ +#ifndef UNDAR_VM_H +#define UNDAR_VM_H + +#include "libc.h" + +/** + * Instruction Types + * + * A : [8:opcode][8:dest][8:src1][8:src2] + * B : [8:opcode][8:dest][16:immediate] + * C : [8:opcode][24:immediate] + */ +#define DECODE_OP(instruction) ((((u32)(instruction)) >> 24) & 0xFF) + +#define ENCODE_A(opcode, dest, src1, src2) ((((u32)(opcode) & 0xFF) << 24) | \ + (((u32)(dest) & 0xFF) << 16) | \ + (((u32)(src1) & 0xFF) << 8) | \ + (((u32)(src2) & 0xFF))) + +#define DECODE_A(instruction) \ + u8 dest = (((u32)(instruction)) >> 16) & 0xFF; \ + u8 src1 = (((u32)(instruction)) >> 8) & 0xFF; \ + u8 src2 = ((u32)(instruction)) & 0xFF; + +#define ENCODE_B(opcode, dest, imm) ((((u32)(opcode) & 0xFF) << 24) | \ + (((u32)(dest) & 0xFF) << 16) | \ + (((u32)(imm)) & 0xFFFF)) +#define DECODE_B(instruction) \ + u8 dest = (((u32)(instruction)) >> 16) & 0xFF; \ + u16 imm = ((u32)(instruction)) & 0xFFFF; + +#define ENCODE_C(opcode, imm) ((((u32)(opcode) & 0xFF) << 24) | \ + (((u32)(imm)) & 0xFFFFFF)) +#define DECODE_C(instruction) \ + u32 imm = ((u32)(instruction)) & 0xFFFFFF; + +typedef enum { + OP_HALT, /* halt : A : all zeros : halt execution */ + OP_CALL, /* call : A : dest args return : creates a new frame */ + OP_RETURN, /* return : B : dest return_flags: returns from a frame to the parent frame */ + OP_SYSCALL, /* syscall : A : id args mem_ptr : does a system call based on id with args */ + OP_LOAD_IMM, /* load_immediate : B : locals[dest] = const as u16 */ + OP_LOAD_UPPER_IMM, /* load_upper_immediate : B : locals[dest] = const as u32 << 16 | u16 */ + OP_LOAD_IND_8, /* load_indirect_8 : A : locals[dest] = memory[locals[src1]] as u8 */ + OP_LOAD_IND_16, /* load_indirect_16 : A : locals[dest] = memory[locals[src1]] as u16 */ + OP_LOAD_IND_32, /* load_indirect_32 : A : locals[dest] = memory[locals[src1]] as u32 */ + OP_LOAD_ABS_8, /* load_absolute_8 : A : locals[dest] = memory[src1] as u8 */ + OP_LOAD_ABS_16, /* load_absolute_16 : A : locals[dest] = memory[src1] as u16 */ + OP_LOAD_ABS_32, /* load_absolute_32 : A : locals[dest] = memory[src1] as u32 */ + OP_LOAD_OFF_8, /* load_offset_8 : A : locals[dest] = memory[locals[src1] + src2] as u8 */ + OP_LOAD_OFF_16, /* load_offset_16 : A : locals[dest] = memory[locals[src1] + src2] as u16 */ + OP_LOAD_OFF_32, /* load_offset_32 : A : locals[dest] = memory[locals[src1] + src2] as u32 */ + OP_STORE_ABS_8, /* store_absolute_8 : A : memory[dest] = src1 && 0xFF */ + OP_STORE_ABS_16, /* store_absolute_16 : A : memory[dest] = src1 && 0xFFFF */ + OP_STORE_ABS_32, /* store_absolute_32 : A : memory[dest] = src1 */ + OP_STORE_IND_8, /* store_indirect_8 : A : memory[dest] = locals[src1] && 0xFF */ + OP_STORE_IND_16, /* store_indirect_16 : A : memory[dest] = locals[src1] && 0xFFFF*/ + OP_STORE_IND_32, /* store_indirect_32 : A : memory[dest] = locals[src1] */ + OP_STORE_OFF_8, /* store_offset_8 : A : memory[locals[dest] + src2] = locals[src1] && 0xFF */ + OP_STORE_OFF_16, /* store_offset_16 : A : memory[locals[dest] + src2] = locals[src1] && 0xFFFF */ + OP_STORE_OFF_32, /* store_offset_32 : A : memory[locals[dest] + src2] = locals[src1] */ + OP_MEM_ALLOC, /* alloc : A : memory[dest] = [locals[src1] as size + 4] */ + OP_MEM_CPY_8, /* memcpy_8 : A : memory[src1..src1+src2] = memory[dest..dest+src2] */ + OP_MEM_CPY_16, /* memcpy_16 : A : memory[src1..src1+src2] = memory[dest..dest+src2] */ + OP_MEM_CPY_32, /* memcpy_32 : A : memory[src1..src1+src2] = memory[dest..dest+src2] */ + OP_MEM_SET_8, /* memset_8 : A : memory[dest..dest+src2] = local[src1] as u8 */ + OP_MEM_SET_16, /* memset_16 : A : memory[dest..dest+src2] = local[src1] as u16 */ + OP_MEM_SET_32, /* memset_32 : A : memory[dest..dest+src2] = local[src1] as u32 */ + OP_MOV, /* mov : A : locals[dest] = locals[src1] */ + OP_PUSH, /* push : B : push u32 value onto the childs locals */ + OP_POP, /* pop : C : pop u32 value off the stack (move MP back) */ + OP_ADD_INT, /* add_int : A : locals[dest] = locals[src1] + locals[src2] */ + OP_SUB_INT, /* sub_int : A : locals[dest] = locals[src1] - locals[src2] */ + OP_MUL_INT, /* mul_int : A : locals[dest] = locals[src1] * locals[src2] */ + OP_DIV_INT, /* div_int : A : locals[dest] = locals[src1] / locals[src2] */ + OP_ADD_NAT, /* add_nat : A : locals[dest] = locals[src1] + locals[src2] */ + OP_SUB_NAT, /* sub_nat : A : locals[dest] = locals[src1] - locals[src2] */ + OP_MUL_NAT, /* mul_nat : A : locals[dest] = locals[src1] * locals[src2] */ + OP_DIV_NAT, /* div_nat : A : locals[dest] = locals[src1] / locals[src2] */ + OP_ADD_REAL, /* add_real : A : locals[dest] = locals[src1] + locals[src2] */ + OP_SUB_REAL, /* sub_real : A : locals[dest] = locals[src1] - locals[src2] */ + OP_MUL_REAL, /* mul_real : A : locals[dest] = locals[src1] * locals[src2] */ + OP_DIV_REAL, /* div_real : A : locals[dest] = locals[src1] / locals[src2] */ + OP_INT_TO_REAL, /* int_to_real : A : locals[dest] = locals[src1] as real */ + OP_INT_TO_NAT, /* int_to_nat : A : locals[dest] = locals[src1] as nat */ + OP_NAT_TO_REAL, /* nat_to_real : A : locals[dest] = locals[src1] as real */ + OP_NAT_TO_INT, /* nat_to_int : A : locals[dest] = locals[src1] as int */ + OP_REAL_TO_INT, /* real_to_int : A : locals[dest] = locals[src1] as int */ + OP_REAL_TO_NAT, /* real_to_nat : A : locals[dest] = locals[src1] as nat */ + OP_BIT_SHIFT_LEFT, /* bit_shift_left : A : locals[dest] = locals[src1] << locals[src2] */ + OP_BIT_SHIFT_RIGHT,/* bit_shift_right : A : locals[dest] = locals[src1] >> locals[src2] */ + OP_BIT_SHIFT_R_EXT,/* bit_shift_r_ext : A : locals[dest] as i32 = locals[src1] >> locals[src2] */ + OP_BIT_AND, /* bit_and : A : locals[dest] = locals[src1] & locals[src2] */ + OP_BIT_OR, /* bit_or : A : locals[dest] = locals[src1] | locals[src2] */ + OP_BIT_XOR, /* bit_xor : A : locals[dest] = locals[src1] ^ locals[src2] */ + OP_JMP_IMM, /* jump_immediate : C : jump to imm unconditionally */ + OP_JMP_ABS, /* jump_absolute : A : jump to locals[dest] unconditionally */ + OP_JMP_OFF, /* jump_offset : A : jump to locals[dest] + locals[src1] unconditionally */ + OP_JMP_FLAG, /* jump_if_flag : A : jump to locals[dest] if flag > 0 */ + OP_JEQ_INT, /* jump_eq_int : A : jump to locals[dest] if locals[src1] as int == locals[src2] as int */ + OP_JNE_INT, /* jump_neq_int : A : jump to locals[dest] if locals[src1] as int != locals[src2] as int */ + OP_JGT_INT, /* jump_gt_int : A : jump to locals[dest] if locals[src1] as int > locals[src2] as int */ + OP_JLT_INT, /* jump_lt_int : A : jump to locals[dest] if locals[src1] as int < locals[src2] as int */ + OP_JLE_INT, /* jump_le_int : A : jump to locals[dest] if locals[src1] as int <= locals[src2] as int */ + OP_JGE_INT, /* jump_ge_int : A : jump to locals[dest] if locals[src1] as int >= locals[src2] as int */ + OP_JEQ_NAT, /* jump_eq_nat : A : jump to locals[dest] if locals[src1] as nat == locals[src2] as nat */ + OP_JNE_NAT, /* jump_neq_nat : A : jump to locals[dest] if locals[src1] as nat != locals[src2] as nat */ + OP_JGT_NAT, /* jump_gt_nat : A : jump to locals[dest] if locals[src1] as nat > locals[src2] as nat */ + OP_JLT_NAT, /* jump_lt_nat : A : jump to locals[dest] if locals[src1] as nat < locals[src2] as nat */ + OP_JLE_NAT, /* jump_le_nat : A : jump to locals[dest] if locals[src1] as nat <= locals[src2] as nat */ + OP_JGE_NAT, /* jump_ge_nat : A : jump to locals[dest] if locals[src1] as nat >= locals[src2] as nat */ + OP_JEQ_REAL, /* jump_eq_real : A : jump to locals[dest] if locals[src1] as real == locals[src2] as real */ + OP_JNE_REAL, /* jump_neq_real : A : jump to locals[dest] if locals[src1] as real != locals[src2] as real */ + OP_JGE_REAL, /* jump_ge_real : A : jump to locals[dest] if locals[src1] as real >= locals[src2] as real */ + OP_JGT_REAL, /* jump_gt_real : A : jump to locals[dest] if locals[src1] as real > locals[src2] as real */ + OP_JLT_REAL, /* jump_lt_real : A : jump to locals[dest] if locals[src1] as real < locals[src2] as real */ + OP_JLE_REAL, /* jump_le_real : A : jump to locals[dest] if locals[src1] as real <= locals[src2] as real */ + OP_MAX_OPCODE /* not an opcode count of instructions */ +} Opcode; + +typedef enum { + SYSCALL_DBG_PRINT, /* temporary debugging print, use tunnel later */ + SYSCALL_MAX +} Syscall; + +extern u32 pc; /* program counter */ +extern u32 cp; /* code pointer */ +extern u32 mp; /* memory pointer */ +extern u32 fp; /* frame pointer */ +extern u8 sp; /* child local count */ +extern u32 flag; /* flag */ +extern u8 interrupt; /* device interrupt */ +extern u32 *code; /* code */ +extern u8 *mem; /* memory */ + +#define READ_U8(addr) (mem[addr]) + +#define READ_U16(addr) \ + (((u16)mem[(addr) + 1] << 8) | ((u16)mem[(addr)])) + +#define READ_U32(addr) \ + (((u32)mem[(addr) + 3] << 24) | \ + ((u32)mem[(addr) + 2] << 16) | \ + ((u32)mem[(addr) + 1] << 8) | ((u32)mem[(addr)])) + +#define WRITE_U8(addr, value) \ + do { \ + mem[addr] = (value) & 0xFF; \ + } while (0) + +#define WRITE_U16(addr, value) \ + do { \ + mem[addr] = (value) & 0xFF; \ + mem[addr + 1] = ((value) >> 8) & 0xFF; \ + } while (0) + +#define WRITE_U32(addr, value) \ + do { \ + mem[addr] = (value) & 0xFF; \ + mem[addr + 1] = ((value) >> 8) & 0xFF; \ + mem[addr + 2] = ((value) >> 16) & 0xFF; \ + mem[addr + 3] = ((value) >> 24) & 0xFF; \ + } while (0) + +#define MATH_OP(type, op) \ + do { \ + DECODE_A(instruction) \ + u32 rd = fp + (dest * 4); \ + u32 r1 = fp + (src1 * 4); \ + u32 r2 = fp + (src2 * 4); \ + type result = ((type)READ_U32(r1) op (type)READ_U32(r2)); \ + mem[(rd)] = (result) & 0xFF; \ + mem[(rd) + 1] = ((result) >> 8) & 0xFF; \ + mem[(rd) + 2] = ((result) >> 16) & 0xFF; \ + mem[(rd) + 3] = ((result) >> 24) & 0xFF; \ + return true; \ + } while (0) + +#define MATH_OP_NO_CAST(op) \ + do { \ + DECODE_A(instruction) \ + u32 rd = fp + (dest * 4); \ + u32 r1 = fp + (src1 * 4); \ + u32 r2 = fp + (src2 * 4); \ + WRITE_U32(rd, (READ_U32(r1) op READ_U32(r2))); \ + return true; \ + } while (0) + +#define COMPARE_AND_JUMP(type, op) \ + do { \ + DECODE_A(instruction) \ + i32 cond; \ + u32 mask, target; \ + type value; \ + type value2; \ + u32 rd = fp + (dest * 4); \ + u32 r1 = fp + (src1 * 4); \ + u32 r2 = fp + (src2 * 4); \ + target = READ_U32(rd); \ + value = (type)READ_U32(r1); \ + value2 = (type)READ_U32(r2); \ + cond = !!(value op value2); \ + mask = -(u32)cond; \ + pc = (target & mask) | (pc & ~mask); \ + return true; \ + } while (0) + +extern bool init_vm(); +extern u32 syscall(u32 id, u32 args, u32 mem_ptr); +bool step_vm(); + +#endif