fxos/lib/lang.cpp

277 lines
5.9 KiB
C++
Raw Normal View History

//---------------------------------------------------------------------------//
// 1100101 |_ mov #0, r4 __ //
// 11 |_ <0xb380 %5c4> / _|_ _____ ___ //
// 0110 |_ 3.50 -> 3.60 | _\ \ / _ (_-< //
// |_ base# + offset |_| /_\_\___/__/ //
//---------------------------------------------------------------------------//
#include <fxos/lang.h>
2022-03-27 13:12:53 +02:00
#include <fxos/util/format.h>
#include <string>
#include <cstring>
namespace FxOS {
//---
// CPU registers
//---
char const *regnames[] = {
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
"r0_bank", "r1_bank", "r2_bank", "r3_bank",
"r4_bank", "r5_bank", "r6_bank", "r7_bank",
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
"mach", "macl", "pr", "pc",
"sr", "ssr", "spc", "gbr", "vbr", "dbr", "sgr"
};
/* Construction from string */
CpuRegister::CpuRegister(std::string name)
{
int regcount = (sizeof regnames / sizeof regnames[0]);
char const *name_c = name.c_str();
for(int i = 0; i < regcount; i++) {
if(!strcmp(regnames[i], name_c)) {
m_name = CpuRegisterName(i+1);
return;
}
}
m_name = CpuRegister::UNDEFINED;
}
/* Conversion to string */
std::string CpuRegister::str() const noexcept
{
int regcount = (sizeof regnames / sizeof regnames[0]);
int i = m_name - 1;
if(i < 0 || i >= regcount)
return format("<Register%d>", i+1);
return regnames[i];
}
//---
// 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_PcAddr(int disp)
{
Argument arg;
arg.kind = Argument::PcAddr;
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 base.str();
case Argument::Deref:
return format("@%s", base.str());
case Argument::PostInc:
return format("@%s+", base.str());
case Argument::PreDec:
return format("@-%s", base.str());
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);
case Argument::PcAddr:
return format("pc+%u", disp);
case Argument::Imm:
return format("#%d", imm);
default:
return "(invalid)";
}
}
//---
// Instruction management
//---
Instruction::Instruction(char const *mn):
opcode {0}, opsize {0}, arg_count {0}
{
int len = strlen(mn);
int pos = std::max(0, len - 2);
if(!strncmp(mn + pos, ".b", 2)) {
opsize = 1;
len -= 2;
}
else if(!strncmp(mn + pos, ".w", 2)) {
opsize = 2;
len -= 2;
}
else if(!strncmp(mn + pos, ".l", 2)) {
opsize = 4;
len -= 2;
}
len = std::min(len, 11);
strncpy(mnemonic, mn, len);
mnemonic[len] = 0;
}
Instruction::Instruction(char const *mn, Argument arg):
Instruction(mn)
{
args[0] = arg;
arg_count = 1;
}
Instruction::Instruction(char const *mn, Argument arg1, Argument arg2):
Instruction(mn)
{
args[0] = arg1;
args[1] = arg2;
arg_count = 2;
}
//---
// Instruction classes
//---
bool Instruction::isterminal() const noexcept
{
if(!strcmp(mnemonic, "rte") || !strcmp(mnemonic, "rts"))
return true;
/* Also jmp @rn which is regarded as a terminal call */
if(!strcmp(mnemonic,"jmp") && args[0].kind == Argument::Deref)
return true;
/* Same for braf because we can't analyse further */
if(!strcmp(mnemonic, "braf"))
return true;
return false;
}
bool Instruction::isjump() const noexcept
{
return !strcmp(mnemonic, "bra");
}
bool Instruction::iscondjump() const noexcept
{
char const *v[] = {
"bf", "bf.s", "bf/s", "bt", "bt.s", "bt/s", NULL,
};
for(int i = 0; v[i]; i++) {
if(!strcmp(mnemonic, v[i]))
return true;
}
return false;
}
bool Instruction::isdelayed() const noexcept
{
char const *v[] = {
"rte", "rts", "jmp", "jsr", "bra", "braf", "bsr", "bsrf",
"bf.s", "bf/s", "bt.s", "bt/s", NULL,
};
for(int i = 0; v[i]; i++) {
if(!strcmp(mnemonic, v[i]))
return true;
}
return false;
}
bool Instruction::isvaliddelayslot() const noexcept
{
return !isdelayed() && !isterminal() && !isjump() && !iscondjump();
}
} /* namespace FxOS */