diff --git a/src/builder.cpp b/src/builder.cpp index f0a9040..a906185 100644 --- a/src/builder.cpp +++ b/src/builder.cpp @@ -1,185 +1,329 @@ #include "builder.hpp" #include "vm.hpp" +#include +#include #include using namespace vc5; +namespace { + +class InsBuilder { +public: + InsBuilder(Op op) + : m_ins(std::to_underlying(op)) + { + } + + void build(Builder& vm) const + { + vm.push(m_ins); + if (m_has_imm) { + vm.push(m_imm); + } + } + + void set(uint16_t bit) + { + m_ins |= 1 << bit; + } + + void reg(Reg reg, uint16_t bit, uint16_t mask) + { + m_ins |= (std::to_underlying(reg) & mask) << bit; + } + + void op1_reg(Reg reg) + { + this->reg(reg, 10, 0b111); + } + + void op2_reg(Reg reg) + { + this->reg(reg, 7, 0b111); + } + + void dst_reg(Reg reg) + { + this->reg(reg, 13, 0b111); + } + + void imm_without_flag(uint16_t imm) + { + m_imm = imm; + m_has_imm = true; + } + + void imm(uint16_t imm) + { + imm_without_flag(imm); + set(6); + } + +private: + uint16_t m_ins; + uint16_t m_imm = 0; + bool m_has_imm = false; +}; + +} + void Builder::nop() { - auto ins = std::to_underlying(Op::Nop); - push(ins); + auto i = InsBuilder(Op::Nop); + i.build(*this); } void Builder::hlt() { - auto ins = std::to_underlying(Op::Nop); - push(ins); + auto i = InsBuilder(Op::Hlt); + i.build(*this); } void Builder::jmp_reg(Reg op1) { + auto i = InsBuilder(Op::Jmp); + i.op1_reg(op1); + i.build(*this); } void Builder::jmp_imm(uint16_t op1) { + auto i = InsBuilder(Op::Jmp); + i.imm(op1); + i.build(*this); } void Builder::jnz_reg(Reg op1, Reg op2) { + auto i = InsBuilder(Op::Jnz); + i.op1_reg(op1); + i.op2_reg(op2); + i.build(*this); } void Builder::jnz_imm(Reg op1, uint16_t op2) { + auto i = InsBuilder(Op::Jnz); + i.op1_reg(op1); + i.imm(op2); + i.build(*this); } -void Builder::mov_word_load_reg(Reg dst, Reg src) +void Builder::mov_reg(Reg dst, Reg src) { + auto i = InsBuilder(Op::Mov); + i.reg(dst, 12, 0b1111); + i.reg(src, 7, 0b1111); + i.build(*this); } -void Builder::mov_word_load_imm(Reg dst, uint16_t imm) +void Builder::mov_imm(Reg dst, uint16_t imm) { + auto i = InsBuilder(Op::Mov); + i.reg(dst, 12, 0b1111); + i.imm(imm); + i.build(*this); } -void Builder::mov_word_load_mem_reg(Reg dst, Reg addr, uint16_t offset) +void Builder::load_word_reg(Reg dst, Reg addr, uint16_t offset) { + auto i = InsBuilder(Op::LoadWord); + i.dst_reg(dst); + i.op1_reg(addr); + i.imm_without_flag(offset); + i.build(*this); } -void Builder::mov_word_load_mem_imm(Reg dst, uint16_t addr) +void Builder::load_word_imm(Reg dst, uint16_t addr) { + auto i = InsBuilder(Op::LoadWord); + i.dst_reg(dst); + i.imm(addr); + i.build(*this); } -void Builder::mov_word_store_reg_reg(Reg dst, uint16_t offset, Reg op2) +void Builder::store_word_reg(Reg dst, uint16_t offset, Reg op2) { + auto i = InsBuilder(Op::StoreWord); + i.dst_reg(dst); + i.imm_without_flag(offset); + i.op2_reg(op2); + i.build(*this); } -void Builder::mov_word_store_reg_imm(Reg dst, uint16_t offset, uint16_t op2) +void Builder::store_word_imm(uint16_t dst, Reg op2) { + auto i = InsBuilder(Op::StoreWord); + i.imm(dst); + i.op2_reg(op2); + i.build(*this); } -void Builder::mov_word_store_imm_reg(uint16_t dst, Reg op2) +void Builder::load_byte_reg(Reg dst, Reg addr, uint16_t offset) { + auto i = InsBuilder(Op::LoadByte); + i.dst_reg(dst); + i.op1_reg(addr); + i.imm_without_flag(offset); + i.build(*this); } -void Builder::mov_word_store_imm_imm(uint16_t dst, uint16_t op2) +void Builder::load_byte_imm(Reg dst, uint16_t addr) { + auto i = InsBuilder(Op::LoadByte); + i.dst_reg(dst); + i.imm(addr); + i.build(*this); } -void Builder::mov_byte_load_reg(Reg dst, Reg src) +void Builder::store_byte_reg(Reg dst, uint16_t offset, Reg op2) { + auto i = InsBuilder(Op::StoreByte); + i.dst_reg(dst); + i.imm_without_flag(offset); + i.op2_reg(op2); + i.build(*this); } -void Builder::mov_byte_load_imm(Reg dst, uint8_t imm) -{ -} - -void Builder::mov_byte_load_mem_reg(Reg dst, Reg addr, uint16_t offset) -{ -} - -void Builder::mov_byte_load_mem_imm(Reg dst, uint16_t addr) -{ -} - -void Builder::mov_byte_store_reg_reg(Reg dst, uint16_t offset, Reg op2) -{ -} - -void Builder::mov_byte_store_reg_imm(Reg dst, uint16_t offset, uint8_t op2) -{ -} - -void Builder::mov_byte_store_imm_reg(uint16_t dst, Reg op2) -{ -} - -void Builder::mov_byte_store_imm_imm(uint16_t dst, uint8_t op2) +void Builder::store_byte_imm(uint16_t dst, Reg op2) { + auto i = InsBuilder(Op::StoreByte); + i.imm(dst); + i.op2_reg(op2); + i.build(*this); } void Builder::cmp_reg(Reg op1, Reg op2) { + auto i = InsBuilder(Op::Cmp); + i.op1_reg(op1); + i.op2_reg(op2); + i.build(*this); } -void Builder::cmp_imm(Reg op1, Reg op2) +void Builder::cmp_imm(Reg op1, uint16_t op2) { + auto i = InsBuilder(Op::Cmp); + i.op1_reg(op1); + i.imm(op2); + i.build(*this); } void Builder::or_reg(Reg dst, Reg op1, Reg op2) { + binary_reg(dst, op1, op2, Op::Or); } void Builder::and_reg(Reg dst, Reg op1, Reg op2) { + binary_reg(dst, op1, op2, Op::And); } void Builder::xor_reg(Reg dst, Reg op1, Reg op2) { + binary_reg(dst, op1, op2, Op::Xor); } void Builder::shl_reg(Reg dst, Reg op1, Reg op2) { + binary_reg(dst, op1, op2, Op::Shl); } void Builder::rshl_reg(Reg dst, Reg op1, Reg op2) { + binary_reg(dst, op1, op2, Op::RShl); } void Builder::shr_reg(Reg dst, Reg op1, Reg op2) { + binary_reg(dst, op1, op2, Op::Shr); } void Builder::rshr_reg(Reg dst, Reg op1, Reg op2) { + binary_reg(dst, op1, op2, Op::RShr); } void Builder::add_reg(Reg dst, Reg op1, Reg op2) { + binary_reg(dst, op1, op2, Op::Add); } void Builder::sub_reg(Reg dst, Reg op1, Reg op2) { + binary_reg(dst, op1, op2, Op::Sub); } void Builder::rsub_reg(Reg dst, Reg op1, Reg op2) { + binary_reg(dst, op1, op2, Op::RSub); } void Builder::or_imm(Reg dst, Reg op1, uint16_t op2) { + binary_imm(dst, op1, op2, Op::Xor); } void Builder::and_imm(Reg dst, Reg op1, uint16_t op2) { + binary_imm(dst, op1, op2, Op::And); } void Builder::xor_imm(Reg dst, Reg op1, uint16_t op2) { + binary_imm(dst, op1, op2, Op::Xor); } void Builder::shl_imm(Reg dst, Reg op1, uint16_t op2) { + binary_imm(dst, op1, op2, Op::Shl); } void Builder::rshl_imm(Reg dst, Reg op1, uint16_t op2) { + binary_imm(dst, op1, op2, Op::RShl); } void Builder::shr_imm(Reg dst, Reg op1, uint16_t op2) { + binary_imm(dst, op1, op2, Op::Shr); } void Builder::rshr_imm(Reg dst, Reg op1, uint16_t op2) { + binary_imm(dst, op1, op2, Op::RShr); } void Builder::add_imm(Reg dst, Reg op1, uint16_t op2) { + binary_imm(dst, op1, op2, Op::Add); } void Builder::sub_imm(Reg dst, Reg op1, uint16_t op2) { + binary_imm(dst, op1, op2, Op::Sub); } void Builder::rsub_imm(Reg dst, Reg op1, uint16_t op2) { + binary_imm(dst, op1, op2, Op::RSub); +} + +void Builder::binary_reg(Reg dst, Reg op1, Reg op2, Op op) +{ + auto i = InsBuilder(op); + i.dst_reg(dst); + i.op1_reg(op1); + i.op2_reg(op2); + i.build(*this); +} + +void Builder::binary_imm(Reg dst, Reg op1, uint16_t op2, Op op) +{ + auto i = InsBuilder(op); + i.dst_reg(dst); + i.op1_reg(op1); + i.imm(op2); + i.build(*this); } diff --git a/src/builder.hpp b/src/builder.hpp index b01e076..69b1adc 100644 --- a/src/builder.hpp +++ b/src/builder.hpp @@ -2,9 +2,12 @@ #include "vm.hpp" #include +#include namespace vc5 { +using namespace vc5; + class Builder { public: Builder(uint8_t* data) @@ -18,24 +21,18 @@ public: void jmp_imm(uint16_t op1); void jnz_reg(Reg op1, Reg op2); void jnz_imm(Reg op1, uint16_t op2); - void mov_word_load_reg(Reg dst, Reg src); - void mov_word_load_imm(Reg dst, uint16_t imm); - void mov_word_load_mem_reg(Reg dst, Reg addr, uint16_t offset); - void mov_word_load_mem_imm(Reg dst, uint16_t addr); - void mov_word_store_reg_reg(Reg dst, uint16_t offset, Reg op2); - void mov_word_store_reg_imm(Reg dst, uint16_t offset, uint16_t op2); - void mov_word_store_imm_reg(uint16_t dst, Reg op2); - void mov_word_store_imm_imm(uint16_t dst, uint16_t op2); - void mov_byte_load_reg(Reg dst, Reg src); - void mov_byte_load_imm(Reg dst, uint8_t imm); - void mov_byte_load_mem_reg(Reg dst, Reg addr, uint16_t offset); - void mov_byte_load_mem_imm(Reg dst, uint16_t addr); - void mov_byte_store_reg_reg(Reg dst, uint16_t offset, Reg op2); - void mov_byte_store_reg_imm(Reg dst, uint16_t offset, uint8_t op2); - void mov_byte_store_imm_reg(uint16_t dst, Reg op2); - void mov_byte_store_imm_imm(uint16_t dst, uint8_t op2); + void mov_reg(Reg dst, Reg src); + void mov_imm(Reg dst, uint16_t imm); + void load_word_reg(Reg dst, Reg addr, uint16_t offset); + void load_word_imm(Reg dst, uint16_t addr); + void store_word_reg(Reg dst, uint16_t offset, Reg op2); + void store_word_imm(uint16_t dst, Reg op2); + void load_byte_reg(Reg dst, Reg addr, uint16_t offset); + void load_byte_imm(Reg dst, uint16_t addr); + void store_byte_reg(Reg dst, uint16_t offset, Reg op2); + void store_byte_imm(uint16_t dst, Reg op2); void cmp_reg(Reg op1, Reg op2); - void cmp_imm(Reg op1, Reg op2); + void cmp_imm(Reg op1, uint16_t op2); void or_reg(Reg dst, Reg op1, Reg op2); void and_reg(Reg dst, Reg op1, Reg op2); void xor_reg(Reg dst, Reg op1, Reg op2); @@ -57,14 +54,27 @@ public: void sub_imm(Reg dst, Reg op1, uint16_t op2); void rsub_imm(Reg dst, Reg op1, uint16_t op2); -private: + uint16_t ip() const + { + return m_ip & 0xffff; + } + + void set_ip(uint16_t ip) + { + m_ip = ip; + } + inline void push(uint16_t v) { - m_data[m_ip] = v >> 16; + m_data[m_ip] = v >> 8; m_data[m_ip + 1] = v & 0xff; m_ip += 2; } +private: + void binary_reg(Reg dst, Reg op1, Reg op2, Op op); + void binary_imm(Reg dst, Reg op1, uint16_t op2, Op op); + uint8_t* m_data; size_t m_ip = 0; }; diff --git a/src/main.cpp b/src/main.cpp index b2a9d49..8a0f2b2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,6 +1,66 @@ +#include "builder.hpp" +#include +#include #include +#include + +using namespace vc5; +using R = Reg; int main() { - std::println("hello world"); + constexpr R r0 = R::R0; + constexpr R r1 = R::R1; + constexpr R r2 = R::R2; + constexpr R r3 = R::R3; + constexpr R r4 = R::R4; + constexpr R r5 = R::R5; + constexpr R rbp = R::Rbp; + constexpr R rsp = R::Rsp; + constexpr R rfl = R::Rfl; + constexpr R rip = R::Rip; + + auto program = std::array(); + + auto l = Builder(program.data()); + + l.mov_imm(r0, 4); + + auto l0 = l.ip(); + l.cmp_imm(r0, 0); + l.mov_reg(r1, rfl); + l.and_imm(r1, r1, 1 << std::to_underlying(Flag::Eq)); + + auto i0 = l.ip(); + l.jnz_imm(r1, 0); + + l.sub_imm(r0, r0, 1); + l.jmp_imm(l0); + + auto l1 = l.ip(); + l.hlt(); + + l.set_ip(i0 + 2); + l.push(l1); + + auto vm = VM(); + vm.load(0, program.data(), program.size()); + + vm.run(); + + std::println("--- regs ---"); + std::println("r0\t{}", vm.reg(r0)); + std::println("r1\t{}", vm.reg(r1)); + std::println("r2\t{}", vm.reg(r2)); + std::println("r3\t{}", vm.reg(r3)); + std::println("r4\t{}", vm.reg(r4)); + std::println("r5\t{}", vm.reg(r5)); + std::println("rbp\t{}", vm.reg(rbp)); + std::println("rsp\t{}", vm.reg(rsp)); + std::println("rfl\t{}", vm.reg(rfl)); + std::println("rip\t{}", vm.reg(rip)); + std::println("--- mem ---"); + for (uint16_t i = 0; i < 32; i += 2) { + std::println("{: 4x}\t{}", i, vm.word(i)); + } } diff --git a/src/vm.cpp b/src/vm.cpp index 96b2d2b..2337ca0 100644 --- a/src/vm.cpp +++ b/src/vm.cpp @@ -4,6 +4,26 @@ using namespace vc5; +namespace { + +uint16_t mem_addr(Ins& ins, uint16_t imm) +{ + bool is_imm = ins >> 6 & 1; + if (is_imm) { + return imm; + } + + auto base = ins.op2(); + auto offset = static_cast(imm); + if (offset >= 0) { + return base + static_cast(offset); + } else { + return base - static_cast(-offset); + } +} + +} + int VM::run() { m_halted = false; @@ -17,8 +37,17 @@ int VM::run() int VM::run_instruction() { - auto ins = eat_ins(); + auto ip = *m_rip; + if (ip > 64) + return -1; + + auto ins = Ins(*this); auto op = static_cast(ins & 0b11'1111); + std::println("[{: 4x}]: {:04x} {}, r0 = {}", + ip, + ins.operator uint16_t(), + op_str(op), + m_regs[reg_id(Reg::R0)]); switch (op) { case Op::Nop: @@ -40,85 +69,57 @@ int VM::run_instruction() } break; } - case Op::MovWord: { - bool is_memory = ins >> 10 & 1; - bool addr_is_reg = ins >> 11 & 1; - bool is_store = ins >> 12 & 1; - - if (!is_memory) { - auto src = ins.reg_val_or_imm(6, 7, 0b1111); - auto dst = static_cast(ins >> 12 & 0b1111); - m_regs[dst] = src; - break; - } - - uint16_t addr; - if (addr_is_reg) { - auto reg = is_store ? ins.dst_reg() : ins.op2_reg(); - auto offset = static_cast(eat()); - addr = static_cast( - static_cast(m_regs[reg]) + offset); - } else { - addr = eat(); - } + case Op::Mov: { + auto dst = static_cast(ins >> 12 & 0b1111); + auto src = ins.reg_val_or_imm(6, 7, 0b1111); + m_regs[dst] = src; + break; + } + case Op::LoadWord: { + auto addr = mem_addr(ins, eat()); if ((addr & 0b1) != 0) { std::println(stderr, "error: invalid address alignment"); - *m_rfl |= 1 << flag(Flag::Err); + *m_rfl |= 1 << flag_id(Flag::Err); goto halt_execution; } - if (is_store) { - auto src = ins.op2_or_imm(); - m_mem[addr] = src >> 16; - m_mem[addr + 1] = src & 0xff; - } else { - auto reg = ins.dst_reg(); + auto reg = ins.dst_reg(); - uint16_t value = 0; - value |= static_cast(m_mem[addr]) << 16; - value |= m_mem[addr + 1]; + uint16_t value = 0; + value |= static_cast(m_mem[addr]) << 16; + value |= m_mem[addr + 1]; - m_regs[reg] = value; + m_regs[reg] = value; + break; + } + case Op::StoreWord: { + auto addr = mem_addr(ins, eat()); + + if ((addr & 0b1) != 0) { + std::println(stderr, "error: invalid address alignment"); + *m_rfl |= 1 << flag_id(Flag::Err); + goto halt_execution; } + auto src = ins.op2(); + m_mem[addr] = src >> 16; + m_mem[addr + 1] = src & 0xff; + break; } - case Op::MovByte: { - bool is_memory = ins >> 10 & 1; - bool addr_is_reg = ins >> 11 & 1; - bool is_store = ins >> 12 & 1; + case Op::LoadByte: { + auto addr = mem_addr(ins, eat()); + auto reg = ins.dst_reg(); - if (!is_memory) { - auto src = ins.reg_val_or_imm(6, 7, 0b1111); - auto dst = static_cast(ins >> 12 & 0b1111); - m_regs[dst] = src & 0xff; - break; - } - - uint16_t addr; - if (addr_is_reg) { - auto reg = is_store ? ins.dst_reg() : ins.op2_reg(); - auto offset = static_cast(eat()); - addr = static_cast( - static_cast(m_regs[reg]) + offset); - } else { - addr = eat(); - } - - if (is_store) { - auto src = ins.op2_or_imm(); - m_mem[addr] = src & 0xff; - } else { - auto reg = ins.dst_reg(); - - uint16_t value = 0; - value |= static_cast(m_mem[addr]) << 16; - value |= m_mem[addr + 1]; - - m_regs[reg] = value; - } + m_regs[reg] = m_mem[addr]; + break; + } + case Op::StoreByte: { + auto addr = mem_addr(ins, eat()); + auto src = ins.op2(); + m_mem[addr] = src & 0xff; break; } case Op::Cmp: { @@ -126,19 +127,19 @@ int VM::run_instruction() auto op2 = ins.op2_or_imm(); if (op1 == op2) { - *m_rfl |= 1u << flag(Flag::Eq); + *m_rfl |= 1u << flag_id(Flag::Eq); } else { - *m_rfl &= (uint16_t)~(1u << flag(Flag::Eq)); + *m_rfl &= (uint16_t)~(1u << flag_id(Flag::Eq)); } if (op1 < op2) { - *m_rfl |= 1u << flag(Flag::Be); + *m_rfl |= 1u << flag_id(Flag::Be); } else { - *m_rfl &= (uint16_t)~(1u << flag(Flag::Be)); + *m_rfl &= (uint16_t)~(1u << flag_id(Flag::Be)); } if ((int16_t)op1 < (int16_t)op2) { - *m_rfl |= 1u << flag(Flag::Lt); + *m_rfl |= 1u << flag_id(Flag::Lt); } else { - *m_rfl &= (uint16_t)~(1u << flag(Flag::Lt)); + *m_rfl &= (uint16_t)~(1u << flag_id(Flag::Lt)); } break; } @@ -200,3 +201,50 @@ int VM::run_instruction() halt_execution: return 0; } + +const char* vc5::op_str(Op op) +{ + switch (op) { + case Op::Nop: + return "Nop"; + case Op::Hlt: + return "Hlt"; + case Op::Jmp: + return "Jmp"; + case Op::Jnz: + return "Jnz"; + case Op::Mov: + return "Mov"; + case Op::LoadWord: + return "LoadWord"; + case Op::StoreWord: + return "StoreWord"; + case Op::LoadByte: + return "LoadByte"; + case Op::StoreByte: + return "StoreByte"; + case Op::Cmp: + return "Cmp"; + case Op::Or: + return "Or"; + case Op::And: + return "And"; + case Op::Xor: + return "Xor"; + case Op::Shl: + return "Shl"; + case Op::RShl: + return "RShl"; + case Op::Shr: + return "Shr"; + case Op::RShr: + return "RShr"; + case Op::Add: + return "Add"; + case Op::Sub: + return "Sub"; + case Op::RSub: + return "RSub"; + } + return ">.<"; +} diff --git a/src/vm.hpp b/src/vm.hpp index 8b31134..8e92316 100644 --- a/src/vm.hpp +++ b/src/vm.hpp @@ -3,6 +3,8 @@ #include #include #include +#include +#include #include namespace vc5 { @@ -12,8 +14,11 @@ enum class Op : uint16_t { Hlt, Jmp, Jnz, - MovWord, - MovByte, + Mov, + LoadWord, + StoreWord, + LoadByte, + StoreByte, Cmp, Or, And, @@ -27,6 +32,8 @@ enum class Op : uint16_t { RSub, }; +const char* op_str(Op op); + enum class Reg : uint16_t { R0 = 0, R1 = 1, @@ -48,108 +55,128 @@ enum class Flag : uint16_t { Err = 4, }; +struct Ins; + 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]; - } - } - }; + void load(uint16_t offset, const uint8_t* data, size_t data_size) + { + std::memcpy(&m_mem[offset], data, data_size); + } int run(); + uint16_t reg(Reg reg) const + { + return m_regs[reg_id(reg)]; + }; + + uint16_t word(uint16_t addr) const + { + uint16_t value = 0; + value |= static_cast(m_mem[addr]) << 8; + value |= m_mem[addr + 1]; + return value; + } + uint8_t byte(uint16_t addr) const + { + return m_mem[addr]; + } + private: + friend struct Ins; + + static constexpr uint16_t reg_id(Reg reg) + { + return std::to_underlying(reg); + } + + static constexpr uint16_t flag_id(Flag flag) + { + return std::to_underlying(flag); + } + int run_instruction(); inline uint16_t eat() { uint16_t ins = 0; - ins |= static_cast(m_mem[*m_rip]) << 16; + ins |= static_cast(m_mem[*m_rip]) << 8; 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 = {}; + std::array m_regs = {}; - uint16_t* m_rfl = &m_regs[reg(Reg::Rfl)]; - uint16_t* m_rip = &m_regs[reg(Reg::Rip)]; + uint16_t* m_rfl = &m_regs[reg_id(Reg::Rfl)]; + uint16_t* m_rip = &m_regs[reg_id(Reg::Rip)]; bool m_halted = false; }; +struct Ins { + Ins(VM& vm) + : vm(&vm) + , ins(vm.eat()) + { + } + + 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]; + } + } +}; + }