fix
This commit is contained in:
parent
3116ec1a13
commit
65713e6b9f
222
src/builder.cpp
222
src/builder.cpp
@ -1,185 +1,329 @@
|
|||||||
#include "builder.hpp"
|
#include "builder.hpp"
|
||||||
#include "vm.hpp"
|
#include "vm.hpp"
|
||||||
|
#include <cstdint>
|
||||||
|
#include <print>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
using namespace vc5;
|
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()
|
void Builder::nop()
|
||||||
{
|
{
|
||||||
auto ins = std::to_underlying(Op::Nop);
|
auto i = InsBuilder(Op::Nop);
|
||||||
push(ins);
|
i.build(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Builder::hlt()
|
void Builder::hlt()
|
||||||
{
|
{
|
||||||
auto ins = std::to_underlying(Op::Nop);
|
auto i = InsBuilder(Op::Hlt);
|
||||||
push(ins);
|
i.build(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Builder::jmp_reg(Reg op1)
|
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)
|
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)
|
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)
|
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::store_byte_imm(uint16_t dst, Reg op2)
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
|
auto i = InsBuilder(Op::StoreByte);
|
||||||
|
i.imm(dst);
|
||||||
|
i.op2_reg(op2);
|
||||||
|
i.build(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Builder::cmp_reg(Reg op1, Reg op2)
|
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)
|
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)
|
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)
|
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)
|
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)
|
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)
|
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)
|
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)
|
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)
|
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)
|
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)
|
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)
|
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)
|
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)
|
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)
|
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)
|
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)
|
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)
|
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)
|
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)
|
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);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,9 +2,12 @@
|
|||||||
|
|
||||||
#include "vm.hpp"
|
#include "vm.hpp"
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <print>
|
||||||
|
|
||||||
namespace vc5 {
|
namespace vc5 {
|
||||||
|
|
||||||
|
using namespace vc5;
|
||||||
|
|
||||||
class Builder {
|
class Builder {
|
||||||
public:
|
public:
|
||||||
Builder(uint8_t* data)
|
Builder(uint8_t* data)
|
||||||
@ -18,24 +21,18 @@ public:
|
|||||||
void jmp_imm(uint16_t op1);
|
void jmp_imm(uint16_t op1);
|
||||||
void jnz_reg(Reg op1, Reg op2);
|
void jnz_reg(Reg op1, Reg op2);
|
||||||
void jnz_imm(Reg op1, uint16_t op2);
|
void jnz_imm(Reg op1, uint16_t op2);
|
||||||
void mov_word_load_reg(Reg dst, Reg src);
|
void mov_reg(Reg dst, Reg src);
|
||||||
void mov_word_load_imm(Reg dst, uint16_t imm);
|
void mov_imm(Reg dst, uint16_t imm);
|
||||||
void mov_word_load_mem_reg(Reg dst, Reg addr, uint16_t offset);
|
void load_word_reg(Reg dst, Reg addr, uint16_t offset);
|
||||||
void mov_word_load_mem_imm(Reg dst, uint16_t addr);
|
void load_word_imm(Reg dst, uint16_t addr);
|
||||||
void mov_word_store_reg_reg(Reg dst, uint16_t offset, Reg op2);
|
void store_word_reg(Reg dst, uint16_t offset, Reg op2);
|
||||||
void mov_word_store_reg_imm(Reg dst, uint16_t offset, uint16_t op2);
|
void store_word_imm(uint16_t dst, Reg op2);
|
||||||
void mov_word_store_imm_reg(uint16_t dst, Reg op2);
|
void load_byte_reg(Reg dst, Reg addr, uint16_t offset);
|
||||||
void mov_word_store_imm_imm(uint16_t dst, uint16_t op2);
|
void load_byte_imm(Reg dst, uint16_t addr);
|
||||||
void mov_byte_load_reg(Reg dst, Reg src);
|
void store_byte_reg(Reg dst, uint16_t offset, Reg op2);
|
||||||
void mov_byte_load_imm(Reg dst, uint8_t imm);
|
void store_byte_imm(uint16_t dst, Reg op2);
|
||||||
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 cmp_reg(Reg op1, 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 or_reg(Reg dst, Reg op1, Reg op2);
|
||||||
void and_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);
|
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 sub_imm(Reg dst, Reg op1, uint16_t op2);
|
||||||
void rsub_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)
|
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_data[m_ip + 1] = v & 0xff;
|
||||||
m_ip += 2;
|
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;
|
uint8_t* m_data;
|
||||||
size_t m_ip = 0;
|
size_t m_ip = 0;
|
||||||
};
|
};
|
||||||
|
|||||||
62
src/main.cpp
62
src/main.cpp
@ -1,6 +1,66 @@
|
|||||||
|
#include "builder.hpp"
|
||||||
|
#include <array>
|
||||||
|
#include <cstdint>
|
||||||
#include <print>
|
#include <print>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
using namespace vc5;
|
||||||
|
using R = Reg;
|
||||||
|
|
||||||
int main()
|
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<uint8_t, 65535>();
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
184
src/vm.cpp
184
src/vm.cpp
@ -4,6 +4,26 @@
|
|||||||
|
|
||||||
using namespace vc5;
|
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<int16_t>(imm);
|
||||||
|
if (offset >= 0) {
|
||||||
|
return base + static_cast<uint16_t>(offset);
|
||||||
|
} else {
|
||||||
|
return base - static_cast<uint16_t>(-offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
int VM::run()
|
int VM::run()
|
||||||
{
|
{
|
||||||
m_halted = false;
|
m_halted = false;
|
||||||
@ -17,8 +37,17 @@ int VM::run()
|
|||||||
|
|
||||||
int VM::run_instruction()
|
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<Op>(ins & 0b11'1111);
|
auto op = static_cast<Op>(ins & 0b11'1111);
|
||||||
|
std::println("[{: 4x}]: {:04x} {}, r0 = {}",
|
||||||
|
ip,
|
||||||
|
ins.operator uint16_t(),
|
||||||
|
op_str(op),
|
||||||
|
m_regs[reg_id(Reg::R0)]);
|
||||||
|
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case Op::Nop:
|
case Op::Nop:
|
||||||
@ -40,85 +69,57 @@ int VM::run_instruction()
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Op::MovWord: {
|
case Op::Mov: {
|
||||||
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<uint16_t>(ins >> 12 & 0b1111);
|
auto dst = static_cast<uint16_t>(ins >> 12 & 0b1111);
|
||||||
|
auto src = ins.reg_val_or_imm(6, 7, 0b1111);
|
||||||
m_regs[dst] = src;
|
m_regs[dst] = src;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case Op::LoadWord: {
|
||||||
uint16_t addr;
|
auto addr = mem_addr(ins, eat());
|
||||||
if (addr_is_reg) {
|
|
||||||
auto reg = is_store ? ins.dst_reg() : ins.op2_reg();
|
|
||||||
auto offset = static_cast<int16_t>(eat());
|
|
||||||
addr = static_cast<uint16_t>(
|
|
||||||
static_cast<int16_t>(m_regs[reg]) + offset);
|
|
||||||
} else {
|
|
||||||
addr = eat();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((addr & 0b1) != 0) {
|
if ((addr & 0b1) != 0) {
|
||||||
std::println(stderr, "error: invalid address alignment");
|
std::println(stderr, "error: invalid address alignment");
|
||||||
*m_rfl |= 1 << flag(Flag::Err);
|
*m_rfl |= 1 << flag_id(Flag::Err);
|
||||||
goto halt_execution;
|
goto halt_execution;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_store) {
|
auto reg = ins.dst_reg();
|
||||||
auto src = ins.op2_or_imm();
|
|
||||||
|
uint16_t value = 0;
|
||||||
|
value |= static_cast<uint16_t>(m_mem[addr]) << 16;
|
||||||
|
value |= m_mem[addr + 1];
|
||||||
|
|
||||||
|
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] = src >> 16;
|
||||||
m_mem[addr + 1] = src & 0xff;
|
m_mem[addr + 1] = src & 0xff;
|
||||||
} else {
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op::LoadByte: {
|
||||||
|
auto addr = mem_addr(ins, eat());
|
||||||
auto reg = ins.dst_reg();
|
auto reg = ins.dst_reg();
|
||||||
|
|
||||||
uint16_t value = 0;
|
m_regs[reg] = m_mem[addr];
|
||||||
value |= static_cast<uint16_t>(m_mem[addr]) << 16;
|
|
||||||
value |= m_mem[addr + 1];
|
|
||||||
|
|
||||||
m_regs[reg] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Op::MovByte: {
|
case Op::StoreByte: {
|
||||||
bool is_memory = ins >> 10 & 1;
|
auto addr = mem_addr(ins, eat());
|
||||||
bool addr_is_reg = ins >> 11 & 1;
|
auto src = ins.op2();
|
||||||
bool is_store = ins >> 12 & 1;
|
|
||||||
|
|
||||||
if (!is_memory) {
|
|
||||||
auto src = ins.reg_val_or_imm(6, 7, 0b1111);
|
|
||||||
auto dst = static_cast<uint16_t>(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<int16_t>(eat());
|
|
||||||
addr = static_cast<uint16_t>(
|
|
||||||
static_cast<int16_t>(m_regs[reg]) + offset);
|
|
||||||
} else {
|
|
||||||
addr = eat();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_store) {
|
|
||||||
auto src = ins.op2_or_imm();
|
|
||||||
m_mem[addr] = src & 0xff;
|
m_mem[addr] = src & 0xff;
|
||||||
} else {
|
|
||||||
auto reg = ins.dst_reg();
|
|
||||||
|
|
||||||
uint16_t value = 0;
|
|
||||||
value |= static_cast<uint16_t>(m_mem[addr]) << 16;
|
|
||||||
value |= m_mem[addr + 1];
|
|
||||||
|
|
||||||
m_regs[reg] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Op::Cmp: {
|
case Op::Cmp: {
|
||||||
@ -126,19 +127,19 @@ int VM::run_instruction()
|
|||||||
auto op2 = ins.op2_or_imm();
|
auto op2 = ins.op2_or_imm();
|
||||||
|
|
||||||
if (op1 == op2) {
|
if (op1 == op2) {
|
||||||
*m_rfl |= 1u << flag(Flag::Eq);
|
*m_rfl |= 1u << flag_id(Flag::Eq);
|
||||||
} else {
|
} else {
|
||||||
*m_rfl &= (uint16_t)~(1u << flag(Flag::Eq));
|
*m_rfl &= (uint16_t)~(1u << flag_id(Flag::Eq));
|
||||||
}
|
}
|
||||||
if (op1 < op2) {
|
if (op1 < op2) {
|
||||||
*m_rfl |= 1u << flag(Flag::Be);
|
*m_rfl |= 1u << flag_id(Flag::Be);
|
||||||
} else {
|
} 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) {
|
if ((int16_t)op1 < (int16_t)op2) {
|
||||||
*m_rfl |= 1u << flag(Flag::Lt);
|
*m_rfl |= 1u << flag_id(Flag::Lt);
|
||||||
} else {
|
} else {
|
||||||
*m_rfl &= (uint16_t)~(1u << flag(Flag::Lt));
|
*m_rfl &= (uint16_t)~(1u << flag_id(Flag::Lt));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -200,3 +201,50 @@ int VM::run_instruction()
|
|||||||
halt_execution:
|
halt_execution:
|
||||||
return 0;
|
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 ">.<";
|
||||||
|
}
|
||||||
|
|||||||
113
src/vm.hpp
113
src/vm.hpp
@ -3,6 +3,8 @@
|
|||||||
#include <array>
|
#include <array>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <cstring>
|
||||||
|
#include <span>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
namespace vc5 {
|
namespace vc5 {
|
||||||
@ -12,8 +14,11 @@ enum class Op : uint16_t {
|
|||||||
Hlt,
|
Hlt,
|
||||||
Jmp,
|
Jmp,
|
||||||
Jnz,
|
Jnz,
|
||||||
MovWord,
|
Mov,
|
||||||
MovByte,
|
LoadWord,
|
||||||
|
StoreWord,
|
||||||
|
LoadByte,
|
||||||
|
StoreByte,
|
||||||
Cmp,
|
Cmp,
|
||||||
Or,
|
Or,
|
||||||
And,
|
And,
|
||||||
@ -27,6 +32,8 @@ enum class Op : uint16_t {
|
|||||||
RSub,
|
RSub,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const char* op_str(Op op);
|
||||||
|
|
||||||
enum class Reg : uint16_t {
|
enum class Reg : uint16_t {
|
||||||
R0 = 0,
|
R0 = 0,
|
||||||
R1 = 1,
|
R1 = 1,
|
||||||
@ -48,12 +55,71 @@ enum class Flag : uint16_t {
|
|||||||
Err = 4,
|
Err = 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Ins;
|
||||||
|
|
||||||
class VM {
|
class VM {
|
||||||
public:
|
public:
|
||||||
|
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<uint16_t>(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<uint16_t>(m_mem[*m_rip]) << 8;
|
||||||
|
ins |= m_mem[*m_rip + 1];
|
||||||
|
*m_rip += 2;
|
||||||
|
return ins;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::array<uint8_t, 65536> m_mem = {};
|
||||||
|
std::array<uint16_t, 10> m_regs = {};
|
||||||
|
|
||||||
|
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 {
|
struct Ins {
|
||||||
Ins(VM& vm, uint16_t ins)
|
Ins(VM& vm)
|
||||||
: vm(&vm)
|
: vm(&vm)
|
||||||
, ins(ins)
|
, ins(vm.eat())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,43 +179,4 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
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;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user