mirror of
https://github.com/RPCSX/rpcsx.git
synced 2026-01-14 20:50:11 +01:00
1122 lines
24 KiB
C++
1122 lines
24 KiB
C++
#pragma once
|
|
|
|
#include "util/BitField.h"
|
|
|
|
template <typename T, u32 I, u32 N>
|
|
using ppu_bf_t = bf_t<T, sizeof(T) * 8 - N - I, N>;
|
|
|
|
union ppu_opcode_t
|
|
{
|
|
u32 opcode;
|
|
|
|
ppu_bf_t<u32, 0, 6> main; // 0..5
|
|
cf_t<ppu_bf_t<u32, 30, 1>, ppu_bf_t<u32, 16, 5>> sh64; // 30 + 16..20
|
|
cf_t<ppu_bf_t<u32, 26, 1>, ppu_bf_t<u32, 21, 5>> mbe64; // 26 + 21..25
|
|
ppu_bf_t<u32, 11, 5> vuimm; // 11..15
|
|
ppu_bf_t<u32, 6, 5> vs; // 6..10
|
|
ppu_bf_t<u32, 22, 4> vsh; // 22..25
|
|
ppu_bf_t<u32, 21, 1> oe; // 21
|
|
ppu_bf_t<u32, 11, 10> spr; // 11..20
|
|
ppu_bf_t<u32, 21, 5> vc; // 21..25
|
|
ppu_bf_t<u32, 16, 5> vb; // 16..20
|
|
ppu_bf_t<u32, 11, 5> va; // 11..15
|
|
ppu_bf_t<u32, 6, 5> vd; // 6..10
|
|
ppu_bf_t<u32, 31, 1> lk; // 31
|
|
ppu_bf_t<u32, 30, 1> aa; // 30
|
|
ppu_bf_t<u32, 16, 5> rb; // 16..20
|
|
ppu_bf_t<u32, 11, 5> ra; // 11..15
|
|
ppu_bf_t<u32, 6, 5> rd; // 6..10
|
|
ppu_bf_t<u32, 16, 16> uimm16; // 16..31
|
|
ppu_bf_t<u32, 11, 1> l11; // 11
|
|
ppu_bf_t<u32, 6, 5> rs; // 6..10
|
|
ppu_bf_t<s32, 16, 16> simm16; // 16..31, signed
|
|
ppu_bf_t<s32, 16, 14> ds; // 16..29, signed
|
|
ppu_bf_t<s32, 11, 5> vsimm; // 11..15, signed
|
|
ppu_bf_t<s32, 6, 26> ll; // 6..31, signed
|
|
ppu_bf_t<s32, 6, 24> li; // 6..29, signed
|
|
ppu_bf_t<u32, 20, 7> lev; // 20..26
|
|
ppu_bf_t<u32, 16, 4> i; // 16..19
|
|
ppu_bf_t<u32, 11, 3> crfs; // 11..13
|
|
ppu_bf_t<u32, 10, 1> l10; // 10
|
|
ppu_bf_t<u32, 6, 3> crfd; // 6..8
|
|
ppu_bf_t<u32, 16, 5> crbb; // 16..20
|
|
ppu_bf_t<u32, 11, 5> crba; // 11..15
|
|
ppu_bf_t<u32, 6, 5> crbd; // 6..10
|
|
ppu_bf_t<u32, 31, 1> rc; // 31
|
|
ppu_bf_t<u32, 26, 5> me32; // 26..30
|
|
ppu_bf_t<u32, 21, 5> mb32; // 21..25
|
|
ppu_bf_t<u32, 16, 5> sh32; // 16..20
|
|
ppu_bf_t<u32, 11, 5> bi; // 11..15
|
|
ppu_bf_t<u32, 6, 5> bo; // 6..10
|
|
ppu_bf_t<u32, 19, 2> bh; // 19..20
|
|
ppu_bf_t<u32, 21, 5> frc; // 21..25
|
|
ppu_bf_t<u32, 16, 5> frb; // 16..20
|
|
ppu_bf_t<u32, 11, 5> fra; // 11..15
|
|
ppu_bf_t<u32, 6, 5> frd; // 6..10
|
|
ppu_bf_t<u32, 12, 8> crm; // 12..19
|
|
ppu_bf_t<u32, 6, 5> frs; // 6..10
|
|
ppu_bf_t<u32, 7, 8> flm; // 7..14
|
|
ppu_bf_t<u32, 6, 1> l6; // 6
|
|
ppu_bf_t<u32, 15, 1> l15; // 15
|
|
cf_t<ppu_bf_t<s32, 16, 14>, ff_t<u32, 0, 2>> bt14;
|
|
cf_t<ppu_bf_t<s32, 6, 24>, ff_t<u32, 0, 2>> 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<u32, 2> op_branch_targets(u32 pc, ppu_opcode_t op);
|
|
|
|
// PPU decoder object. D provides functions. T is function pointer type returned.
|
|
template <typename D, typename T = decltype(&D::UNK)>
|
|
class ppu_decoder
|
|
{
|
|
// Fast lookup table
|
|
std::array<T, 0x20000> 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<instruction_info> 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 <typename... Args>
|
|
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<T, 0x20000>& 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
|