#ifndef ZRL_OPCODES_H #define ZRL_OPCODES_H #include "common.h" #include typedef enum { OP_HALT, /* halt : terminate execution */ OP_JMP, /* jump : jump to address dest unconditionally */ OP_GET_PC, /* pc : dest = current program counter */ OP_CALL, /* call : creates a new frame */ OP_RETURN, /* retn : returns from a frame to the parent frame */ OP_LOAD, /* load : dest = &[next memory location] */ OP_STORE, /* stor : next memory location = src1 as float */ OP_PUSH, /* push : push str ref from register onto the stack and copy str */ OP_POP, /* pop : pop int from stack onto the register */ OP_REG_MOV, /* rmov : dest = src1 */ OP_REG_SWAP, /* rswp : dest = src1, src1 = dest */ OP_GET_ACC, /* gacc : dest = accumulator */ OP_MEM_SWAP, /* mswp : &dest = &src1, &src1 = &dest */ OP_MEM_MOV, /* mmov : &dest = &src1 */ OP_MEM_ALLOC, /* aloc : dest [next memory location as size] */ OP_GET, /* get : dest = ptr : dest = memory[ptr] */ OP_PUT, /* put : ptr = src1 : memory[ptr] = src */ OP_OFFSET, /* offs : dest = ptr + src1 : dest = p + o */ OP_SYSCALL, /* sysc : */ OP_ADD_INT, /* addi : dest = src1 + src2 */ OP_SUB_INT, /* subi : dest = src1 - src2 */ OP_MUL_INT, /* muli : dest = src1 * src2 */ OP_DIV_INT, /* divi : dest = src1 / src2 */ OP_ADD_UINT, /* addu : dest = src1 + src2 */ OP_SUB_UINT, /* subu : dest = src1 - src2 */ OP_MUL_UINT, /* mulu : dest = src1 * src2 */ OP_DIV_UINT, /* divu : dest = src1 / src2 */ OP_ADD_REAL, /* addr : dest = src1 + src2 */ OP_SUB_REAL, /* subr : dest = src1 - src2 */ OP_MUL_REAL, /* mulr : dest = src1 * src2 */ OP_DIV_REAL, /* divr : dest = src1 / src2 */ OP_INT_TO_REAL, /* itor : dest = src1 as real */ OP_UINT_TO_REAL, /* utor : dest = src1 as real */ OP_REAL_TO_INT, /* rtoi : dest = src1 as int */ OP_REAL_TO_UINT, /* rtou : dest = src1 as uint */ OP_JEQ_INT, /* jeqi : jump to address dest if src1 as int == src2 as int */ OP_JGT_INT, /* jgti : jump to address dest if src1 as int > src2 as int*/ OP_JLT_INT, /* jlti : jump to address dest if src1 as int < src2 as int */ OP_JLE_INT, /* jlei : jump to address dest if src1 as int <= src2 as int */ OP_JGE_INT, /* jgei : jump to address dest if src1 as int >= src2 as int*/ OP_JEQ_UINT, /* jequ : jump to address dest if src1 as int == src2 as uint */ OP_JGT_UINT, /* jgtu : jump to address dest if src1 as int > src2 as uint*/ OP_JLT_UINT, /* jltu : jump to address dest if src1 as int < src2 as uint */ OP_JLE_UINT, /* jleu : jump to address dest if src1 as int <= src2 as uint */ OP_JGE_UINT, /* jgeu : jump to address dest if src1 as int >= src2 as uint*/ OP_JEQ_REAL, /* jeqr : jump to address dest if src1 as real == src2 as real */ OP_JGE_REAL, /* jgtr : jump to address dest if src1 as real >= src2 as real */ OP_JGT_REAL, /* jltr : jump to address dest if src1 as real > src2 as real */ OP_JLT_REAL, /* jler : jump to address dest if src1 as real < src2 as real */ OP_JLE_REAL, /* jger : jump to address dest if src1 as real <= src2 as real */ OP_INT_TO_STRING, /* itos : dest = src1 as str */ OP_UINT_TO_STRING, /* utos : dest = src1 as str */ OP_REAL_TO_STRING, /* rtos : dest = src1 as str */ OP_CMP_STRING, /* cmps : dest = (str == src2) as bool */ OP_STRING_TO_INT, /* stoi : dest = src1 as int */ OP_STRING_TO_UINT, /* stou : dest = src1 as uint */ OP_STRING_TO_REAL, /* stor : dest = src1 as real */ /* to remove (replace with device), just for testing for now */ OP_DBG_PRINT_STRING, OP_DBG_READ_STRING, } Opcode; /* defines a uint32 opcode */ #define OP(opcode, dest, src1, src2) \ ((opcode << 24) | (dest << 16) | (src1 << 8) | src2) #define OP_SYSCALL_OPCODE(syscall_id, arg_count, src) \ ((OP_SYSCALL << 24) | ((syscall_id & 0xFF) << 16) | (arg_count & 0xFF) | src) typedef union value_u { int32_t i; /* Integers */ float f; /* Float */ uint32_t u; /* Unsigned integers, also used for pointer address */ char c[4]; /* 4 Byte char array for string packing */ } Value; typedef struct slice_s { uint32_t start; uint32_t end; } Slice; #define MAX_REGS 32 typedef struct frame_s { Value registers[MAX_REGS]; /* R0-R31 */ uint32_t rp; /* register pointer (last unused) */ Slice allocated; /* start and end of global allocated block */ } Frame; typedef enum { SYSCALL_EXIT = 0, SYSCALL_DEVICE_OPEN, SYSCALL_DEVICE_READ, SYSCALL_DEVICE_WRITE, SYSCALL_DEVICE_CLOSE, SYSCALL_DEVICE_IOCTL, } SyscallID; typedef struct device_ops_s { int (*open)(void *device_data, uint32_t mode); int (*read)(void *device_data, uint8_t *buffer, uint32_t size); int (*write)(void *device_data, const uint8_t *buffer, uint32_t size); int (*close)(void *device_data); int (*ioctl)(void *device_data, uint32_t cmd, void *args); /* optional control */ } DeviceOps; #define DEVICE_TYPE_MAX_LENGTH 24 /* 23 chars + null terminator */ #define DEVICE_PATH_MAX_LENGTH 64 /* 63 chars + null terminator */ typedef struct device_s { char type[DEVICE_TYPE_MAX_LENGTH]; /* e.g., "screen", "mouse", "gpio" */ char path[DEVICE_PATH_MAX_LENGTH]; /* "/dev/screen", "/dev/input/mouse/0", etc. */ void *data; /* device-specific data */ DeviceOps *ops; /* operations vtable */ uint32_t flags; /* permissions, status, etc. */ } Device; #define MEMORY_SIZE (640 * 480 + 65536) #define CODE_SIZE 8192 #define FRAMES_SIZE 128 #define STACK_SIZE 256 #define DEVICES_SIZE 8 typedef struct vm_s { uint32_t pc; /* program counter */ uint32_t cp; /* code pointer (last allocated opcode) */ uint32_t fp; /* frame pointer (current frame) */ uint32_t sp; /* stack pointer (top of stack) */ uint32_t rp; /* return stack pointer (top of stack) */ uint32_t mp; /* memory pointer (last allocated value) */ uint32_t dc; /* device count */ uint32_t acc; /* accumulator (temporary results like SYSCALL status) */ Device devices[DEVICES_SIZE]; /* device definitions */ Frame frames[FRAMES_SIZE]; /* function call frames */ Value stack[STACK_SIZE]; /* main stack */ Value return_stack[STACK_SIZE]; /* return stack (for call recursion) */ Value code[CODE_SIZE]; /* code block */ Value memory[MEMORY_SIZE]; /* memory block */ } VM; #endif