#pragma once #include "util/BitField.h" template using ppu_bf_t = bf_t; union ppu_opcode_t { u32 opcode; ppu_bf_t main; // 0..5 cf_t, ppu_bf_t> sh64; // 30 + 16..20 cf_t, ppu_bf_t> mbe64; // 26 + 21..25 ppu_bf_t vuimm; // 11..15 ppu_bf_t vs; // 6..10 ppu_bf_t vsh; // 22..25 ppu_bf_t oe; // 21 ppu_bf_t spr; // 11..20 ppu_bf_t vc; // 21..25 ppu_bf_t vb; // 16..20 ppu_bf_t va; // 11..15 ppu_bf_t vd; // 6..10 ppu_bf_t lk; // 31 ppu_bf_t aa; // 30 ppu_bf_t rb; // 16..20 ppu_bf_t ra; // 11..15 ppu_bf_t rd; // 6..10 ppu_bf_t uimm16; // 16..31 ppu_bf_t l11; // 11 ppu_bf_t rs; // 6..10 ppu_bf_t simm16; // 16..31, signed ppu_bf_t ds; // 16..29, signed ppu_bf_t vsimm; // 11..15, signed ppu_bf_t ll; // 6..31, signed ppu_bf_t li; // 6..29, signed ppu_bf_t lev; // 20..26 ppu_bf_t i; // 16..19 ppu_bf_t crfs; // 11..13 ppu_bf_t l10; // 10 ppu_bf_t crfd; // 6..8 ppu_bf_t crbb; // 16..20 ppu_bf_t crba; // 11..15 ppu_bf_t crbd; // 6..10 ppu_bf_t rc; // 31 ppu_bf_t me32; // 26..30 ppu_bf_t mb32; // 21..25 ppu_bf_t sh32; // 16..20 ppu_bf_t bi; // 11..15 ppu_bf_t bo; // 6..10 ppu_bf_t bh; // 19..20 ppu_bf_t frc; // 21..25 ppu_bf_t frb; // 16..20 ppu_bf_t fra; // 11..15 ppu_bf_t frd; // 6..10 ppu_bf_t crm; // 12..19 ppu_bf_t frs; // 6..10 ppu_bf_t flm; // 7..14 ppu_bf_t l6; // 6 ppu_bf_t l15; // 15 cf_t, ff_t> bt14; cf_t, ff_t> bt24; }; constexpr u64 ppu_rotate_mask(u32 mb, u32 me) { const u64 mask = ~0ull << (~(me - mb) & 63); return (mask >> (mb & 63)) | (mask << ((64 - mb) & 63)); } constexpr u32 ppu_decode(u32 inst) { return ((inst >> 26) | (inst << 6)) & 0x1ffff; // Rotate + mask } std::array op_branch_targets(u32 pc, ppu_opcode_t op); // PPU decoder object. D provides functions. T is function pointer type returned. template class ppu_decoder { // Fast lookup table std::array m_table{}; struct instruction_info { u32 value; T ptr0; T ptr_rc; u32 magn; // Non-zero for "columns" (effectively, number of most significant bits "eaten") constexpr instruction_info(u32 v, T p, T p_rc, u32 m = 0) : value(v), ptr0(p), ptr_rc(p_rc), magn(m) { } constexpr instruction_info(u32 v, const T* p, const T* p_rc, u32 m = 0) : value(v), ptr0(*p), ptr_rc(*p_rc), magn(m) { } }; // Fill lookup table void fill_table(u32 main_op, u32 count, u32 sh, std::initializer_list entries) noexcept { if (sh < 11) { for (const auto& v : entries) { for (u32 i = 0; i < 1u << (v.magn + (11 - sh - count)); i++) { for (u32 j = 0; j < 1u << sh; j++) { const u32 k = (((i << (count - v.magn)) | v.value) << sh) | j; ::at32(m_table, (k << 6) | main_op) = k & 1 ? v.ptr_rc : v.ptr0; } } } } else { // Main table (special case) for (const auto& v : entries) { for (u32 i = 0; i < 1u << 11; i++) { ::at32(m_table, i << 6 | v.value) = i & 1 ? v.ptr_rc : v.ptr0; } } } } // Helper static const D& _first(const D& arg) { return arg; } public: template ppu_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; \ }() #define GET(name) GET_(name), GET_(name) #define GETRC(name) GET_(name), GET_(name##_) static_assert(sizeof...(Args) <= 1); for (auto& x : m_table) { x = GET(UNK); } // Main opcodes (field 0..5) fill_table(0x00, 6, -1, { {0x02, GET(TDI)}, {0x03, GET(TWI)}, {0x07, GET(MULLI)}, {0x08, GET(SUBFIC)}, {0x0a, GET(CMPLI)}, {0x0b, GET(CMPI)}, {0x0c, GET(ADDIC)}, {0x0d, GET(ADDIC)}, {0x0e, GET(ADDI)}, {0x0f, GET(ADDIS)}, {0x10, GET(BC)}, {0x11, GET(SC)}, {0x12, GET(B)}, {0x14, GETRC(RLWIMI)}, {0x15, GETRC(RLWINM)}, {0x17, GETRC(RLWNM)}, {0x18, GET(ORI)}, {0x19, GET(ORIS)}, {0x1a, GET(XORI)}, {0x1b, GET(XORIS)}, {0x1c, GET(ANDI)}, {0x1d, GET(ANDIS)}, {0x20, GET(LWZ)}, {0x21, GET(LWZU)}, {0x22, GET(LBZ)}, {0x23, GET(LBZU)}, {0x24, GET(STW)}, {0x25, GET(STWU)}, {0x26, GET(STB)}, {0x27, GET(STBU)}, {0x28, GET(LHZ)}, {0x29, GET(LHZU)}, {0x2a, GET(LHA)}, {0x2b, GET(LHAU)}, {0x2c, GET(STH)}, {0x2d, GET(STHU)}, {0x2e, GET(LMW)}, {0x2f, GET(STMW)}, {0x30, GET(LFS)}, {0x31, GET(LFSU)}, {0x32, GET(LFD)}, {0x33, GET(LFDU)}, {0x34, GET(STFS)}, {0x35, GET(STFSU)}, {0x36, GET(STFD)}, {0x37, GET(STFDU)}, }); // Group 0x04 opcodes (field 21..31) fill_table(0x04, 11, 0, { {0x0, GET(VADDUBM)}, {0x2, GET(VMAXUB)}, {0x4, GET(VRLB)}, {0x006, GET(VCMPEQUB)}, {0x406, GET(VCMPEQUB_)}, {0x8, GET(VMULOUB)}, {0xa, GET(VADDFP)}, {0xc, GET(VMRGHB)}, {0xe, GET(VPKUHUM)}, {0x20, GET(VMHADDSHS), 5}, {0x21, GET(VMHRADDSHS), 5}, {0x22, GET(VMLADDUHM), 5}, {0x24, GET(VMSUMUBM), 5}, {0x25, GET(VMSUMMBM), 5}, {0x26, GET(VMSUMUHM), 5}, {0x27, GET(VMSUMUHS), 5}, {0x28, GET(VMSUMSHM), 5}, {0x29, GET(VMSUMSHS), 5}, {0x2a, GET(VSEL), 5}, {0x2b, GET(VPERM), 5}, {0x2c, GET(VSLDOI), 5}, {0x2e, GET(VMADDFP), 5}, {0x2f, GET(VNMSUBFP), 5}, {0x40, GET(VADDUHM)}, {0x42, GET(VMAXUH)}, {0x44, GET(VRLH)}, {0x046, GET(VCMPEQUH)}, {0x446, GET(VCMPEQUH_)}, {0x48, GET(VMULOUH)}, {0x4a, GET(VSUBFP)}, {0x4c, GET(VMRGHH)}, {0x4e, GET(VPKUWUM)}, {0x80, GET(VADDUWM)}, {0x82, GET(VMAXUW)}, {0x84, GET(VRLW)}, {0x086, GET(VCMPEQUW)}, {0x486, GET(VCMPEQUW_)}, {0x8c, GET(VMRGHW)}, {0x8e, GET(VPKUHUS)}, {0x0c6, GET(VCMPEQFP)}, {0x4c6, GET(VCMPEQFP_)}, {0xce, GET(VPKUWUS)}, {0x102, GET(VMAXSB)}, {0x104, GET(VSLB)}, {0x108, GET(VMULOSB)}, {0x10a, GET(VREFP)}, {0x10c, GET(VMRGLB)}, {0x10e, GET(VPKSHUS)}, {0x142, GET(VMAXSH)}, {0x144, GET(VSLH)}, {0x148, GET(VMULOSH)}, {0x14a, GET(VRSQRTEFP)}, {0x14c, GET(VMRGLH)}, {0x14e, GET(VPKSWUS)}, {0x180, GET(VADDCUW)}, {0x182, GET(VMAXSW)}, {0x184, GET(VSLW)}, {0x18a, GET(VEXPTEFP)}, {0x18c, GET(VMRGLW)}, {0x18e, GET(VPKSHSS)}, {0x1c4, GET(VSL)}, {0x1c6, GET(VCMPGEFP)}, {0x5c6, GET(VCMPGEFP_)}, {0x1ca, GET(VLOGEFP)}, {0x1ce, GET(VPKSWSS)}, {0x200, GET(VADDUBS)}, {0x202, GET(VMINUB)}, {0x204, GET(VSRB)}, {0x206, GET(VCMPGTUB)}, {0x606, GET(VCMPGTUB_)}, {0x208, GET(VMULEUB)}, {0x20a, GET(VRFIN)}, {0x20c, GET(VSPLTB)}, {0x20e, GET(VUPKHSB)}, {0x240, GET(VADDUHS)}, {0x242, GET(VMINUH)}, {0x244, GET(VSRH)}, {0x246, GET(VCMPGTUH)}, {0x646, GET(VCMPGTUH_)}, {0x248, GET(VMULEUH)}, {0x24a, GET(VRFIZ)}, {0x24c, GET(VSPLTH)}, {0x24e, GET(VUPKHSH)}, {0x280, GET(VADDUWS)}, {0x282, GET(VMINUW)}, {0x284, GET(VSRW)}, {0x286, GET(VCMPGTUW)}, {0x686, GET(VCMPGTUW_)}, {0x28a, GET(VRFIP)}, {0x28c, GET(VSPLTW)}, {0x28e, GET(VUPKLSB)}, {0x2c4, GET(VSR)}, {0x2c6, GET(VCMPGTFP)}, {0x6c6, GET(VCMPGTFP_)}, {0x2ca, GET(VRFIM)}, {0x2ce, GET(VUPKLSH)}, {0x300, GET(VADDSBS)}, {0x302, GET(VMINSB)}, {0x304, GET(VSRAB)}, {0x306, GET(VCMPGTSB)}, {0x706, GET(VCMPGTSB_)}, {0x308, GET(VMULESB)}, {0x30a, GET(VCFUX)}, {0x30c, GET(VSPLTISB)}, {0x30e, GET(VPKPX)}, {0x340, GET(VADDSHS)}, {0x342, GET(VMINSH)}, {0x344, GET(VSRAH)}, {0x346, GET(VCMPGTSH)}, {0x746, GET(VCMPGTSH_)}, {0x348, GET(VMULESH)}, {0x34a, GET(VCFSX)}, {0x34c, GET(VSPLTISH)}, {0x34e, GET(VUPKHPX)}, {0x380, GET(VADDSWS)}, {0x382, GET(VMINSW)}, {0x384, GET(VSRAW)}, {0x386, GET(VCMPGTSW)}, {0x786, GET(VCMPGTSW_)}, {0x38a, GET(VCTUXS)}, {0x38c, GET(VSPLTISW)}, {0x3c6, GET(VCMPBFP)}, {0x7c6, GET(VCMPBFP_)}, {0x3ca, GET(VCTSXS)}, {0x3ce, GET(VUPKLPX)}, {0x400, GET(VSUBUBM)}, {0x402, GET(VAVGUB)}, {0x404, GET(VAND)}, {0x40a, GET(VMAXFP)}, {0x40c, GET(VSLO)}, {0x440, GET(VSUBUHM)}, {0x442, GET(VAVGUH)}, {0x444, GET(VANDC)}, {0x44a, GET(VMINFP)}, {0x44c, GET(VSRO)}, {0x480, GET(VSUBUWM)}, {0x482, GET(VAVGUW)}, {0x484, GET(VOR)}, {0x4c4, GET(VXOR)}, {0x502, GET(VAVGSB)}, {0x504, GET(VNOR)}, {0x542, GET(VAVGSH)}, {0x580, GET(VSUBCUW)}, {0x582, GET(VAVGSW)}, {0x600, GET(VSUBUBS)}, {0x604, GET(MFVSCR)}, {0x608, GET(VSUM4UBS)}, {0x640, GET(VSUBUHS)}, {0x644, GET(MTVSCR)}, {0x648, GET(VSUM4SHS)}, {0x680, GET(VSUBUWS)}, {0x688, GET(VSUM2SWS)}, {0x700, GET(VSUBSBS)}, {0x708, GET(VSUM4SBS)}, {0x740, GET(VSUBSHS)}, {0x780, GET(VSUBSWS)}, {0x788, GET(VSUMSWS)}, }); // Group 0x13 opcodes (field 21..30) fill_table(0x13, 10, 1, { {0x000, GET(MCRF)}, {0x010, GET(BCLR)}, {0x021, GET(CRNOR)}, {0x081, GET(CRANDC)}, {0x096, GET(ISYNC)}, {0x0c1, GET(CRXOR)}, {0x0e1, GET(CRNAND)}, {0x101, GET(CRAND)}, {0x121, GET(CREQV)}, {0x1a1, GET(CRORC)}, {0x1c1, GET(CROR)}, {0x210, GET(BCCTR)}, }); // Group 0x1e opcodes (field 27..30) fill_table(0x1e, 4, 1, { {0x0, GETRC(RLDICL)}, {0x1, GETRC(RLDICL)}, {0x2, GETRC(RLDICR)}, {0x3, GETRC(RLDICR)}, {0x4, GETRC(RLDIC)}, {0x5, GETRC(RLDIC)}, {0x6, GETRC(RLDIMI)}, {0x7, GETRC(RLDIMI)}, {0x8, GETRC(RLDCL)}, {0x9, GETRC(RLDCR)}, }); // Group 0x1f opcodes (field 21..30) fill_table(0x1f, 10, 1, { {0x000, GET(CMP)}, {0x004, GET(TW)}, {0x006, GET(LVSL)}, {0x007, GET(LVEBX)}, {0x008, GETRC(SUBFC)}, {0x208, GETRC(SUBFCO)}, {0x009, GETRC(MULHDU)}, {0x00a, GETRC(ADDC)}, {0x20a, GETRC(ADDCO)}, {0x00b, GETRC(MULHWU)}, {0x013, GET(MFOCRF)}, {0x014, GET(LWARX)}, {0x015, GET(LDX)}, {0x017, GET(LWZX)}, {0x018, GETRC(SLW)}, {0x01a, GETRC(CNTLZW)}, {0x01b, GETRC(SLD)}, {0x01c, GETRC(AND)}, {0x020, GET(CMPL)}, {0x026, GET(LVSR)}, {0x027, GET(LVEHX)}, {0x028, GETRC(SUBF)}, {0x228, GETRC(SUBFO)}, {0x035, GET(LDUX)}, {0x036, GET(DCBST)}, {0x037, GET(LWZUX)}, {0x03a, GETRC(CNTLZD)}, {0x03c, GETRC(ANDC)}, {0x044, GET(TD)}, {0x047, GET(LVEWX)}, {0x049, GETRC(MULHD)}, {0x04b, GETRC(MULHW)}, {0x054, GET(LDARX)}, {0x056, GET(DCBF)}, {0x057, GET(LBZX)}, {0x067, GET(LVX)}, {0x068, GETRC(NEG)}, {0x268, GETRC(NEGO)}, {0x077, GET(LBZUX)}, {0x07c, GETRC(NOR)}, {0x087, GET(STVEBX)}, {0x088, GETRC(SUBFE)}, {0x288, GETRC(SUBFEO)}, {0x08a, GETRC(ADDE)}, {0x28a, GETRC(ADDEO)}, {0x090, GET(MTOCRF)}, {0x095, GET(STDX)}, {0x096, GET(STWCX)}, {0x097, GET(STWX)}, {0x0a7, GET(STVEHX)}, {0x0b5, GET(STDUX)}, {0x0b7, GET(STWUX)}, {0x0c7, GET(STVEWX)}, {0x0c8, GETRC(SUBFZE)}, {0x2c8, GETRC(SUBFZEO)}, {0x0ca, GETRC(ADDZE)}, {0x2ca, GETRC(ADDZEO)}, {0x0d6, GET(STDCX)}, {0x0d7, GET(STBX)}, {0x0e7, GET(STVX)}, {0x0e8, GETRC(SUBFME)}, {0x2e8, GETRC(SUBFMEO)}, {0x0e9, GETRC(MULLD)}, {0x2e9, GETRC(MULLDO)}, {0x0ea, GETRC(ADDME)}, {0x2ea, GETRC(ADDMEO)}, {0x0eb, GETRC(MULLW)}, {0x2eb, GETRC(MULLWO)}, {0x0f6, GET(DCBTST)}, {0x0f7, GET(STBUX)}, {0x10a, GETRC(ADD)}, {0x30a, GETRC(ADDO)}, {0x116, GET(DCBT)}, {0x117, GET(LHZX)}, {0x11c, GETRC(EQV)}, {0x136, GET(ECIWX)}, {0x137, GET(LHZUX)}, {0x13c, GETRC(XOR)}, {0x153, GET(MFSPR)}, {0x155, GET(LWAX)}, {0x156, GET(DST)}, {0x157, GET(LHAX)}, {0x167, GET(LVXL)}, {0x173, GET(MFTB)}, {0x175, GET(LWAUX)}, {0x176, GET(DSTST)}, {0x177, GET(LHAUX)}, {0x197, GET(STHX)}, {0x19c, GETRC(ORC)}, {0x1b6, GET(ECOWX)}, {0x1b7, GET(STHUX)}, {0x1bc, GETRC(OR)}, {0x1c9, GETRC(DIVDU)}, {0x3c9, GETRC(DIVDUO)}, {0x1cb, GETRC(DIVWU)}, {0x3cb, GETRC(DIVWUO)}, {0x1d3, GET(MTSPR)}, {0x1d6, GET(DCBI)}, {0x1dc, GETRC(NAND)}, {0x1e7, GET(STVXL)}, {0x1e9, GETRC(DIVD)}, {0x3e9, GETRC(DIVDO)}, {0x1eb, GETRC(DIVW)}, {0x3eb, GETRC(DIVWO)}, {0x207, GET(LVLX)}, {0x214, GET(LDBRX)}, {0x215, GET(LSWX)}, {0x216, GET(LWBRX)}, {0x217, GET(LFSX)}, {0x218, GETRC(SRW)}, {0x21b, GETRC(SRD)}, {0x227, GET(LVRX)}, {0x237, GET(LFSUX)}, {0x255, GET(LSWI)}, {0x256, GET(SYNC)}, {0x257, GET(LFDX)}, {0x277, GET(LFDUX)}, {0x287, GET(STVLX)}, {0x294, GET(STDBRX)}, {0x295, GET(STSWX)}, {0x296, GET(STWBRX)}, {0x297, GET(STFSX)}, {0x2a7, GET(STVRX)}, {0x2b7, GET(STFSUX)}, {0x2d5, GET(STSWI)}, {0x2d7, GET(STFDX)}, {0x2f7, GET(STFDUX)}, {0x307, GET(LVLXL)}, {0x316, GET(LHBRX)}, {0x318, GETRC(SRAW)}, {0x31a, GETRC(SRAD)}, {0x327, GET(LVRXL)}, {0x336, GET(DSS)}, {0x338, GETRC(SRAWI)}, {0x33a, GETRC(SRADI)}, {0x33b, GETRC(SRADI)}, {0x356, GET(EIEIO)}, {0x387, GET(STVLXL)}, {0x396, GET(STHBRX)}, {0x39a, GETRC(EXTSH)}, {0x3a7, GET(STVRXL)}, {0x3ba, GETRC(EXTSB)}, {0x3d7, GET(STFIWX)}, {0x3da, GETRC(EXTSW)}, {0x3d6, GET(ICBI)}, {0x3f6, GET(DCBZ)}, }); // Group 0x3a opcodes (field 30..31) fill_table(0x3a, 2, 0, { {0x0, GET(LD)}, {0x1, GET(LDU)}, {0x2, GET(LWA)}, }); // Group 0x3b opcodes (field 21..30) fill_table(0x3b, 10, 1, { {0x12, GETRC(FDIVS), 5}, {0x14, GETRC(FSUBS), 5}, {0x15, GETRC(FADDS), 5}, {0x16, GETRC(FSQRTS), 5}, {0x18, GETRC(FRES), 5}, {0x19, GETRC(FMULS), 5}, {0x1c, GETRC(FMSUBS), 5}, {0x1d, GETRC(FMADDS), 5}, {0x1e, GETRC(FNMSUBS), 5}, {0x1f, GETRC(FNMADDS), 5}, }); // Group 0x3e opcodes (field 30..31) fill_table(0x3e, 2, 0, { {0x0, GET(STD)}, {0x1, GET(STDU)}, }); // Group 0x3f opcodes (field 21..30) fill_table(0x3f, 10, 1, { {0x026, GETRC(MTFSB1)}, {0x040, GET(MCRFS)}, {0x046, GETRC(MTFSB0)}, {0x086, GETRC(MTFSFI)}, {0x247, GETRC(MFFS)}, {0x2c7, GETRC(MTFSF)}, {0x000, GET(FCMPU)}, {0x00c, GETRC(FRSP)}, {0x00e, GETRC(FCTIW)}, {0x00f, GETRC(FCTIWZ)}, {0x012, GETRC(FDIV), 5}, {0x014, GETRC(FSUB), 5}, {0x015, GETRC(FADD), 5}, {0x016, GETRC(FSQRT), 5}, {0x017, GETRC(FSEL), 5}, {0x019, GETRC(FMUL), 5}, {0x01a, GETRC(FRSQRTE), 5}, {0x01c, GETRC(FMSUB), 5}, {0x01d, GETRC(FMADD), 5}, {0x01e, GETRC(FNMSUB), 5}, {0x01f, GETRC(FNMADD), 5}, {0x020, GET(FCMPO)}, {0x028, GETRC(FNEG)}, {0x048, GETRC(FMR)}, {0x088, GETRC(FNABS)}, {0x108, GETRC(FABS)}, {0x32e, GETRC(FCTID)}, {0x32f, GETRC(FCTIDZ)}, {0x34e, GETRC(FCFID)}, }); } const std::array& get_table() const noexcept { return m_table; } T decode(u32 inst) const noexcept { return m_table[ppu_decode(inst)]; } }; #undef GET_ #undef GET #undef GETRC namespace ppu_instructions { namespace fields { enum { r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15, r16, r17, r18, r19, r20, r21, r22, r23, r24, r25, r26, r27, r28, r29, r30, r31, }; enum { f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, F16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31, }; enum { v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, }; enum { cr0, cr1, cr2, cr3, cr4, cr5, cr6, cr7, }; } // namespace fields using namespace fields; inline u32 ADDI(u32 rt, u32 ra, s32 si) { ppu_opcode_t op{0x0eu << 26}; op.rd = rt; op.ra = ra; op.simm16 = si; return op.opcode; } inline u32 ADDIS(u32 rt, u32 ra, s32 si) { ppu_opcode_t op{0x0fu << 26}; op.rd = rt; op.ra = ra; op.simm16 = si; return op.opcode; } inline u32 XORIS(u32 rt, u32 ra, s32 si) { ppu_opcode_t op{0x1bu << 26}; op.rd = rt; op.ra = ra; op.simm16 = si; return op.opcode; } inline u32 ORI(u32 rt, u32 ra, u32 ui) { ppu_opcode_t op{0x18u << 26}; op.rd = rt; op.ra = ra; op.uimm16 = ui; return op.opcode; } inline u32 ORIS(u32 rt, u32 ra, u32 ui) { ppu_opcode_t op{0x19u << 26}; op.rd = rt; op.ra = ra; op.uimm16 = ui; return op.opcode; } inline u32 OR(u32 ra, u32 rs, u32 rb, bool rc = false) { ppu_opcode_t op{0x1fu << 26 | 0x1bcu << 1}; op.rs = rs; op.ra = ra; op.rb = rb; op.rc = rc; return op.opcode; } inline u32 SC(u32 lev) { ppu_opcode_t op{0x11u << 26 | 1 << 1}; op.lev = lev; return op.opcode; } inline u32 B(s32 li, bool aa = false, bool lk = false) { ppu_opcode_t op{0x12u << 26}; op.ll = li; op.aa = aa; op.lk = lk; return op.opcode; } inline u32 BC(u32 bo, u32 bi, s32 bd, bool aa = false, bool lk = false) { ppu_opcode_t op{0x10u << 26}; op.bo = bo; op.bi = bi; op.ds = bd / 4; op.aa = aa; op.lk = lk; return op.opcode; } inline u32 BCLR(u32 bo, u32 bi, u32 bh, bool lk = false) { ppu_opcode_t op{0x13u << 26 | 0x10u << 1}; op.bo = bo; op.bi = bi; op.bh = bh; op.lk = lk; return op.opcode; } inline u32 BCCTR(u32 bo, u32 bi, u32 bh, bool lk = false) { ppu_opcode_t op{0x13u << 26 | 0x210u << 1}; op.bo = bo; op.bi = bi; op.bh = bh; op.lk = lk; return op.opcode; } inline u32 MFSPR(u32 rt, u32 spr) { ppu_opcode_t op{0x1fu << 26 | 0x153u << 1}; op.rd = rt; op.spr = spr; return op.opcode; } inline u32 MTSPR(u32 spr, u32 rs) { ppu_opcode_t op{0x1fu << 26 | 0x1d3u << 1}; op.rs = rs; op.spr = spr; return op.opcode; } inline u32 LWZ(u32 rt, u32 ra, s32 si) { ppu_opcode_t op{0x20u << 26}; op.rd = rt; op.ra = ra; op.simm16 = si; return op.opcode; } inline u32 STW(u32 rt, u32 ra, s32 si) { ppu_opcode_t op{0x24u << 26}; op.rd = rt; op.ra = ra; op.simm16 = si; return op.opcode; } inline u32 STD(u32 rs, u32 ra, s32 si) { ppu_opcode_t op{0x3eu << 26}; op.rs = rs; op.ra = ra; op.ds = si / 4; return op.opcode; } inline u32 STDU(u32 rs, u32 ra, s32 si) { ppu_opcode_t op{0x3eu << 26 | 1}; op.rs = rs; op.ra = ra; op.ds = si / 4; return op.opcode; } inline u32 LD(u32 rt, u32 ra, s32 si) { ppu_opcode_t op{0x3au << 26}; op.rd = rt; op.ra = ra; op.ds = si / 4; return op.opcode; } inline u32 LDU(u32 rt, u32 ra, s32 si) { ppu_opcode_t op{0x3au << 26 | 1}; op.rd = rt; op.ra = ra; op.ds = si / 4; return op.opcode; } inline u32 CMPI(u32 bf, u32 l, u32 ra, u32 ui) { ppu_opcode_t op{0xbu << 26}; op.crfd = bf; op.l10 = l; op.ra = ra; op.uimm16 = ui; return op.opcode; } inline u32 CMPLI(u32 bf, u32 l, u32 ra, u32 ui) { ppu_opcode_t op{0xau << 26}; op.crfd = bf; op.l10 = l; op.ra = ra; op.uimm16 = ui; return op.opcode; } inline u32 RLDICL(u32 ra, u32 rs, u32 sh, u32 mb, bool rc = false) { ppu_opcode_t op{30 << 26}; op.ra = ra; op.rs = rs; op.sh64 = sh; op.mbe64 = mb; op.rc = rc; return op.opcode; } inline u32 RLDICR(u32 ra, u32 rs, u32 sh, u32 mb, bool rc = false) { return RLDICL(ra, rs, sh, mb, rc) | 1 << 2; } inline u32 STFD(u32 frs, u32 ra, s32 si) { ppu_opcode_t op{54u << 26}; op.frs = frs; op.ra = ra; op.simm16 = si; return op.opcode; } inline u32 STVX(u32 vs, u32 ra, u32 rb) { ppu_opcode_t op{31 << 26 | 231 << 1}; op.vs = vs; op.ra = ra; op.rb = rb; return op.opcode; } inline u32 LFD(u32 frd, u32 ra, s32 si) { ppu_opcode_t op{50u << 26}; op.frd = frd; op.ra = ra; op.simm16 = si; return op.opcode; } inline u32 LVX(u32 vd, u32 ra, u32 rb) { ppu_opcode_t op{31 << 26 | 103 << 1}; op.vd = vd; op.ra = ra; op.rb = rb; return op.opcode; } inline constexpr u32 EIEIO() { return 0x7c0006ac; } namespace implicts { inline u32 NOP() { return ORI(r0, r0, 0); } inline u32 MR(u32 rt, u32 ra) { return OR(rt, ra, ra, false); } inline u32 LI(u32 rt, u32 imm) { return ADDI(rt, r0, imm); } inline u32 LIS(u32 rt, u32 imm) { return ADDIS(rt, r0, imm); } inline u32 BLR() { return BCLR(0x10 | 0x04, 0, 0); } inline u32 BCTR() { return BCCTR(0x10 | 0x04, 0, 0); } inline u32 BCTRL() { return BCCTR(0x10 | 0x04, 0, 0, true); } inline u32 MFCTR(u32 reg) { return MFSPR(reg, 9 << 5); } inline u32 MTCTR(u32 reg) { return MTSPR(9 << 5, reg); } inline u32 MFLR(u32 reg) { return MFSPR(reg, 8 << 5); } inline u32 MTLR(u32 reg) { return MTSPR(8 << 5, reg); } inline u32 BNE(u32 cr, s32 imm) { return BC(4, 2 | cr << 2, imm); } inline u32 BEQ(u32 cr, s32 imm) { return BC(12, 2 | cr << 2, imm); } inline u32 BGT(u32 cr, s32 imm) { return BC(12, 1 | cr << 2, imm); } inline u32 BNE(s32 imm) { return BNE(cr0, imm); } inline u32 BEQ(s32 imm) { return BEQ(cr0, imm); } inline u32 BGT(s32 imm) { return BGT(cr0, imm); } inline u32 CMPDI(u32 cr, u32 reg, u32 imm) { return CMPI(cr, 1, reg, imm); } inline u32 CMPDI(u32 reg, u32 imm) { return CMPDI(cr0, reg, imm); } inline u32 CMPWI(u32 cr, u32 reg, u32 imm) { return CMPI(cr, 0, reg, imm); } inline u32 CMPWI(u32 reg, u32 imm) { return CMPWI(cr0, reg, imm); } inline u32 CMPLDI(u32 cr, u32 reg, u32 imm) { return CMPLI(cr, 1, reg, imm); } inline u32 CMPLDI(u32 reg, u32 imm) { return CMPLDI(cr0, reg, imm); } inline u32 CMPLWI(u32 cr, u32 reg, u32 imm) { return CMPLI(cr, 0, reg, imm); } inline u32 CMPLWI(u32 reg, u32 imm) { return CMPLWI(cr0, reg, imm); } inline u32 EXTRDI(u32 x, u32 y, u32 n, u32 b) { return RLDICL(x, y, b + n, 64 - b, false); } inline u32 SRDI(u32 x, u32 y, u32 n) { return RLDICL(x, y, 64 - n, n, false); } inline u32 CLRLDI(u32 x, u32 y, u32 n) { return RLDICL(x, y, 0, n, false); } inline u32 CLRRDI(u32 x, u32 y, u32 n) { return RLDICR(x, y, 0, 63 - n, false); } inline constexpr u32 TRAP() { return 0x7FE00008; } // tw 31,r0,r0 } // namespace implicts using namespace implicts; } // namespace ppu_instructions