#pragma once #include "Utilities/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; m_table.at((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++) { m_table.at(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, }; } 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 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 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; } 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 u32 TRAP() { return 0x7FE00008; } // tw 31,r0,r0 } using namespace implicts; }