fxos/lib/lang.cpp

226 lines
4.0 KiB
C++

#include <fxos/lang.h>
#include <fxos/util.h>
#include <stdexcept>
#include <string>
#include <map>
namespace FxOS {
//---
// CPU registers
//---
using Reg = CpuRegister::CpuRegisterName;
static std::map<Reg, std::string> regnames = {
{ Reg::R0, "r0" },
{ Reg::R1, "r1" },
{ Reg::R2, "r2" },
{ Reg::R3, "r3" },
{ Reg::R4, "r4" },
{ Reg::R5, "r5" },
{ Reg::R6, "r6" },
{ Reg::R7, "r7" },
{ Reg::R0B, "r0_bank" },
{ Reg::R1B, "r1_bank" },
{ Reg::R2B, "r2_bank" },
{ Reg::R3B, "r3_bank" },
{ Reg::R4B, "r4_bank" },
{ Reg::R5B, "r5_bank" },
{ Reg::R6B, "r6_bank" },
{ Reg::R7B, "r7_bank" },
{ Reg::R8, "r8" },
{ Reg::R9, "r9" },
{ Reg::R10, "r10" },
{ Reg::R11, "r11" },
{ Reg::R12, "r12" },
{ Reg::R13, "r13" },
{ Reg::R14, "r14" },
{ Reg::R15, "r15" },
{ Reg::MACH, "mach" },
{ Reg::MACL, "macl" },
{ Reg::PR, "pr" },
{ Reg::PC, "pc" },
{ Reg::SR, "sr" },
{ Reg::SSR, "ssr" },
{ Reg::SPC, "spc" },
{ Reg::GBR, "gbr" },
{ Reg::VBR, "vbr" },
{ Reg::DBR, "dbr" },
{ Reg::SGR, "sgr" },
};
/* Construction from string - pretty slow */
CpuRegister::CpuRegister(std::string name)
{
for(auto it = regnames.begin(); it != regnames.end(); it++)
{
if(it->second == name)
{
m_name = it->first;
return;
}
}
throw std::invalid_argument("invalid CpuRegister name");
}
/* Conversion to string */
std::string CpuRegister::str() const noexcept
{
return regnames.at(m_name);
}
//---
// Instruction arguments
//---
/* External constructors */
Argument Argument_Reg(CpuRegister base)
{
Argument arg;
arg.kind = Argument::Reg;
arg.base = base;
return arg;
}
Argument Argument_Deref(CpuRegister base)
{
Argument arg;
arg.kind = Argument::Deref;
arg.base = base;
return arg;
}
Argument Argument_PostInc(CpuRegister base)
{
Argument arg;
arg.kind = Argument::PostInc;
arg.base = base;
return arg;
}
Argument Argument_PreDec(CpuRegister base)
{
Argument arg;
arg.kind = Argument::PreDec;
arg.base = base;
return arg;
}
Argument Argument_StructDeref(int disp, int opsize, CpuRegister base)
{
Argument arg;
arg.kind = Argument::StructDeref;
arg.base = base;
arg.disp = disp;
arg.opsize = opsize;
return arg;
}
Argument Argument_ArrayDeref(CpuRegister index, CpuRegister base)
{
Argument arg;
arg.kind = Argument::ArrayDeref;
arg.base = base;
arg.index = index;
return arg;
}
Argument Argument_PcRel(int disp, int opsize)
{
Argument arg;
arg.kind = Argument::PcRel;
arg.disp = disp;
arg.opsize = opsize;
return arg;
}
Argument Argument_PcJump(int disp)
{
Argument arg;
arg.kind = Argument::PcJump;
arg.disp = disp;
return arg;
}
Argument Argument_Imm(int imm)
{
Argument arg;
arg.kind = Argument::Imm;
arg.imm = imm;
return arg;
}
/* String representation */
std::string Argument::str() const
{
switch(kind)
{
case Argument::Reg:
return format("r%d", base);
case Argument::Deref:
return format("@r%d", base);
case Argument::PostInc:
return format("@r%d+", base);
case Argument::PreDec:
return format("@-%dr", base);
case Argument::StructDeref:
return format("@(%d,%s)", disp, base.str().c_str());
case Argument::ArrayDeref:
return format("@(%s,%s)", index.str().c_str(),
base.str().c_str());
case Argument::PcRel:
return format("@(%d,pc)", disp);
case Argument::PcJump:
return format("pc+%d", disp);
default:
return "(invalid)";
}
}
//---
// Instruction creation
//---
Instruction::Instruction(std::string mn):
opcode(0), opsize(0)
{
int pos = std::max(0, (int)mn.size() - 2);
if(mn.substr(pos, 2) == ".b")
{
opsize = 1;
mn.erase(pos, 2);
}
else if(mn.substr(pos, 2) == ".w")
{
opsize = 2;
mn.erase(pos, 2);
}
else if(mn.substr(pos, 2) == ".l")
{
opsize = 4;
mn.erase(pos, 2);
}
mnemonic = mn;
}
Instruction::Instruction(std::string mn, Argument arg):
Instruction(mn)
{
args.push_back(arg);
}
Instruction::Instruction(std::string mn, Argument arg1, Argument arg2):
Instruction(mn)
{
args.push_back(arg1);
args.push_back(arg2);
}
} /* namespace FxOS */