undar-lang/src/vm/opcodes.h

178 lines
11 KiB
C

#ifndef ZRE_OPCODES_H
#define ZRE_OPCODES_H
#include "common.h"
typedef enum {
OP_HALT, /* [obj1 `halt` - | terminate execution with code ] */
OP_JMP, /* [dest `jump` - | jump to address dest unconditionally ] */
OP_JMPF, /* [dest `jump-if-flag` - | jump to address dest if flag is ne 0 ] */
OP_CALL, /* [&code_ref `call` - | creates a new frame ] */
OP_RETURN, /* [obj1 `return` - | returns from a frame to the parent frame, pushes obj1 on stack ] */
OP_LOAD_8, /* [&dest `load-8` u8 | push memory[obj1] onto stack as u8 ] */
OP_LOAD_16, /* [&dest `load-16` u16 | push memory[obj1] onto stack as u16 ] */
OP_LOAD_32, /* [&dest `load` u32 | push memory[obj1] onto stack as u32 ] */
OP_STORE_8, /* [&dest obj1 `store-8` - | memory[dest] = obj1 << 8 ] */
OP_STORE_16, /* [&dest obj1 `store-16`- | memory[dest] = obj1 << 16 ] */
OP_STORE_32, /* [&dest obj1 `store` - | memory[dest] = obj1 ] */
OP_MALLOC, /* [size `malloc` ptr | allocate 'size + 4' of memory and push ptr to memory on stack ] */
OP_MEMSET_8, /* [ `memset-8` | dest <-> dest+count = obj1 as u8 ] */
OP_MEMSET_16, /* [ `memset-16` | dest <-> dest+count = obj1 as u8 ] */
OP_MEMSET_32, /* [ `memset-32` | dest <-> dest+count = obj1 as u32 ] */
OP_PUSH, /* [ `push` | push const of ref ] */
OP_POP, /* [ `pop` | pop cosnt or ref ] */
OP_DUP, /* [ obj1 `dup` obj1 obj1 | ] */
OP_EXCH, /* [ obj1 obj2 `exch` obj2 obj1 | ] */
OP_OVER, /* [ obj1 obj2 `over` obj1 obj2 obj1 | ] */
OP_PICK, /* [ N `pick` objN | ] */
OP_ROT, /* [ obj1 obj2 obj3 `rot` obj2 obj3 obj1 | ] */
OP_DEPTH, /* [ - `depth` stack_size | ] */
OP_SYSCALL, /* [ `syscall` | obj1 obj2 obj3 obj4 more? does a system call based on args ] */
OP_SLL, /* [ `bit-shift-left` | dest = obj1 << obj2 ] */
OP_SRL, /* [ `bit-shift-right` | dest = obj1 >> obj2 ] */
OP_SRE, /* [ `bit-shift-re` | dest as i32 = obj1 >> obj2 ] */
OP_BAND, /* [ `bit-and` | dest = obj1 & obj2 ] */
OP_BOR, /* [ `bit-or` | dest = obj1 | obj2 ] */
OP_BXOR, /* [ `bit-xor` | dest = obj1 ^ obj2 ] */
OP_ADD_INT, /* [ `add-int` | dest = obj1 + obj2 ] */
OP_SUB_INT, /* [ `sub-int` | dest = obj1 - obj2 ] */
OP_MUL_INT, /* [ `mul-int` | dest = obj1 * obj2 ] */
OP_DIV_INT, /* [ `div-int` | dest = obj1 / obj2 ] */
OP_ADD_UINT, /* [ `add-nat` | dest = obj1 + obj2 ] */
OP_SUB_UINT, /* [ `sub-nat` | dest = obj1 - obj2 ] */
OP_MUL_UINT, /* [ `mul-nat` | dest = obj1 * obj2 ] */
OP_DIV_UINT, /* [ `div-nat` | dest = obj1 / obj2 ] */
OP_ADD_REAL, /* [ `add-real` | dest = obj1 + obj2 ] */
OP_SUB_REAL, /* [ `sub-real` | dest = obj1 - obj2 ] */
OP_MUL_REAL, /* [ `mul-real` | dest = obj1 * obj2 ] */
OP_DIV_REAL, /* [ `div-real` | dest = obj1 / obj2 ] */
OP_INT_TO_REAL, /* [ `int-to-real` | dest = obj1 as real ] */
OP_UINT_TO_REAL, /* [ `nat-to-real` | dest = obj1 as real ] */
OP_REAL_TO_INT, /* [ `real-to-int` | dest = obj1 as int ] */
OP_REAL_TO_UINT, /* [ `real-to-nat` | dest = obj1 as uint ] */
OP_JEQ_INT, /* [ `jump-eq-int` | jump to address dest if obj1 as int == obj2 as int ] */
OP_JNEQ_INT, /* [ `jump-neq-int` | jump to address dest if obj1 as int != obj2 as int ] */
OP_JGT_INT, /* [ `jump-gt-int` | jump to address dest if obj1 as int > obj2 as int ] */
OP_JLT_INT, /* [ `jump-lt-int` | jump to address dest if obj1 as int < obj2 as int ] */
OP_JLE_INT, /* [ `jump-le-int` | jump to address dest if obj1 as int <= obj2 as int ] */
OP_JGE_INT, /* [ `jump-ge-int` | jump to address dest if obj1 as int >= obj2 as int ] */
OP_JEQ_UINT, /* [ `jump-eq-nat` | jump to address dest if obj1 as uint == obj2 as uint ] */
OP_JNEQ_UINT, /* [ `jump-neq-nat` | jump to address dest if obj1 as uint != obj2 as uint ] */
OP_JGT_UINT, /* [ `jump-gt-nat` | jump to address dest if obj1 as uint > obj2 as uint ] */
OP_JLT_UINT, /* [ `jump-lt-nat` | jump to address dest if obj1 as uint < obj2 as uint ] */
OP_JLE_UINT, /* [ `jump-le-nat` | jump to address dest if obj1 as uint <= obj2 as uint ] */
OP_JGE_UINT, /* [ `jump-ge-nat` | jump to address dest if obj1 as uint >= obj2 as uint ] */
OP_JEQ_REAL, /* [ `jump-eq-real` | jump to address dest if obj1 as real == obj2 as real ] */
OP_JNEQ_REAL, /* [ `jump-neq-real` | jump to address dest if obj1 as real != obj2 as real ] */
OP_JGE_REAL, /* [ `jump-ge-real` | jump to address dest if obj1 as real >= obj2 as real ] */
OP_JGT_REAL, /* [ `jump-gt-real` | jump to address dest if obj1 as real > obj2 as real ] */
OP_JLT_REAL, /* [ `jump-lt-real` | jump to address dest if obj1 as real < obj2 as real ] */
OP_JLE_REAL, /* [ `jump-le-real` | jump to address dest if obj1 as real <= obj2 as real ] */
OP_STRLEN, /* [&str `string-length` len &str | length of string from str ptr ] */
OP_STREQ, /* [ `string-eq` | dest = obj1 ptr string == obj2 ptr string ] */
OP_STRCAT, /* [ `string-concat` | dest = ptr of obj1 ptr string + obj2 ptr string ] */
OP_STR_GET_CHAR, /* [ `string-get-char` | dest = ptr of obj1 ptr str, obj2 index of str ] */
OP_STR_FIND_CHAR, /* [ `string-find-char` | dest = ptr of obj1 ptr string, obj2 uint8 char ] */
OP_STR_SLICE, /* [ `string-slice` | dest = ptr of obj1 ptr str, obj2 start index, obj3 end index ] */
OP_INT_TO_STRING, /* [ `int-to-string` | dest = obj1 as str ] */
OP_UINT_TO_STRING, /* [ `nat-to-string` | dest = obj1 as str ] */
OP_REAL_TO_STRING, /* [ `real-to-string` | dest = obj1 as str ] */
OP_STRING_TO_INT, /* [ `string-to-int` | dest = obj1 as int ] */
OP_STRING_TO_UINT, /* [ `string-to-nat` | dest = obj1 as uint ] */
OP_STRING_TO_REAL /* [ `string-to-real` | dest = obj1 as real ] */
} Opcode;
typedef struct frame_s {
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,
const u8 *buffer); /* 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 (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 rp; /* return 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 */
u32 return_stack[FRAMES_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 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