undar-lang/vm/vm.h

195 lines
13 KiB
C

#ifndef UNDAR_VM_H
#define UNDAR_VM_H
#include "libc.h"
/**
* Instruction Types
*
* A : [8:opcode][8:dest][8:src1][8:src2]
* B : [8:opcode][8:dest][16:immediate]
* C : [8:opcode][24: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;
#define ENCODE_C(opcode, imm) ((((u32)(opcode) & 0xFF) << 24) | \
(((u32)(imm)) & 0xFFFFFF))
#define DECODE_C(instruction) \
u32 imm = ((u32)(instruction)) & 0xFFFFFF;
typedef enum {
OP_HALT, /* halt : A : all zeros : halt execution */
OP_CALL, /* call : A : dest args fn_ptr : creates a new frame */
OP_RETURN, /* return : A : dest args : 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_ABS_8, /* load_absolute_8 : A : locals[dest] = memory[src1] as u8 */
OP_LOAD_ABS_16, /* load_absolute_16 : A : locals[dest] = memory[src1] as u16 */
OP_LOAD_ABS_32, /* load_absolute_32 : A : locals[dest] = memory[src1] as u32 */
OP_LOAD_OFF_8, /* load_offset_8 : A : locals[dest] = memory[locals[src1] + offset] as u8 */
OP_LOAD_OFF_16, /* load_offset_16 : A : locals[dest] = memory[locals[src1] + offset] as u16 */
OP_LOAD_OFF_32, /* load_offset_32 : A : locals[dest] = memory[locals[src1] + offset] as u32 */
OP_STORE_ABS_8, /* store_absolute_8 : A : memory[dest] = src1 && 0xFF */
OP_STORE_ABS_16, /* store_absolute_16 : A : memory[dest] = src1 && 0xFFFF */
OP_STORE_ABS_32, /* store_absolute_32 : A : memory[dest] = src1 */
OP_STORE_IND_8, /* store_indirect_8 : A : memory[dest] = locals[src1] && 0xFF */
OP_STORE_IND_16, /* store_indirect_16 : A : memory[dest] = locals[src1] && 0xFFFF*/
OP_STORE_IND_32, /* store_indirect_32 : A : memory[dest] = locals[src1] */
OP_STORE_OFF_8, /* store_offset_8 : A : memory[locals[dest] + offset] = locals[src1] && 0xFF */
OP_STORE_OFF_16, /* store_offset_16 : A : memory[locals[dest] + offset] = locals[src1] && 0xFFFF */
OP_STORE_OFF_32, /* store_offset_32 : A : memory[locals[dest] + offset] = locals[src1] */
OP_MEM_ALLOC, /* alloc : A : memory[dest] = [locals[src1] as size + 4] */
OP_MEM_CPY, /* memcpy : A : memory[src1 .. src1 + count] = memory[dest .. dest + count] */
OP_MEM_SET_8, /* memset_8 : A : memory[dest .. dest + count] = local[src1] as u8 */
OP_MEM_SET_16, /* memset_16 : A : memory[dest .. dest + count] = local[src1] as u16 */
OP_MEM_SET_32, /* memset_32 : A : memory[dest .. dest + count] = local[src1] as u32 */
OP_REG_MOV, /* register_move : A : locals[dest] = locals[src1] */
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_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_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_JMP_IMM, /* jump_immediate : C : jump to imm unconditionally */
OP_JMP_ABS, /* jump_absolute : A : jump to locals[dest] unconditionally */
OP_JMP_OFF, /* jump_offset : A : jump to locals[dest] + locals[src1] unconditionally */
OP_JMP_FLAG, /* jump_if_flag : A : jump to locals[dest] if flag > 0 */
OP_JEQ_INT, /* jump_eq_int : A : jump to locals[dest] if locals[src1] as int == locals[src2] as int */
OP_JNE_INT, /* jump_neq_int : A : jump to locals[dest] if locals[src1] as int != locals[src2] as int */
OP_JGT_INT, /* jump_gt_int : A : jump to locals[dest] if locals[src1] as int > locals[src2] as int */
OP_JLT_INT, /* jump_lt_int : A : jump to locals[dest] if locals[src1] as int < locals[src2] as int */
OP_JLE_INT, /* jump_le_int : A : jump to locals[dest] if locals[src1] as int <= locals[src2] as int */
OP_JGE_INT, /* jump_ge_int : A : jump to locals[dest] if locals[src1] as int >= locals[src2] as int */
OP_JEQ_NAT, /* jump_eq_nat : A : jump to locals[dest] if locals[src1] as nat == locals[src2] as nat */
OP_JNE_NAT, /* jump_neq_nat : A : jump to locals[dest] if locals[src1] as nat != locals[src2] as nat */
OP_JGT_NAT, /* jump_gt_nat : A : jump to locals[dest] if locals[src1] as nat > locals[src2] as nat */
OP_JLT_NAT, /* jump_lt_nat : A : jump to locals[dest] if locals[src1] as nat < locals[src2] as nat */
OP_JLE_NAT, /* jump_le_nat : A : jump to locals[dest] if locals[src1] as nat <= locals[src2] as nat */
OP_JGE_NAT, /* jump_ge_nat : A : jump to locals[dest] if locals[src1] as nat >= locals[src2] as nat */
OP_JEQ_REAL, /* jump_eq_real : A : jump to locals[dest] if locals[src1] as real == locals[src2] as real */
OP_JNE_REAL, /* jump_neq_real : A : jump to locals[dest] if locals[src1] as real != locals[src2] as real */
OP_JGE_REAL, /* jump_ge_real : A : jump to locals[dest] if locals[src1] as real >= locals[src2] as real */
OP_JGT_REAL, /* jump_gt_real : A : jump to locals[dest] if locals[src1] as real > locals[src2] as real */
OP_JLT_REAL, /* jump_lt_real : A : jump to locals[dest] if locals[src1] as real < locals[src2] as real */
OP_JLE_REAL, /* jump_le_real : A : jump to locals[dest] if locals[src1] as real <= locals[src2] as real */
OP_MAX_OPCODE /* not an opcode count of instructions */
} Opcode;
extern u32 pc; /* program counter */
extern u32 cp; /* code pointer */
extern u32 mp; /* memory pointer */
extern u32 fp; /* frame pointer */
extern u32 flag; /* 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) \
(((u32)mem[(addr) + 3] << 24) | \
((u32)mem[(addr) + 2] << 16) | \
((u32)mem[(addr) + 1] << 8) | ((u32)mem[(addr)]))
#define WRITE_U8(addr, value) \
do { \
if ((addr) < sizeof(mem)) { \
mem[(addr)] = (value) & 0xFF; \
} \
} while (0)
#define WRITE_U16(addr, value) \
do { \
if ((addr) + 1 < sizeof(mem)) { \
mem[(addr)] = (value) & 0xFF; \
mem[(addr) + 1] = ((value) >> 8) & 0xFF; \
} \
} while (0)
#define WRITE_U32(addr, value) \
do { \
if ((addr) + 3 < sizeof(mem)) { \
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 { \
DECODE_A(instruction) \
u32 rd = fp + dest; \
u32 r1 = fp + src1; \
u32 r2 = fp + src2; \
mem[rd] = (type)mem[r1] op(type) mem[r2]; \
return true; \
} while (0)
#define COMPARE_AND_JUMP(type, op) \
do { \
DECODE_A(instruction) \
i32 cond; \
u32 mask, target; \
type value; \
type value2; \
u32 rd = fp + dest; \
u32 r1 = fp + src1; \
u32 r2 = fp + src2; \
target = mem[rd]; \
value = (type)mem[r1]; \
value2 = (type)mem[r2]; \
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();
#endif