Cemu/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterImpl.cpp
Exzap 3bceb39966
Remove PUBLIC_RELEASE flag and tie asserts to debug config (#287)
Removes the -DPUBLIC_RELEASE flag. Cemu's debug asserts are now only enabled if the build configuration is Debug. Similarly, on Windows the console is only shown for Debug builds.
2022-09-24 08:43:27 +02:00

1231 lines
31 KiB
C++

#include "PPCInterpreterInternal.h"
#include "PPCInterpreterHelper.h"
#include "Cafe/HW/Espresso/Debugger/Debugger.h"
class PPCItpCafeOSUsermode
{
public:
static const bool allowSupervisorMode = false;
static const bool allowDSI = false;
inline static uint32 memory_readCodeU32(PPCInterpreter_t* hCPU, uint32 address)
{
return _swapEndianU32(*(uint32*)(memory_base + address));
}
inline static void ppcMem_writeDataDouble(PPCInterpreter_t* hCPU, uint32 address, double vf)
{
uint64 v = *(uint64*)&vf;
uint32 v1 = v & 0xFFFFFFFF;
uint32 v2 = v >> 32;
uint8* ptr = memory_getPointerFromVirtualOffset(address);
*(uint32*)(ptr + 4) = CPU_swapEndianU32(v1);
*(uint32*)(ptr + 0) = CPU_swapEndianU32(v2);
}
inline static void ppcMem_writeDataU64(PPCInterpreter_t* hCPU, uint32 address, uint64 v)
{
*(uint64*)(memory_getPointerFromVirtualOffset(address)) = CPU_swapEndianU64(v);
}
inline static void ppcMem_writeDataU32(PPCInterpreter_t* hCPU, uint32 address, uint32 v)
{
*(uint32*)(memory_getPointerFromVirtualOffset(address)) = CPU_swapEndianU32(v);
}
inline static void ppcMem_writeDataU16(PPCInterpreter_t* hCPU, uint32 address, uint16 v)
{
*(uint16*)(memory_getPointerFromVirtualOffset(address)) = CPU_swapEndianU16(v);
}
inline static void ppcMem_writeDataU8(PPCInterpreter_t* hCPU, uint32 address, uint8 v)
{
*(uint8*)(memory_getPointerFromVirtualOffset(address)) = v;
}
inline static double ppcMem_readDataDouble(PPCInterpreter_t* hCPU, uint32 address)
{
uint32 v[2];
v[1] = *(uint32*)(memory_getPointerFromVirtualOffset(address));
v[0] = *(uint32*)(memory_getPointerFromVirtualOffset(address) + 4);
v[0] = CPU_swapEndianU32(v[0]);
v[1] = CPU_swapEndianU32(v[1]);
return *(double*)v;
}
inline static float ppcMem_readDataFloat(PPCInterpreter_t* hCPU, uint32 address)
{
uint32 v = *(uint32*)(memory_getPointerFromVirtualOffset(address));
v = CPU_swapEndianU32(v);
return *(float*)&v;
}
inline static uint64 ppcMem_readDataU64(PPCInterpreter_t* hCPU, uint32 address)
{
uint64 v = *(uint64*)(memory_getPointerFromVirtualOffset(address));
return CPU_swapEndianU64(v);
}
inline static uint32 ppcMem_readDataU32(PPCInterpreter_t* hCPU, uint32 address)
{
uint32 v = *(uint32*)(memory_getPointerFromVirtualOffset(address));
return CPU_swapEndianU32(v);
}
inline static uint16 ppcMem_readDataU16(PPCInterpreter_t* hCPU, uint32 address)
{
uint16 v = *(uint16*)(memory_getPointerFromVirtualOffset(address));
return CPU_swapEndianU16(v);
}
inline static uint8 ppcMem_readDataU8(PPCInterpreter_t* hCPU, uint32 address)
{
return *(uint8*)(memory_getPointerFromVirtualOffset(address));
}
inline static uint64 ppcMem_readDataFloatEx(PPCInterpreter_t* hCPU, uint32 addr)
{
return ConvertToDoubleNoFTZ(_swapEndianU32(*(uint32*)(memory_base + addr)));
}
inline static void ppcMem_writeDataFloatEx(PPCInterpreter_t* hCPU, uint32 addr, uint64 value)
{
*(uint32*)(memory_base + addr) = _swapEndianU32(ConvertToSingleNoFTZ(value));
}
inline static uint64 getTB(PPCInterpreter_t* hCPU)
{
return PPCInterpreter_getMainCoreCycleCounter();
}
};
uint32 debug_lastTranslatedHit;
void generateDSIException(PPCInterpreter_t* hCPU, uint32 dataAddress)
{
// todo - check if we are already inside an interrupt handler (in which case the DSI exception is queued and not executed immediately?)
// set flag to cancel current instruction
hCPU->memoryException = true;
hCPU->sprExtended.srr0 = hCPU->instructionPointer;
hCPU->sprExtended.srr1 = hCPU->sprExtended.msr & 0x87C0FFFF;
hCPU->sprExtended.dar = dataAddress;
hCPU->sprExtended.msr &= ~0x04EF36;
hCPU->instructionPointer = 0xFFF00300;
uint32 dsisr = 0;
dsisr |= (1<<(31-1)); // set if no TLB/BAT match found
hCPU->sprExtended.dsisr = dsisr;
}
class PPCItpSupervisorWithMMU
{
public:
static const bool allowSupervisorMode = true;
static const bool allowDSI = true;
inline static uint32 ppcMem_translateVirtualDataToPhysicalAddr(PPCInterpreter_t* hCPU, uint32 vAddr)
{
// check if address translation is disabled for data accesses
if (GET_MSR_BIT(MSR_DR) == 0)
{
return vAddr;
}
#ifdef CEMU_DEBUG_ASSERT
if (hCPU->memoryException)
assert_dbg(); // should not be set anymore
#endif
// how to determine if BAT is valid:
// BAT_entry_valid = (Vs & ~MSR[PR]) | (Vp & MSR[PR]) (The entry has separate enable flags for usermode and supervisor mode)
for (sint32 i = 0; i < 8; i++)
{
// upper
uint32 batU = hCPU->sprExtended.dbatU[i];
uint32 BEPI = ((batU >> 17) & 0x7FFF) << 17;
uint32 Vp = (batU >> 0) & 1;
uint32 Vs = (batU >> 1) & 1;
uint32 BL = (((batU >> 2) & 0x7FF) ^ 0x7FF) << 17;
BL |= 0xF0000000;
if (Vs == 0)
continue; // todo - check if in supervisor/usermode
// lower
uint32 batL = hCPU->sprExtended.dbatL[i];
uint32 PP = (batL >> 0) & 3;
uint32 WIMG = (batL >> 3) & 0xF;
uint32 BRPN = ((batL >> 17) & 0x7FFF) << 17;
// check for match
if ((vAddr&BL) == BEPI)
{
// match
vAddr = (vAddr&~BL) | (BRPN&BL);
debug_lastTranslatedHit = vAddr;
return vAddr;
}
}
// no match
debug_lastTranslatedHit = 0xFFFFFFFF;
// find segment
uint32 segmentIndex = (vAddr>>28);
//uint32 pageIndex = (vAddr >> 12) & 0xFFFF; // for 4KB pages
// uint32 byteOffset = vAddr & 0xFFF; // for 4KB pages
uint32 pageIndex = (vAddr >> 17) & 0x7FF; // for 128KB pages
uint32 byteOffset = vAddr & 0x1FFFF;
uint32 srValue = hCPU->sprExtended.sr[segmentIndex];
uint8 sr_ks = (srValue >> 30) & 1; // supervisor
uint8 sr_kp = (srValue >> 29) & 1; // user mode
uint8 sr_n = (srValue >> 28) & 1; // no-execute
uint32 sr_vsid = (srValue & 0xFFFFFF);
//uint32 vpn = pageIndex | (sr_vsid << 16); // 40bit virtual page number
// look up in page table
//uint32 lookupHash = (sr_vsid ^ pageIndex) & 0x7FFFF; // not correct for 4KB pages? sr_vsid must be shifted?
//uint32 lookupHash = (sr_vsid ^ pageIndex) & 0x7FFFF;
//uint32 lookupHash = ((sr_vsid>>8) ^ pageIndex) & 0x7FFFF;
uint32 lookupHash = ((sr_vsid >> 0) ^ pageIndex) & 0x7FFFF;
//lookupHash ^= 0x7FFFF;
uint32 pageTableAddr = hCPU->sprExtended.sdr1&0xFFFF0000;
uint32 pageTableMask = hCPU->sprExtended.sdr1&0x1FF;
for (uint32 ch = 0; ch < 2; ch++)
{
uint32 ptegSelectLow = (lookupHash & 0x3FF);
uint32 maskOR = (lookupHash >> 10) & pageTableMask;
uint32* pteg = (uint32*)(memory_base + (pageTableAddr | (maskOR << 16)) + ptegSelectLow * 64);
for (sint32 t = 0; t < 8; t++)
{
uint32 w0 = _swapEndianU32(pteg[0]);
uint32 w1 = _swapEndianU32(pteg[1]);
pteg += 2;
if ((w0 & 0x80000000) == 0)
continue; // entry not valid
uint32 abPageIndex = (w0 >> 0) & 0x3F;
uint8 h = (w0 >> 6) & 1;
uint32 ptegVSID = (w0 >> 7) & 0xFFFFFF;
if (abPageIndex == (pageIndex >> 5) && ptegVSID == sr_vsid && h == ch)
{
if (ch == 1)
assert_dbg();
// match
uint32 ptegPhysicalPage = (w1 >> 12) & 0xFFFFF;
// replace page (128KB)
vAddr = (vAddr & ~0xFFFE0000) | (ptegPhysicalPage << 12);
return vAddr;
}
}
// calculate hash 2
lookupHash = ~lookupHash;
}
forceLogDebug_printf("DSI exception at 0x%08x LR 0x%08x DataAddress %08x", hCPU->instructionPointer, hCPU->spr.LR, vAddr);
generateDSIException(hCPU, vAddr);
// todo: Check hash func 1
// todo: Check protection bits
// todo: Check supervisor/usermode bits
// also use this function in all the mem stuff below
// note: bat has higher priority than TLB
// since iterating the bats and page table is too slow, we need to pre-process the data somehow.
return vAddr;
}
inline static uint32 ppcMem_translateVirtualCodeToPhysicalAddr(PPCInterpreter_t* hCPU, uint32 vAddr)
{
// check if address translation is disabled for instruction accesses
if (GET_MSR_BIT(MSR_IR) == 0)
{
return vAddr;
}
// how to determine if BAT is valid:
// BAT_entry_valid = (Vs & ~MSR[PR]) | (Vp & MSR[PR]) (The entry has separate enable flags for usermode and supervisor mode)
for (sint32 i = 0; i < 8; i++)
{
// upper
uint32 batU = hCPU->sprExtended.ibatU[i];
uint32 BEPI = ((batU >> 17) & 0x7FFF) << 17;
uint32 Vp = (batU >> 0) & 1;
uint32 Vs = (batU >> 1) & 1;
uint32 BL = (((batU >> 2) & 0x7FF) ^ 0x7FF) << 17;
BL |= 0xF0000000;
if (Vs == 0)
continue; // todo - check if in supervisor/usermode
// lower
uint32 batL = hCPU->sprExtended.ibatL[i];
uint32 PP = (batL >> 0) & 3;
uint32 WIMG = (batL >> 3) & 0xF;
uint32 BRPN = ((batL >> 17) & 0x7FFF) << 17;
// check for match
if ((vAddr&BL) == BEPI)
{
// match
vAddr = (vAddr&~BL) | (BRPN&BL);
debug_lastTranslatedHit = vAddr;
return vAddr;
}
}
assert_dbg();
// no match
// todo - throw exception if translation is enabled?
return vAddr;
}
static uint32 memory_readCodeU32(PPCInterpreter_t* hCPU, uint32 address)
{
return _swapEndianU32(*(uint32*)(memory_base + ppcMem_translateVirtualCodeToPhysicalAddr(hCPU, address)));
}
inline static uint8* ppcMem_getDataPtr(PPCInterpreter_t* hCPU, uint32 vAddr)
{
return memory_base + ppcMem_translateVirtualDataToPhysicalAddr(hCPU, vAddr);
}
inline static void ppcMem_writeDataDouble(PPCInterpreter_t* hCPU, uint32 address, double vf)
{
uint64 v = *(uint64*)&vf;
uint32 v1 = v & 0xFFFFFFFF;
uint32 v2 = v >> 32;
uint8* ptr = ppcMem_getDataPtr(hCPU, address);
*(uint32*)(ptr + 4) = CPU_swapEndianU32(v1);
*(uint32*)(ptr + 0) = CPU_swapEndianU32(v2);
}
inline static void ppcMem_writeDataU64(PPCInterpreter_t* hCPU, uint32 address, uint64 v)
{
*(uint64*)(ppcMem_getDataPtr(hCPU, address)) = CPU_swapEndianU64(v);
}
inline static void ppcMem_writeDataU32(PPCInterpreter_t* hCPU, uint32 address, uint32 v)
{
uint32 pAddr = ppcMem_translateVirtualDataToPhysicalAddr(hCPU, address);
if (hCPU->memoryException)
return;
if (pAddr >= 0x0c000000 && pAddr < 0x0d100000)
{
cemu_assert_unimplemented();
return;
}
*(uint32*)(memory_base + pAddr) = CPU_swapEndianU32(v);
}
inline static void ppcMem_writeDataU16(PPCInterpreter_t* hCPU, uint32 address, uint16 v)
{
*(uint16*)(ppcMem_getDataPtr(hCPU, address)) = CPU_swapEndianU16(v);
}
inline static void ppcMem_writeDataU8(PPCInterpreter_t* hCPU, uint32 address, uint8 v)
{
*(uint8*)(ppcMem_getDataPtr(hCPU, address)) = v;
}
inline static double ppcMem_readDataDouble(PPCInterpreter_t* hCPU, uint32 address)
{
uint32 v[2];
v[1] = *(uint32*)(ppcMem_getDataPtr(hCPU, address));
v[0] = *(uint32*)(ppcMem_getDataPtr(hCPU, address) + 4);
v[0] = CPU_swapEndianU32(v[0]);
v[1] = CPU_swapEndianU32(v[1]);
return *(double*)v;
}
inline static float ppcMem_readDataFloat(PPCInterpreter_t* hCPU, uint32 address)
{
uint32 v = *(uint32*)(ppcMem_getDataPtr(hCPU, address));
v = CPU_swapEndianU32(v);
return *(float*)&v;
}
inline static uint64 ppcMem_readDataU64(PPCInterpreter_t* hCPU, uint32 address)
{
uint64 v = *(uint64*)(ppcMem_getDataPtr(hCPU, address));
return CPU_swapEndianU64(v);
}
inline static uint32 ppcMem_readDataU32(PPCInterpreter_t* hCPU, uint32 address)
{
uint32 pAddr = ppcMem_translateVirtualDataToPhysicalAddr(hCPU, address);
if (hCPU->memoryException)
return 0;
if (pAddr >= 0x01FFF000 && pAddr < 0x02000000)
{
debug_printf("Access u32 boot param block 0x%08x IP %08x LR %08x\n", pAddr, hCPU->instructionPointer, hCPU->spr.LR);
forceLogDebug_printf("Access u32 boot param block 0x%08x (org %08x) IP %08x LR %08x\n", pAddr, address, hCPU->instructionPointer, hCPU->spr.LR);
}
if (pAddr >= 0xFFEB73B0 && pAddr < (0xFFEB73B0+0x40C))
{
debug_printf("Access cached u32 boot param block 0x%08x IP %08x LR %08x\n", pAddr, hCPU->instructionPointer, hCPU->spr.LR);
forceLogDebug_printf("Access cached u32 boot param block 0x%08x (org %08x) IP %08x LR %08x\n", pAddr, address, hCPU->instructionPointer, hCPU->spr.LR);
}
if (pAddr >= 0x0c000000 && pAddr < 0x0d100000)
{
cemu_assert_unimplemented();
return 0;
}
uint32 v = *(uint32*)(memory_base + pAddr);
return CPU_swapEndianU32(v);
}
inline static uint16 ppcMem_readDataU16(PPCInterpreter_t* hCPU, uint32 address)
{
uint16 v = *(uint16*)(ppcMem_getDataPtr(hCPU, address));
return CPU_swapEndianU16(v);
}
inline static uint8 ppcMem_readDataU8(PPCInterpreter_t* hCPU, uint32 address)
{
uint32 pAddr = ppcMem_translateVirtualDataToPhysicalAddr(hCPU, address);
if (pAddr >= 0x0c000000 && pAddr < 0x0d100000)
{
cemu_assert_unimplemented();
return 0;
}
return *(uint8*)(memory_base + pAddr);
}
inline static uint64 ppcMem_readDataFloatEx(PPCInterpreter_t* hCPU, uint32 addr)
{
return ConvertToDoubleNoFTZ(_swapEndianU32(*(uint32*)(memory_base + addr)));
}
inline static void ppcMem_writeDataFloatEx(PPCInterpreter_t* hCPU, uint32 addr, uint64 value)
{
*(uint32*)(memory_base + addr) = _swapEndianU32(ConvertToSingleNoFTZ(value));
}
inline static uint64 getTB(PPCInterpreter_t* hCPU)
{
return hCPU->global->tb / 20ULL;
}
};
uint32 testIP[100];
uint32 testIPC = 0;
template <typename ppcItpCtrl>
class PPCInterpreterContainer
{
public:
#include "PPCInterpreterSPR.hpp"
#include "PPCInterpreterOPC.hpp"
#include "PPCInterpreterLoadStore.hpp"
#include "PPCInterpreterALU.hpp"
static void executeInstruction(PPCInterpreter_t* hCPU)
{
if constexpr(ppcItpCtrl::allowSupervisorMode)
{
hCPU->global->tb++;
}
#ifdef __DEBUG_OUTPUT_INSTRUCTION
debug_printf("%08x: ", hCPU->instructionPointer);
#endif
uint32 opcode = ppcItpCtrl::memory_readCodeU32(hCPU, hCPU->instructionPointer);
switch ((opcode >> 26))
{
case 0:
debug_printf("ZERO[NOP] | 0x%08X\n", (unsigned int)hCPU->instructionPointer);
#ifdef CEMU_DEBUG_ASSERT
assert_dbg();
while (true) std::this_thread::sleep_for(std::chrono::seconds(1));
#endif
hCPU->instructionPointer += 4;
break;
case 1: // virtual HLE
PPCInterpreter_virtualHLE(hCPU, opcode);
break;
case 4:
switch (PPC_getBits(opcode, 30, 5))
{
case 0: // subcategory compare
switch (PPC_getBits(opcode, 25, 5))
{
case 0: // Sonic All Stars Racing
PPCInterpreter_PS_CMPU0(hCPU, opcode);
break;
case 1:
PPCInterpreter_PS_CMPO0(hCPU, opcode);
break;
case 2: // Assassin's Creed 3, Sonic All Stars Racing
PPCInterpreter_PS_CMPU1(hCPU, opcode);
break;
default:
debug_printf("Unknown execute %04X as [4->0] at %08X\n", PPC_getBits(opcode, 25, 5), hCPU->instructionPointer);
cemu_assert_unimplemented();
break;
}
break;
case 6:
PPCInterpreter_PSQ_LX(hCPU, opcode);
break;
case 7:
PPCInterpreter_PSQ_STX(hCPU, opcode);
break;
case 8:
switch (PPC_getBits(opcode, 25, 5))
{
case 1:
PPCInterpreter_PS_NEG(hCPU, opcode);
break;
case 2:
PPCInterpreter_PS_MR(hCPU, opcode);
break;
case 4:
PPCInterpreter_PS_NABS(hCPU, opcode);
break;
case 8:
PPCInterpreter_PS_ABS(hCPU, opcode);
break;
default:
debug_printf("Unknown execute %04X as [4->8] at %08X\n", PPC_getBits(opcode, 25, 5), hCPU->instructionPointer);
cemu_assert_unimplemented();
break;
}
break;
case 10:
PPCInterpreter_PS_SUM0(hCPU, opcode);
break;
case 11:
PPCInterpreter_PS_SUM1(hCPU, opcode);
break;
case 12:
PPCInterpreter_PS_MULS0(hCPU, opcode);
break;
case 13:
PPCInterpreter_PS_MULS1(hCPU, opcode);
break;
case 14:
PPCInterpreter_PS_MADDS0(hCPU, opcode);
break;
case 15:
PPCInterpreter_PS_MADDS1(hCPU, opcode);
break;
case 16: // sub category - merge
switch (PPC_getBits(opcode, 25, 5))
{
case 16:
PPCInterpreter_PS_MERGE00(hCPU, opcode);
break;
case 17:
PPCInterpreter_PS_MERGE01(hCPU, opcode);
break;
case 18:
PPCInterpreter_PS_MERGE10(hCPU, opcode);
break;
case 19:
PPCInterpreter_PS_MERGE11(hCPU, opcode);
break;
default:
debug_printf("Unknown execute %04X as [4->16] at %08X\n", PPC_getBits(opcode, 25, 5), hCPU->instructionPointer);
debugBreakpoint();
break;
}
break;
case 18:
PPCInterpreter_PS_DIV(hCPU, opcode);
break;
case 20:
PPCInterpreter_PS_SUB(hCPU, opcode);
break;
case 21:
PPCInterpreter_PS_ADD(hCPU, opcode);
break;
case 22:
PPCInterpreter_DCBZL(hCPU, opcode);
break;
case 23:
PPCInterpreter_PS_SEL(hCPU, opcode);
break;
case 24:
PPCInterpreter_PS_RES(hCPU, opcode);
break;
case 25:
PPCInterpreter_PS_MUL(hCPU, opcode);
break;
case 26: // sub category with only one entry - RSQRTE
PPCInterpreter_PS_RSQRTE(hCPU, opcode);
break;
case 28:
PPCInterpreter_PS_MSUB(hCPU, opcode);
break;
case 29:
PPCInterpreter_PS_MADD(hCPU, opcode);
break;
case 30:
PPCInterpreter_PS_NMSUB(hCPU, opcode);
break;
case 31:
PPCInterpreter_PS_NMADD(hCPU, opcode);
break;
default:
debug_printf("Unknown execute %04X as [4] at %08X\n", PPC_getBits(opcode, 30, 5), hCPU->instructionPointer);
cemu_assert_unimplemented();
break;
}
break;
case 7:
PPCInterpreter_MULLI(hCPU, opcode);
break;
case 8:
PPCInterpreter_SUBFIC(hCPU, opcode);
break;
case 10:
PPCInterpreter_CMPLI(hCPU, opcode);
break;
case 11:
PPCInterpreter_CMPI(hCPU, opcode);
break;
case 12:
PPCInterpreter_ADDIC(hCPU, opcode);
break;
case 13:
PPCInterpreter_ADDIC_(hCPU, opcode);
break;
case 14:
PPCInterpreter_ADDI(hCPU, opcode);
break;
case 15:
PPCInterpreter_ADDIS(hCPU, opcode);
break;
case 16:
PPCInterpreter_BCX(hCPU, opcode);
break;
case 17:
if (PPC_getBits(opcode, 30, 1) == 1) {
PPCInterpreter_SC(hCPU, opcode);
}
else {
debug_printf("Unsupported Opcode [0x17 --> 0x0]\n");
cemu_assert_unimplemented();
}
break;
case 18:
PPCInterpreter_BX(hCPU, opcode);
break;
case 19: // opcode category
switch (PPC_getBits(opcode, 30, 10))
{
case 0:
PPCInterpreter_MCRF(hCPU, opcode);
break;
case 16:
PPCInterpreter_BCLRX(hCPU, opcode);
break;
case 33:
PPCInterpreter_CRNOR(hCPU, opcode);
break;
case 50:
PPCInterpreter_RFI(hCPU, opcode);
break;
case 129:
PPCInterpreter_CRANDC(hCPU, opcode);
break;
case 150:
PPCInterpreter_ISYNC(hCPU, opcode);
break;
case 193:
PPCInterpreter_CRXOR(hCPU, opcode);
break;
case 257:
PPCInterpreter_CRAND(hCPU, opcode);
break;
case 289:
PPCInterpreter_CREQV(hCPU, opcode);
break;
case 417:
PPCInterpreter_CRORC(hCPU, opcode);
break;
case 449:
PPCInterpreter_CROR(hCPU, opcode);
break;
case 528:
PPCInterpreter_BCCTR(hCPU, opcode);
break;
default:
debug_printf("Unknown execute %04X as [19] at %08X\n", PPC_getBits(opcode, 30, 10), hCPU->instructionPointer);
cemu_assert_unimplemented();
break;
}
break;
case 20:
PPCInterpreter_RLWIMI(hCPU, opcode);
break;
case 21:
PPCInterpreter_RLWINM(hCPU, opcode);
break;
case 23:
PPCInterpreter_RLWNM(hCPU, opcode);
break;
case 24:
PPCInterpreter_ORI(hCPU, opcode);
break;
case 25:
PPCInterpreter_ORIS(hCPU, opcode);
break;
case 26:
PPCInterpreter_XORI(hCPU, opcode);
break;
case 27:
PPCInterpreter_XORIS(hCPU, opcode);
break;
case 28:
PPCInterpreter_ANDI_(hCPU, opcode);
break;
case 29:
PPCInterpreter_ANDIS_(hCPU, opcode);
break;
case 31: // opcode category
switch (PPC_getBits(opcode, 30, 10))
{
case 0:
PPCInterpreter_CMP(hCPU, opcode);
break;
case 4:
#ifdef CEMU_DEBUG_ASSERT
debug_printf("TW instruction executed at %08x\n", hCPU->instructionPointer);
#endif
PPCInterpreter_TW(hCPU, opcode);
break;
case 8:
PPCInterpreter_SUBFC(hCPU, opcode);
break;
case 10:
PPCInterpreter_ADDC(hCPU, opcode);
break;
case 11:
PPCInterpreter_MULHWU_(hCPU, opcode);
break;
case 19:
PPCInterpreter_MFCR(hCPU, opcode);
break;
case 20:
PPCInterpreter_LWARX(hCPU, opcode);
break;
case 23:
PPCInterpreter_LWZX(hCPU, opcode);
break;
case 24:
PPCInterpreter_SLWX(hCPU, opcode);
break;
case 26:
PPCInterpreter_CNTLZW(hCPU, opcode);
break;
case 28:
PPCInterpreter_ANDX(hCPU, opcode);
break;
case 32:
PPCInterpreter_CMPL(hCPU, opcode);
break;
case 40:
PPCInterpreter_SUBF(hCPU, opcode);
break;
case 54:
PPCInterpreter_DCBST(hCPU, opcode);
break;
case 55:
PPCInterpreter_LWZXU(hCPU, opcode);
break;
case 60:
PPCInterpreter_ANDCX(hCPU, opcode);
break;
case 75:
PPCInterpreter_MULHW_(hCPU, opcode);
break;
case 83:
PPCInterpreter_MFMSR(hCPU, opcode);
break;
case 86:
PPCInterpreter_DCBF(hCPU, opcode);
break;
case 87:
PPCInterpreter_LBZX(hCPU, opcode);
break;
case 104:
PPCInterpreter_NEG(hCPU, opcode);
break;
case 119: // Sonic Lost World
PPCInterpreter_LBZXU(hCPU, opcode);
break;
case 124:
PPCInterpreter_NORX(hCPU, opcode);
break;
case 136:
PPCInterpreter_SUBFE(hCPU, opcode);
break;
case 138:
PPCInterpreter_ADDE(hCPU, opcode);
break;
case 144:
PPCInterpreter_MTCRF(hCPU, opcode);
break;
case 146:
PPCInterpreter_MTMSR(hCPU, opcode);
break;
case 150:
PPCInterpreter_STWCX(hCPU, opcode);
break;
case 151:
PPCInterpreter_STWX(hCPU, opcode);
break;
case 183:
PPCInterpreter_STWUX(hCPU, opcode);
break;
case 200:
PPCInterpreter_SUBFZE(hCPU, opcode);
break;
case 202:
PPCInterpreter_ADDZE(hCPU, opcode);
break;
case 210:
PPCInterpreter_MTSR(hCPU, opcode);
break;
case 215:
PPCInterpreter_STBX(hCPU, opcode);
break;
case 232: // Trine 2
PPCInterpreter_SUBFME(hCPU, opcode);
break;
case 234:
PPCInterpreter_ADDME(hCPU, opcode);
break;
case 235:
PPCInterpreter_MULLW(hCPU, opcode);
break;
case 247:
PPCInterpreter_STBUX(hCPU, opcode);
break;
case 266:
PPCInterpreter_ADD(hCPU, opcode);
break;
case 278:
PPCInterpreter_DCBT(hCPU, opcode);
break;
case 279:
PPCInterpreter_LHZX(hCPU, opcode);
break;
case 284:
PPCInterpreter_EQV(hCPU, opcode);
break;
case 306:
PPCInterpreter_TLBIE(hCPU, opcode);
break;
case 311: // Wii U Menu v177 (US)
PPCInterpreter_LHZUX(hCPU, opcode);
break;
case 316:
PPCInterpreter_XOR(hCPU, opcode);
break;
case 339:
PPCInterpreter_MFSPR(hCPU, opcode);
break;
case 343:
PPCInterpreter_LHAX(hCPU, opcode);
break;
case 371:
PPCInterpreter_MFTB(hCPU, opcode);
break;
case 375: // Wii U Menu v177 (US)
PPCInterpreter_LHAUX(hCPU, opcode);
break;
case 407:
PPCInterpreter_STHX(hCPU, opcode);
break;
case 412:
PPCInterpreter_ORC(hCPU, opcode);
break;
case 439:
PPCInterpreter_STHUX(hCPU, opcode);
break;
case 444:
PPCInterpreter_OR(hCPU, opcode);
break;
case 459:
PPCInterpreter_DIVWU(hCPU, opcode);
break;
case 467:
PPCInterpreter_MTSPR(hCPU, opcode);
break;
case 470:
PPCInterpreter_DCBI(hCPU, opcode);
break;
case 476:
PPCInterpreter_NANDX(hCPU, opcode);
break;
case 491:
PPCInterpreter_DIVW(hCPU, opcode);
break;
case 512:
PPCInterpreter_MCRXR(hCPU, opcode);
break;
case 520: // Affordable Space Adventures + other Unity games
PPCInterpreter_SUBFCO(hCPU, opcode);
break;
case 522:
PPCInterpreter_ADDCO(hCPU, opcode);
break;
case 534:
PPCInterpreter_LWBRX(hCPU, opcode);
break;
case 535:
PPCInterpreter_LFSX(hCPU, opcode);
break;
case 536:
PPCInterpreter_SRWX(hCPU, opcode);
break;
case 552:
PPCInterpreter_SUBFO(hCPU, opcode);
break;
case 566:
PPCInterpreter_TLBSYNC(hCPU, opcode);
break;
case 567:
PPCInterpreter_LFSUX(hCPU, opcode);
break;
case 595:
PPCInterpreter_MFSR(hCPU, opcode);
break;
case 597:
PPCInterpreter_LSWI(hCPU, opcode);
break;
case 598:
PPCInterpreter_SYNC(hCPU, opcode);
break;
case 599:
PPCInterpreter_LFDX(hCPU, opcode);
break;
case 616:
PPCInterpreter_NEGO(hCPU, opcode);
break;
case 631:
PPCInterpreter_LFDUX(hCPU, opcode);
break;
case 648: // 136 | OE
PPCInterpreter_SUBFEO(hCPU, opcode);
break;
case 650: // 138 | OE
PPCInterpreter_ADDEO(hCPU, opcode);
break;
case 662:
PPCInterpreter_STWBRX(hCPU, opcode);
break;
case 663:
PPCInterpreter_STFSX(hCPU, opcode);
break;
case 695:
PPCInterpreter_STFSUX(hCPU, opcode);
break;
case 725:
PPCInterpreter_STSWI(hCPU, opcode);
break;
case 727:
PPCInterpreter_STFDX(hCPU, opcode);
break;
case 747:
PPCInterpreter_MULLWO(hCPU, opcode);
break;
case 759:
PPCInterpreter_STFDUX(hCPU, opcode);
break;
case 778:
PPCInterpreter_ADDO(hCPU, opcode);
break;
case 790:
PPCInterpreter_LHBRX(hCPU, opcode);
break;
case 792:
PPCInterpreter_SRAW(hCPU, opcode);
break;
case 824:
PPCInterpreter_SRAWI(hCPU, opcode);
break;
case 854:
PPCInterpreter_EIEIO(hCPU, opcode);
break;
case 918:
PPCInterpreter_STHBRX(hCPU, opcode);
break;
case 922:
PPCInterpreter_EXTSH(hCPU, opcode);
break;
case 954:
PPCInterpreter_EXTSB(hCPU, opcode);
break;
case 971:
PPCInterpreter_DIVWUO(hCPU, opcode);
break;
case 982:
PPCInterpreter_ICBI(hCPU, opcode);
break;
case 983:
PPCInterpreter_STFIWX(hCPU, opcode);
break;
case 1003:
PPCInterpreter_DIVWO(hCPU, opcode);
break;
case 1014:
PPCInterpreter_DCBZ(hCPU, opcode);
break;
default:
debug_printf("Unknown execute %04X as [31] at %08X\n", PPC_getBits(opcode, 30, 10), hCPU->instructionPointer);
#ifdef CEMU_DEBUG_ASSERT
assert_dbg();
#endif
hCPU->instructionPointer += 4;
break;
}
break;
case 32:
PPCInterpreter_LWZ(hCPU, opcode);
break;
case 33:
PPCInterpreter_LWZU(hCPU, opcode);
break;
case 34:
PPCInterpreter_LBZ(hCPU, opcode);
break;
case 35:
PPCInterpreter_LBZU(hCPU, opcode);
break;
case 36:
PPCInterpreter_STW(hCPU, opcode);
break;
case 37:
PPCInterpreter_STWU(hCPU, opcode);
break;
case 38:
PPCInterpreter_STB(hCPU, opcode);
break;
case 39:
PPCInterpreter_STBU(hCPU, opcode);
break;
case 40:
PPCInterpreter_LHZ(hCPU, opcode);
break;
case 41:
PPCInterpreter_LHZU(hCPU, opcode);
break;
case 42:
PPCInterpreter_LHA(hCPU, opcode);
break;
case 43:
PPCInterpreter_LHAU(hCPU, opcode);
break;
case 44:
PPCInterpreter_STH(hCPU, opcode);
break;
case 45:
PPCInterpreter_STHU(hCPU, opcode);
break;
case 46:
PPCInterpreter_LMW(hCPU, opcode);
break;
case 47:
PPCInterpreter_STMW(hCPU, opcode);
break;
case 48:
PPCInterpreter_LFS(hCPU, opcode);
break;
case 49:
PPCInterpreter_LFSU(hCPU, opcode);
break;
case 50:
PPCInterpreter_LFD(hCPU, opcode);
break;
case 51:
PPCInterpreter_LFDU(hCPU, opcode);
break;
case 52:
PPCInterpreter_STFS(hCPU, opcode);
break;
case 53:
PPCInterpreter_STFSU(hCPU, opcode);
break;
case 54:
PPCInterpreter_STFD(hCPU, opcode);
break;
case 55:
PPCInterpreter_STFDU(hCPU, opcode);
break;
case 56:
PPCInterpreter_PSQ_L(hCPU, opcode);
break;
case 57:
PPCInterpreter_PSQ_LU(hCPU, opcode);
break;
case 59: //Opcode category
switch (PPC_getBits(opcode, 30, 5))
{
case 18:
PPCInterpreter_FDIVS(hCPU, opcode);
break;
case 20:
PPCInterpreter_FSUBS(hCPU, opcode);
break;
case 21:
PPCInterpreter_FADDS(hCPU, opcode);
break;
case 24:
PPCInterpreter_FRES(hCPU, opcode);
break;
case 25:
PPCInterpreter_FMULS(hCPU, opcode);
break;
case 28:
PPCInterpreter_FMSUBS(hCPU, opcode);
break;
case 29:
PPCInterpreter_FMADDS(hCPU, opcode);
break;
case 30:
PPCInterpreter_FNMSUBS(hCPU, opcode);
break;
case 31:
PPCInterpreter_FNMADDS(hCPU, opcode);
break;
default:
debug_printf("Unknown execute %04X as [59] at %08X\n", PPC_getBits(opcode, 30, 10), hCPU->instructionPointer);
cemu_assert_unimplemented();
break;
}
break;
case 60:
PPCInterpreter_PSQ_ST(hCPU, opcode);
break;
case 61:
PPCInterpreter_PSQ_STU(hCPU, opcode);
break;
case 63: // opcode category
switch (PPC_getBits(opcode, 30, 5))
{
case 0:
PPCInterpreter_FCMPU(hCPU, opcode);
break;
case 12:
PPCInterpreter_FRSP(hCPU, opcode);
break;
case 15:
PPCInterpreter_FCTIWZ(hCPU, opcode);
break;
case 18:
PPCInterpreter_FDIV(hCPU, opcode);
break;
case 20:
PPCInterpreter_FSUB(hCPU, opcode);
break;
case 21:
PPCInterpreter_FADD(hCPU, opcode);
break;
case 23:
PPCInterpreter_FSEL(hCPU, opcode);
break;
case 25:
PPCInterpreter_FMUL(hCPU, opcode);
break;
case 26:
PPCInterpreter_FRSQRTE(hCPU, opcode);
break;
case 28:
PPCInterpreter_FMSUB(hCPU, opcode);
break;
case 29:
PPCInterpreter_FMADD(hCPU, opcode);
break;
case 30:
PPCInterpreter_FNMSUB(hCPU, opcode);
break;
case 31:
PPCInterpreter_FNMADD(hCPU, opcode);
break;
default:
switch (PPC_getBits(opcode, 30, 10))
{
case 14:
PPCInterpreter_FCTIW(hCPU, opcode);
break;
case 32:
PPCInterpreter_FCMPO(hCPU, opcode);
break;
case 38:
PPCInterpreter_MTFSB1X(hCPU, opcode);
break;
case 40:
PPCInterpreter_FNEG(hCPU, opcode);
break;
case 72:
PPCInterpreter_FMR(hCPU, opcode);
break;
case 136: // Darksiders 2
PPCInterpreter_FNABS(hCPU, opcode);
break;
case 264:
PPCInterpreter_FABS(hCPU, opcode);
break;
case 583:
PPCInterpreter_MFFS(hCPU, opcode);
break;
case 711: // IBM documentation has this wrong as 771?
PPCInterpreter_MTFSF(hCPU, opcode);
break;
default:
debug_printf("Unknown execute %04X as [63] at %08X\n", PPC_getBits(opcode, 30, 10), hCPU->instructionPointer);
cemu_assert_unimplemented();
break;
}
}
break;
default:
debug_printf("Unknown execute %04X at %08X\n", PPC_getBits(opcode, 5, 6), (unsigned int)hCPU->instructionPointer);
cemu_assert_unimplemented();
}
}
};
// Slim interpreter, trades some features for extra performance
// Used when emulator runs in CafeOS HLE mode
// Assumes the following:
// - No MMU (linear memory with 1:1 mapping of physical to virtual)
// - No interrupts
// - Always runs in user mode
// - Paired single mode is always enabled
void PPCInterpreterSlim_executeInstruction(PPCInterpreter_t* hCPU)
{
PPCInterpreterContainer<PPCItpCafeOSUsermode>::executeInstruction(hCPU);
}
// Full interpreter, supports most PowerPC features
// Used when emulator runs in LLE mode
void PPCInterpreterFull_executeInstruction(PPCInterpreter_t* hCPU)
{
PPCInterpreterContainer<PPCItpSupervisorWithMMU>::executeInstruction(hCPU);
}