vc5/src/vm.hpp
2026-01-04 23:28:32 +01:00

156 lines
2.6 KiB
C++

#pragma once
#include <array>
#include <cstddef>
#include <cstdint>
#include <utility>
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<uint16_t>(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<uint8_t, 65536> m_mem = {};
std::array<uint16_t, 8> m_regs = {};
uint16_t* m_rfl = &m_regs[reg(Reg::Rfl)];
uint16_t* m_rip = &m_regs[reg(Reg::Rip)];
bool m_halted = false;
};
}