From 6b625c4663a827b673d91d160846f095cd13fd3b Mon Sep 17 00:00:00 2001 From: zongor Date: Sat, 3 Jan 2026 23:10:17 -0800 Subject: [PATCH] Add opcodes, get rid of VM for less redirection, add encode/decode macros --- SPECIFICATION.org | 271 ++++++++++++++++------------------------------ vm/vm.c | 185 ++++++++++++++++++++++++++++++- vm/vm.h | 246 ++++++++++++++++++++++++++--------------- 3 files changed, 433 insertions(+), 269 deletions(-) diff --git a/SPECIFICATION.org b/SPECIFICATION.org index 7a7f338..6230b8f 100644 --- a/SPECIFICATION.org +++ b/SPECIFICATION.org @@ -11,8 +11,8 @@ especially microcontrollers and some retro game systems like the PS1. ** Numbers | type | size (bytes) | description | |------+--------------+---------------------------------------| -| u8 | 1 | unsigned 8bit, alias =char= and =byte= | | bool | 1 | unsigned 8bit, =false= or =true= | +| u8 | 1 | unsigned 8bit, alias =char= and =byte= | | i8 | 1 | signed 8bit for interop | | u16 | 2 | unsigned 16bit for interop | | i16 | 2 | signed 16bit for interop | @@ -30,130 +30,103 @@ In the C version you can see these are two seperate arrays 'code' and 'mem'. During compilation constants and local variables are put onto 'mem' * Opcodes + +*** All 32 bit instructions (registers are all 32 bit values) +**** Type A: [8:opcode][8:dest][8:src1][8:src2] +- call : dest num-of-args ptr-to-function +- return : dest return-arg 0 +- syscall : id num-of-args ptr-to-memory +- load-indirect-8 : dest src1 0 +- load-indirect-16 : dest src1 0 +- load-indirect-32 : dest src1 0 +- load-absolute-8 : dest src1 0 +- load-absolute-16 : dest src1 0 +- load-absolute-32 : dest src1 0 +- load-offset-8 : dest src1 src2 +- load-offset-16 : dest src1 src2 +- load-offset-32 : dest src1 src2 +- store-absolute-8 : dest src1 0 +- store-indirect-8 : dest src1 0 +- store-offset-8 : dest src1 src2 +- store-absolute-16 : dest src1 0 +- store-indirect-16 : dest src1 0 +- store-offset-16 : dest src1 src2 +- store-absolute-32 : dest src1 0 +- store-indirect-32 : dest src1 0 +- store-offset-32 : dest src1 src2 +- alloc : dest size 0 +- memset-8 : dest src1 count +- memset-16 : dest src1 count +- memset-32 : dest src1 count +- memcpy-8 : dest src1 count +- memcpy-16 : dest src1 count +- memcpy-32 : dest src1 count +- mov : dest src1 0 +- add-int : dest src1 src2 +- sub-int : dest src1 src2 +- mul-int : dest src1 src2 +- div-int : dest src1 src2 +- neg-int : dest src1 src2 +- abs-int : dest src1 src2 +- add-nat : dest src1 src2 +- sub-nat : dest src1 src2 +- mul-nat : dest src1 src2 +- div-nat : dest src1 src2 +- neg-nat : dest src1 src2 +- abs-nat : dest src1 src2 +- add-real : dest src1 src2 +- sub-real : dest src1 src2 +- mul-real : dest src1 src2 +- div-real : dest src1 src2 +- neg-real : dest src1 src2 +- abs-real : dest src1 src2 +- int-to-real : dest src1 src2 +- int-to-nat : dest src1 src2 +- nat-to-real : dest src1 src2 +- nat-to-int : dest src1 src2 +- real-to-int : dest src1 src2 +- real-to-nat : dest src1 src2 +- shift-left : dest src1 src2 +- shift-right : dest src1 src2 +- shift-right-extend : dest src1 src2 +- and : dest src1 src2 +- or : dest src1 src2 +- xor : dest src1 src2 +- jump-absolute : dest 0 0 +- jump-offset : dest src1 0 +- jmp-flag : dest 0 0 | jump if flag > 0 +- jeq-int : dest src1 src2 +- jne-int : dest src1 src2 +- jgt-int : dest src1 src2 +- jlt-int : dest src1 src2 +- jle-int : dest src1 src2 +- jge-int : dest src1 src2 +- jeq-nat : dest src1 src2 +- jne-nat : dest src1 src2 +- jgt-nat : dest src1 src2 +- jlt-nat : dest src1 src2 +- jle-nat : dest src1 src2 +- jge-nat : dest src1 src2 +- jeq-real : dest src1 src2 +- jne-real : dest src1 src2 +- jgt-real : dest src1 src2 +- jlt-real : dest src1 src2 +- jle-real : dest src1 src2 +- jge-real : dest src1 src2 -| 2^n | count | -|----+-------| -| 2^3 | 8 | -| 2^4 | 16 | -| 2^5 | 32 | -| 2^6 | 64 | -| 2^8 | 128 | +**** Type B: [8:opcode][8:dest][16:immediate] +- load-immediate : dest imm : for small 16 bit consts, and lower part of 32 bit consts +- load-upper-immediate : dest imm : for large 32 bit consts -** could be encoded -- op type [this is to maximize jump immidate and load immidate size] -- memory location -- local value / register -- local value type +**** Type C: [8:opcode][24:immediate] +- halt : immediate is unused (all zeros) +- jump-immediate : immediate jump -*** Simplest -[opcode][dest][src1][src2] -[8][8][8][8] - -*** Maximize inline jump and load-immidate -[0 0 0 0 0 0 0 0][0 0 0 0 0 0 0 0][0 0 0 0 0 0 0 0][0 0 0 0 0 0 0 0] - -[0 0 0 | 0 0 0 0 0][0 0 0 | 0 0 0 0 0][0 0 0 | 0 0 0 0 0][0 0 0 | 0 0 0 | 0 0 ] noop -[0 0 0 | 0 0 0 0 0][0 0 0 | 0 0 0 0 0][0 0 0 | 0 0 0 0 0][0 0 0 | 0 0 1 | 0 0 ] call -[0 0 0 | 0 0 0 0 0][0 0 0 | 0 0 0 0 0][0 0 0 | 0 0 0 0 0][0 0 0 | 0 1 0 | 0 0 ] return -[0 0 0 | 0 0 0 0 0][0 0 0 | 0 0 0 0 0][0 0 0 | 0 0 0 0 0][0 0 0 | 0 1 1 | 0 0 ] syscall? -[0 0 0 | 0 0 0 0 0][0 0 0 | 0 0 0 0 0][0 0 0 | 0 0 0 0 1][0 0 0 | 1 0 0 | 0 0 ] exit - -[0 0 0 0 0 0 0 0][0 0 0 0 0 0 0 0][0 0 0 0 0 0 0 0][0 0 0 0 0 0 | 0 1 ] jump ~1GB range -[0 0 0 0 0 0 0 0][0 0 0 0 0 0 0 0][0 0 0 0 0 0 0 0][0 0 0 0 0 0 | 1 0 ] load-immidate 2^30 max - -*** multibyte ops -- ones that would be easier if they were multibyte - - jump - - load immidate - - syscall - - call - - -0 0 - system, lowest because lower opcodes are faster -0 1 - memory -1 0 - math -1 1 - jump - -[0 0][0 0 0 0 0 0] = [system][no op] -[0 0][1 0 0 0 0 0] = [system][loadimm] -[0 0][0 0 0 0 0 0] = [system][return] - - -J [0 0 0 0 0 0 0 0][0 0 0 0 0 0 0 0][0 0 0 0 0 0 0 0][0 0 0 0 0 0 | 0 1] -L [0 0 0 0 0 0 0 0][0 0 0 0 0 0 0 0][0 0 0 0 0 0 0 0][0 | o o o o o | 1 0] - -R [r r r r r r | r r][r r r r | r r r r][r r | b b | 0 0 0 0][o o o o o o | 1 1] - - - -[0 0 0 0 0 | r r r][r r r r | r r r r][r r | r r r r r r][b b | t | o o o | 1 1] - -[0 0 0 | r r r r r][0 0 0 | r r r r r][0 0 0 | r r r r r][b b | t | o o o | 1 1] -[0 0 0 | 0 0 0 0 0][0 0 0 | 0 0 0 0 0][0 0 0 | 0 0 0 0 0][0 0 | 1 | 0 0 1 | 1 1] [math][add][f][8] -[0 0 0 | 0 0 0 0 0][0 0 0 | 0 0 0 0 0][0 0 0 | 0 0 0 0 0][0 0 | 1 | 0 1 0 | 1 1] [math][sub][f][8] -[0 0 0 | 0 0 0 0 0][0 0 0 | 0 0 0 0 0][0 0 0 | 0 0 0 0 0][0 0 | 1 | 0 1 1 | 1 1] [math][mul][f][8] -[0 0 0 | 0 0 0 0 0][0 0 0 | 0 0 0 0 0][0 0 0 | 0 0 0 0 0][0 0 | 1 | 1 0 0 | 1 1] [math][div][f][8] -[0 0 0 | 0 0 0 0 0][0 0 0 | 0 0 0 0 0][0 0 0 | 0 0 0 0 0][0 0 | 1 | 1 0 1 | 1 1] [math][mod][f][8] - -[0 1][0 0 1][0][0 0] = [math][sub][f][16] -[0 1][0 1 0][0][0 0] = [math][mul][f][32] -[0 1][0 1 1][0][0 0] = [math][div][f][?] -[0 1][1 0 0][0][0 0] = [math][and][f][?] - -[1 1][0][0 0][0 0] = [jmp][u][eq] -[1 1][0][0 0][0 0] = [jmp][u][ne] -[1 1][0][0 0][0 0] = [jmp][u][lt] -[1 1][0][0 0][0 0] = [jmp][u][gt] - -[1 1][1][0 0 0][0 0] = [jmp][s][le] -[1 1][1][0 0 0][0 0] = [jmp][s][ge] -[1 1][1][0 0 0][0 0] = [jmp][s][] -[1 1][1][0 0 0][0 0] = [jmp][s][] - -3 2 2 1 -[...] i 32 0 - -3 1 3 1 -[...] u rl j -[...] u ab j -[...] u eq j -[...] u nq j -[...] u lt j -[...] u le j -[...] u gt j -[...] u ge j - -[jmp][dest][18] -[lli][dest][2] - - - -int 3 - -add -sub -mul -div - -jeq -jne - -jlt -jle -jgt -jge - -Maybe opcodes could be Huffman encoded? That way the smaller opcodes get more operand data within the u32 - -At compile time each function gets N number of locals (up to 255). These are allocated onto memory along with everything else, but they come before the heap values. - -Maybe instead of push pushing onto a stack it instead pushes onto a child frame? Pops would just mark what locals need to be replaced by the child function? Maybe we can get rid of call/return and just use jumps? - -U8 u8 u8 u8 -Push/pop parent_local child_local metadata ** Maybe more flexible calling convention? +At compile time each function gets N number of locals (up to 255). These are allocated onto memory along with everything else, but they come before the heap values. + Memory-to-memory with register characteristics? Passed in values @@ -185,63 +158,3 @@ Update the new pointer’s local position. Add the new size to the mp. Repeat for each returned value that is a replaced heap value. -Opcodes are variable sized, each part is 8 bytes to maximize portability. - -8 bit -Type Z: [u8:opcode] -16 bit -Type Q: [u8:opcode][u8:dest] -24 bit -Type I: [u8:opcode][u8:dest][u8:src1] -32 bit -Type M: [u8:opcode][u8:dest][u8:src1][u8:src2] -40 bit -Type J: [u8:opcode][u32:dest] -56 bit -Type S: [u8:opcode][u8:dest][u8:src1][u32:imm] - -Fixed size - -*** All 32 bit instructions (registers are all 32 bit values) -**** Type I: [8:opcode][8:dest][16:immediate] -- load-immediate : for small 16 bit consts, and lower part of 32 bit consts -- load-upper-immediate : for large 32 bit consts -- load-indirect : dest -- store-indirect : dest -- load-absolute : dest -- store-absolute : dest -- jump-absolute : dest - -**** Type M: [8:opcode][8:dest][8:src1][8:src2] -- load-offset dest src1 src2 -- store-offset dest src1 src2 -- call dest num-of-args ptr-to-function -- return dest return-arg -- syscall id num-of-args ptr-to-memory -- memset dest src1 count -- long-jump : src1 used as address -- add -- sub -- mul -- div -- and -- or -- xor -- shift-left -- shift-right -- shift-right-sign-extend -- neg -- abs -- mov : move register value -- alloc : dest size unused -- jeq (jump eq) -- jne (jump not eq) -- jgt (jump greater than) -- jlt (jump less than) -- jle (jump less than or eq) -- jge (jump greater then or eq) -- jf (jump if flag < zero) - -**** Type Z: [8:opcode][24:immediate] -- noop : immediate is unused (all zeros) -- jump : immediate jump diff --git a/vm/vm.c b/vm/vm.c index 4ae2857..f21cab7 100644 --- a/vm/vm.c +++ b/vm/vm.c @@ -1,6 +1,187 @@ #include "vm.h" -bool step_vm(VM *vm) { - USED(vm); +u32 mp; /* memory pointer */ +u32 cp; /* code pointer */ +u32 pc; /* program counter */ +u32 flag; /* flag */ +u32 *code; /* code */ +u8 *mem; /* memory */ + +bool step_vm() { + + u32 instruction = code[pc]; + u8 opcode = DECODE_OP(instruction); + + switch (opcode) { + case OP_HALT: { + return false; + } + case OP_CALL: { + + } + case OP_RETURN: { + } + case OP_SYSCALL: { + } + case OP_LOAD_IMM: { + } + case OP_LOAD_UPPER_IMM: { + } + 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: { + } + case OP_MEM_CPY: { + } + case OP_MEM_SET_8: { + } + case OP_MEM_SET_16: { + } + case OP_MEM_SET_32: { + } + case OP_REG_MOV: { + } + case OP_ADD_INT: { + } + case OP_SUB_INT: { + } + case OP_MUL_INT: { + } + case OP_DIV_INT: { + } + case OP_ABS_INT: { + } + case OP_NEG_INT: { + } + case OP_ADD_NAT: { + } + case OP_SUB_NAT: { + } + case OP_MUL_NAT: { + } + case OP_DIV_NAT: { + } + case OP_ABS_NAT: { + } + case OP_NEG_NAT: { + } + case OP_ADD_REAL: { + } + case OP_SUB_REAL: { + } + case OP_MUL_REAL: { + } + case OP_DIV_REAL: { + } + case OP_ABS_REAL: { + } + case OP_NEG_REAL: { + } + case OP_INT_TO_REAL: { + } + case OP_INT_TO_NAT: { + } + case OP_NAT_TO_REAL: { + } + case OP_NAT_TO_INT: { + } + case OP_REAL_TO_INT: { + } + case OP_REAL_TO_NAT: { + } + case OP_BIT_SHIFT_LEFT: { + } + case OP_BIT_SHIFT_RIGHT: { + } + case OP_BIT_SHIFT_R_EXT: { + } + case OP_BIT_AND: { + } + case OP_BIT_OR: { + } + case OP_BIT_XOR: { + } + case OP_JMP_IMM: { + } + case OP_JMP_ABS: { + } + case OP_JMP_OFF: { + } + case OP_JMP_FLAG: { + } + case OP_JEQ_INT: { + } + case OP_JNE_INT: { + } + case OP_JGT_INT: { + } + case OP_JLT_INT: { + } + case OP_JLE_INT: { + } + case OP_JGE_INT: { + } + case OP_JEQ_NAT: { + } + case OP_JNE_NAT: { + } + case OP_JGT_NAT: { + } + case OP_JLT_NAT: { + } + case OP_JLE_NAT: { + } + case OP_JGE_NAT: { + } + case OP_JEQ_REAL: { + } + case OP_JNE_REAL: { + } + case OP_JGE_REAL: { + } + case OP_JGT_REAL: { + } + case OP_JLT_REAL: { + } + case OP_JLE_REAL: { + } + } + + /* something went very wrong */ + flag = 255; return false; } diff --git a/vm/vm.h b/vm/vm.h index d6cf7ea..be3e180 100644 --- a/vm/vm.h +++ b/vm/vm.h @@ -3,98 +3,168 @@ #include "libc.h" -typedef enum { - OP_NOOP, /* noop : no nothing for 1 cycle */ - OP_CALL, /* call : creates a new frame */ - OP_RETURN, /* return : returns from a frame to the parent frame */ - OP_SYSCALL, /* syscall : syscall(u8 src1 count_args, u32 ptr_memory) */ - OP_LOAD_IMM, /* load_immediate : locals[dest] = constant */ - OP_LOAD_IND_8, /* load_indirect_8 : locals[dest] = memory[locals[src1]] as u8 */ - OP_LOAD_IND_16, /* load_indirect_16 : locals[dest] = memory[locals[src1]] as u16 */ - OP_LOAD_IND_32, /* load_indirect_32 : locals[dest] = memory[locals[src1]] as u32 */ - OP_LOAD_ABS_8, /* load_absolute_8 : locals[dest] = memory[src1] as u8 */ - OP_LOAD_ABS_16, /* load_absolute_16 : locals[dest] = memory[src1] as u16 */ - OP_LOAD_ABS_32, /* load_absolute_32 : locals[dest] = memory[src1] as u32 */ - OP_LOAD_OFF_8, /* load_offset_8 : locals[dest] = memory[locals[src1] + offset] as u8 */ - OP_LOAD_OFF_16, /* load_offset_16 : locals[dest] = memory[locals[src1] + offset] as u16 */ - OP_LOAD_OFF_32, /* load_offset_32 : locals[dest] = memory[locals[src1] + offset] as u32 */ - OP_STORE_ABS_8, /* store_absolute_8 : memory[dest] = src1 && 0xFF */ - OP_STORE_ABS_16, /* store_absolute_16 : memory[dest] = src1 && 0xFFFF */ - OP_STORE_ABS_32, /* store_absolute_32 : memory[dest] = src1 */ - OP_STORE_IND_8, /* store_indirect_8 : memory[dest] = locals[src1] && 0xFF */ - OP_STORE_IND_16, /* store_indirect_16 : memory[dest] = locals[src1] && 0xFFFF*/ - OP_STORE_IND_32, /* store_indirect_32 : memory[dest] = locals[src1] */ - OP_STORE_OFF_8, /* store_offset_8 : memory[locals[dest] + offset] = locals[src1] && 0xFF */ - OP_STORE_OFF_16, /* store_offset_16 : memory[locals[dest] + offset] = locals[src1] && 0xFFFF */ - OP_STORE_OFF_32, /* store_offset_32 : memory[locals[dest] + offset] = locals[src1] */ - OP_MALLOC, /* malloc : dest = fat ptr to memory of ((src1 as size) + 4) */ - OP_MEMSET_8, /* memset_8 : dest <-> dest+count = src1 as u8 */ - OP_MEMSET_16, /* memset_16 : dest <-> dest+count = src1 as u16 */ - OP_MEMSET_32, /* memset_32 : dest <-> dest+count = src1 as u32 */ - OP_REG_MOV, /* register_move : locals[dest] = locals[src1] */ - OP_ADD_INT, /* add_int : locals[dest] = locals[src1] + locals[src2] */ - OP_SUB_INT, /* sub_int : locals[dest] = locals[src1] _ locals[src2] */ - OP_MUL_INT, /* mul_int : locals[dest] = locals[src1] * locals[src2] */ - OP_DIV_INT, /* div_int : locals[dest] = locals[src1] / locals[src2] */ - OP_ABS_INT, /* abs_int : locals[dest] = | locals[src1] | */ - OP_NEG_INT, /* neg_int : locals[dest] = -locals[src1] */ - OP_ADD_NAT, /* add_nat : locals[dest] = locals[src1] + locals[src2] */ - OP_SUB_NAT, /* sub_nat : locals[dest] = locals[src1] _ locals[src2] */ - OP_MUL_NAT, /* mul_nat : locals[dest] = locals[src1] * locals[src2] */ - OP_DIV_NAT, /* div_nat : locals[dest] = locals[src1] / locals[src2] */ - OP_ABS_NAT, /* abs_nat : locals[dest] = | locals[src1] | */ - OP_NEG_NAT, /* neg_nat : locals[dest] = -locals[src1] */ - OP_ADD_REAL, /* add_real : locals[dest] = locals[src1] + locals[src2] */ - OP_SUB_REAL, /* sub_real : locals[dest] = locals[src1] _ locals[src2] */ - OP_MUL_REAL, /* mul_real : locals[dest] = locals[src1] * locals[src2] */ - OP_DIV_REAL, /* div_real : locals[dest] = locals[src1] / locals[src2] */ - OP_ABS_REAL, /* abs_real : locals[dest] = | locals[src1] | */ - OP_NEG_REAL, /* neg_real : locals[dest] = _locals[src1] */ - OP_INT_TO_REAL, /* int_to_real : locals[dest] = locals[src1] as real */ - OP_INT_TO_NAT, /* int_to_nat : locals[dest] = locals[src1] as nat */ - OP_NAT_TO_REAL, /* nat_to_real : locals[dest] = locals[src1] as real */ - OP_NAT_TO_INT, /* nat_to_int : locals[dest] = locals[src1] as int */ - OP_REAL_TO_INT, /* real_to_int : locals[dest] = locals[src1] as int */ - OP_REAL_TO_NAT, /* real_to_nat : locals[dest] = locals[src1] as nat */ - OP_BIT_SHIFT_LEFT, /* bit_shift_left : locals[dest] = locals[src1] << locals[src2] */ - OP_BIT_SHIFT_RIGHT,/* bit_shift_right : locals[dest] = locals[src1] >> locals[src2] */ - OP_BIT_SHIFT_R_EXT,/* bit_shift_r_ext : locals[dest] as i32 = locals[src1] >> locals[src2] */ - OP_BAND, /* bit_and : locals[dest] = locals[src1] & locals[src2] */ - OP_BOR, /* bit_or : locals[dest] = locals[src1] | locals[src2] */ - OP_BXOR, /* bit_xor : locals[dest] = locals[src1] ^ locals[src2] */ - OP_JMP, /* jump : jump to &dest unconditionally */ - OP_JMPF, /* jump_if_flag : jump to &dest if flag != 0 */ - OP_JEQ_INT, /* jump_eq_int : jump to &dest if locals[src1] as int == locals[src2] as int */ - OP_JNEQ_INT, /* jump_neq_int : jump to &dest if locals[src1] as int != locals[src2] as int */ - OP_JGT_INT, /* jump_gt_int : jump to &dest if locals[src1] as int > locals[src2] as int */ - OP_JLT_INT, /* jump_lt_int : jump to &dest if locals[src1] as int < locals[src2] as int */ - OP_JLE_INT, /* jump_le_int : jump to &dest if locals[src1] as int <= locals[src2] as int */ - OP_JGE_INT, /* jump_ge_int : jump to &dest if locals[src1] as int >= locals[src2] as int */ - OP_JEQ_NAT, /* jump_eq_nat : jump to &dest if locals[src1] as nat == locals[src2] as nat */ - OP_JNEQ_NAT, /* jump_neq_nat : jump to &dest if locals[src1] as nat != locals[src2] as nat */ - OP_JGT_NAT, /* jump_gt_nat : jump to &dest if locals[src1] as nat > locals[src2] as nat */ - OP_JLT_NAT, /* jump_lt_nat : jump to &dest if locals[src1] as nat < locals[src2] as nat */ - OP_JLE_NAT, /* jump_le_nat : jump to &dest if locals[src1] as nat <= locals[src2] as nat */ - OP_JGE_NAT, /* jump_ge_nat : jump to &dest if locals[src1] as nat >= locals[src2] as nat */ - OP_JEQ_REAL, /* jump_eq_real : jump to &dest if locals[src1] as real == locals[src2] as real */ - OP_JNEQ_REAL, /* jump_neq_real : jump to &dest if locals[src1] as real != locals[src2] as real */ - OP_JGE_REAL, /* jump_ge_real : jump to &dest if locals[src1] as real >= locals[src2] as real */ - OP_JGT_REAL, /* jump_gt_real : jump to &dest if locals[src1] as real > locals[src2] as real */ - OP_JLT_REAL, /* jump_lt_real : jump to &dest if locals[src1] as real < locals[src2] as real */ - OP_JLE_REAL, /* jump_le_real : jump to &dest if locals[src1] as real <= locals[src2] as real */ - OP_MAX_OPCODE /* not really an opcode but used to check max length of ops */ -} Opcode; +/** + * 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) -typedef struct vm_s VM; +#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 : C : all zeros : halt execution */ + OP_CALL, /* call : A : dest args fn_ptr : creates a new frame */ + OP_RETURN, /* return : A : dest args : 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] + offset] as u8 */ + OP_LOAD_OFF_16, /* load_offset_16 : A : locals[dest] = memory[locals[src1] + offset] as u16 */ + OP_LOAD_OFF_32, /* load_offset_32 : A : locals[dest] = memory[locals[src1] + offset] 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] + offset] = locals[src1] && 0xFF */ + OP_STORE_OFF_16, /* store_offset_16 : A : memory[locals[dest] + offset] = locals[src1] && 0xFFFF */ + OP_STORE_OFF_32, /* store_offset_32 : A : memory[locals[dest] + offset] = locals[src1] */ + OP_MEM_ALLOC, /* alloc : A : memory[dest] = [locals[src1] as size + 4] */ + OP_MEM_CPY, /* memcpy : A : memory[src1 .. src1 + count] = memory[dest .. dest + count] */ + OP_MEM_SET_8, /* memset_8 : A : memory[dest .. dest + count] = local[src1] as u8 */ + OP_MEM_SET_16, /* memset_16 : A : memory[dest .. dest + count] = local[src1] as u16 */ + OP_MEM_SET_32, /* memset_32 : A : memory[dest .. dest + count] = local[src1] as u32 */ + OP_REG_MOV, /* register_move : A : locals[dest] = locals[src1] */ + 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_ABS_INT, /* abs_int : A : locals[dest] = | locals[src1] | */ + OP_NEG_INT, /* neg_int : A : locals[dest] = -locals[src1] */ + 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_ABS_NAT, /* abs_nat : A : locals[dest] = | locals[src1] | */ + OP_NEG_NAT, /* neg_nat : A : locals[dest] = -locals[src1] */ + 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_ABS_REAL, /* abs_real : A : locals[dest] = | locals[src1] | */ + OP_NEG_REAL, /* neg_real : A : locals[dest] = -locals[src1] */ + 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; #define MEM_SIZE 65536 -struct vm_s { - u32 pc; - u8 mem[MEM_SIZE]; -}; +extern u32 mp; /* memory pointer */ +extern u32 cp; /* code pointer */ +extern u32 pc; /* program counter */ +extern u32 flag; /* flag */ +extern u32 *code; /* code */ +extern u8 *mem; /* memory */ -extern bool init_vm(VM *vm); -bool step_vm(VM *vm); +#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 { \ + if ((addr) < sizeof(mem)) { \ + mem[(addr)] = (value) & 0xFF; \ + } \ + } while (0) + +#define write_u16(addr, value) \ + do { \ + if ((addr) + 1 < sizeof(mem)) { \ + mem[(addr)] = (value) & 0xFF; \ + mem[(addr) + 1] = ((value) >> 8) & 0xFF; \ + } \ + } while (0) + +#define write_u32(addr, value) \ + do { \ + if ((addr) + 3 < sizeof(mem)) { \ + mem[(addr)] = (value) & 0xFF; \ + mem[(addr) + 1] = ((value) >> 8) & 0xFF; \ + mem[(addr) + 2] = ((value) >> 16) & 0xFF; \ + mem[(addr) + 3] = ((value) >> 24) & 0xFF; \ + } \ + } while (0) + +extern bool init_vm(); +bool step_vm(); #endif