mirror of
https://github.com/cemu-project/Cemu.git
synced 2025-07-04 14:01:17 +12:00
251 lines
8.4 KiB
C++
251 lines
8.4 KiB
C++
#pragma once
|
|
#include "Cafe/HW/MMU/MMU.h"
|
|
|
|
enum
|
|
{
|
|
CPUException_NOTHING,
|
|
CPUException_FPUUNAVAILABLE,
|
|
CPUException_EXTERNAL,
|
|
CPUException_SYSTEMCALL
|
|
};
|
|
|
|
#define PPC_LWARX_RESERVATION_MAX (4)
|
|
|
|
union FPR_t
|
|
{
|
|
double fpr;
|
|
struct
|
|
{
|
|
double fp0;
|
|
double fp1;
|
|
};
|
|
struct
|
|
{
|
|
uint64 guint;
|
|
};
|
|
struct
|
|
{
|
|
uint64 fp0int;
|
|
uint64 fp1int;
|
|
};
|
|
};
|
|
|
|
typedef struct
|
|
{
|
|
struct
|
|
{
|
|
uint32 scr;
|
|
uint32 car;
|
|
//uint32 bcr;
|
|
}sprGlobal;
|
|
uint64 tb;
|
|
}PPCInterpreterGlobal_t;
|
|
|
|
struct PPCInterpreter_t
|
|
{
|
|
uint32 instructionPointer;
|
|
uint32 gpr[32];
|
|
FPR_t fpr[32];
|
|
uint32 fpscr;
|
|
uint8 cr[32]; // 0 -> bit not set, 1 -> bit set (upper 7 bits of each byte must always be zero) (cr0 starts at index 0, cr1 at index 4 ..)
|
|
uint8 xer_ca; // carry from xer
|
|
uint8 LSQE;
|
|
uint8 PSE;
|
|
// thread remaining cycles
|
|
sint32 remainingCycles; // if this value goes below zero, the next thread is scheduled
|
|
sint32 skippedCycles; // number of skipped cycles
|
|
struct
|
|
{
|
|
uint32 LR;
|
|
uint32 CTR;
|
|
uint32 XER;
|
|
uint32 UPIR;
|
|
uint32 UGQR[8];
|
|
}spr;
|
|
// LWARX and STWCX
|
|
uint32 reservedMemAddr;
|
|
uint32 reservedMemValue;
|
|
// temporary storage for recompiler
|
|
FPR_t temporaryFPR[8];
|
|
uint32 temporaryGPR[4];
|
|
// values below this are not used by Cafe OS usermode
|
|
struct
|
|
{
|
|
uint32 fpecr; // is this the same register as fpscr ?
|
|
uint32 DEC;
|
|
uint32 srr0;
|
|
uint32 srr1;
|
|
uint32 PVR;
|
|
uint32 msr;
|
|
uint32 sprg[4];
|
|
// DSI/ISI
|
|
uint32 dar;
|
|
uint32 dsisr;
|
|
// DMA
|
|
uint32 dmaU;
|
|
uint32 dmaL;
|
|
// MMU
|
|
uint32 dbatU[8];
|
|
uint32 dbatL[8];
|
|
uint32 ibatU[8];
|
|
uint32 ibatL[8];
|
|
uint32 sr[16];
|
|
uint32 sdr1;
|
|
}sprExtended;
|
|
// global CPU values
|
|
PPCInterpreterGlobal_t* global;
|
|
// interpreter control
|
|
bool memoryException;
|
|
// core context (starts at 0xFFFFFF00?)
|
|
/* 0xFFFFFFE4 */ uint32 coreInterruptMask;
|
|
|
|
// extra variables for recompiler
|
|
void* rspTemp;
|
|
};
|
|
|
|
// parameter access (legacy C style)
|
|
|
|
static uint32 PPCInterpreter_getCallParamU32(PPCInterpreter_t* hCPU, uint32 index)
|
|
{
|
|
if (index >= 8)
|
|
return memory_readU32(hCPU->gpr[1] + 8 + (index - 8) * 4);
|
|
return hCPU->gpr[3 + index];
|
|
}
|
|
|
|
static uint64 PPCInterpreter_getCallParamU64(PPCInterpreter_t* hCPU, uint32 index)
|
|
{
|
|
uint64 v = ((uint64)PPCInterpreter_getCallParamU32(hCPU, index)) << 32ULL;
|
|
v |= ((uint64)PPCInterpreter_getCallParamU32(hCPU, index+1));
|
|
return v;
|
|
}
|
|
|
|
#define ppcGetCallParamU32(__index) PPCInterpreter_getCallParamU32(hCPU, __index)
|
|
#define ppcGetCallParamU16(__index) ((uint16)(PPCInterpreter_getCallParamU32(hCPU, __index)&0xFFFF))
|
|
#define ppcGetCallParamU8(__index) ((uint8)(PPCInterpreter_getCallParamU32(hCPU, __index)&0xFF))
|
|
#define ppcGetCallParamStruct(__index, __type) ((__type*)memory_getPointerFromVirtualOffsetAllowNull(PPCInterpreter_getCallParamU32(hCPU, __index)))
|
|
|
|
// legacy way of accessing parameters
|
|
#define ppcDefineParamU32(__name, __index) uint32 __name = PPCInterpreter_getCallParamU32(hCPU, __index)
|
|
#define ppcDefineParamU16(__name, __index) uint16 __name = (uint16)PPCInterpreter_getCallParamU32(hCPU, __index)
|
|
#define ppcDefineParamU32BEPtr(__name, __index) uint32be* __name = (uint32be*)((uint8*)memory_getPointerFromVirtualOffsetAllowNull(PPCInterpreter_getCallParamU32(hCPU, __index)))
|
|
#define ppcDefineParamS32(__name, __index) sint32 __name = (sint32)PPCInterpreter_getCallParamU32(hCPU, __index)
|
|
#define ppcDefineParamU64(__name, __index) uint64 __name = PPCInterpreter_getCallParamU64(hCPU, __index)
|
|
#define ppcDefineParamMPTR(__name, __index) MPTR __name = (MPTR)PPCInterpreter_getCallParamU32(hCPU, __index)
|
|
#define ppcDefineParamMEMPTR(__name, __type, __index) MEMPTR<__type> __name{PPCInterpreter_getCallParamU32(hCPU, __index)}
|
|
#define ppcDefineParamU8(__name, __index) uint8 __name = (PPCInterpreter_getCallParamU32(hCPU, __index)&0xFF)
|
|
#define ppcDefineParamStructPtr(__name, __type, __index) __type* __name = ((__type*)memory_getPointerFromVirtualOffsetAllowNull(PPCInterpreter_getCallParamU32(hCPU, __index)))
|
|
#define ppcDefineParamTypePtr(__name, __type, __index) __type* __name = ((__type*)memory_getPointerFromVirtualOffsetAllowNull(PPCInterpreter_getCallParamU32(hCPU, __index)))
|
|
#define ppcDefineParamPtr(__name, __type, __index) __type* __name = ((__type*)memory_getPointerFromVirtualOffsetAllowNull(PPCInterpreter_getCallParamU32(hCPU, __index)))
|
|
#define ppcDefineParamStr(__name, __index) char* __name = ((char*)memory_getPointerFromVirtualOffsetAllowNull(PPCInterpreter_getCallParamU32(hCPU, __index)))
|
|
#define ppcDefineParamUStr(__name, __index) uint8* __name = ((uint8*)memory_getPointerFromVirtualOffsetAllowNull(PPCInterpreter_getCallParamU32(hCPU, __index)))
|
|
#define ppcDefineParamWStr(__name, __index) wchar_t* __name = ((wchar_t*)memory_getPointerFromVirtualOffsetAllowNull(PPCInterpreter_getCallParamU32(hCPU, __index)))
|
|
#define ppcDefineParamWStrBE(__name, __index) uint16be* __name = ((uint16be*)memory_getPointerFromVirtualOffsetAllowNull(PPCInterpreter_getCallParamU32(hCPU, __index)))
|
|
|
|
// GPR constants
|
|
|
|
#define GPR_SP 1
|
|
|
|
// interpreter functions
|
|
|
|
PPCInterpreter_t* PPCInterpreter_createInstance(unsigned int Entrypoint);
|
|
PPCInterpreter_t* PPCInterpreter_getCurrentInstance();
|
|
void PPCInterpreter_setCurrentInstance(PPCInterpreter_t* hCPU);
|
|
|
|
uint64 PPCInterpreter_getMainCoreCycleCounter();
|
|
|
|
void PPCInterpreter_nextInstruction(PPCInterpreter_t* cpuInterpreter);
|
|
void PPCInterpreter_jumpToInstruction(PPCInterpreter_t* cpuInterpreter, uint32 newIP);
|
|
|
|
void PPCInterpreterSlim_executeInstruction(PPCInterpreter_t* hCPU);
|
|
void PPCInterpreterFull_executeInstruction(PPCInterpreter_t* hCPU);
|
|
|
|
// misc
|
|
|
|
uint32 PPCInterpreter_getXER(PPCInterpreter_t* hCPU);
|
|
void PPCInterpreter_setXER(PPCInterpreter_t* hCPU, uint32 v);
|
|
|
|
// Wii U clocks (deprecated. Moved to Espresso/Const.h)
|
|
#define ESPRESSO_CORE_CLOCK 1243125000
|
|
#define ESPRESSO_BUS_CLOCK 248625000
|
|
#define ESPRESSO_TIMER_CLOCK (ESPRESSO_BUS_CLOCK/4) // 62156250
|
|
|
|
#define ESPRESSO_CORE_CLOCK_TO_TIMER_CLOCK(__cc) ((__cc)/20ULL)
|
|
|
|
// interrupt vectors
|
|
#define CPU_EXCEPTION_DSI 0x00000300
|
|
#define CPU_EXCEPTION_INTERRUPT 0x00000500 // todo: validate
|
|
#define CPU_EXCEPTION_FPUUNAVAIL 0x00000800 // todo: validate
|
|
#define CPU_EXCEPTION_SYSTEMCALL 0x00000C00 // todo: validate
|
|
#define CPU_EXCEPTION_DECREMENTER 0x00000900 // todo: validate
|
|
|
|
// FPU available check
|
|
//#define FPUCheckAvailable() if ((hCPU->msr & MSR_FP) == 0) { IPTException(hCPU, CPU_EXCEPTION_FPUUNAVAIL); return; }
|
|
#define FPUCheckAvailable() // since the emulated code always runs in usermode we can assume that MSR_FP is always set
|
|
|
|
// spr
|
|
void PPCSpr_set(PPCInterpreter_t* hCPU, uint32 spr, uint32 newValue);
|
|
uint32 PPCSpr_get(PPCInterpreter_t* hCPU, uint32 spr);
|
|
|
|
uint32 PPCInterpreter_getCoreIndex(PPCInterpreter_t* hCPU);
|
|
uint32 PPCInterpreter_getCurrentCoreIndex();
|
|
|
|
// decrement register
|
|
void PPCInterpreter_setDEC(PPCInterpreter_t* hCPU, uint32 newValue);
|
|
|
|
// timing for main processor
|
|
extern uint64 ppcCyclesSince2000; // on init this is set to the cycles that passed since 1.1.2000
|
|
extern uint64 ppcCyclesSince2000TimerClock; // on init this is set to the cycles that passed since 1.1.2000 / 20
|
|
extern uint64 ppcCyclesSince2000_UTC;
|
|
extern uint64 ppcMainThreadDECCycleValue; // value that was set to dec register
|
|
extern uint64 ppcMainThreadDECCycleStart; // at which cycle the dec register was set
|
|
|
|
// PPC timer
|
|
void PPCTimer_init();
|
|
void PPCTimer_waitForInit();
|
|
uint64 PPCTimer_getFromRDTSC();
|
|
|
|
uint64 PPCTimer_microsecondsToTsc(uint64 us);
|
|
uint64 PPCTimer_tscToMicroseconds(uint64 us);
|
|
uint64 PPCTimer_getRawTsc();
|
|
|
|
void PPCTimer_start();
|
|
|
|
// core info and control
|
|
extern uint32 ppcThreadQuantum;
|
|
|
|
uint8* PPCInterpreterGetAndModifyStackPointer(sint32 offset);
|
|
uint8* PPCInterpreterGetStackPointer();
|
|
void PPCInterpreterModifyStackPointer(sint32 offset);
|
|
|
|
uint32 PPCInterpreter_makeCallableExportDepr(void (*ppcCallableExport)(PPCInterpreter_t* hCPU));
|
|
|
|
static inline float flushDenormalToZero(float f)
|
|
{
|
|
uint32 v = *(uint32*)&f;
|
|
return *(float*)&v;
|
|
}
|
|
|
|
// HLE interface
|
|
|
|
typedef void(*HLECALL)(PPCInterpreter_t* hCPU);
|
|
|
|
typedef sint32 HLEIDX;
|
|
HLEIDX PPCInterpreter_registerHLECall(HLECALL hleCall, std::string hleName);
|
|
HLECALL PPCInterpreter_getHLECall(HLEIDX funcIndex);
|
|
|
|
// HLE scheduler
|
|
|
|
void PPCInterpreter_relinquishTimeslice();
|
|
|
|
void PPCCore_boostQuantum(sint32 numCycles);
|
|
void PPCCore_deboostQuantum(sint32 numCycles);
|
|
|
|
void PPCCore_switchToScheduler();
|
|
void PPCCore_switchToSchedulerWithLock();
|
|
|
|
PPCInterpreter_t* PPCCore_executeCallbackInternal(uint32 functionMPTR);
|
|
void PPCCore_init();
|
|
|
|
// LLE scheduler
|
|
|
|
void PPCCoreLLE_startSingleCoreScheduler(uint32 entrypoint);
|