WIP more stack ops

This commit is contained in:
zongor 2026-01-19 21:54:12 -08:00
parent 1b77649e36
commit 9f8575e5a2
2 changed files with 120 additions and 73 deletions

44
vm/vm.c
View File

@ -49,8 +49,6 @@ bool step_vm() {
lc = 0; lc = 0;
/* push parents frame value to reset the heap to */ /* push parents frame value to reset the heap to */
(*header++) = fp; (*header++) = fp;
/* push return address to child frame */
globals[gmp + 1] = pc;
/* increase the mp to new size */ /* increase the mp to new size */
mp += FRAME_HEADER_SIZE; mp += FRAME_HEADER_SIZE;
/* now set the frame pointer, where the locals start */ /* now set the frame pointer, where the locals start */
@ -102,6 +100,16 @@ bool step_vm() {
status = syscall(id, size, rd); status = syscall(id, size, rd);
return true; return true;
} }
case OP_PUSH: {
return false;
}
case OP_POP: {
--sp;
return true;
}
case OP_SET: {
return false;
}
case OP_MEM_ALLOC: { case OP_MEM_ALLOC: {
u32 size = stack[--sp]; u32 size = stack[--sp];
stack[sp++] = mp; stack[sp++] = mp;
@ -221,6 +229,38 @@ bool step_vm() {
status = 0; status = 0;
return true; return true;
} }
case OP_DUP: {
u32 a = stack[--sp];
stack[sp++] = a;
stack[sp++] = a;
return true;
}
case OP_EXCH: {
u32 a = stack[--sp];
u32 b = stack[--sp];
stack[sp++] = b;
stack[sp++] = a;
return true;
}
case OP_OVER: {
u32 a = stack[sp - 1];
stack[sp++] = a;
return true;
}
case OP_PICK: {
u32 n = stack[--sp];
u32 b = stack[sp - n];
stack[sp++] = b;
return true;
}
case OP_ROT: {
return false;
}
case OP_DEPTH: {
u32 a = sp;
stack[sp++] = a;
return true;
}
case OP_ADD_INT: { case OP_ADD_INT: {
MATH_OP(i32, +); MATH_OP(i32, +);
} }

149
vm/vm.h
View File

@ -4,76 +4,83 @@
#include "libc.h" #include "libc.h"
typedef enum { typedef enum {
OP_HALT, /* `halt` | halt execution */ OP_HALT, /* - `halt` | halt execution */
OP_CALL, /* ptr `call` | creates a new frame */ OP_CALL, /* ptr `call` | creates a new frame */
OP_RETURN, /* `return` | returns from a frame to the parent frame */ OP_RETURN, /* - `return` | returns from a frame to the parent frame */
OP_SYSCALL, /* `syscall` | id args mem_ptr : does a system call based on id with args */ OP_SYSCALL, /* id args mem_ptr `syscall` - | id args mem_ptr : does a system call based on id with args */
OP_LOAD_8, /* &dest `load-8` u8 | push memory[obj1] onto stack as u8 */ OP_LOAD_8, /* &dest `load-8` u8 | push memory[obj1] onto stack as u8 */
OP_LOAD_16, /* &dest `load-16` u16 | push memory[obj1] onto stack as u16 */ OP_LOAD_16, /* &dest `load-16` u16 | push memory[obj1] onto stack as u16 */
OP_LOAD_32, /* &dest `load` u32 | push memory[obj1] onto stack as u32 */ OP_LOAD_32, /* &dest `load` u32 | push memory[obj1] onto stack as u32 */
OP_STORE_8, /* &dest obj1 `store-8` - | memory[dest] = obj1 << 8 */ OP_STORE_8, /* &dest obj1 `store-8` - | memory[dest] = obj1 << 8 */
OP_STORE_16, /* &dest obj1 `store-16`- | memory[dest] = obj1 << 16 */ OP_STORE_16, /* &dest obj1 `store-16`- | memory[dest] = obj1 << 16 */
OP_STORE_32, /* &dest obj1 `store` - | memory[dest] = obj1 */ OP_STORE_32, /* &dest obj1 `store` - | memory[dest] = obj1 */
OP_MALLOC, /* size `malloc` ptr | allocate 'size + 4' of memory and push ptr to memory on stack */ OP_MALLOC, /* size `malloc` ptr | allocate 'size + 4' of memory and push ptr to memory on stack */
OP_GET, /* &local `get` obj1 | get the value from the local slot */ OP_PUSH, /* &local `get` obj1 | get the value from the local slot */
OP_SET, /* obj1 &local `set` - | set the value of the local slot */ OP_POP, /* - `pop` - | removes top item from the stack */
OP_MEM_ALLOC, /* size `alloc` ptr | allocate 'size + 4' of memory and push ptr to memory on stack */ OP_SET, /* obj1 &local `set` - | set the value of the local slot */
OP_MEM_CPY_8, /* `memcpy_8` | memory[src1..src1+src2] = memory[dest..dest+src2] */ OP_DUP, /* obj1 `dup` obj1 obj1 | duplicates the top of the stack */
OP_MEM_CPY_16, /* `memcpy_16` | memory[src1..src1+src2] = memory[dest..dest+src2] */ OP_EXCH, /* obj2 obj1 `exch` obj1 obj2 | swaps the top two values on the stack */
OP_MEM_CPY_32, /* `memcpy_32` | memory[src1..src1+src2] = memory[dest..dest+src2] */ OP_OVER, /* obj2 obj1 `over` obj2 | copys the 2nd to the top element and pushes to the stack */
OP_MEM_SET_8, /* `memset_8` | memory[dest..dest+src2] = local[src1] as u8 */ OP_PICK, /* N `pick` objN | gets the nth element on the stack and pushes it on top */
OP_MEM_SET_16, /* `memset_16` | memory[dest..dest+src2] = local[src1] as u16 */ OP_ROT, /* obj3 obj2 obj1 `rot` obj2 obj1 obj3 | takes the 3rd element and moves it to the top of the stack */
OP_MEM_SET_32, /* `memset_32` | memory[dest..dest+src2] = local[src1] as u32 */ OP_DEPTH, /* - `depth` heap_count | pushes the number of elements on the stack to the stack*/
OP_ADD_INT, /* obj2 obj1 `add_int` obj | obj1 + obj2 then push result on stack */ OP_MEM_ALLOC, /* size `alloc` ptr | allocate 'size + 4' of memory and push ptr to memory on stack */
OP_SUB_INT, /* obj2 obj1 `sub_int` obj | obj1 - obj2 then push result on stack */ OP_MEM_CPY_8, /* size src dest `memcpy_8` - | memory[src..src+size] = memory[dest..dest+size] */
OP_MUL_INT, /* obj2 obj1 `mul_int` obj | obj1 * obj2 then push result on stack */ OP_MEM_CPY_16, /* size src dest `memcpy_16` - | memory[src..src+size] = memory[dest..dest+size] */
OP_DIV_INT, /* obj2 obj1 `div_int` obj | obj1 / obj2 then push result on stack */ OP_MEM_CPY_32, /* size src dest `memcpy_32` - | memory[src..src+size] = memory[dest..dest+size] */
OP_ADD_NAT, /* obj2 obj1 `add_nat` obj | obj1 + obj2 then push result on stack */ OP_MEM_SET_8, /* size src dest `memset_8` - | memory[dest..dest+size] = local[src] as u8 */
OP_SUB_NAT, /* obj2 obj1 `sub_nat` obj | obj1 - obj2 then push result on stack */ OP_MEM_SET_16, /* size src dest `memset_16` - | memory[dest..dest+size] = local[src] as u16 */
OP_MUL_NAT, /* obj2 obj1 `mul_nat` obj | obj1 * obj2 then push result on stack */ OP_MEM_SET_32, /* size src dest `memset_32` - | memory[dest..dest+size] = local[src] as u32 */
OP_DIV_NAT, /* obj2 obj1 `div_nat` obj | obj1 / obj2 then push result on stack */ OP_ADD_INT, /* obj2 obj1 `add_int` obj | obj1 + obj2 then push result on stack */
OP_ADD_REAL, /* obj2 obj1 `add_real` obj | obj1 + obj2 then push result on stack */ OP_SUB_INT, /* obj2 obj1 `sub_int` obj | obj1 - obj2 then push result on stack */
OP_SUB_REAL, /* obj2 obj1 `sub_real` obj | obj1 - obj2 then push result on stack */ OP_MUL_INT, /* obj2 obj1 `mul_int` obj | obj1 * obj2 then push result on stack */
OP_MUL_REAL, /* obj2 obj1 `mul_real` obj | obj1 * obj2 then push result on stack */ OP_DIV_INT, /* obj2 obj1 `div_int` obj | obj1 / obj2 then push result on stack */
OP_DIV_REAL, /* obj2 obj1 `div_real` obj | obj1 / obj2 then push result on stack */ OP_ADD_NAT, /* obj2 obj1 `add_nat` obj | obj1 + obj2 then push result on stack */
OP_INT_TO_REAL, /* obj1 `int_to_real` obj1 as real | casts an int to a fixed number */ OP_SUB_NAT, /* obj2 obj1 `sub_nat` obj | obj1 - obj2 then push result on stack */
OP_INT_TO_NAT, /* obj1 `int_to_nat` obj1 as nat | casts an int to a unsigned int */ OP_MUL_NAT, /* obj2 obj1 `mul_nat` obj | obj1 * obj2 then push result on stack */
OP_NAT_TO_REAL, /* obj1 `nat_to_real` obj1 as real | casts a unsigned int to a fixed number */ OP_DIV_NAT, /* obj2 obj1 `div_nat` obj | obj1 / obj2 then push result on stack */
OP_NAT_TO_INT, /* obj1 `nat_to_int` obj1 as int | casts a unsigned int to an int */ OP_ADD_REAL, /* obj2 obj1 `add_real` obj | obj1 + obj2 then push result on stack */
OP_REAL_TO_INT, /* obj1 `real_to_int` obj1 as int | casts a fixed number to an int */ OP_SUB_REAL, /* obj2 obj1 `sub_real` obj | obj1 - obj2 then push result on stack */
OP_REAL_TO_NAT, /* obj1 `real_to_nat` obj1 as nat | casts a fixed number to an unsigned int */ OP_MUL_REAL, /* obj2 obj1 `mul_real` obj | obj1 * obj2 then push result on stack */
OP_BIT_SHIFT_LEFT, /* obj2 obj1 `bit_shift_left` obj | src1] << locals[src2] */ OP_DIV_REAL, /* obj2 obj1 `div_real` obj | obj1 / obj2 then push result on stack */
OP_BIT_SHIFT_RIGHT,/* obj2 obj1 `bit_shift_right` obj | src1] >> locals[src2] */ OP_INT_TO_REAL, /* obj1 `int_to_real` obj1 as real | casts an int to a fixed number */
OP_BIT_SHIFT_R_EXT,/* obj2 obj1 `bit_shift_r_ext` obj | src1 >> src2 then cast result as i32 */ OP_INT_TO_NAT, /* obj1 `int_to_nat` obj1 as nat | casts an int to a unsigned int */
OP_BIT_AND, /* obj2 obj1 `bit_and` obj | obj1 & obj2 */ OP_NAT_TO_REAL, /* obj1 `nat_to_real` obj1 as real | casts a unsigned int to a fixed number */
OP_BIT_OR, /* obj2 obj1 `bit_or` obj | obj1 | obj2 */ OP_NAT_TO_INT, /* obj1 `nat_to_int` obj1 as int | casts a unsigned int to an int */
OP_BIT_XOR, /* obj2 obj1 `bit_xor` obj | obj1 ^ obj2 */ OP_REAL_TO_INT, /* obj1 `real_to_int` obj1 as int | casts a fixed number to an int */
OP_JMP, /* pc `jump` | jump unconditionally */ OP_REAL_TO_NAT, /* obj1 `real_to_nat` obj1 as nat | casts a fixed number to an unsigned int */
OP_JMP_FLAG, /* pc `jump_if_flag` | jump to pc if flag > 0 */ OP_BIT_SHIFT_LEFT, /* obj2 obj1 `bit_shift_left` obj | src1] << locals[src2] */
OP_JEQ_INT, /* obj2 obj1 pc `jump_eq_int` | jump to pc if obj1 as int == obj2 as int */ OP_BIT_SHIFT_RIGHT,/* obj2 obj1 `bit_shift_right` obj | src1] >> locals[src2] */
OP_JNE_INT, /* obj2 obj1 pc `jump_neq_int` | jump to pc if obj1 as int != obj2 as int */ OP_BIT_SHIFT_R_EXT,/* obj2 obj1 `bit_shift_r_ext` obj | src1 >> src2 then cast result as i32 */
OP_JGT_INT, /* obj2 obj1 pc `jump_gt_int` | jump to pc if obj1 as int > obj2 as int */ OP_BIT_AND, /* obj2 obj1 `bit_and` obj | obj1 & obj2 */
OP_JLT_INT, /* obj2 obj1 pc `jump_lt_int` | jump to pc if obj1 as int < obj2 as int */ OP_BIT_OR, /* obj2 obj1 `bit_or` obj | obj1 | obj2 */
OP_JLE_INT, /* obj2 obj1 pc `jump_le_int` | jump to pc if obj1 as int <= obj2 as int */ OP_BIT_XOR, /* obj2 obj1 `bit_xor` obj | obj1 ^ obj2 */
OP_JGE_INT, /* obj2 obj1 pc `jump_ge_int` | jump to pc if obj1 as int >= obj2 as int */ OP_JMP, /* pc `jump` | jump unconditionally */
OP_JEQ_NAT, /* obj2 obj1 pc `jump_eq_nat` | jump to pc if obj1 as nat == obj2 as nat */ OP_JMP_FLAG, /* pc `jump_if_flag` | jump to pc if flag > 0 */
OP_JNE_NAT, /* obj2 obj1 pc `jump_neq_nat` | jump to pc if obj1 as nat != obj2 as nat */ OP_JEQ_INT, /* obj2 obj1 pc `jump_eq_int` | jump to pc if obj1 as int == obj2 as int */
OP_JGT_NAT, /* obj2 obj1 pc `jump_gt_nat` | jump to pc if obj1 as nat > obj2 as nat */ OP_JNE_INT, /* obj2 obj1 pc `jump_neq_int` | jump to pc if obj1 as int != obj2 as int */
OP_JLT_NAT, /* obj2 obj1 pc `jump_lt_nat` | jump to pc if obj1 as nat < obj2 as nat */ OP_JGT_INT, /* obj2 obj1 pc `jump_gt_int` | jump to pc if obj1 as int > obj2 as int */
OP_JLE_NAT, /* obj2 obj1 pc `jump_le_nat` | jump to pc if obj1 as nat <= obj2 as nat */ OP_JLT_INT, /* obj2 obj1 pc `jump_lt_int` | jump to pc if obj1 as int < obj2 as int */
OP_JGE_NAT, /* obj2 obj1 pc `jump_ge_nat` | jump to pc if obj1 as nat >= obj2 as nat */ OP_JLE_INT, /* obj2 obj1 pc `jump_le_int` | jump to pc if obj1 as int <= obj2 as int */
OP_JEQ_REAL, /* obj2 obj1 pc `jump_eq_real` | jump to pc if obj1 as real == obj2 as real */ OP_JGE_INT, /* obj2 obj1 pc `jump_ge_int` | jump to pc if obj1 as int >= obj2 as int */
OP_JNE_REAL, /* obj2 obj1 pc `jump_neq_real` | jump to pc if obj1 as real != obj2 as real */ OP_JEQ_NAT, /* obj2 obj1 pc `jump_eq_nat` | jump to pc if obj1 as nat == obj2 as nat */
OP_JGE_REAL, /* obj2 obj1 pc `jump_ge_real` | jump to pc if obj1 as real >= obj2 as real */ OP_JNE_NAT, /* obj2 obj1 pc `jump_neq_nat` | jump to pc if obj1 as nat != obj2 as nat */
OP_JGT_REAL, /* obj2 obj1 pc `jump_gt_real` | jump to pc if obj1 as real > obj2 as real */ OP_JGT_NAT, /* obj2 obj1 pc `jump_gt_nat` | jump to pc if obj1 as nat > obj2 as nat */
OP_JLT_REAL, /* obj2 obj1 pc `jump_lt_real` | jump to pc if obj1 as real < obj2 as real */ OP_JLT_NAT, /* obj2 obj1 pc `jump_lt_nat` | jump to pc if obj1 as nat < obj2 as nat */
OP_JLE_REAL, /* obj2 obj1 pc `jump_le_real` | jump to pc if obj1 as real <= obj2 as real */ OP_JLE_NAT, /* obj2 obj1 pc `jump_le_nat` | jump to pc if obj1 as nat <= obj2 as nat */
OP_INT_TO_STR, /* obj1 `int-to-string` str_ptr | convert obj1 to str */ OP_JGE_NAT, /* obj2 obj1 pc `jump_ge_nat` | jump to pc if obj1 as nat >= obj2 as nat */
OP_NAT_TO_STR, /* obj1 `nat-to-string` str_ptr | convert obj1 to str */ OP_JEQ_REAL, /* obj2 obj1 pc `jump_eq_real` | jump to pc if obj1 as real == obj2 as real */
OP_REAL_TO_STR, /* obj1 `real-to-string` str_ptr | convert obj1 to str */ OP_JNE_REAL, /* obj2 obj1 pc `jump_neq_real` | jump to pc if obj1 as real != obj2 as real */
OP_STR_TO_INT, /* str_ptr `string-to-int` obj | convert obj1 to int */ OP_JGE_REAL, /* obj2 obj1 pc `jump_ge_real` | jump to pc if obj1 as real >= obj2 as real */
OP_STR_TO_NAT, /* str_ptr `string-to-nat` obj | convert obj1 to nat */ OP_JGT_REAL, /* obj2 obj1 pc `jump_gt_real` | jump to pc if obj1 as real > obj2 as real */
OP_STR_TO_REAL, /* str_ptr `string-to-real` obj | convert obj1 to real */ OP_JLT_REAL, /* obj2 obj1 pc `jump_lt_real` | jump to pc if obj1 as real < obj2 as real */
OP_JLE_REAL, /* obj2 obj1 pc `jump_le_real` | jump to pc if obj1 as real <= obj2 as real */
OP_INT_TO_STR, /* obj1 `int-to-string` str_ptr | convert obj1 to str */
OP_NAT_TO_STR, /* obj1 `nat-to-string` str_ptr | convert obj1 to str */
OP_REAL_TO_STR, /* obj1 `real-to-string` str_ptr | convert obj1 to str */
OP_STR_TO_INT, /* str_ptr `string-to-int` obj | convert obj1 to int */
OP_STR_TO_NAT, /* str_ptr `string-to-nat` obj | convert obj1 to nat */
OP_STR_TO_REAL, /* str_ptr `string-to-real` obj | convert obj1 to real */
OP_MAX_OPCODE /* not an opcode count of instructions */ OP_MAX_OPCODE /* not an opcode count of instructions */
} Opcode; } Opcode;
@ -149,8 +156,8 @@ extern u8 *mem; /* memory */
#define MATH_OP_NO_CAST(op) \ #define MATH_OP_NO_CAST(op) \
do { \ do { \
u32 a = stack[--sp]; \
u32 b = stack[--sp]; \ u32 b = stack[--sp]; \
u32 a = stack[--sp]; \
stack[sp++] = a op b; \ stack[sp++] = a op b; \
return true; \ return true; \
} while (0) } while (0)