#define DEFINE_BINARY_INSTRUCTIONS #include "builder.hpp" #include "vm.hpp" #include #include #include using namespace vc5::tools; 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; }; } #define LOG_F \ { \ std::println("assembling {} at {}", __func__, this->m_ip); \ } #define LOG void Builder::nop() { LOG; auto i = InsBuilder(Op::Nop); i.build(*this); } void Builder::hlt() { LOG; auto i = InsBuilder(Op::Hlt); i.build(*this); } void Builder::jmp_reg(Reg op1) { LOG; auto i = InsBuilder(Op::Jmp); i.op1_reg(op1); i.build(*this); } void Builder::jmp_imm(uint16_t op1) { LOG; auto i = InsBuilder(Op::Jmp); i.imm(op1); i.build(*this); } void Builder::jnz_reg(Reg op1, Reg op2) { LOG; 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) { LOG; auto i = InsBuilder(Op::Jnz); i.op1_reg(op1); i.imm(op2); i.build(*this); } void Builder::mov_reg(Reg dst, Reg src) { LOG; auto i = InsBuilder(Op::Mov); i.reg(dst, 12, 0b1111); i.reg(src, 7, 0b1111); i.build(*this); } void Builder::mov_imm(Reg dst, uint16_t imm) { LOG; auto i = InsBuilder(Op::Mov); i.reg(dst, 12, 0b1111); i.imm(imm); i.build(*this); } void Builder::ldw_reg(Reg dst, Reg addr, uint16_t offset) { LOG; auto i = InsBuilder(Op::LdW); i.dst_reg(dst); i.op1_reg(addr); i.imm_without_flag(offset); i.build(*this); } void Builder::ldw_imm(Reg dst, uint16_t addr) { LOG; auto i = InsBuilder(Op::LdW); i.dst_reg(dst); i.imm(addr); i.build(*this); } void Builder::stw_reg(Reg dst, uint16_t offset, Reg op2) { LOG; auto i = InsBuilder(Op::StW); i.dst_reg(dst); i.imm_without_flag(offset); i.op2_reg(op2); i.build(*this); } void Builder::stw_imm(uint16_t dst, Reg op2) { LOG; auto i = InsBuilder(Op::StW); i.imm(dst); i.op2_reg(op2); i.build(*this); } void Builder::ldb_reg(Reg dst, Reg addr, uint16_t offset) { LOG; auto i = InsBuilder(Op::LdB); i.dst_reg(dst); i.op1_reg(addr); i.imm_without_flag(offset); i.build(*this); } void Builder::ldb_imm(Reg dst, uint16_t addr) { LOG; auto i = InsBuilder(Op::LdB); i.dst_reg(dst); i.imm(addr); i.build(*this); } void Builder::stb_reg(Reg dst, uint16_t offset, Reg op2) { LOG; auto i = InsBuilder(Op::StB); i.dst_reg(dst); i.imm_without_flag(offset); i.op2_reg(op2); i.build(*this); } void Builder::stb_imm(uint16_t dst, Reg op2) { LOG; auto i = InsBuilder(Op::StB); i.imm(dst); i.op2_reg(op2); i.build(*this); } void Builder::cmp_reg(Reg op1, Reg op2) { LOG; auto i = InsBuilder(Op::Cmp); i.op1_reg(op1); i.op2_reg(op2); i.build(*this); } void Builder::cmp_imm(Reg op1, uint16_t op2) { LOG; auto i = InsBuilder(Op::Cmp); i.op1_reg(op1); i.imm(op2); i.build(*this); } #define X(NAME, OP) \ void Builder::NAME##_reg(Reg dst, Reg op1, Reg op2) \ { \ LOG; \ binary_reg(dst, op1, op2, Op::OP); \ } \ void Builder::NAME##_imm(Reg dst, Reg op1, uint16_t op2) \ { \ LOG; \ binary_imm(dst, op1, op2, Op::OP); \ } BINARY_INSTRUCTIONS #undef X 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); } void Builder::call_reg(Reg op1) { LOG; auto i = InsBuilder(Op::Call); i.op1_reg(op1); i.build(*this); } void Builder::call_imm(uint16_t op1) { LOG; auto i = InsBuilder(Op::Call); i.imm(op1); i.build(*this); } void Builder::ret() { LOG; auto i = InsBuilder(Op::Ret); i.build(*this); } void Builder::reti() { LOG; auto i = InsBuilder(Op::RetI); i.build(*this); } void Builder::lvcd_reg(Reg op1) { LOG; auto i = InsBuilder(Op::LVCD); i.op1_reg(op1); i.build(*this); } void Builder::lvcd_imm(uint16_t op1) { LOG; auto i = InsBuilder(Op::LVCD); i.imm(op1); i.build(*this); } void Builder::lkbd_reg(Reg op1) { LOG; auto i = InsBuilder(Op::LKBD); i.op1_reg(op1); i.build(*this); } void Builder::lkbd_imm(uint16_t op1) { LOG; auto i = InsBuilder(Op::LKBD); i.imm(op1); i.build(*this); } void Builder::dskr(Reg dst, Reg op1) { LOG; auto i = InsBuilder(Op::DSKR); i.dst_reg(dst); i.op1_reg(op1); i.build(*this); } void Builder::dskw(Reg dst, Reg op1) { LOG; auto i = InsBuilder(Op::DSKW); i.dst_reg(dst); i.op1_reg(op1); i.build(*this); }