277 lines
5.9 KiB
C++
277 lines
5.9 KiB
C++
//---------------------------------------------------------------------------//
|
|
// 1100101 |_ mov #0, r4 __ //
|
|
// 11 |_ <0xb380 %5c4> / _|_ _____ ___ //
|
|
// 0110 |_ 3.50 -> 3.60 | _\ \ / _ (_-< //
|
|
// |_ base# + offset |_| /_\_\___/__/ //
|
|
//---------------------------------------------------------------------------//
|
|
|
|
#include <fxos/lang.h>
|
|
#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 */
|