159 lines
7.6 KiB
C
159 lines
7.6 KiB
C
#ifndef ZRE_OPCODES_H
|
|
#define ZRE_OPCODES_H
|
|
|
|
#include "common.h"
|
|
|
|
typedef enum {
|
|
OP_HALT, /* halt : terminate execution */
|
|
OP_JMP, /* jump : jump to address dest unconditionally */
|
|
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_LOAD_IMM, /* 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_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_STRLEN, /* strl : dest = length of str at src1 ptr */
|
|
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_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 */
|
|
} Opcode;
|
|
|
|
#define MAX_REGS 32
|
|
typedef struct frame_s {
|
|
u32 registers[MAX_REGS]; /* R0-R31 */
|
|
u32 rp; /* register pointer (last unused) */
|
|
u32 start; /* start and end of global allocated block */
|
|
u32 end;
|
|
} 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 {
|
|
i32 (*open)(void *device_data, u32 mode);
|
|
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, 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 */
|
|
u32 flags; /* permissions, status, etc. */
|
|
} Device;
|
|
|
|
#define MEMORY_SIZE 1024 /*(640 * 480 + 65536)*/
|
|
#define CODE_SIZE 128 /*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 rp; /* return stack pointer (top of stack) */
|
|
u32 mp; /* memory pointer (last allocated value) */
|
|
u32 dc; /* device count */
|
|
u32 acc; /* accumulator (temporary results like SYSCALL status) */
|
|
Frame frames[FRAMES_SIZE]; /* function call frames */
|
|
u32 stack[STACK_SIZE]; /* main stack */
|
|
u32 return_stack[STACK_SIZE]; /* return stack (for call recursion) */
|
|
Device devices[DEVICES_SIZE]; /* device definitions */
|
|
u8 code[CODE_SIZE]; /* code block */
|
|
u8 memory[MEMORY_SIZE]; /* memory block */
|
|
} VM;
|
|
|
|
#define AS_INT(v) ((i32)(v))
|
|
#define AS_UINT(v) ((u32)(v))
|
|
#define AS_FIXED(v) ((float)(i32)(v) / 65536.0f)
|
|
#define TO_FIXED(f) ((u32)((i32)( \
|
|
((f) >= 0.0f) ? ((f) * 65536.0f + 0.5f) : ((f) * 65536.0f - 0.5f) \
|
|
)))
|
|
|
|
#define read_u8(vm, location, addr) ((vm)->location[addr])
|
|
#define read_u16(vm, location, addr) \
|
|
(((uint16_t)(vm)->location[(addr)] << 8) | \
|
|
((uint16_t)(vm)->location[(addr) + 1]))
|
|
#define read_u32(vm, location, addr) \
|
|
(((u32)(vm)->location[(addr)] << 24) | \
|
|
((u32)(vm)->location[(addr) + 1] << 16) | \
|
|
((u32)(vm)->location[(addr) + 2] << 8) | ((u32)(vm)->location[(addr) + 3]))
|
|
|
|
#define write_u8(vm, location, addr, value) \
|
|
do { \
|
|
if ((addr) < sizeof((vm)->location)) { \
|
|
(vm)->location[(addr)] = (value); \
|
|
} \
|
|
} while (0)
|
|
|
|
#define write_u16(vm, location, addr, value) \
|
|
do { \
|
|
if ((addr) + 1 < sizeof((vm)->location)) { \
|
|
(vm)->location[(addr)] = ((value) >> 8) & 0xFF; \
|
|
(vm)->location[(addr) + 1] = (value) & 0xFF; \
|
|
} \
|
|
} while (0)
|
|
|
|
#define write_u32(vm, location, addr, value) \
|
|
do { \
|
|
if ((addr) + 3 < sizeof((vm)->location)) { \
|
|
(vm)->location[(addr)] = ((value) >> 24) & 0xFF; \
|
|
(vm)->location[(addr) + 1] = ((value) >> 16) & 0xFF; \
|
|
(vm)->location[(addr) + 2] = ((value) >> 8) & 0xFF; \
|
|
(vm)->location[(addr) + 3] = (value) & 0xFF; \
|
|
} \
|
|
} while (0)
|
|
|
|
#endif
|