#pragma once #include "Utilities/BitField.h" union spu_opcode_t { u32 opcode; bf_t rt; // 25..31, for 3-op instructions bf_t rc; // 25..31 bf_t ra; // 18..24 bf_t rb; // 11..17 bf_t rt4; // 4..10, for 4-op instructions bf_t e; // 13, "enable interrupts" bit bf_t d; // 12, "disable interrupts" bit bf_t de; // 12..13 combined 'e' and 'd' bits bf_t c; // 11, "C" bit for SYNC instruction bf_t r0h; // 7..8, signed bf_t roh; // 16..17, signed bf_t i7; // 11..17 bf_t si7; // 11..17, signed bf_t i8; // 10..17 bf_t si10; // 8..17, signed bf_t i16; // 9..24 bf_t si16; // 9..24, signed bf_t i18; // 7..24 }; inline u32 spu_branch_target(u32 pc, u32 imm = 0) { return (pc + (imm << 2)) & 0x3fffc; } inline u32 spu_ls_target(u32 pc, u32 imm = 0) { return (pc + (imm << 2)) & 0x3fff0; } inline u32 spu_decode(u32 inst) { return inst >> 21; } std::array op_branch_targets(u32 pc, spu_opcode_t op); // SPU decoder object. D provides functions. T is function pointer type returned. template class spu_decoder { // Fast lookup table std::array m_table{}; struct instruction_info { u32 magn; // Count = 2 ^ magn u32 value; T pointer; instruction_info(u32 m, u32 v, T p) noexcept : magn(m) , value(v) , pointer(p) { } instruction_info(u32 m, u32 v, const T* p) noexcept : magn(m) , value(v) , pointer(*p) { } }; // Helper static const D& _first(const D& arg) { return arg; } public: template spu_decoder(const Args&... args) noexcept { // If an object is passed to the constructor, assign values from that object #define GET(name) [&]{ if constexpr (sizeof...(Args) > 0) return _first(args...).name; else return &D::name; }() static_assert(sizeof...(Args) <= 1); const std::initializer_list instructions { { 0, 0x0, GET(STOP) }, { 0, 0x1, GET(LNOP) }, { 0, 0x2, GET(SYNC) }, { 0, 0x3, GET(DSYNC) }, { 0, 0xc, GET(MFSPR) }, { 0, 0xd, GET(RDCH) }, { 0, 0xf, GET(RCHCNT) }, { 0, 0x40, GET(SF) }, { 0, 0x41, GET(OR) }, { 0, 0x42, GET(BG) }, { 0, 0x48, GET(SFH) }, { 0, 0x49, GET(NOR) }, { 0, 0x53, GET(ABSDB) }, { 0, 0x58, GET(ROT) }, { 0, 0x59, GET(ROTM) }, { 0, 0x5a, GET(ROTMA) }, { 0, 0x5b, GET(SHL) }, { 0, 0x5c, GET(ROTH) }, { 0, 0x5d, GET(ROTHM) }, { 0, 0x5e, GET(ROTMAH) }, { 0, 0x5f, GET(SHLH) }, { 0, 0x78, GET(ROTI) }, { 0, 0x79, GET(ROTMI) }, { 0, 0x7a, GET(ROTMAI) }, { 0, 0x7b, GET(SHLI) }, { 0, 0x7c, GET(ROTHI) }, { 0, 0x7d, GET(ROTHMI) }, { 0, 0x7e, GET(ROTMAHI) }, { 0, 0x7f, GET(SHLHI) }, { 0, 0xc0, GET(A) }, { 0, 0xc1, GET(AND) }, { 0, 0xc2, GET(CG) }, { 0, 0xc8, GET(AH) }, { 0, 0xc9, GET(NAND) }, { 0, 0xd3, GET(AVGB) }, { 0, 0x10c, GET(MTSPR) }, { 0, 0x10d, GET(WRCH) }, { 0, 0x128, GET(BIZ) }, { 0, 0x129, GET(BINZ) }, { 0, 0x12a, GET(BIHZ) }, { 0, 0x12b, GET(BIHNZ) }, { 0, 0x140, GET(STOPD) }, { 0, 0x144, GET(STQX) }, { 0, 0x1a8, GET(BI) }, { 0, 0x1a9, GET(BISL) }, { 0, 0x1aa, GET(IRET) }, { 0, 0x1ab, GET(BISLED) }, { 0, 0x1ac, GET(HBR) }, { 0, 0x1b0, GET(GB) }, { 0, 0x1b1, GET(GBH) }, { 0, 0x1b2, GET(GBB) }, { 0, 0x1b4, GET(FSM) }, { 0, 0x1b5, GET(FSMH) }, { 0, 0x1b6, GET(FSMB) }, { 0, 0x1b8, GET(FREST) }, { 0, 0x1b9, GET(FRSQEST) }, { 0, 0x1c4, GET(LQX) }, { 0, 0x1cc, GET(ROTQBYBI) }, { 0, 0x1cd, GET(ROTQMBYBI) }, { 0, 0x1cf, GET(SHLQBYBI) }, { 0, 0x1d4, GET(CBX) }, { 0, 0x1d5, GET(CHX) }, { 0, 0x1d6, GET(CWX) }, { 0, 0x1d7, GET(CDX) }, { 0, 0x1d8, GET(ROTQBI) }, { 0, 0x1d9, GET(ROTQMBI) }, { 0, 0x1db, GET(SHLQBI) }, { 0, 0x1dc, GET(ROTQBY) }, { 0, 0x1dd, GET(ROTQMBY) }, { 0, 0x1df, GET(SHLQBY) }, { 0, 0x1f0, GET(ORX) }, { 0, 0x1f4, GET(CBD) }, { 0, 0x1f5, GET(CHD) }, { 0, 0x1f6, GET(CWD) }, { 0, 0x1f7, GET(CDD) }, { 0, 0x1f8, GET(ROTQBII) }, { 0, 0x1f9, GET(ROTQMBII) }, { 0, 0x1fb, GET(SHLQBII) }, { 0, 0x1fc, GET(ROTQBYI) }, { 0, 0x1fd, GET(ROTQMBYI) }, { 0, 0x1ff, GET(SHLQBYI) }, { 0, 0x201, GET(NOP) }, { 0, 0x240, GET(CGT) }, { 0, 0x241, GET(XOR) }, { 0, 0x248, GET(CGTH) }, { 0, 0x249, GET(EQV) }, { 0, 0x250, GET(CGTB) }, { 0, 0x253, GET(SUMB) }, { 0, 0x258, GET(HGT) }, { 0, 0x2a5, GET(CLZ) }, { 0, 0x2a6, GET(XSWD) }, { 0, 0x2ae, GET(XSHW) }, { 0, 0x2b4, GET(CNTB) }, { 0, 0x2b6, GET(XSBH) }, { 0, 0x2c0, GET(CLGT) }, { 0, 0x2c1, GET(ANDC) }, { 0, 0x2c2, GET(FCGT) }, { 0, 0x2c3, GET(DFCGT) }, { 0, 0x2c4, GET(FA) }, { 0, 0x2c5, GET(FS) }, { 0, 0x2c6, GET(FM) }, { 0, 0x2c8, GET(CLGTH) }, { 0, 0x2c9, GET(ORC) }, { 0, 0x2ca, GET(FCMGT) }, { 0, 0x2cb, GET(DFCMGT) }, { 0, 0x2cc, GET(DFA) }, { 0, 0x2cd, GET(DFS) }, { 0, 0x2ce, GET(DFM) }, { 0, 0x2d0, GET(CLGTB) }, { 0, 0x2d8, GET(HLGT) }, { 0, 0x35c, GET(DFMA) }, { 0, 0x35d, GET(DFMS) }, { 0, 0x35e, GET(DFNMS) }, { 0, 0x35f, GET(DFNMA) }, { 0, 0x3c0, GET(CEQ) }, { 0, 0x3ce, GET(MPYHHU) }, { 0, 0x340, GET(ADDX) }, { 0, 0x341, GET(SFX) }, { 0, 0x342, GET(CGX) }, { 0, 0x343, GET(BGX) }, { 0, 0x346, GET(MPYHHA) }, { 0, 0x34e, GET(MPYHHAU) }, { 0, 0x398, GET(FSCRRD) }, { 0, 0x3b8, GET(FESD) }, { 0, 0x3b9, GET(FRDS) }, { 0, 0x3ba, GET(FSCRWR) }, { 0, 0x3bf, GET(DFTSV) }, { 0, 0x3c2, GET(FCEQ) }, { 0, 0x3c3, GET(DFCEQ) }, { 0, 0x3c4, GET(MPY) }, { 0, 0x3c5, GET(MPYH) }, { 0, 0x3c6, GET(MPYHH) }, { 0, 0x3c7, GET(MPYS) }, { 0, 0x3c8, GET(CEQH) }, { 0, 0x3ca, GET(FCMEQ) }, { 0, 0x3cb, GET(DFCMEQ) }, { 0, 0x3cc, GET(MPYU) }, { 0, 0x3d0, GET(CEQB) }, { 0, 0x3d4, GET(FI) }, { 0, 0x3d8, GET(HEQ) }, { 1, 0x1d8, GET(CFLTS) }, { 1, 0x1d9, GET(CFLTU) }, { 1, 0x1da, GET(CSFLT) }, { 1, 0x1db, GET(CUFLT) }, { 2, 0x40, GET(BRZ) }, { 2, 0x41, GET(STQA) }, { 2, 0x42, GET(BRNZ) }, { 2, 0x44, GET(BRHZ) }, { 2, 0x46, GET(BRHNZ) }, { 2, 0x47, GET(STQR) }, { 2, 0x60, GET(BRA) }, { 2, 0x61, GET(LQA) }, { 2, 0x62, GET(BRASL) }, { 2, 0x64, GET(BR) }, { 2, 0x65, GET(FSMBI) }, { 2, 0x66, GET(BRSL) }, { 2, 0x67, GET(LQR) }, { 2, 0x81, GET(IL) }, { 2, 0x82, GET(ILHU) }, { 2, 0x83, GET(ILH) }, { 2, 0xc1, GET(IOHL) }, { 3, 0x4, GET(ORI) }, { 3, 0x5, GET(ORHI) }, { 3, 0x6, GET(ORBI) }, { 3, 0xc, GET(SFI) }, { 3, 0xd, GET(SFHI) }, { 3, 0x14, GET(ANDI) }, { 3, 0x15, GET(ANDHI) }, { 3, 0x16, GET(ANDBI) }, { 3, 0x1c, GET(AI) }, { 3, 0x1d, GET(AHI) }, { 3, 0x24, GET(STQD) }, { 3, 0x34, GET(LQD) }, { 3, 0x44, GET(XORI) }, { 3, 0x45, GET(XORHI) }, { 3, 0x46, GET(XORBI) }, { 3, 0x4c, GET(CGTI) }, { 3, 0x4d, GET(CGTHI) }, { 3, 0x4e, GET(CGTBI) }, { 3, 0x4f, GET(HGTI) }, { 3, 0x5c, GET(CLGTI) }, { 3, 0x5d, GET(CLGTHI) }, { 3, 0x5e, GET(CLGTBI) }, { 3, 0x5f, GET(HLGTI) }, { 3, 0x74, GET(MPYI) }, { 3, 0x75, GET(MPYUI) }, { 3, 0x7c, GET(CEQI) }, { 3, 0x7d, GET(CEQHI) }, { 3, 0x7e, GET(CEQBI) }, { 3, 0x7f, GET(HEQI) }, { 4, 0x8, GET(HBRA) }, { 4, 0x9, GET(HBRR) }, { 4, 0x21, GET(ILA) }, { 7, 0x8, GET(SELB) }, { 7, 0xb, GET(SHUFB) }, { 7, 0xc, GET(MPYA) }, { 7, 0xd, GET(FNMS) }, { 7, 0xe, GET(FMA) }, { 7, 0xf, GET(FMS) }, }; for (auto& x : m_table) { x = GET(UNK); } for (auto& entry : instructions) { for (u32 i = 0; i < 1u << entry.magn; i++) { m_table[entry.value << entry.magn | i] = entry.pointer; } } } const std::array& get_table() const noexcept { return m_table; } T decode(u32 inst) const noexcept { return m_table[spu_decode(inst)]; } }; #undef GET