1
0
Fork 0

Add test works, WIP fibonacci test

This commit is contained in:
zongor 2026-01-07 23:35:57 -08:00
parent 206fd8f266
commit 9fe4f97016
3 changed files with 904 additions and 0 deletions

89
arch/linux/tui/main.c Normal file
View File

@ -0,0 +1,89 @@
#include "../../../vm/vm.h"
#include <stdio.h>
#include <string.h>
#define CODE_SIZE 8192
#define MEMORY_SIZE 65536
u8 lmem[MEMORY_SIZE] = {0};
u32 lcode[CODE_SIZE] = {0};
bool init_vm() {
mem = lmem;
memset(mem, 0, MEMORY_SIZE*sizeof(u8));
code = lcode;
sp = 0;
mp = 0;
cp = 0;
pc = 0;
interrupt = 0;
return true;
}
u32 syscall(u32 id, u32 args, u32 mem_ptr) {
USED(args);
switch(id) {
case SYSCALL_DBG_PRINT: {
printf("%d\n", mem[mem_ptr]);
return 0;
}
}
return 1; // generic error
}
void test_add_two_num() {
i32 main_local_count = 4;
mp += (4 * main_local_count);
code[cp++] = ENCODE_B(OP_LOAD_IMM, 0, 1);
code[cp++] = ENCODE_B(OP_PUSH, 0, 0);
code[cp++] = ENCODE_B(OP_LOAD_IMM, 1, 1);
code[cp++] = ENCODE_B(OP_PUSH, 1, 0);
i32 add = cp + 4;
code[cp++] = ENCODE_B(OP_LOAD_IMM, 2, add);
code[cp++] = ENCODE_A(OP_CALL, 2, 3, 3);
code[cp++] = ENCODE_A(OP_SYSCALL, SYSCALL_DBG_PRINT, 1, 3);
code[cp++] = ENCODE_A(OP_HALT, 0, 0, 0);
/* add */
code[cp++] = ENCODE_A(OP_ADD_INT, 2, 1, 0);
code[cp++] = ENCODE_B(OP_RETURN, 2, 0);
}
void test_fibonacci() {
/* fn main() */
i32 main_local_count = 3;
mp += (4 * main_local_count);
code[cp++] = ENCODE_B(OP_LOAD_IMM, 0, 35);
code[cp++] = ENCODE_B(OP_PUSH, 0, 0);
i32 fib = cp + 4;
code[cp++] = ENCODE_B(OP_LOAD_IMM, 1, fib);
code[cp++] = ENCODE_A(OP_CALL, 1, 3, 2);
code[cp++] = ENCODE_A(OP_SYSCALL, SYSCALL_DBG_PRINT, 1, 2);
code[cp++] = ENCODE_A(OP_HALT, 0, 0, 0);
/* fn fib */
code[cp++] = ENCODE_B(OP_LOAD_IMM, 1, 2);
code[cp++] = ENCODE_B(OP_LOAD_IMM, 2, fib);
code[cp++] = ENCODE_A(OP_JLT_INT, 2, 0, 1);
code[cp++] = ENCODE_B(OP_LOAD_IMM, 3, 2);
code[cp++] = ENCODE_A(OP_SUB_INT, 4, 0, 3);
code[cp++] = ENCODE_B(OP_PUSH, 4, 0);
code[cp++] = ENCODE_A(OP_CALL, 2, 3, 2);
code[cp++] = ENCODE_B(OP_RETURN, 0, 0);
}
i32 main() {
init_vm();
test_add_two_num();
while(step_vm()) {
// do stuff
}
return 0;
}

603
vm/vm.c Normal file
View File

@ -0,0 +1,603 @@
#include "vm.h"
#define FRAME_HEADER_SIZE 12
u32 pc; /* program counter */
u32 cp; /* code pointer */
u32 mp; /* memory pointer */
u32 fp; /* frame pointer */
u8 sp; /* child local count */
u32 flag; /* flag */
u8 interrupt; /* device interrupt */
u32 *code; /* code */
u8 *mem; /* memory */
bool step_vm() {
u32 instruction = code[pc++];
u8 opcode = DECODE_OP(instruction);
switch (opcode) {
case OP_HALT: {
/* no need to decode, all are zeros */
return false;
}
case OP_CALL: {
DECODE_A(instruction)
u32 fn_ptr;
u32 rd = fp + (dest * 4);
u32 r1 = src1;
u32 r2 = fp + src2;
fn_ptr = READ_U32(rd);
/* 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);
mp += 4;
/* push local address to return the value to */
WRITE_U32(mp, r2);
mp += 4;
/* now set the frame pointer, where the locals start */
fp = mp;
/* move mp by count many locals */
mp += (4 * r1);
/* jump to dest_ptr */
pc = fn_ptr;
return true;
}
case OP_RETURN: {
DECODE_B(instruction)
u32 i, size = 0;
u32 return_local = fp + (dest * 4);
u32 return_value = READ_U32(return_local);
bool is_ptr = (((u32)(1)) << 15) & imm;
bool replaces_value = (((u32)(1)) << 14) & imm;
/* 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 = 4 * READ_U32(frame_start + 8);
USED(replaces_value);
/* 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: {
DECODE_A(instruction)
u32 id = dest;
u32 args = src1;
u32 rd = fp + (src2 * 4);
flag = syscall(id, args, rd);
return true;
}
case OP_LOAD_IMM: {
DECODE_B(instruction)
u32 rd = fp + (dest * 4);
WRITE_U32(rd, imm);
return true;
}
case OP_LOAD_UPPER_IMM: {
DECODE_B(instruction)
u32 rd = fp + (dest * 4);
u32 value = READ_U32(rd);
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;
u32 rd = fp + (dest * 4);
u32 r1 = fp + (src1 * 4);
USED(src2);
ldest = READ_U32(rd);
WRITE_U32(ldest, mp);
size = READ_U32(r1);
WRITE_U32(mp, size);
mp += (size + 4);
return true;
}
case OP_MEM_CPY_8: {
DECODE_A(instruction)
u32 i, count, mdest, msrc;
u32 rd = fp + (dest * 4);
u32 r1 = fp + (src1 * 4);
u32 r2 = fp + (src2 * 4);
mdest = READ_U32(rd);
msrc = READ_U32(r1);
count = READ_U32(r2);
if (mdest + count >= mp) {
flag = 1;
return true;
}
for (i = 0; i < count; i++) {
u8 value = READ_U8(mdest + i);
WRITE_U8(msrc + i, value);
}
flag = 0;
return true;
}
case OP_MEM_CPY_16: {
DECODE_A(instruction)
u32 i, count, mdest, msrc;
u32 rd = fp + (dest * 4);
u32 r1 = fp + (src1 * 4);
u32 r2 = fp + (src2 * 4);
mdest = READ_U32(rd);
msrc = READ_U32(r1);
count = READ_U32(r2);
if (mdest + count >= mp) {
flag = 1;
return true;
}
for (i = 0; i < count; i++) {
u16 value = READ_U16(mdest + i);
WRITE_U16(msrc + i, value);
}
flag = 0;
return true;
}
case OP_MEM_CPY_32: {
DECODE_A(instruction)
u32 i, count, mdest, msrc;
u32 rd = fp + (dest * 4);
u32 r1 = fp + (src1 * 4);
u32 r2 = fp + (src2 * 4);
mdest = READ_U32(rd);
msrc = READ_U32(r1);
count = READ_U32(r2);
if (mdest + count >= mp) {
flag = 1;
return true;
}
for (i = 0; i < count; i++) {
u32 value = READ_U32(mdest + i);
WRITE_U32(msrc + i, value);
}
flag = 0;
return true;
}
case OP_MEM_SET_8: {
DECODE_A(instruction)
u32 i, start, end;
u32 rd = fp + (dest * 4);
u32 r1 = fp + (src1 * 4);
u32 r2 = fp + (src2 * 4);
u8 value = (u8)READ_U32(r1);
u32 count = READ_U32(r2);
if (r2 == 0) {
flag = 1;
return true;
}
start = READ_U32(rd);
end = start + count;
if (start >= mp || r2 > mp || end > mp) {
flag = 1;
return true;
}
for (i = start; i < end; i++) {
WRITE_U8(i, value);
}
flag = 0;
return true;
}
case OP_MEM_SET_16: {
DECODE_A(instruction)
u32 i, start, end;
u32 rd = fp + (dest * 4);
u32 r1 = fp + (src1 * 4);
u32 r2 = fp + (src2 * 4);
u16 value = (u16)READ_U32(r1);
u32 count = READ_U32(r2);
if (r2 == 0) {
flag = 1;
return true;
}
start = READ_U32(rd);
end = start + count;
if (start >= mp || r2 > mp || end > mp) {
flag = 1;
return true;
}
for (i = start; i < end; i += 2) {
WRITE_U16(i, value);
}
flag = 0;
return true;
}
case OP_MEM_SET_32: {
DECODE_A(instruction)
u32 i, start, end;
u32 rd = fp + (dest * 4);
u32 r1 = fp + (src1 * 4);
u32 r2 = fp + (src2 * 4);
u32 value = READ_U32(r1);
u32 count = READ_U32(r2);
if (r2 == 0) {
flag = 1;
return true;
}
start = READ_U32(rd);
end = start + count;
if (start >= mp || r2 > mp || end > mp) {
flag = 1;
return true;
}
for (i = start; i < end; i += 4) {
WRITE_U32(i, value);
}
flag = 0;
return true;
}
case OP_MOV: {
DECODE_A(instruction)
u32 rd = fp + (dest * 4);
u32 r1 = fp + (src1 * 4);
u32 value = READ_U32(r1);
USED(src2);
WRITE_U32(rd, value);
return true;
}
case OP_PUSH: {
DECODE_B(instruction)
u32 rd = fp + (dest * 4);
u32 val = READ_U32(rd);
USED(imm);
WRITE_U32((mp + (4 * (sp + 3))), val);
sp++;
return true;
}
case OP_POP: {
DECODE_C(instruction)
USED(imm);
mp -= 4;
return true;
}
case OP_ADD_INT: {
MATH_OP(i32, +);
}
case OP_SUB_INT: {
MATH_OP(i32, -);
}
case OP_MUL_INT: {
MATH_OP(i32, *);
}
case OP_DIV_INT: {
MATH_OP(i32, /);
}
case OP_ADD_NAT: {
MATH_OP(u32, +);
}
case OP_SUB_NAT: {
MATH_OP(u32, -);
}
case OP_MUL_NAT: {
MATH_OP(u32, *);
}
case OP_DIV_NAT: {
MATH_OP(u32, /);
}
case OP_ADD_REAL: {
MATH_OP(i32, +);
}
case OP_SUB_REAL: {
MATH_OP(i32, -);
}
case OP_MUL_REAL: {
DECODE_A(instruction)
u32 rd = fp + (dest * 4);
u32 r1 = fp + (src1 * 4);
u32 r2 = fp + (src2 * 4);
i32 src1_whole = (i32)READ_U32(r1) >> 16;
i32 src2_whole = (i32)READ_U32(r2) >> 16;
i32 src1_decimal = (i32)READ_U32(r1) & 16;
i32 src2_decimal = (i32)READ_U32(r2) & 16;
i32 result = 0;
result += (src1_whole * src2_whole) << 16;
result += (src1_whole * src2_decimal);
result += (src1_decimal * src2_whole);
result += ((src1_decimal * src2_decimal) >> 16) & 16;
WRITE_U32(rd, result);
return true;
}
case OP_DIV_REAL: {
DECODE_A(instruction)
i32 result;
u32 rd = fp + (dest * 4);
u32 r1 = fp + (src1 * 4);
u32 r2 = fp + (src2 * 4);
i32 src1_val = (i32)READ_U32(r1);
i32 src2_val = (i32)READ_U32(r2);
u32 src2_reciprocal = 1;
src2_reciprocal <<= 31;
src2_reciprocal = (u32)(src2_reciprocal / src2_val);
result = src1_val * src2_reciprocal;
result <<= 1;
WRITE_U32(rd, result);
return true;
}
case OP_INT_TO_REAL: {
DECODE_A(instruction)
u32 rd = fp + (dest * 4);
u32 r1 = fp + (src1 * 4);
i32 result = (i32)READ_U32(r1) << 16;
USED(src2);
WRITE_U32(rd, result);
return true;
}
case OP_INT_TO_NAT: {
DECODE_A(instruction)
u32 rd = fp + (dest * 4);
u32 r1 = fp + (src1 * 4);
u32 result = (u32)READ_U32(r1);
USED(src2);
WRITE_U32(rd, result);
return true;
}
case OP_NAT_TO_REAL: {
DECODE_A(instruction)
u32 rd = fp + (dest * 4);
u32 r1 = fp + (src1 * 4);
i32 result = ((i32)READ_U32(r1) << 16);
USED(src2);
WRITE_U32(rd, result);
return true;
}
case OP_NAT_TO_INT: {
DECODE_A(instruction)
u32 rd = fp + (dest * 4);
u32 r1 = fp + (src1 * 4);
i32 result = ((i32)READ_U32(r1));
USED(src2);
WRITE_U32(rd, result);
return true;
}
case OP_REAL_TO_INT: {
DECODE_A(instruction)
u32 rd = fp + (dest * 4);
u32 r1 = fp + (src1 * 4);
i32 result = ((i32)READ_U32(r1) >> 16);
USED(src2);
WRITE_U32(rd, result);
return true;
}
case OP_REAL_TO_NAT: {
DECODE_A(instruction)
u32 rd = fp + (dest * 4);
u32 r1 = fp + (src1 * 4);
u32 result = ((u32)READ_U32(r1) >> 16);
USED(src2);
WRITE_U32(rd, result);
return true;
}
case OP_BIT_SHIFT_LEFT: {
MATH_OP_NO_CAST(<<);
}
case OP_BIT_SHIFT_RIGHT: {
MATH_OP_NO_CAST(>>);
}
case OP_BIT_SHIFT_R_EXT: {
MATH_OP(i32, >>);
}
case OP_BIT_AND: {
MATH_OP_NO_CAST(&);
}
case OP_BIT_OR: {
MATH_OP_NO_CAST(|);
}
case OP_BIT_XOR: {
MATH_OP_NO_CAST(^);
}
case OP_JMP_IMM: {
DECODE_C(instruction)
pc = imm;
return true;
}
case OP_JMP_ABS: {
DECODE_A(instruction)
u32 rd = fp + (dest * 4);
u32 jmp_dest = READ_U32(rd);
if (jmp_dest > cp) {
flag = 1;
return true;
}
USED(src1);
USED(src2);
pc = jmp_dest;
return true;
}
case OP_JMP_OFF: {
DECODE_A(instruction)
u32 rd = fp + (dest * 4);
u32 r1 = fp + (src1 * 4);
u32 jmp_dest = READ_U32(rd) + READ_U32(r1);
if (jmp_dest > cp) {
flag = 1;
return true;
}
USED(src2);
pc = jmp_dest;
return true;
}
case OP_JMP_FLAG: {
DECODE_A(instruction)
u32 mask;
u32 rd = fp + (dest * 4);
u32 jmp_dest = READ_U32(rd);
if (jmp_dest > cp) {
flag = 1;
return true;
}
USED(src1);
USED(src2);
mask = -(u32)(flag == 0);
pc = (jmp_dest & mask) | (pc & ~mask);
return true;
}
case OP_JEQ_INT: {
COMPARE_AND_JUMP(i32, ==);
}
case OP_JNE_INT: {
COMPARE_AND_JUMP(i32, !=);
}
case OP_JGT_INT: {
COMPARE_AND_JUMP(i32, >);
}
case OP_JLT_INT: {
COMPARE_AND_JUMP(i32, <);
}
case OP_JLE_INT: {
COMPARE_AND_JUMP(i32, <=);
}
case OP_JGE_INT: {
COMPARE_AND_JUMP(i32, >=);
}
case OP_JEQ_NAT: {
COMPARE_AND_JUMP(u32, ==);
}
case OP_JNE_NAT: {
COMPARE_AND_JUMP(u32, !=);
}
case OP_JGT_NAT: {
COMPARE_AND_JUMP(u32, >);
}
case OP_JLT_NAT: {
COMPARE_AND_JUMP(u32, <);
}
case OP_JLE_NAT: {
COMPARE_AND_JUMP(u32, <=);
}
case OP_JGE_NAT: {
COMPARE_AND_JUMP(u32, >=);
}
case OP_JEQ_REAL: {
COMPARE_AND_JUMP(i32, ==);
}
case OP_JNE_REAL: {
COMPARE_AND_JUMP(i32, !=);
}
case OP_JGE_REAL: {
COMPARE_AND_JUMP(i32, >=);
}
case OP_JGT_REAL: {
COMPARE_AND_JUMP(i32, >);
}
case OP_JLT_REAL: {
COMPARE_AND_JUMP(i32, <);
}
case OP_JLE_REAL: {
COMPARE_AND_JUMP(i32, <=);
}
}
/* something went very wrong */
flag = 255;
return false;
}

212
vm/vm.h Normal file
View File

@ -0,0 +1,212 @@
#ifndef UNDAR_VM_H
#define UNDAR_VM_H
#include "libc.h"
/**
* Instruction Types
*
* A : [8:opcode][8:dest][8:src1][8:src2]
* B : [8:opcode][8:dest][16:immediate]
* C : [8:opcode][24:immediate]
*/
#define DECODE_OP(instruction) ((((u32)(instruction)) >> 24) & 0xFF)
#define ENCODE_A(opcode, dest, src1, src2) ((((u32)(opcode) & 0xFF) << 24) | \
(((u32)(dest) & 0xFF) << 16) | \
(((u32)(src1) & 0xFF) << 8) | \
(((u32)(src2) & 0xFF)))
#define DECODE_A(instruction) \
u8 dest = (((u32)(instruction)) >> 16) & 0xFF; \
u8 src1 = (((u32)(instruction)) >> 8) & 0xFF; \
u8 src2 = ((u32)(instruction)) & 0xFF;
#define ENCODE_B(opcode, dest, imm) ((((u32)(opcode) & 0xFF) << 24) | \
(((u32)(dest) & 0xFF) << 16) | \
(((u32)(imm)) & 0xFFFF))
#define DECODE_B(instruction) \
u8 dest = (((u32)(instruction)) >> 16) & 0xFF; \
u16 imm = ((u32)(instruction)) & 0xFFFF;
#define ENCODE_C(opcode, imm) ((((u32)(opcode) & 0xFF) << 24) | \
(((u32)(imm)) & 0xFFFFFF))
#define DECODE_C(instruction) \
u32 imm = ((u32)(instruction)) & 0xFFFFFF;
typedef enum {
OP_HALT, /* halt : A : all zeros : halt execution */
OP_CALL, /* call : A : dest args return : creates a new 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+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_PUSH, /* push : B : push u32 value onto the childs locals */
OP_POP, /* pop : C : pop u32 value off the stack (move MP back) */
OP_ADD_INT, /* add_int : A : locals[dest] = locals[src1] + locals[src2] */
OP_SUB_INT, /* sub_int : A : locals[dest] = locals[src1] - locals[src2] */
OP_MUL_INT, /* mul_int : A : locals[dest] = locals[src1] * locals[src2] */
OP_DIV_INT, /* div_int : A : locals[dest] = locals[src1] / locals[src2] */
OP_ADD_NAT, /* add_nat : A : locals[dest] = locals[src1] + locals[src2] */
OP_SUB_NAT, /* sub_nat : A : locals[dest] = locals[src1] - locals[src2] */
OP_MUL_NAT, /* mul_nat : A : locals[dest] = locals[src1] * locals[src2] */
OP_DIV_NAT, /* div_nat : A : locals[dest] = locals[src1] / locals[src2] */
OP_ADD_REAL, /* add_real : A : locals[dest] = locals[src1] + locals[src2] */
OP_SUB_REAL, /* sub_real : A : locals[dest] = locals[src1] - locals[src2] */
OP_MUL_REAL, /* mul_real : A : locals[dest] = locals[src1] * locals[src2] */
OP_DIV_REAL, /* div_real : A : locals[dest] = locals[src1] / locals[src2] */
OP_INT_TO_REAL, /* int_to_real : A : locals[dest] = locals[src1] as real */
OP_INT_TO_NAT, /* int_to_nat : A : locals[dest] = locals[src1] as nat */
OP_NAT_TO_REAL, /* nat_to_real : A : locals[dest] = locals[src1] as real */
OP_NAT_TO_INT, /* nat_to_int : A : locals[dest] = locals[src1] as int */
OP_REAL_TO_INT, /* real_to_int : A : locals[dest] = locals[src1] as int */
OP_REAL_TO_NAT, /* real_to_nat : A : locals[dest] = locals[src1] as nat */
OP_BIT_SHIFT_LEFT, /* bit_shift_left : A : locals[dest] = locals[src1] << locals[src2] */
OP_BIT_SHIFT_RIGHT,/* bit_shift_right : A : locals[dest] = locals[src1] >> locals[src2] */
OP_BIT_SHIFT_R_EXT,/* bit_shift_r_ext : A : locals[dest] as i32 = locals[src1] >> locals[src2] */
OP_BIT_AND, /* bit_and : A : locals[dest] = locals[src1] & locals[src2] */
OP_BIT_OR, /* bit_or : A : locals[dest] = locals[src1] | locals[src2] */
OP_BIT_XOR, /* bit_xor : A : locals[dest] = locals[src1] ^ locals[src2] */
OP_JMP_IMM, /* jump_immediate : C : jump to imm unconditionally */
OP_JMP_ABS, /* jump_absolute : A : jump to locals[dest] unconditionally */
OP_JMP_OFF, /* jump_offset : A : jump to locals[dest] + locals[src1] unconditionally */
OP_JMP_FLAG, /* jump_if_flag : A : jump to locals[dest] if flag > 0 */
OP_JEQ_INT, /* jump_eq_int : A : jump to locals[dest] if locals[src1] as int == locals[src2] as int */
OP_JNE_INT, /* jump_neq_int : A : jump to locals[dest] if locals[src1] as int != locals[src2] as int */
OP_JGT_INT, /* jump_gt_int : A : jump to locals[dest] if locals[src1] as int > locals[src2] as int */
OP_JLT_INT, /* jump_lt_int : A : jump to locals[dest] if locals[src1] as int < locals[src2] as int */
OP_JLE_INT, /* jump_le_int : A : jump to locals[dest] if locals[src1] as int <= locals[src2] as int */
OP_JGE_INT, /* jump_ge_int : A : jump to locals[dest] if locals[src1] as int >= locals[src2] as int */
OP_JEQ_NAT, /* jump_eq_nat : A : jump to locals[dest] if locals[src1] as nat == locals[src2] as nat */
OP_JNE_NAT, /* jump_neq_nat : A : jump to locals[dest] if locals[src1] as nat != locals[src2] as nat */
OP_JGT_NAT, /* jump_gt_nat : A : jump to locals[dest] if locals[src1] as nat > locals[src2] as nat */
OP_JLT_NAT, /* jump_lt_nat : A : jump to locals[dest] if locals[src1] as nat < locals[src2] as nat */
OP_JLE_NAT, /* jump_le_nat : A : jump to locals[dest] if locals[src1] as nat <= locals[src2] as nat */
OP_JGE_NAT, /* jump_ge_nat : A : jump to locals[dest] if locals[src1] as nat >= locals[src2] as nat */
OP_JEQ_REAL, /* jump_eq_real : A : jump to locals[dest] if locals[src1] as real == locals[src2] as real */
OP_JNE_REAL, /* jump_neq_real : A : jump to locals[dest] if locals[src1] as real != locals[src2] as real */
OP_JGE_REAL, /* jump_ge_real : A : jump to locals[dest] if locals[src1] as real >= locals[src2] as real */
OP_JGT_REAL, /* jump_gt_real : A : jump to locals[dest] if locals[src1] as real > locals[src2] as real */
OP_JLT_REAL, /* jump_lt_real : A : jump to locals[dest] if locals[src1] as real < locals[src2] as real */
OP_JLE_REAL, /* jump_le_real : A : jump to locals[dest] if locals[src1] as real <= locals[src2] as real */
OP_MAX_OPCODE /* not an opcode count of instructions */
} Opcode;
typedef enum {
SYSCALL_DBG_PRINT, /* temporary debugging print, use tunnel later */
SYSCALL_MAX
} Syscall;
extern u32 pc; /* program counter */
extern u32 cp; /* code pointer */
extern u32 mp; /* memory pointer */
extern u32 fp; /* frame pointer */
extern u8 sp; /* child local count */
extern u32 flag; /* flag */
extern u8 interrupt; /* device interrupt */
extern u32 *code; /* code */
extern u8 *mem; /* memory */
#define READ_U8(addr) (mem[addr])
#define READ_U16(addr) \
(((u16)mem[(addr) + 1] << 8) | ((u16)mem[(addr)]))
#define READ_U32(addr) \
(((u32)mem[(addr) + 3] << 24) | \
((u32)mem[(addr) + 2] << 16) | \
((u32)mem[(addr) + 1] << 8) | ((u32)mem[(addr)]))
#define WRITE_U8(addr, value) \
do { \
mem[addr] = (value) & 0xFF; \
} while (0)
#define WRITE_U16(addr, value) \
do { \
mem[addr] = (value) & 0xFF; \
mem[addr + 1] = ((value) >> 8) & 0xFF; \
} while (0)
#define WRITE_U32(addr, value) \
do { \
mem[addr] = (value) & 0xFF; \
mem[addr + 1] = ((value) >> 8) & 0xFF; \
mem[addr + 2] = ((value) >> 16) & 0xFF; \
mem[addr + 3] = ((value) >> 24) & 0xFF; \
} while (0)
#define MATH_OP(type, op) \
do { \
DECODE_A(instruction) \
u32 rd = fp + (dest * 4); \
u32 r1 = fp + (src1 * 4); \
u32 r2 = fp + (src2 * 4); \
type result = ((type)READ_U32(r1) op (type)READ_U32(r2)); \
mem[(rd)] = (result) & 0xFF; \
mem[(rd) + 1] = ((result) >> 8) & 0xFF; \
mem[(rd) + 2] = ((result) >> 16) & 0xFF; \
mem[(rd) + 3] = ((result) >> 24) & 0xFF; \
return true; \
} while (0)
#define MATH_OP_NO_CAST(op) \
do { \
DECODE_A(instruction) \
u32 rd = fp + (dest * 4); \
u32 r1 = fp + (src1 * 4); \
u32 r2 = fp + (src2 * 4); \
WRITE_U32(rd, (READ_U32(r1) op READ_U32(r2))); \
return true; \
} while (0)
#define COMPARE_AND_JUMP(type, op) \
do { \
DECODE_A(instruction) \
i32 cond; \
u32 mask, target; \
type value; \
type value2; \
u32 rd = fp + (dest * 4); \
u32 r1 = fp + (src1 * 4); \
u32 r2 = fp + (src2 * 4); \
target = READ_U32(rd); \
value = (type)READ_U32(r1); \
value2 = (type)READ_U32(r2); \
cond = !!(value op value2); \
mask = -(u32)cond; \
pc = (target & mask) | (pc & ~mask); \
return true; \
} while (0)
extern bool init_vm();
extern u32 syscall(u32 id, u32 args, u32 mem_ptr);
bool step_vm();
#endif