151 lines
9.0 KiB
C
151 lines
9.0 KiB
C
#ifndef UNDAR_VM_H
|
|
#define UNDAR_VM_H
|
|
|
|
#include "libc.h"
|
|
|
|
typedef enum {
|
|
OP_HALT, /* - `halt` | halt execution */
|
|
OP_CALL, /* ptr `call` - | creates a new frame */
|
|
OP_RETURN, /* - `return` - | returns from a frame to the parent frame */
|
|
OP_SYSCALL, /* id mem_ptr `syscall` - | does a system call based on id with args */
|
|
OP_LOAD_8, /* dest `ld8` u8 | push memory[obj1] onto stack as u8 */
|
|
OP_LOAD_16, /* dest `ld16` u16 | push memory[obj1] onto stack as u16 */
|
|
OP_LOAD_32, /* dest `ld32` u32 | push memory[obj1] onto stack as u32 */
|
|
OP_STORE_8, /* dest obj1 `st8` - | memory[dest] = obj1 << 8 */
|
|
OP_STORE_16, /* dest obj1 `st16` - | memory[dest] = obj1 << 16 */
|
|
OP_STORE_32, /* dest obj1 `st32` - | memory[dest] = obj1 */
|
|
OP_MALLOC, /* size `alloc` ptr | allocate 'size + 4' of memory and push ptr to memory on stack */
|
|
OP_PUSH_8, /* const `push8` obj1 | push a 8 bit const onto the stack */
|
|
OP_PUSH_16, /* const `push16` obj1 | push a 16 bit const onto the stack */
|
|
OP_PUSH_32, /* const `push32` obj1 | push a 32 bit const onto the stack */
|
|
OP_POP, /* - `pop` - | removes top item from the stack */
|
|
OP_DUP, /* obj1 `dup` obj1 obj1 | duplicates the top of the stack */
|
|
OP_EXCH, /* obj2 obj1 `exch` obj1 obj2 | swaps the top two values on the stack */
|
|
OP_OVER, /* obj2 obj1 `over` obj2 | copys the 2nd to the top element and pushes to the stack */
|
|
OP_PICK, /* N `pick` objN | gets the nth element on the stack and pushes it on top */
|
|
OP_DEPTH, /* - `depth` stack_count | pushes the number of elements on the stack to the stack */
|
|
OP_MEM_ALLOC, /* size `alloc` ptr | allocate 'size + 4' of memory and push ptr to memory on stack */
|
|
OP_MEM_CPY_8, /* size src dest `mcpy8` - | memory[src..src+size] = memory[dest..dest+size] */
|
|
OP_MEM_CPY_16, /* size src dest `mcpy16` - | memory[src..src+size] = memory[dest..dest+size] */
|
|
OP_MEM_CPY_32, /* size src dest `mcpy32` - | memory[src..src+size] = memory[dest..dest+size] */
|
|
OP_MEM_SET_8, /* size src dest `mset8` - | memory[dest..dest+size] = local[src] as u8 */
|
|
OP_MEM_SET_16, /* size src dest `mset16` - | memory[dest..dest+size] = local[src] as u16 */
|
|
OP_MEM_SET_32, /* size src dest `mset32` - | memory[dest..dest+size] = local[src] as u32 */
|
|
OP_ADD_INT, /* obj2 obj1 `addi` obj | obj1 + obj2 then push result on stack */
|
|
OP_SUB_INT, /* obj2 obj1 `subi` obj | obj1 - obj2 then push result on stack */
|
|
OP_MUL_INT, /* obj2 obj1 `muli` obj | obj1 * obj2 then push result on stack */
|
|
OP_DIV_INT, /* obj2 obj1 `divi` obj | obj1 / obj2 then push result on stack */
|
|
OP_ADD_NAT, /* obj2 obj1 `addn` obj | obj1 + obj2 then push result on stack */
|
|
OP_SUB_NAT, /* obj2 obj1 `subn` obj | obj1 - obj2 then push result on stack */
|
|
OP_MUL_NAT, /* obj2 obj1 `muln` obj | obj1 * obj2 then push result on stack */
|
|
OP_DIV_NAT, /* obj2 obj1 `divn` obj | obj1 / obj2 then push result on stack */
|
|
OP_ADD_REAL, /* obj2 obj1 `addr` obj | obj1 + obj2 then push result on stack */
|
|
OP_SUB_REAL, /* obj2 obj1 `subr` obj | obj1 - obj2 then push result on stack */
|
|
OP_MUL_REAL, /* obj2 obj1 `mulr` obj | obj1 * obj2 then push result on stack */
|
|
OP_DIV_REAL, /* obj2 obj1 `divr` obj | obj1 / obj2 then push result on stack */
|
|
OP_INT_TO_REAL, /* obj1 `itor` real | casts an int to a fixed number */
|
|
OP_INT_TO_NAT, /* obj1 `iton` nat | casts an int to a unsigned int */
|
|
OP_NAT_TO_REAL, /* obj1 `ntor` real | casts a unsigned int to a fixed number */
|
|
OP_NAT_TO_INT, /* obj1 `ntoi` int | casts a unsigned int to an int */
|
|
OP_REAL_TO_INT, /* obj1 `rtoi` int | casts a fixed number to an int */
|
|
OP_REAL_TO_NAT, /* obj1 `rton` nat | casts a fixed number to an unsigned int */
|
|
OP_BIT_SHIFT_LEFT, /* obj2 obj1 `sll` obj | src1] << locals[src2] */
|
|
OP_BIT_SHIFT_RIGHT, /* obj2 obj1 `srl` obj | src1] >> locals[src2] */
|
|
OP_BIT_SHIFT_R_EXT, /* obj2 obj1 `sre` obj | src1 >> src2 then cast result as i32 */
|
|
OP_BIT_AND, /* obj2 obj1 `band` obj | obj1 & obj2 */
|
|
OP_BIT_OR, /* obj2 obj1 `bor` obj | obj1 | obj2 */
|
|
OP_BIT_XOR, /* obj2 obj1 `bxor` obj | obj1 ^ obj2 */
|
|
OP_NEG, /* obj1 `neg` obj | -obj1 */
|
|
OP_NOT, /* obj1 `not` obj | not obj1 */
|
|
OP_JMP, /* pc `jump` | jump unconditionally */
|
|
OP_JMP_FLAG, /* pc `jmpf` | jump to pc if flag > 0 */
|
|
OP_JNZ, /* obj1 pc `jnz` | jump to pc if obj1 != 0 */
|
|
OP_EQU, /* obj2 obj1 `equ` bool | unsigned obj1 == obj2 */
|
|
OP_NEU, /* obj2 obj1 `neu` bool | unsigned obj1 != obj2 */
|
|
OP_GTU, /* obj2 obj1 `gtu` bool | unsigned obj1 > obj2 */
|
|
OP_LTU, /* obj2 obj1 `ltu` bool | unsigned obj1 < obj2 */
|
|
OP_LEU, /* obj2 obj1 `leu` bool | unsigned obj1 <= obj2 */
|
|
OP_GEU, /* obj2 obj1 `geu` bool | unsigned obj1 >= obj2 */
|
|
OP_EQS, /* obj2 obj1 `eqs` bool | signed obj1 == obj2 */
|
|
OP_NES, /* obj2 obj1 `nes` bool | signed obj1 != obj2 */
|
|
OP_GTS, /* obj2 obj1 `gts` bool | signed obj1 > obj2 */
|
|
OP_LTS, /* obj2 obj1 `lts` bool | signed obj1 < obj2 */
|
|
OP_LES, /* obj2 obj1 `les` bool | signed obj1 <= obj2 */
|
|
OP_GES, /* obj2 obj1 `ges` bool | signed obj1 >= obj2 */
|
|
OP_INT_TO_STR, /* obj1 `itos` str_ptr | convert obj1 to str */
|
|
OP_NAT_TO_STR, /* obj1 `ntos` str_ptr | convert obj1 to str */
|
|
OP_REAL_TO_STR, /* obj1 `rtos` str_ptr | convert obj1 to str */
|
|
OP_STR_TO_INT, /* str_ptr `stoi` obj | convert obj1 to int */
|
|
OP_STR_TO_NAT, /* str_ptr `ntoi` obj | convert obj1 to nat */
|
|
OP_STR_TO_REAL, /* str_ptr `stor` obj | convert obj1 to real */
|
|
OP_MAX_OPCODE /* not an opcode count of instructions */
|
|
} Opcode;
|
|
|
|
typedef enum {
|
|
SYSCALL_CONSOLE_WRITE,
|
|
SYSCALL_CONSOLE_READ,
|
|
SYSCALL_MAX
|
|
} Syscall;
|
|
|
|
typedef struct frame_s Frame;
|
|
struct frame_s {
|
|
u32 return_pc;
|
|
u32 start_mp;
|
|
};
|
|
|
|
extern u8 *code; /* code */
|
|
extern u32 cp; /* code pointer */
|
|
extern u8 *mem; /* memory */
|
|
extern u32 mp; /* memory pointer */
|
|
extern u32 *stack; /* stack */
|
|
extern u32 sp; /* stack pointer */
|
|
extern Frame *frames; /* call frames */
|
|
extern u32 fp; /* frame pointer */
|
|
extern u32 pc; /* program counter */
|
|
extern u8 status; /* status flag */
|
|
extern u8 interrupt; /* device interrupt */
|
|
|
|
#define READ_U8(addr) (mem[addr])
|
|
|
|
#define READ_U16(addr) \
|
|
(((u16)mem[(addr) + 1] << 8) | ((u16)mem[(addr)]))
|
|
|
|
#define READ_U32(addr) \
|
|
(((u32)mem[(addr) + 3] << 24) | \
|
|
((u32)mem[(addr) + 2] << 16) | \
|
|
((u32)mem[(addr) + 1] << 8) | ((u32)mem[(addr)]))
|
|
|
|
#define WRITE_U8(addr, value) \
|
|
do { \
|
|
mem[addr] = (value) & 0xFF; \
|
|
} while (0)
|
|
|
|
#define WRITE_U16(addr, value) \
|
|
do { \
|
|
mem[addr] = (value) & 0xFF; \
|
|
mem[addr + 1] = ((value) >> 8) & 0xFF; \
|
|
} while (0)
|
|
|
|
#define WRITE_U32(addr, value) \
|
|
do { \
|
|
mem[addr] = (value) & 0xFF; \
|
|
mem[addr + 1] = ((value) >> 8) & 0xFF; \
|
|
mem[addr + 2] = ((value) >> 16) & 0xFF; \
|
|
mem[addr + 3] = ((value) >> 24) & 0xFF; \
|
|
} while (0)
|
|
|
|
#define MATH_OP(type, op) \
|
|
do { \
|
|
type b = (type)stack[--sp]; \
|
|
type a = (type)stack[--sp]; \
|
|
stack[sp++] = (type)(a op b); \
|
|
return true; \
|
|
} while (0)
|
|
|
|
extern bool init_vm();
|
|
extern u32 syscall(u32 id, u32 mem_ptr);
|
|
bool step_vm();
|
|
u32 str_alloc(char *str, u32 length);
|
|
|
|
#endif
|