#ifndef ZRE_OPCODES_H #define ZRE_OPCODES_H #include "common.h" typedef enum { OP_HALT, /* halt : terminate execution with code [src1] */ OP_CALL, /* call : creates a new frame */ OP_RETURN, /* return : returns from a frame to the parent frame */ OP_SYSCALL, /* syscall : src1 src2 src3 src4 more? does a system call based on args */ OP_LOAD_IMM, /* load-immediate : registers[dest] = constant */ OP_LOAD_IND_8, /* load-indirect-8 : registers[dest] = memory[registers[src1]] as u8 */ OP_LOAD_IND_16, /* load-indirect-16 : registers[dest] = memory[registers[src1]] as u8 */ OP_LOAD_IND_32, /* load-indirect-32 : registers[dest] = memory[registers[src1]] as u32 */ OP_LOAD_ABS_8, /* load-absolute-8 : registers[dest] = memory[src1 as u32] */ OP_LOAD_ABS_16, /* load-absolute-16 : registers[dest] = memory[src1 as u32] */ OP_LOAD_ABS_32, /* load-absolute-32 : registers[dest] = memory[src1 as u32] */ OP_LOAD_OFF_8, /* load-offset-8 : registers[dest] = memory[registers[src1] + offset] as u8 */ OP_LOAD_OFF_16, /* load-offset-16 : registers[dest] = memory[registers[src1] + offset] as u16 */ OP_LOAD_OFF_32, /* load-offset-32 : registers[dest] = memory[registers[src1] + offset] as u32 */ OP_STORE_ABS_8, /* store-absolute-8 : memory[dest] = src1 && 0xFF */ OP_STORE_ABS_16, /* store-absolute-16 : memory[dest] = src1 && 0xFFFF */ OP_STORE_ABS_32, /* store-absolute-32 : memory[dest] = src1 */ OP_STORE_IND_8, /* store-indirect-8 : memory[dest] = registers[src1] && 0xFF */ OP_STORE_IND_16, /* store-indirect-16 : memory[dest] = registers[src1] && 0xFFFF*/ OP_STORE_IND_32, /* store-indirect-32 : memory[dest] = registers[src1] */ OP_STORE_OFF_8, /* store-offset-8 : memory[registers[dest] + offset] = registers[src1] && 0xFF */ OP_STORE_OFF_16, /* store-offset-16 : memory[registers[dest] + offset] = registers[src1] && 0xFFFF */ OP_STORE_OFF_32, /* store-offset-32 : memory[registers[dest] + offset] = registers[src1] */ OP_MALLOC, /* malloc : dest = fat ptr to memory of ((src1 as size) + 4) */ OP_MEMSET_8, /* memset-8 : dest <-> dest+count = src1 as u8 */ OP_MEMSET_16, /* memset-16 : dest <-> dest+count = src1 as u8 */ OP_MEMSET_32, /* memset-32 : dest <-> dest+count = src1 as u32 */ OP_REG_MOV, /* register-move : dest = src1 */ OP_ADD_INT, /* add-int : registers[dest] = registers[src1] + registers[src2] */ OP_SUB_INT, /* sub-int : registers[dest] = registers[src1] - registers[src2] */ OP_MUL_INT, /* mul-int : registers[dest] = registers[src1] * registers[src2] */ OP_DIV_INT, /* div-int : registers[dest] = registers[src1] / registers[src2] */ OP_ADD_NAT, /* add-nat : registers[dest] = registers[src1] + registers[src2] */ OP_SUB_NAT, /* sub-nat : registers[dest] = registers[src1] - registers[src2] */ OP_MUL_NAT, /* mul-nat : registers[dest] = registers[src1] * registers[src2] */ OP_DIV_NAT, /* div-nat : registers[dest] = registers[src1] / registers[src2] */ OP_ADD_REAL, /* add-real : registers[dest] = registers[src1] + registers[src2] */ OP_SUB_REAL, /* sub-real : registers[dest] = registers[src1] - registers[src2] */ OP_MUL_REAL, /* mul-real : registers[dest] = registers[src1] * registers[src2] */ OP_DIV_REAL, /* div-real : registers[dest] = registers[src1] / registers[src2] */ OP_INT_TO_REAL, /* int-to-real : registers[dest] = registers[src1] as real */ OP_NAT_TO_REAL, /* nat-to-real : registers[dest] = registers[src1] as real */ OP_REAL_TO_INT, /* real-to-int : registers[dest] = registers[src1] as int */ OP_REAL_TO_NAT, /* real-to-nat : registers[dest] = registers[src1] as nat */ OP_SLL, /* bit-shift-left : registers[dest] = registers[src1] << registers[src2] */ OP_SRL, /* bit-shift-right : registers[dest] = registers[src1] >> registers[src2] */ OP_SRE, /* bit-shift-re : registers[dest] as i32 = registers[src1] >> registers[src2] */ OP_BAND, /* bit-and : registers[dest] = registers[src1] & registers[src2] */ OP_BOR, /* bit-or : registers[dest] = registers[src1] | registers[src2] */ OP_BXOR, /* bit-xor : registers[dest] = registers[src1] ^ registers[src2] */ OP_JMP, /* jump : jump to address dest unconditionally */ OP_JMPF, /* jump-if-flag : jump to address dest if flag is ne 0 */ OP_JEQ_INT, /* jump-eq-int : jump to address dest if registers[src1] as int == registers[src2] as int */ OP_JNEQ_INT, /* jump-neq-int : jump to address dest if registers[src1] as int != registers[src2] as int */ OP_JGT_INT, /* jump-gt-int : jump to address dest if registers[src1] as int > registers[src2] as int */ OP_JLT_INT, /* jump-lt-int : jump to address dest if registers[src1] as int < registers[src2] as int */ OP_JLE_INT, /* jump-le-int : jump to address dest if registers[src1] as int <= registers[src2] as int */ OP_JGE_INT, /* jump-ge-int : jump to address dest if registers[src1] as int >= registers[src2] as int */ OP_JEQ_NAT, /* jump-eq-nat : jump to address dest if registers[src1] as nat == registers[src2] as nat */ OP_JNEQ_NAT, /* jump-neq-nat : jump to address dest if registers[src1] as nat != registers[src2] as nat */ OP_JGT_NAT, /* jump-gt-nat : jump to address dest if registers[src1] as nat > registers[src2] as nat */ OP_JLT_NAT, /* jump-lt-nat : jump to address dest if registers[src1] as nat < registers[src2] as nat */ OP_JLE_NAT, /* jump-le-nat : jump to address dest if registers[src1] as nat <= registers[src2] as nat */ OP_JGE_NAT, /* jump-ge-nat : jump to address dest if registers[src1] as nat >= registers[src2] as nat */ OP_JEQ_REAL, /* jump-eq-real : jump to address dest if registers[src1] as real == registers[src2] as real */ OP_JNEQ_REAL, /* jump-neq-real : jump to address dest if registers[src1] as real != registers[src2] as real */ OP_JGE_REAL, /* jump-ge-real : jump to address dest if registers[src1] as real >= registers[src2] as real */ OP_JGT_REAL, /* jump-gt-real : jump to address dest if registers[src1] as real > registers[src2] as real */ OP_JLT_REAL, /* jump-lt-real : jump to address dest if registers[src1] as real < registers[src2] as real */ OP_JLE_REAL, /* jump-le-real : jump to address dest if registers[src1] as real <= registers[src2] as real */ OP_STRLEN, /* string-length : registers[dest] = length of str at src1 ptr */ OP_STREQ, /* string-eq : registers[dest] = src1 ptr string == src2 ptr string */ OP_STRCAT, /* string-concat : registers[dest] = ptr of src1 ptr string + src2 ptr string */ OP_STR_GET_CHAR, /* string-get-char : registers[dest] = ptr of src1 ptr str, src2 index of str */ OP_STR_FIND_CHAR, /* string-find-char : registers[dest] = ptr of src1 ptr string, src2 nat8 char */ OP_STR_SLICE, /* string-slice : registers[dest] = ptr of src1 ptr str, src2 start index, src3 end index */ OP_INT_TO_STRING, /* int-to-string : registers[dest] = src1 as str */ OP_NAT_TO_STRING, /* nat-to-string : registers[dest] = src1 as str */ OP_REAL_TO_STRING, /* real-to-string : registers[dest] = src1 as str */ OP_STRING_TO_INT, /* string-to-int : registers[dest] = src1 as int */ OP_STRING_TO_NAT, /* string-to-nat : registers[dest] = src1 as nat */ OP_STRING_TO_REAL /* string-to-real : registers[dest] = src1 as real */ } Opcode; #define MAX_REGS 32 typedef struct frame_s { u32 registers[MAX_REGS]; /* R0-R31 */ u32 start; /* start of memory block */ u32 end; /* end of memory block */ u32 return_reg; /* register to store return value in parent */ u32 heap_mask; /* bitfield: 1 bit per register (R0=bit0, R1=bit1, etc) */ } Frame; typedef enum { SYSCALL_EXIT = 0, SYSCALL_DEVICE_OPEN, SYSCALL_DEVICE_READ, SYSCALL_DEVICE_WRITE, SYSCALL_DEVICE_CLOSE, SYSCALL_DEVICE_IOCTL, SYSCALL_DEVICE_REFRESH } SyscallID; typedef struct device_ops_s { i32 (*open)(void *device_data, u32 mode, u32 handle, u8 *buffer, u32 size); i32 (*read)(void *device_data, u8 *buffer, u32 size); i32 (*write)(void *device_data, const u8 *buffer, u32 size); i32 (*close)(void *device_data); i32 (*ioctl)(void *device_data, u32 cmd, const u8 *buffer); /* optional control */ i32 (*refresh)(void *device_data, u8 *buffer); } DeviceOps; #define DEVICE_TYPE_MAX_LENGTH 16 /* 15 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 */ u32 flags; /* permissions, status, etc. */ u32 handle; /* id for fast access in VM */ u32 size; /* id for fast access in VM */ } 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 { u32 pc; /* program counter */ u32 cp; /* code pointer (last allocated opcode) */ u32 fp; /* frame pointer (current frame) */ u32 sp; /* stack pointer (top of stack) */ u32 mp; /* memory pointer (last allocated value) */ u32 dc; /* device count */ i32 flag; /* flag (temporary results like SYSCALL status) */ Frame frames[FRAMES_SIZE]; /* function call frames */ u32 stack[STACK_SIZE]; /* main stack */ Device devices[DEVICES_SIZE]; /* device definitions */ u8 code[CODE_SIZE]; /* code block */ u8 memory[MEMORY_SIZE]; /* memory block */ } VM; #define read_u8(vm, location, addr) ((vm)->location[addr]) #define read_u16(vm, location, addr) \ (((u16)(vm)->location[(addr) + 1] << 8) | ((u16)(vm)->location[(addr)])) #define read_u32(vm, location, addr) \ (((u32)(vm)->location[(addr) + 3] << 24) | \ ((u32)(vm)->location[(addr) + 2] << 16) | \ ((u32)(vm)->location[(addr) + 1] << 8) | ((u32)(vm)->location[(addr)])) #define write_u8(vm, location, addr, value) \ do { \ if ((addr) < sizeof((vm)->location)) { \ (vm)->location[(addr)] = (value) & 0xFF; \ } \ } while (0) #define write_u16(vm, location, addr, value) \ do { \ if ((addr) + 1 < sizeof((vm)->location)) { \ (vm)->location[(addr)] = (value) & 0xFF; \ (vm)->location[(addr) + 1] = ((value) >> 8) & 0xFF; \ } \ } while (0) #define write_u32(vm, location, addr, value) \ do { \ if ((addr) + 3 < sizeof((vm)->location)) { \ (vm)->location[(addr)] = (value) & 0xFF; \ (vm)->location[(addr) + 1] = ((value) >> 8) & 0xFF; \ (vm)->location[(addr) + 2] = ((value) >> 16) & 0xFF; \ (vm)->location[(addr) + 3] = ((value) >> 24) & 0xFF; \ } \ } while (0) #endif