190 lines
12 KiB
C
190 lines
12 KiB
C
#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
|