352 lines
6.3 KiB
C++
352 lines
6.3 KiB
C++
#define DEFINE_BINARY_INSTRUCTIONS
|
|
#include "builder.hpp"
|
|
#include "vm.hpp"
|
|
#include <cstdint>
|
|
#include <print>
|
|
#include <utility>
|
|
|
|
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);
|
|
}
|