Remove duplicate file, merge local

This commit is contained in:
zongor 2026-01-03 19:29:37 -08:00
parent 39d088bd9c
commit f465cdb39a
3 changed files with 140 additions and 137 deletions

134
'
View File

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

View File

@ -184,3 +184,64 @@ Copy the new sized value and put it at the current end of the heap.
Update the new pointers 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

82
vm/vm.h
View File

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