213 lines
13 KiB
C
213 lines
13 KiB
C
#ifndef UNDAR_VM_H
|
|
#define UNDAR_VM_H
|
|
|
|
#include "libc.h"
|
|
|
|
/*
|
|
* Locals
|
|
* one 32bit value
|
|
* [lllll|tt|p]
|
|
* 5 bits -> local position (up to 32 per scope)
|
|
* 2 bits -> type
|
|
* 1 bit -> is pointer?
|
|
*
|
|
* 1 -> ptr,
|
|
* 00 -> 8
|
|
* 10 -> 16
|
|
* 01 -> 32
|
|
* 11 -> string
|
|
*
|
|
* 0 -> value
|
|
* 00 -> bool?
|
|
* 10 -> nat
|
|
* 01 -> int
|
|
* 11 -> real
|
|
*/
|
|
|
|
/**
|
|
* Instruction Types
|
|
*
|
|
* A : [8:opcode][8:dest][8:src1][8:src2]
|
|
* B : [8:opcode][8:dest][16:immediate]
|
|
*/
|
|
#define DECODE_OP(instruction) ((((u32)(instruction)) >> 24) & 0xFF)
|
|
|
|
#define ENCODE_A(opcode, dest, src1, src2) ((((u32)(opcode) & 0xFF) << 24) | \
|
|
(((u32)(dest) & 0xFF) << 16) | \
|
|
(((u32)(src1) & 0xFF) << 8) | \
|
|
(((u32)(src2) & 0xFF)))
|
|
|
|
#define DECODE_A(instruction) \
|
|
u8 dest = (((u32)(instruction)) >> 16) & 0xFF; \
|
|
u8 src1 = (((u32)(instruction)) >> 8) & 0xFF; \
|
|
u8 src2 = ((u32)(instruction)) & 0xFF;
|
|
|
|
#define ENCODE_B(opcode, dest, imm) ((((u32)(opcode) & 0xFF) << 24) | \
|
|
(((u32)(dest) & 0xFF) << 16) | \
|
|
(((u32)(imm)) & 0xFFFF))
|
|
#define DECODE_B(instruction) \
|
|
u8 dest = (((u32)(instruction)) >> 16) & 0xFF; \
|
|
u16 imm = ((u32)(instruction)) & 0xFFFF;
|
|
|
|
typedef enum {
|
|
OP_HALT, /* halt : B : all zeros : halt execution */
|
|
OP_CALL, /* call : A : dest args return : creates a new frame */
|
|
OP_RETURN, /* return : B : dest return_flags : returns from a frame to the parent frame */
|
|
OP_SYSCALL, /* syscall : A : id args mem_ptr : does a system call based on id with args */
|
|
OP_LOAD_IMM, /* load_immediate : B : locals[dest] = const as u16 */
|
|
OP_LOAD_UPPER_IMM, /* load_upper_immediate : B : locals[dest] = const as u32 << 16 | u16 */
|
|
OP_LOAD_IND_8, /* load_indirect_8 : A : locals[dest] = memory[locals[src1]] as u8 */
|
|
OP_LOAD_IND_16, /* load_indirect_16 : A : locals[dest] = memory[locals[src1]] as u16 */
|
|
OP_LOAD_IND_32, /* load_indirect_32 : A : locals[dest] = memory[locals[src1]] as u32 */
|
|
OP_LOAD_OFF_8, /* load_offset_8 : A : locals[dest] = memory[locals[src1] + locals[src2]] as u8 */
|
|
OP_LOAD_OFF_16, /* load_offset_16 : A : locals[dest] = memory[locals[src1] + locals[src2]] as u16 */
|
|
OP_LOAD_OFF_32, /* load_offset_32 : A : locals[dest] = memory[locals[src1] + locals[src2]] as u32 */
|
|
OP_STORE_IND_8, /* store_indirect_8 : A : memory[locals[dest]] = locals[src1] && 0xFF */
|
|
OP_STORE_IND_16, /* store_indirect_16 : A : memory[locals[dest]] = locals[src1] && 0xFFFF*/
|
|
OP_STORE_IND_32, /* store_indirect_32 : A : memory[locals[dest]] = locals[src1] */
|
|
OP_STORE_OFF_8, /* store_offset_8 : A : memory[locals[dest] + locals[src2]] = locals[src1] && 0xFF */
|
|
OP_STORE_OFF_16, /* store_offset_16 : A : memory[locals[dest] + locals[src2]] = locals[src1] && 0xFFFF */
|
|
OP_STORE_OFF_32, /* store_offset_32 : A : memory[locals[dest] + locals[src2]] = locals[src1] */
|
|
OP_MEM_ALLOC, /* alloc : A : memory[dest] = [locals[src1] as size + 4] */
|
|
OP_MEM_CPY_8, /* memcpy_8 : A : memory[src1..src1+src2] = memory[dest..dest+src2] */
|
|
OP_MEM_CPY_16, /* memcpy_16 : A : memory[src1..src1+src2] = memory[dest..dest+src2] */
|
|
OP_MEM_CPY_32, /* memcpy_32 : A : memory[src1..src1+src2] = memory[dest..dest+src2] */
|
|
OP_MEM_SET_8, /* memset_8 : A : memory[dest..dest+src2] = local[src1] as u8 */
|
|
OP_MEM_SET_16, /* memset_16 : A : memory[dest..dest+src2] = local[src1] as u16 */
|
|
OP_MEM_SET_32, /* memset_32 : A : memory[dest..dest+src2] = local[src1] as u32 */
|
|
OP_MOV, /* mov : A : locals[dest] = locals[src1] */
|
|
OP_PARG, /* push_arg : B : push u32 value onto the childs locals */
|
|
OP_ADD_INT, /* add_int : A : locals[dest] = locals[src1] + locals[src2] */
|
|
OP_SUB_INT, /* sub_int : A : locals[dest] = locals[src1] - locals[src2] */
|
|
OP_MUL_INT, /* mul_int : A : locals[dest] = locals[src1] * locals[src2] */
|
|
OP_DIV_INT, /* div_int : A : locals[dest] = locals[src1] / locals[src2] */
|
|
OP_ADD_NAT, /* add_nat : A : locals[dest] = locals[src1] + locals[src2] */
|
|
OP_SUB_NAT, /* sub_nat : A : locals[dest] = locals[src1] - locals[src2] */
|
|
OP_MUL_NAT, /* mul_nat : A : locals[dest] = locals[src1] * locals[src2] */
|
|
OP_DIV_NAT, /* div_nat : A : locals[dest] = locals[src1] / locals[src2] */
|
|
OP_ADD_REAL, /* add_real : A : locals[dest] = locals[src1] + locals[src2] */
|
|
OP_SUB_REAL, /* sub_real : A : locals[dest] = locals[src1] - locals[src2] */
|
|
OP_MUL_REAL, /* mul_real : A : locals[dest] = locals[src1] * locals[src2] */
|
|
OP_DIV_REAL, /* div_real : A : locals[dest] = locals[src1] / locals[src2] */
|
|
OP_BIT_SHIFT_LEFT, /* bit_shift_left : A : locals[dest] = locals[src1] << locals[src2] */
|
|
OP_BIT_SHIFT_RIGHT,/* bit_shift_right : A : locals[dest] = locals[src1] >> locals[src2] */
|
|
OP_BIT_SHIFT_R_EXT,/* bit_shift_r_ext : A : locals[dest] as i32 = locals[src1] >> locals[src2] */
|
|
OP_BIT_AND, /* bit_and : A : locals[dest] = locals[src1] & locals[src2] */
|
|
OP_BIT_OR, /* bit_or : A : locals[dest] = locals[src1] | locals[src2] */
|
|
OP_BIT_XOR, /* bit_xor : A : locals[dest] = locals[src1] ^ locals[src2] */
|
|
OP_EQS, /* eq_signed : A : locals[dest] = locals[src1] == locals[src2] */
|
|
OP_NES, /* ne_signed : A : locals[dest] = locals[src1] != locals[src2] */
|
|
OP_GTS, /* gt_signed : A : locals[dest] = locals[src1] > locals[src2] */
|
|
OP_LTS, /* lt_signed : A : locals[dest] = locals[src1] < locals[src2] */
|
|
OP_LES, /* le_signed : A : locals[dest] = locals[src1] <= locals[src2] */
|
|
OP_GES, /* ge_signed : A : locals[dest] = locals[src1] >= locals[src2] */
|
|
OP_EQU, /* eq_unsigned : A : locals[dest] = locals[src1] == locals[src2] */
|
|
OP_NEU, /* ne_unsigned : A : locals[dest] = locals[src1] != locals[src2] */
|
|
OP_GTU, /* gt_unsigned : A : locals[dest] = locals[src1] > locals[src2] */
|
|
OP_LTU, /* lt_unsigned : A : locals[dest] = locals[src1] < locals[src2] */
|
|
OP_LEU, /* le_unsigned : A : locals[dest] = locals[src1] <= locals[src2] */
|
|
OP_GEU, /* ge_unsigned : A : locals[dest] = locals[src1] >= locals[src2] */
|
|
OP_JMP_FLAG, /* jump_if_flag : A : jump to locals[dest] if flag > 0 */
|
|
OP_JMP_ABS, /* jump_absolute : A : jump to locals[dest] if locals[src1] != 0 */
|
|
OP_JMP_OFF, /* jump_offset : A : jump to locals[dest] + locals[src2] if locals[src1] != 0 */
|
|
OP_JEQS, /* jump_eq_signed : A : jump to locals[dest] if locals[src1] as i32 == locals[src2] as i32 */
|
|
OP_JNES, /* jump_neq_signed : A : jump to locals[dest] if locals[src1] as i32 != locals[src2] as i32 */
|
|
OP_JGTS, /* jump_gt_signed : A : jump to locals[dest] if locals[src1] as i32 > locals[src2] as i32 */
|
|
OP_JLTS, /* jump_lt_signed : A : jump to locals[dest] if locals[src1] as i32 < locals[src2] as i32 */
|
|
OP_JLES, /* jump_le_signed : A : jump to locals[dest] if locals[src1] as i32 <= locals[src2] as i32 */
|
|
OP_JGES, /* jump_ge_signed : A : jump to locals[dest] if locals[src1] as i32 >= locals[src2] as i32 */
|
|
OP_JEQU, /* jump_eq_unsigned : A : jump to locals[dest] if locals[src1] as u32 == locals[src2] as u32 */
|
|
OP_JNEU, /* jump_neq_unsigned : A : jump to locals[dest] if locals[src1] as u32 != locals[src2] as u32 */
|
|
OP_JGTU, /* jump_gt_unsigned : A : jump to locals[dest] if locals[src1] as u32 > locals[src2] as u32 */
|
|
OP_JLTU, /* jump_lt_unsigned : A : jump to locals[dest] if locals[src1] as u32 < locals[src2] as u32 */
|
|
OP_JLEU, /* jump_le_unsigned : A : jump to locals[dest] if locals[src1] as u32 <= locals[src2] as u32 */
|
|
OP_JGEU, /* jump_ge_unsigned : A : jump to locals[dest] if locals[src1] as u32 >= locals[src2] as u32 */
|
|
OP_INT_TO_REAL, /* int_to_real : A : locals[dest] = locals[src1] as real */
|
|
OP_INT_TO_NAT, /* int_to_nat : A : locals[dest] = locals[src1] as nat */
|
|
OP_NAT_TO_REAL, /* nat_to_real : A : locals[dest] = locals[src1] as real */
|
|
OP_NAT_TO_INT, /* nat_to_int : A : locals[dest] = locals[src1] as int */
|
|
OP_REAL_TO_INT, /* real_to_int : A : locals[dest] = locals[src1] as int */
|
|
OP_REAL_TO_NAT, /* real_to_nat : A : locals[dest] = locals[src1] as nat */
|
|
OP_INT_TO_STR, /* int_to_str : A : locals[dest] = &mem[mp..] <~ locals[src1] as str */
|
|
OP_NAT_TO_STR, /* nat_to_str : A : locals[dest] = &mem[mp..] <~ locals[src1] as str */
|
|
OP_REAL_TO_STR, /* real_to_str : A : locals[dest] = &mem[mp..] <~ locals[src1] as str */
|
|
OP_STR_TO_INT, /* str_to_int : A : locals[dest] = mem[locals[src1]..] ~> int */
|
|
OP_STR_TO_NAT, /* str_to_nat : A : locals[dest] = mem[locals[src1]..] ~> nat */
|
|
OP_STR_TO_REAL, /* str_to_real : A : locals[dest] = mem[locals[src1]..] ~> real */
|
|
OP_MAX_OPCODE /* not an opcode just a count of instructions */
|
|
} Opcode;
|
|
|
|
typedef enum {
|
|
SYSCALL_CONSOLE_WRITE,
|
|
SYSCALL_CONSOLE_READ,
|
|
SYSCALL_MAX
|
|
} Syscall;
|
|
|
|
extern u32 pc; /* program counter */
|
|
extern u32 cp; /* code pointer */
|
|
extern u32 mp; /* memory pointer */
|
|
extern u32 fp; /* frame pointer */
|
|
extern u8 lc; /* child local count */
|
|
extern u8 status; /* status flag */
|
|
extern u8 interrupt; /* device interrupt */
|
|
extern u32 *code; /* code */
|
|
extern u8 *mem; /* memory */
|
|
|
|
#define READ_U8(addr) (mem[addr])
|
|
|
|
#define READ_U16(addr) \
|
|
(((u16)mem[(addr) + 1] << 8) | ((u16)mem[(addr)]))
|
|
|
|
#define READ_U32(addr) (globals[(addr / 4)])
|
|
|
|
#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 { \
|
|
globals[(addr / 4)] = value; \
|
|
} while (0)
|
|
|
|
#define MATH_OP(type, op) \
|
|
do { \
|
|
DECODE_A(instruction) \
|
|
locals[dest] = ((type)locals[src1] op (type)locals[src2]); \
|
|
return true; \
|
|
} while (0)
|
|
|
|
#define MATH_OP_NO_CAST(op) \
|
|
do { \
|
|
DECODE_A(instruction) \
|
|
locals[dest] = (locals[src1] op locals[src2]); \
|
|
return true; \
|
|
} while (0)
|
|
|
|
#define COMPARE_AND_JUMP(type, op) \
|
|
do { \
|
|
DECODE_A(instruction) \
|
|
i32 cond; \
|
|
u32 mask; \
|
|
u32 target = locals[dest]; \
|
|
type value = (type)locals[src1]; \
|
|
type value2 = (type)locals[src2]; \
|
|
cond = !!(value op value2); \
|
|
mask = -(u32)cond; \
|
|
pc = (target & mask) | (pc & ~mask); \
|
|
return true; \
|
|
} while (0)
|
|
|
|
extern bool init_vm();
|
|
extern u32 syscall(u32 id, u32 args, u32 mem_ptr);
|
|
bool step_vm();
|
|
u32 str_alloc(char *str, u32 length);
|
|
|
|
#endif
|