fib example

This commit is contained in:
zongor 2026-02-11 21:00:20 -08:00
parent ee39c8ba95
commit 18697c92b6
4 changed files with 137 additions and 70 deletions

View File

@ -71,31 +71,86 @@ u32 syscall(u32 id, u32 mem_ptr) {
return 1; // generic error
}
static void repl() {
ScopeTable st;
char line[1024];
for (;;) {
printf("> ");
//static void repl() {
// ScopeTable st;
// char line[1024];
// for (;;) {
// printf("> ");
//
// if (!fgets(line, sizeof(line), stdin)) {
// printf("\n");
// break;
// }
//
// reset();
//
// compile(&st, line);
//
// while(step_vm()) {}
//
// syscall(SYSCALL_CONSOLE_WRITE, stack[0]);
// }
//}
if (!fgets(line, sizeof(line), stdin)) {
printf("\n");
break;
}
void fib() {
u8 fib_ptr = 10;
code[cp++] = OP_PUSH_8;
code[cp++] = 35;
code[cp++] = OP_PUSH_8;
code[cp++] = fib_ptr;
code[cp++] = OP_CALL;
code[cp++] = OP_INT_TO_STR;
code[cp++] = OP_PUSH_8;
code[cp++] = SYSCALL_CONSOLE_WRITE;
code[cp++] = OP_SYSCALL;
code[cp++] = OP_HALT;
/* fib (int n) int */
code[cp++] = OP_SET_IMM;
code[cp++] = 0;
/* if (n < 2) { */
code[cp++] = OP_GET_IMM;
code[cp++] = 0;
code[cp++] = OP_PUSH_8;
code[cp++] = 2;
code[cp++] = OP_LTS;
code[cp++] = OP_PUSH_8;
u8 if_true = cp + 5;
code[cp++] = if_true;
code[cp++] = OP_JNZ;
code[cp++] = OP_PUSH_8;
u8 if_false = cp + 5;
code[cp++] = if_false;
code[cp++] = OP_JMP;
code[cp++] = OP_GET_IMM;
code[cp++] = 0;
code[cp++] = OP_RETURN;
code[cp++] = OP_GET_IMM;
code[cp++] = 0;
code[cp++] = OP_PUSH_8;
code[cp++] = 2;
code[cp++] = OP_SUB_INT;
code[cp++] = OP_PUSH_8;
code[cp++] = fib_ptr;
code[cp++] = OP_CALL;
code[cp++] = OP_GET_IMM;
code[cp++] = 0;
code[cp++] = OP_PUSH_8;
code[cp++] = 1;
code[cp++] = OP_SUB_INT;
code[cp++] = OP_PUSH_8;
code[cp++] = fib_ptr;
code[cp++] = OP_CALL;
code[cp++] = OP_ADD_INT;
code[cp++] = OP_RETURN;
reset();
compile(&st, line);
while(step_vm()) {}
syscall(SYSCALL_CONSOLE_WRITE, stack[0]);
}
while(step_vm()) {}
}
i32 main() {
init_vm();
repl();
fib();
//repl();
return 0;
}

View File

@ -4,6 +4,11 @@
#include <stdio.h>
#include <stdlib.h>
Token operator_stack[128];
u8 osp;
Token value_stack[256];
u8 vsp;
Parser parser;
Symbol *symbol_table_lookup(ScopeTable *table, const char *name, u32 length,

104
vm/vm.c
View File

@ -28,66 +28,25 @@ u32 str_alloc(char *str, u32 length) {
}
bool step_vm() {
u8 opcode = code[pc++];
/*u32 *locals = (u32*)(&mem[fp]);*/
u32 *globals = (u32*)(mem);
u16 opcode = code[pc++];
switch (opcode) {
case OP_HALT: {
/* no need to decode, all are zeros */
return false;
}
case OP_CALL: {
/* function to jump to */
u32 fn_ptr = stack[--sp];
/* get mp in 'global indexing mode' */
u32 *header = &globals[mp / 4];
/* push parents frame value to reset the heap to */
(*header++) = fp;
/* increase the mp to new size */
mp += FRAME_HEADER_SIZE;
/* now set the frame pointer, where the locals start */
fp = mp;
/* move mp forward by count many locals */
mp += stack[--sp];
/* jump to dest_ptr */
frames[fp].return_pc = pc;
frames[fp++].start_mp = mp;
pc = fn_ptr;
return false;
return true;
}
case OP_RETURN: {
/* TODO: Fix this one so it makes sense with a stack based system */
u32 size = 0;
u32 return_value = stack[--sp];
bool is_ptr = (((u32)(1)) << 15) & return_value;
/* reset mp to saved mp, use header size to get "real" start of frame */
u32 *frame_start = &globals[(fp / 4) - 3];
u32 parent_fp = *frame_start++;
u32 return_address = *frame_start++;
u32 parent_local_return_address = *frame_start++;
/* reset memory to parents end of memory */
mp = fp - FRAME_HEADER_SIZE;
/* reset the frame pointer */
fp = parent_fp;
if (is_ptr) {
/* copy value to end of mp if it is a pointer */
globals[parent_local_return_address/4] = mp;
size = globals[return_value/4];
globals[mp/4] = size;
mp += 4;
mcpy(&mem[mp], &mem[return_value], size);
mp += size;
} else {
/* otherwise just write the return value to its location */
mcpy(&mem[parent_local_return_address], &return_value, sizeof(u32));
}
/* jump to parent frame */
pc = return_address;
return false;
u32 return_pc = frames[--fp].return_pc;
u32 return_mp = frames[fp].start_mp;
mp = return_mp;
pc = return_pc;
return true;
}
case OP_SYSCALL: {
u32 id = stack[--sp]; /* syscall id */
@ -115,10 +74,48 @@ bool step_vm() {
stack[sp++] = value;
return true;
}
case OP_PUSH_MP: {
stack[sp++] = mp;
return true;
}
case OP_PUSH_START_MP: {
stack[sp++] = frames[fp - 1].start_mp;
return true;
}
case OP_POP: {
--sp;
return true;
}
case OP_SET:{
Frame *f = &frames[fp - 1];
u32 *locals = f->locals;
u8 ptr = (u8)stack[--sp];
u32 value = stack[--sp];
locals[ptr] = value;
return true;
}
case OP_SET_IMM:{
Frame *f = &frames[fp - 1];
u32 *locals = f->locals;
u8 ptr = code[pc++];
u32 value = stack[--sp];
locals[ptr] = value;
return true;
}
case OP_GET:{
Frame *f = &frames[fp - 1];
u32 *locals = f->locals;
u8 ptr = (u8)stack[--sp];
stack[sp++] = locals[ptr];
return true;
}
case OP_GET_IMM:{
Frame *f = &frames[fp - 1];
u32 *locals = f->locals;
u8 ptr = code[pc++];
stack[sp++] = locals[ptr];
return true;
}
case OP_LOAD_8: {
u32 ptr = stack[--sp];
u32 value = mem[ptr];
@ -180,6 +177,7 @@ bool step_vm() {
ptr_dest = &mem[dest];
ptr_src = &mem[src];
if (ptr_dest == ptr_src) { return true; }
mcpy(ptr_dest, ptr_src, count*sizeof(u8));
status = 0;
@ -199,6 +197,7 @@ bool step_vm() {
ptr_dest = &mem[dest];
ptr_src = &mem[src];
if (ptr_dest == ptr_src) { return true; }
mcpy(ptr_dest, ptr_src, count*sizeof(u16));
status = 0;
@ -218,6 +217,7 @@ bool step_vm() {
ptr_dest = &mem[dest];
ptr_src = &mem[src];
if (ptr_dest == ptr_src) { return true; }
mcpy(ptr_dest, ptr_src, count*sizeof(u32));
status = 0;
@ -472,9 +472,9 @@ bool step_vm() {
return true;
}
case OP_JNZ: {
u32 mask, target;
u32 mask;
u32 target = stack[--sp];
i32 cond = stack[--sp];
target = stack[--sp];
mask = -(u32)cond;
pc = (target & mask) | (pc & ~mask);
return true;

View File

@ -18,6 +18,12 @@ typedef enum {
OP_PUSH_8, /* const `push8` obj1 | push a 8 bit const onto the stack */
OP_PUSH_16, /* const `push16` obj1 | push a 16 bit const onto the stack */
OP_PUSH_32, /* const `push32` obj1 | push a 32 bit const onto the stack */
OP_PUSH_MP, /* - `pmp` mp | push current mp to stack */
OP_PUSH_START_MP, /* - `psmp` mp | push the frames start mp to stack (parent frames end mp); used for returning heap values to parent */
OP_SET, /* obj dest `set` - | sets a local to the next value on top of the stack (max 255) */
OP_GET, /* dest `get` obj | pushes a local from the value on top of the stack (max 255) */
OP_SET_IMM, /* obj #dest `seti` - | sets a local to the next immediate location (max 255) */
OP_GET_IMM, /* #dest `geti` obj | pushes a local from the immediate location (max 255) */
OP_POP, /* - `pop` - | removes top item from the stack */
OP_DUP, /* obj1 `dup` obj1 obj1 | duplicates the top of the stack */
OP_EXCH, /* obj2 obj1 `exch` obj1 obj2 | swaps the top two values on the stack */
@ -89,6 +95,7 @@ typedef enum {
typedef struct frame_s Frame;
struct frame_s {
u32 locals[256];
u32 return_pc;
u32 start_mp;
};