WIP: implement call and return instructions

This commit is contained in:
zongor 2026-01-05 21:18:23 -08:00
parent 34b6fa96ca
commit 4635c83e42
2 changed files with 132 additions and 31 deletions

125
vm/vm.c
View File

@ -1,5 +1,7 @@
#include "vm.h"
#define FRAME_HEADER_SIZE 12
u32 pc; /* program counter */
u32 cp; /* code pointer */
u32 mp; /* memory pointer */
@ -20,19 +22,70 @@ bool step_vm() {
return false;
}
case OP_CALL: {
/* DECODE_A(instruction) */
DECODE_A(instruction)
u32 fn_ptr, local_count, return_ptr;
u32 rd = fp + dest;
u32 r1 = fp + src1;
u32 r2 = fp + src2;
fn_ptr = READ_U32(rd);
local_count = READ_U32(r1);
return_ptr = READ_U32(r2);
/* 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 + 1);
mp += 4;
/* push local address to return the value to */
/* push current mp value to reset the heap to */
/* move mp by args many locals */
WRITE_U32(mp, return_ptr);
mp += 4;
/* now set the frame pointer, where the locals start */
fp = mp;
/* move mp by count many locals */
mp += (4 * local_count);
/* jump to dest_ptr */
pc = fn_ptr;
return true;
}
case OP_RETURN: {
/* DECODE_A(instruction) */
/* copy return value to parent return local */
/* reset mp to saved mp */
DECODE_B(instruction)
u32 i, size = 0;
u32 return_local = fp + dest;
u32 return_value = READ_U32(return_local);
bool is_ptr = imm >> 31;
/* 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 = READ_U32(frame_start + 8);
/* 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: {
@ -56,6 +109,42 @@ bool step_vm() {
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;
@ -86,7 +175,7 @@ bool step_vm() {
return true;
}
for (i = 0; i < count; i ++) {
for (i = 0; i < count; i++) {
u8 value = READ_U8(mdest + i);
WRITE_U8(msrc + i, value);
}
@ -111,7 +200,7 @@ bool step_vm() {
return true;
}
for (i = 0; i < count; i ++) {
for (i = 0; i < count; i++) {
u16 value = READ_U16(mdest + i);
WRITE_U16(msrc + i, value);
}
@ -136,7 +225,7 @@ bool step_vm() {
return true;
}
for (i = 0; i < count; i ++) {
for (i = 0; i < count; i++) {
u32 value = READ_U32(mdest + i);
WRITE_U32(msrc + i, value);
}
@ -154,7 +243,7 @@ bool step_vm() {
u8 value = (u8)READ_U32(r1);
u32 count = READ_U32(r2);
if (r2 == 0) {
flag = 1;
return true;
@ -168,7 +257,7 @@ bool step_vm() {
return true;
}
for (i = start; i < end; i ++) {
for (i = start; i < end; i++) {
WRITE_U8(i, value);
}
@ -185,7 +274,7 @@ bool step_vm() {
u16 value = (u16)READ_U32(r1);
u32 count = READ_U32(r2);
if (r2 == 0) {
flag = 1;
return true;
@ -322,7 +411,7 @@ bool step_vm() {
i32 result = (i32)READ_U32(r1) << 16;
USED(src2);
WRITE_U32(rd, result);
return true;
return true;
}
case OP_INT_TO_NAT: {
DECODE_A(instruction)
@ -340,7 +429,7 @@ bool step_vm() {
i32 result = ((i32)READ_U32(r1) << 16);
USED(src2);
WRITE_U32(rd, result);
return true;
return true;
}
case OP_NAT_TO_INT: {
DECODE_A(instruction)
@ -404,7 +493,7 @@ bool step_vm() {
USED(src2);
pc = jmp_dest;
return true;
return true;
}
case OP_JMP_OFF: {
DECODE_A(instruction)
@ -419,11 +508,11 @@ bool step_vm() {
USED(src2);
pc = jmp_dest;
return true;
return true;
}
case OP_JMP_FLAG: {
DECODE_A(instruction)
u32 mask;
u32 mask;
u32 rd = fp + dest;
u32 jmp_dest = READ_U32(rd);
if (jmp_dest > cp) {
@ -435,7 +524,7 @@ bool step_vm() {
mask = -(u32)(flag == 0);
pc = (jmp_dest & mask) | (pc & ~mask);
return true;
return true;
}
case OP_JEQ_INT: {
COMPARE_AND_JUMP(i32, ==);

38
vm/vm.h
View File

@ -37,17 +37,35 @@
typedef enum {
OP_HALT, /* halt : A : all zeros : halt execution */
OP_CALL, /* call : A : dest args return : creates a new frame */
OP_RETURN, /* return : A : dest : returns from a frame to the parent 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 + count] = memory[dest .. dest + count] */
OP_MEM_CPY_16, /* memcpy_16 : A : memory[src1 .. src1 + count] = memory[dest .. dest + count] */
OP_MEM_CPY_32, /* memcpy_32 : 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_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_ADD_INT, /* add_int : A : locals[dest] = locals[src1] + locals[src2] */
OP_SUB_INT, /* sub_int : A : locals[dest] = locals[src1] - locals[src2] */
@ -112,12 +130,6 @@ extern u8 interrupt; /* device interrupt */
extern u32 *code; /* code */
extern u8 *mem; /* memory */
/**
* Frames
*
*
*/
#define READ_U8(addr) (mem[addr])
#define READ_U16(addr) \