#pragma once #include #include #include #include namespace vc5 { enum class Op : uint16_t { Nop, Hlt, Jmp, Jnz, MovWord, MovByte, Cmp, Or, And, Xor, Shl, RShl, Shr, RShr, Add, Sub, RSub, }; enum class Reg : uint16_t { R0 = 0, R1 = 1, R2 = 2, R3 = 3, R4 = 4, R5 = 5, Rbp = 6, Rsp = 7, Rfl = 8, Rip = 9, }; enum class Flag : uint16_t { Zero = 0, Eq = 1, Be = 2, Lt = 3, Err = 4, }; class VM { public: struct Ins { Ins(VM& vm, uint16_t ins) : vm(&vm) , ins(ins) { } VM* vm; uint16_t ins; operator uint16_t() { return ins; } inline uint16_t dst_reg() const { return ins >> 13 & 0b111; } inline uint16_t op1_reg() const { return ins >> 10 & 0b111; } inline uint16_t op2_reg() const { return ins >> 7 & 0b111; } inline uint16_t op1() const { return vm->m_regs[op1_reg()]; } inline uint16_t op2() const { return vm->m_regs[op2_reg()]; } inline uint16_t op1_or_imm() { return reg_val_or_imm(6, 10, 0b111); } inline uint16_t op2_or_imm() { return reg_val_or_imm(6, 7, 0b111); } inline uint16_t reg_val_or_imm( uint16_t is_imm_bit, uint16_t reg_bit, uint16_t reg_mask) { bool is_imm = (ins >> is_imm_bit & 1) != 0; if (is_imm) { return vm->eat(); } else { return vm->m_regs[ins >> reg_bit & reg_mask]; } } }; int run(); private: int run_instruction(); inline uint16_t eat() { uint16_t ins = 0; ins |= static_cast(m_mem[*m_rip]) << 16; ins |= m_mem[*m_rip + 1]; *m_rip += 2; return ins; } inline Ins eat_ins() { auto ins = eat(); return Ins(*this, ins); } static constexpr uint16_t reg(Reg reg) { return std::to_underlying(reg); } static constexpr uint16_t flag(Flag flag) { return std::to_underlying(flag); } std::array m_mem = {}; std::array m_regs = {}; uint16_t* m_rfl = &m_regs[reg(Reg::Rfl)]; uint16_t* m_rip = &m_regs[reg(Reg::Rip)]; bool m_halted = false; }; }