187 lines
6.0 KiB
C++
187 lines
6.0 KiB
C++
//---------------------------------------------------------------------------//
|
|
// 1100101 |_ mov #0, r4 __ //
|
|
// 11 |_ <0xb380 %5c4> / _|_ _____ ___ //
|
|
// 0110 |_ 3.50 -> 3.60 | _\ \ / _ (_-< //
|
|
// |_ base# + offset |_| /_\_\___/__/ //
|
|
//---------------------------------------------------------------------------//
|
|
// fxos/lang: Assembler language syntax
|
|
//
|
|
// This file defines the syntactic tools needed to read and manipulate
|
|
// assembler instructions.
|
|
//
|
|
// The CpuRegister class is a glorified type-safe enumeration. Registers can be
|
|
// named, fi. CpuRegister::R0; they can be constructed from their lowercase
|
|
// name as a string, fi. CpuRegister("r0"); and they can be printed with the
|
|
// .str() method.
|
|
//
|
|
// The Argument struct represents an argument to an instruction. This is
|
|
// syntactic only; for instance Deref (@rn) does not mean that memory is
|
|
// accessed, since [jmp @rn] or [ocbwb @rn] do not actually access @rn.
|
|
// Constructor functions such as Argument_Deref() are provided.
|
|
//
|
|
// Finally, the Instruction struct represents an abstract instruction out of
|
|
// context. Each Instruction object only models one particular instance of one
|
|
// particular instruction, for instance [mov #14, r2] and not [mov #imm, rn].
|
|
// The rationale for this is disassembly speed and a number of simplifications
|
|
// for passes; and there are less than 65'000 non-DSP instructions anyway.
|
|
//---
|
|
|
|
#ifndef FXOS_LANG_H
|
|
#define FXOS_LANG_H
|
|
|
|
#include <string>
|
|
#include <cstdint>
|
|
|
|
namespace FxOS {
|
|
|
|
/* CPU register names, with a little meat for conversion to and from string */
|
|
class CpuRegister
|
|
{
|
|
public:
|
|
// clang-format off
|
|
enum CpuRegisterName: int8_t {
|
|
/* Value 0 is reserved for special purposes such as "no register" */
|
|
UNDEFINED = 0,
|
|
/* Caller-saved general-purpose registers */
|
|
R0, R1, R2, R3, R4, R5, R6, R7,
|
|
/* Banked general-purpose registers. fxos does not account for
|
|
banking identities, these are just for naming and output. */
|
|
R0B, R1B, R2B, R3B, R4B, R5B, R6B, R7B,
|
|
/* Callee-saved general-purpose registers */
|
|
R8, R9, R10, R11, R12, R13, R14, R15,
|
|
/* System registers */
|
|
MACH, MACL, PR, PC,
|
|
/* Control registers */
|
|
SR, SSR, SPC, GBR, VBR, DBR, SGR,
|
|
};
|
|
// clang-format on
|
|
|
|
CpuRegister() = default;
|
|
|
|
/* Construction from CpuRegisterName */
|
|
constexpr CpuRegister(CpuRegisterName name): m_name(name)
|
|
{
|
|
}
|
|
|
|
/* Construction from string */
|
|
CpuRegister(std::string register_name);
|
|
|
|
/* Conversion to string */
|
|
std::string str() const noexcept;
|
|
|
|
/* Conversion to CpuRegisterName for switch statements */
|
|
constexpr operator CpuRegisterName() noexcept
|
|
{
|
|
return m_name;
|
|
}
|
|
|
|
/* Comparison operators */
|
|
constexpr bool operator==(CpuRegister r) const
|
|
{
|
|
return m_name == r.m_name;
|
|
}
|
|
constexpr bool operator!=(CpuRegister r) const
|
|
{
|
|
return m_name != r.m_name;
|
|
}
|
|
|
|
private:
|
|
CpuRegisterName m_name;
|
|
};
|
|
|
|
/* Addressing modes for arguments */
|
|
struct AsmArgument
|
|
{
|
|
/* Various addressing modes in the language */
|
|
enum Kind : int8_t {
|
|
Reg, /* rn */
|
|
Deref, /* @rn */
|
|
PostInc, /* @rn+ */
|
|
PreDec, /* @-rn */
|
|
StructDeref, /* @(disp,rn) or @(disp,gbr) */
|
|
ArrayDeref, /* @(r0,rn) or @(r0,gbr) */
|
|
PcRel, /* @(disp,pc) with 4-alignment correction */
|
|
PcJump, /* pc+disp */
|
|
PcAddr, /* pc+disp (the address itself, for mova) */
|
|
Imm, /* #imm */
|
|
};
|
|
|
|
AsmArgument() = default;
|
|
|
|
/* String representation */
|
|
std::string str() const;
|
|
|
|
/* Addressing mode */
|
|
Kind kind;
|
|
/* Base register. Valid for all modes except Imm */
|
|
CpuRegister base;
|
|
/* Index register. Valid for ArrayDeref */
|
|
CpuRegister index;
|
|
/* Operation size (0, 1, 2 or 4). Generally a multiplier for disp */
|
|
int8_t opsize;
|
|
|
|
union
|
|
{
|
|
/* Displacement in bytes. For StructDeref, PcRel, PcJump, and PcAddr */
|
|
int disp;
|
|
/* Immediate value. Valid for Imm */
|
|
int imm;
|
|
};
|
|
};
|
|
|
|
/* AsmArgument constructors */
|
|
|
|
AsmArgument AsmArgument_Reg(CpuRegister base);
|
|
AsmArgument AsmArgument_Deref(CpuRegister base);
|
|
AsmArgument AsmArgument_PostInc(CpuRegister base);
|
|
AsmArgument AsmArgument_PreDec(CpuRegister base);
|
|
AsmArgument AsmArgument_StructDeref(int disp, int opsize, CpuRegister base);
|
|
AsmArgument AsmArgument_ArrayDeref(CpuRegister index, CpuRegister base);
|
|
AsmArgument AsmArgument_PcRel(int disp, int opsize);
|
|
AsmArgument AsmArgument_PcJump(int disp);
|
|
AsmArgument AsmArgument_PcAddr(int disp);
|
|
AsmArgument AsmArgument_Imm(int imm);
|
|
|
|
/* Assembler instruction */
|
|
struct AsmInstruction
|
|
{
|
|
AsmInstruction() = default;
|
|
|
|
/* Construct with one or several arguments */
|
|
AsmInstruction(char const *mnemonic);
|
|
AsmInstruction(char const *mnemonic, AsmArgument arg);
|
|
AsmInstruction(char const *mnemonic, AsmArgument arg1, AsmArgument arg2);
|
|
|
|
/* Original opcode. Initialized to 0 when unset, which is an invalid
|
|
instruction by design. */
|
|
uint16_t opcode;
|
|
/* Operation size (0, 1, 2 or 4) */
|
|
int8_t opsize;
|
|
/* Number of arguments */
|
|
uint8_t arg_count;
|
|
|
|
/* Mnemonic **without the size indicator** */
|
|
char mnemonic[12];
|
|
/* Arguments (up to 2) */
|
|
AsmArgument args[2];
|
|
|
|
//---
|
|
// Instruction classes
|
|
//---
|
|
|
|
/* Check whether instruction terminates the function */
|
|
bool isterminal() const noexcept;
|
|
/* Check whether instruction is an unconditional jump */
|
|
bool isjump() const noexcept;
|
|
/* Check whether it's a conditional jump */
|
|
bool iscondjump() const noexcept;
|
|
/* Check whether instruction has a delay slot */
|
|
bool isdelayed() const noexcept;
|
|
/* Check whether instruction can be used in a delay slot */
|
|
bool isvaliddelayslot() const noexcept;
|
|
};
|
|
|
|
} /* namespace FxOS */
|
|
|
|
#endif /* FXOS_LANG_H */
|