diff --git a/' b/' deleted file mode 100644 index c3805a1..0000000 --- a/' +++ /dev/null @@ -1,134 +0,0 @@ -#+TITLE Project Specification - -* Binary interface - -The VM does not use floating point numbers, it instead uses fixed point numbers. - -This is for portability reasons as some devices might not have a FPU in them - -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= | -| i8 | 1 | signed 8bit for interop | -| u16 | 2 | unsigned 16bit for interop | -| i16 | 2 | signed 16bit for interop | -| u32 | 4 | unsigned 32bit, alias =nat= | -| i32 | 4 | signed 32bit, alias =int= | -| f32 | 4 | signed 32bit fixed number, alias =real= | - -* Memory - -Uses a harvard style archecture, meaning the code and ram memory -are split up into two seperate blocks. - -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 - -| 2^n | count | -|----+-------| -| 2^3 | 8 | -| 2^4 | 16 | -| 2^5 | 32 | -| 2^6 | 64 | -| 2^8 | 128 | - -** could be encoded -- op type [this is to maximize jump immidate and load immidate size] -- memory location -- local value / register -- local value type - -*** 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] - - -[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] [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 0 1 | 1 1] [math][add][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 diff --git a/SPECIFICATION.org b/SPECIFICATION.org index e10b954..7a7f338 100644 --- a/SPECIFICATION.org +++ b/SPECIFICATION.org @@ -184,3 +184,64 @@ Copy the new sized value and put it at the current end of the heap. 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.h b/vm/vm.h index f0b3d8e..d6cf7ea 100644 --- a/vm/vm.h +++ b/vm/vm.h @@ -4,17 +4,93 @@ #include "libc.h" typedef enum { - NOOP + 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; typedef struct vm_s VM; -#define CODE_SIZE 4096 #define MEM_SIZE 65536 struct vm_s { u32 pc; - u32 code[CODE_SIZE]; u8 mem[MEM_SIZE]; };