undar-lang-fixed-length/vm/vm.h

197 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]
*/
#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 : A : 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 : A : dest : 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) (((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 { \
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