mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-21 05:09:34 -06:00
Reformat all the things. Have fun with merge conflicts.
This commit is contained in:
@ -6,31 +6,29 @@
|
||||
#include "Common/ChunkFile.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/FPURoundMode.h"
|
||||
#include "Common/MathUtil.h"
|
||||
#include "Common/Logging/Log.h"
|
||||
#include "Common/MathUtil.h"
|
||||
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "Core/Host.h"
|
||||
#include "Core/HW/CPU.h"
|
||||
#include "Core/HW/Memmap.h"
|
||||
#include "Core/HW/SystemTimers.h"
|
||||
#include "Core/Host.h"
|
||||
#include "Core/PowerPC/CPUCoreBase.h"
|
||||
#include "Core/PowerPC/JitInterface.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
#include "Core/PowerPC/PPCTables.h"
|
||||
#include "Core/PowerPC/Interpreter/Interpreter.h"
|
||||
|
||||
#include "Core/PowerPC/JitInterface.h"
|
||||
#include "Core/PowerPC/PPCTables.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
|
||||
namespace PowerPC
|
||||
{
|
||||
|
||||
// STATE_TO_SAVE
|
||||
PowerPCState ppcState;
|
||||
|
||||
static CPUCoreBase* s_cpu_core_base = nullptr;
|
||||
static bool s_cpu_core_base_is_injected = false;
|
||||
Interpreter* const s_interpreter = Interpreter::getInstance();
|
||||
static CoreMode s_mode = MODE_INTERPRETER;
|
||||
static CPUCoreBase* s_cpu_core_base = nullptr;
|
||||
static bool s_cpu_core_base_is_injected = false;
|
||||
Interpreter* const s_interpreter = Interpreter::getInstance();
|
||||
static CoreMode s_mode = MODE_INTERPRETER;
|
||||
|
||||
Watches watches;
|
||||
BreakPoints breakpoints;
|
||||
@ -39,494 +37,496 @@ PPCDebugInterface debug_interface;
|
||||
|
||||
u32 CompactCR()
|
||||
{
|
||||
u32 new_cr = 0;
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
new_cr |= GetCRField(i) << (28 - i * 4);
|
||||
}
|
||||
return new_cr;
|
||||
u32 new_cr = 0;
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
new_cr |= GetCRField(i) << (28 - i * 4);
|
||||
}
|
||||
return new_cr;
|
||||
}
|
||||
|
||||
void ExpandCR(u32 cr)
|
||||
{
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
SetCRField(i, (cr >> (28 - i * 4)) & 0xF);
|
||||
}
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
SetCRField(i, (cr >> (28 - i * 4)) & 0xF);
|
||||
}
|
||||
}
|
||||
|
||||
void DoState(PointerWrap &p)
|
||||
void DoState(PointerWrap& p)
|
||||
{
|
||||
// some of this code has been disabled, because
|
||||
// it changes registers even in MODE_MEASURE (which is suspicious and seems like it could cause desyncs)
|
||||
// and because the values it's changing have been added to CoreTiming::DoState, so it might conflict to mess with them here.
|
||||
// some of this code has been disabled, because
|
||||
// it changes registers even in MODE_MEASURE (which is suspicious and seems like it could cause
|
||||
// desyncs)
|
||||
// and because the values it's changing have been added to CoreTiming::DoState, so it might
|
||||
// conflict to mess with them here.
|
||||
|
||||
// rSPR(SPR_DEC) = SystemTimers::GetFakeDecrementer();
|
||||
// *((u64 *)&TL) = SystemTimers::GetFakeTimeBase(); //works since we are little endian and TL comes first :)
|
||||
// rSPR(SPR_DEC) = SystemTimers::GetFakeDecrementer();
|
||||
// *((u64 *)&TL) = SystemTimers::GetFakeTimeBase(); //works since we are little endian and TL
|
||||
// comes first :)
|
||||
|
||||
p.DoPOD(ppcState);
|
||||
p.DoPOD(ppcState);
|
||||
|
||||
// SystemTimers::DecrementerSet();
|
||||
// SystemTimers::TimeBaseSet();
|
||||
// SystemTimers::DecrementerSet();
|
||||
// SystemTimers::TimeBaseSet();
|
||||
|
||||
JitInterface::DoState(p);
|
||||
JitInterface::DoState(p);
|
||||
}
|
||||
|
||||
static void ResetRegisters()
|
||||
{
|
||||
memset(ppcState.ps, 0, sizeof(ppcState.ps));
|
||||
memset(ppcState.gpr, 0, sizeof(ppcState.gpr));
|
||||
memset(ppcState.spr, 0, sizeof(ppcState.spr));
|
||||
/*
|
||||
0x00080200 = lonestar 2.0
|
||||
0x00088202 = lonestar 2.2
|
||||
0x70000100 = gekko 1.0
|
||||
0x00080100 = gekko 2.0
|
||||
0x00083203 = gekko 2.3a
|
||||
0x00083213 = gekko 2.3b
|
||||
0x00083204 = gekko 2.4
|
||||
0x00083214 = gekko 2.4e (8SE) - retail HW2
|
||||
*/
|
||||
ppcState.spr[SPR_PVR] = 0x00083214;
|
||||
ppcState.spr[SPR_HID1] = 0x80000000; // We're running at 3x the bus clock
|
||||
ppcState.spr[SPR_ECID_U] = 0x0d96e200;
|
||||
ppcState.spr[SPR_ECID_M] = 0x1840c00d;
|
||||
ppcState.spr[SPR_ECID_L] = 0x82bb08e8;
|
||||
memset(ppcState.ps, 0, sizeof(ppcState.ps));
|
||||
memset(ppcState.gpr, 0, sizeof(ppcState.gpr));
|
||||
memset(ppcState.spr, 0, sizeof(ppcState.spr));
|
||||
/*
|
||||
0x00080200 = lonestar 2.0
|
||||
0x00088202 = lonestar 2.2
|
||||
0x70000100 = gekko 1.0
|
||||
0x00080100 = gekko 2.0
|
||||
0x00083203 = gekko 2.3a
|
||||
0x00083213 = gekko 2.3b
|
||||
0x00083204 = gekko 2.4
|
||||
0x00083214 = gekko 2.4e (8SE) - retail HW2
|
||||
*/
|
||||
ppcState.spr[SPR_PVR] = 0x00083214;
|
||||
ppcState.spr[SPR_HID1] = 0x80000000; // We're running at 3x the bus clock
|
||||
ppcState.spr[SPR_ECID_U] = 0x0d96e200;
|
||||
ppcState.spr[SPR_ECID_M] = 0x1840c00d;
|
||||
ppcState.spr[SPR_ECID_L] = 0x82bb08e8;
|
||||
|
||||
ppcState.fpscr = 0;
|
||||
ppcState.pc = 0;
|
||||
ppcState.npc = 0;
|
||||
ppcState.Exceptions = 0;
|
||||
for (auto& v : ppcState.cr_val)
|
||||
v = 0x8000000000000001;
|
||||
ppcState.fpscr = 0;
|
||||
ppcState.pc = 0;
|
||||
ppcState.npc = 0;
|
||||
ppcState.Exceptions = 0;
|
||||
for (auto& v : ppcState.cr_val)
|
||||
v = 0x8000000000000001;
|
||||
|
||||
TL = 0;
|
||||
TU = 0;
|
||||
SystemTimers::TimeBaseSet();
|
||||
TL = 0;
|
||||
TU = 0;
|
||||
SystemTimers::TimeBaseSet();
|
||||
|
||||
// MSR should be 0x40, but we don't emulate BS1, so it would never be turned off :}
|
||||
ppcState.msr = 0;
|
||||
rDEC = 0xFFFFFFFF;
|
||||
SystemTimers::DecrementerSet();
|
||||
// MSR should be 0x40, but we don't emulate BS1, so it would never be turned off :}
|
||||
ppcState.msr = 0;
|
||||
rDEC = 0xFFFFFFFF;
|
||||
SystemTimers::DecrementerSet();
|
||||
}
|
||||
|
||||
void Init(int cpu_core)
|
||||
{
|
||||
// NOTE: This function runs on EmuThread, not the CPU Thread.
|
||||
// Changing the rounding mode has a limited effect.
|
||||
FPURoundMode::SetPrecisionMode(FPURoundMode::PREC_53);
|
||||
// NOTE: This function runs on EmuThread, not the CPU Thread.
|
||||
// Changing the rounding mode has a limited effect.
|
||||
FPURoundMode::SetPrecisionMode(FPURoundMode::PREC_53);
|
||||
|
||||
memset(ppcState.sr, 0, sizeof(ppcState.sr));
|
||||
ppcState.pagetable_base = 0;
|
||||
ppcState.pagetable_hashmask = 0;
|
||||
memset(ppcState.sr, 0, sizeof(ppcState.sr));
|
||||
ppcState.pagetable_base = 0;
|
||||
ppcState.pagetable_hashmask = 0;
|
||||
|
||||
for (int tlb = 0; tlb < 2; tlb++)
|
||||
{
|
||||
for (int set = 0; set < 64; set++)
|
||||
{
|
||||
ppcState.tlb[tlb][set].recent = 0;
|
||||
for (int way = 0; way < 2; way++)
|
||||
{
|
||||
ppcState.tlb[tlb][set].paddr[way] = 0;
|
||||
ppcState.tlb[tlb][set].pte[way] = 0;
|
||||
ppcState.tlb[tlb][set].tag[way] = TLB_TAG_INVALID;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int tlb = 0; tlb < 2; tlb++)
|
||||
{
|
||||
for (int set = 0; set < 64; set++)
|
||||
{
|
||||
ppcState.tlb[tlb][set].recent = 0;
|
||||
for (int way = 0; way < 2; way++)
|
||||
{
|
||||
ppcState.tlb[tlb][set].paddr[way] = 0;
|
||||
ppcState.tlb[tlb][set].pte[way] = 0;
|
||||
ppcState.tlb[tlb][set].tag[way] = TLB_TAG_INVALID;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ResetRegisters();
|
||||
PPCTables::InitTables(cpu_core);
|
||||
ResetRegisters();
|
||||
PPCTables::InitTables(cpu_core);
|
||||
|
||||
// We initialize the interpreter because
|
||||
// it is used on boot and code window independently.
|
||||
s_interpreter->Init();
|
||||
// We initialize the interpreter because
|
||||
// it is used on boot and code window independently.
|
||||
s_interpreter->Init();
|
||||
|
||||
switch (cpu_core)
|
||||
{
|
||||
case PowerPC::CORE_INTERPRETER:
|
||||
s_cpu_core_base = s_interpreter;
|
||||
break;
|
||||
switch (cpu_core)
|
||||
{
|
||||
case PowerPC::CORE_INTERPRETER:
|
||||
s_cpu_core_base = s_interpreter;
|
||||
break;
|
||||
|
||||
default:
|
||||
s_cpu_core_base = JitInterface::InitJitCore(cpu_core);
|
||||
if (!s_cpu_core_base) // Handle Situations where JIT core isn't available
|
||||
{
|
||||
WARN_LOG(POWERPC, "Jit core %d not available. Defaulting to interpreter.", cpu_core);
|
||||
s_cpu_core_base = s_interpreter;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
s_cpu_core_base = JitInterface::InitJitCore(cpu_core);
|
||||
if (!s_cpu_core_base) // Handle Situations where JIT core isn't available
|
||||
{
|
||||
WARN_LOG(POWERPC, "Jit core %d not available. Defaulting to interpreter.", cpu_core);
|
||||
s_cpu_core_base = s_interpreter;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (s_cpu_core_base != s_interpreter)
|
||||
{
|
||||
s_mode = MODE_JIT;
|
||||
}
|
||||
else
|
||||
{
|
||||
s_mode = MODE_INTERPRETER;
|
||||
}
|
||||
if (s_cpu_core_base != s_interpreter)
|
||||
{
|
||||
s_mode = MODE_JIT;
|
||||
}
|
||||
else
|
||||
{
|
||||
s_mode = MODE_INTERPRETER;
|
||||
}
|
||||
|
||||
ppcState.iCache.Init();
|
||||
ppcState.iCache.Init();
|
||||
|
||||
if (SConfig::GetInstance().bEnableDebugging)
|
||||
breakpoints.ClearAllTemporary();
|
||||
if (SConfig::GetInstance().bEnableDebugging)
|
||||
breakpoints.ClearAllTemporary();
|
||||
}
|
||||
|
||||
void Shutdown()
|
||||
{
|
||||
InjectExternalCPUCore(nullptr);
|
||||
JitInterface::Shutdown();
|
||||
s_interpreter->Shutdown();
|
||||
s_cpu_core_base = nullptr;
|
||||
InjectExternalCPUCore(nullptr);
|
||||
JitInterface::Shutdown();
|
||||
s_interpreter->Shutdown();
|
||||
s_cpu_core_base = nullptr;
|
||||
}
|
||||
|
||||
CoreMode GetMode()
|
||||
{
|
||||
return !s_cpu_core_base_is_injected ? s_mode : MODE_INTERPRETER;
|
||||
return !s_cpu_core_base_is_injected ? s_mode : MODE_INTERPRETER;
|
||||
}
|
||||
|
||||
static void ApplyMode()
|
||||
{
|
||||
switch (s_mode)
|
||||
{
|
||||
case MODE_INTERPRETER: // Switching from JIT to interpreter
|
||||
s_cpu_core_base = s_interpreter;
|
||||
break;
|
||||
switch (s_mode)
|
||||
{
|
||||
case MODE_INTERPRETER: // Switching from JIT to interpreter
|
||||
s_cpu_core_base = s_interpreter;
|
||||
break;
|
||||
|
||||
case MODE_JIT: // Switching from interpreter to JIT.
|
||||
// Don't really need to do much. It'll work, the cache will refill itself.
|
||||
s_cpu_core_base = JitInterface::GetCore();
|
||||
if (!s_cpu_core_base) // Has a chance to not get a working JIT core if one isn't active on host
|
||||
s_cpu_core_base = s_interpreter;
|
||||
break;
|
||||
}
|
||||
case MODE_JIT: // Switching from interpreter to JIT.
|
||||
// Don't really need to do much. It'll work, the cache will refill itself.
|
||||
s_cpu_core_base = JitInterface::GetCore();
|
||||
if (!s_cpu_core_base) // Has a chance to not get a working JIT core if one isn't active on host
|
||||
s_cpu_core_base = s_interpreter;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SetMode(CoreMode new_mode)
|
||||
{
|
||||
if (new_mode == s_mode)
|
||||
return; // We don't need to do anything.
|
||||
if (new_mode == s_mode)
|
||||
return; // We don't need to do anything.
|
||||
|
||||
s_mode = new_mode;
|
||||
s_mode = new_mode;
|
||||
|
||||
// If we're using an external CPU core implementation then don't do anything.
|
||||
if (s_cpu_core_base_is_injected)
|
||||
return;
|
||||
// If we're using an external CPU core implementation then don't do anything.
|
||||
if (s_cpu_core_base_is_injected)
|
||||
return;
|
||||
|
||||
ApplyMode();
|
||||
ApplyMode();
|
||||
}
|
||||
|
||||
const char* GetCPUName()
|
||||
{
|
||||
return s_cpu_core_base->GetName();
|
||||
return s_cpu_core_base->GetName();
|
||||
}
|
||||
|
||||
void InjectExternalCPUCore(CPUCoreBase* new_cpu)
|
||||
{
|
||||
// Previously injected.
|
||||
if (s_cpu_core_base_is_injected)
|
||||
s_cpu_core_base->Shutdown();
|
||||
// Previously injected.
|
||||
if (s_cpu_core_base_is_injected)
|
||||
s_cpu_core_base->Shutdown();
|
||||
|
||||
// nullptr means just remove
|
||||
if (!new_cpu)
|
||||
{
|
||||
if (s_cpu_core_base_is_injected)
|
||||
{
|
||||
s_cpu_core_base_is_injected = false;
|
||||
ApplyMode();
|
||||
}
|
||||
return;
|
||||
}
|
||||
// nullptr means just remove
|
||||
if (!new_cpu)
|
||||
{
|
||||
if (s_cpu_core_base_is_injected)
|
||||
{
|
||||
s_cpu_core_base_is_injected = false;
|
||||
ApplyMode();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
new_cpu->Init();
|
||||
s_cpu_core_base = new_cpu;
|
||||
s_cpu_core_base_is_injected = true;
|
||||
new_cpu->Init();
|
||||
s_cpu_core_base = new_cpu;
|
||||
s_cpu_core_base_is_injected = true;
|
||||
}
|
||||
|
||||
void SingleStep()
|
||||
{
|
||||
s_cpu_core_base->SingleStep();
|
||||
s_cpu_core_base->SingleStep();
|
||||
}
|
||||
|
||||
void RunLoop()
|
||||
{
|
||||
Host_UpdateDisasmDialog();
|
||||
s_cpu_core_base->Run();
|
||||
Host_UpdateDisasmDialog();
|
||||
Host_UpdateDisasmDialog();
|
||||
s_cpu_core_base->Run();
|
||||
Host_UpdateDisasmDialog();
|
||||
}
|
||||
|
||||
void UpdatePerformanceMonitor(u32 cycles, u32 num_load_stores, u32 num_fp_inst)
|
||||
{
|
||||
switch (MMCR0.PMC1SELECT)
|
||||
{
|
||||
case 0: // No change
|
||||
break;
|
||||
case 1: // Processor cycles
|
||||
PowerPC::ppcState.spr[SPR_PMC1] += cycles;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
switch (MMCR0.PMC1SELECT)
|
||||
{
|
||||
case 0: // No change
|
||||
break;
|
||||
case 1: // Processor cycles
|
||||
PowerPC::ppcState.spr[SPR_PMC1] += cycles;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (MMCR0.PMC2SELECT)
|
||||
{
|
||||
case 0: // No change
|
||||
break;
|
||||
case 1: // Processor cycles
|
||||
PowerPC::ppcState.spr[SPR_PMC2] += cycles;
|
||||
break;
|
||||
case 11: // Number of loads and stores completed
|
||||
PowerPC::ppcState.spr[SPR_PMC2] += num_load_stores;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
switch (MMCR0.PMC2SELECT)
|
||||
{
|
||||
case 0: // No change
|
||||
break;
|
||||
case 1: // Processor cycles
|
||||
PowerPC::ppcState.spr[SPR_PMC2] += cycles;
|
||||
break;
|
||||
case 11: // Number of loads and stores completed
|
||||
PowerPC::ppcState.spr[SPR_PMC2] += num_load_stores;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (MMCR1.PMC3SELECT)
|
||||
{
|
||||
case 0: // No change
|
||||
break;
|
||||
case 1: // Processor cycles
|
||||
PowerPC::ppcState.spr[SPR_PMC3] += cycles;
|
||||
break;
|
||||
case 11: // Number of FPU instructions completed
|
||||
PowerPC::ppcState.spr[SPR_PMC3] += num_fp_inst;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
switch (MMCR1.PMC3SELECT)
|
||||
{
|
||||
case 0: // No change
|
||||
break;
|
||||
case 1: // Processor cycles
|
||||
PowerPC::ppcState.spr[SPR_PMC3] += cycles;
|
||||
break;
|
||||
case 11: // Number of FPU instructions completed
|
||||
PowerPC::ppcState.spr[SPR_PMC3] += num_fp_inst;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (MMCR1.PMC4SELECT)
|
||||
{
|
||||
case 0: // No change
|
||||
break;
|
||||
case 1: // Processor cycles
|
||||
PowerPC::ppcState.spr[SPR_PMC4] += cycles;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
switch (MMCR1.PMC4SELECT)
|
||||
{
|
||||
case 0: // No change
|
||||
break;
|
||||
case 1: // Processor cycles
|
||||
PowerPC::ppcState.spr[SPR_PMC4] += cycles;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if ((MMCR0.PMC1INTCONTROL && (PowerPC::ppcState.spr[SPR_PMC1] & 0x80000000) != 0) ||
|
||||
(MMCR0.PMCINTCONTROL && (PowerPC::ppcState.spr[SPR_PMC2] & 0x80000000) != 0) ||
|
||||
(MMCR0.PMCINTCONTROL && (PowerPC::ppcState.spr[SPR_PMC3] & 0x80000000) != 0) ||
|
||||
(MMCR0.PMCINTCONTROL && (PowerPC::ppcState.spr[SPR_PMC4] & 0x80000000) != 0))
|
||||
PowerPC::ppcState.Exceptions |= EXCEPTION_PERFORMANCE_MONITOR;
|
||||
if ((MMCR0.PMC1INTCONTROL && (PowerPC::ppcState.spr[SPR_PMC1] & 0x80000000) != 0) ||
|
||||
(MMCR0.PMCINTCONTROL && (PowerPC::ppcState.spr[SPR_PMC2] & 0x80000000) != 0) ||
|
||||
(MMCR0.PMCINTCONTROL && (PowerPC::ppcState.spr[SPR_PMC3] & 0x80000000) != 0) ||
|
||||
(MMCR0.PMCINTCONTROL && (PowerPC::ppcState.spr[SPR_PMC4] & 0x80000000) != 0))
|
||||
PowerPC::ppcState.Exceptions |= EXCEPTION_PERFORMANCE_MONITOR;
|
||||
}
|
||||
|
||||
void CheckExceptions()
|
||||
{
|
||||
u32 exceptions = ppcState.Exceptions;
|
||||
u32 exceptions = ppcState.Exceptions;
|
||||
|
||||
// Example procedure:
|
||||
// set SRR0 to either PC or NPC
|
||||
//SRR0 = NPC;
|
||||
// save specified MSR bits
|
||||
//SRR1 = MSR & 0x87C0FFFF;
|
||||
// copy ILE bit to LE
|
||||
//MSR |= (MSR >> 16) & 1;
|
||||
// clear MSR as specified
|
||||
//MSR &= ~0x04EF36; // 0x04FF36 also clears ME (only for machine check exception)
|
||||
// set to exception type entry point
|
||||
//NPC = 0x00000x00;
|
||||
// Example procedure:
|
||||
// set SRR0 to either PC or NPC
|
||||
// SRR0 = NPC;
|
||||
// save specified MSR bits
|
||||
// SRR1 = MSR & 0x87C0FFFF;
|
||||
// copy ILE bit to LE
|
||||
// MSR |= (MSR >> 16) & 1;
|
||||
// clear MSR as specified
|
||||
// MSR &= ~0x04EF36; // 0x04FF36 also clears ME (only for machine check exception)
|
||||
// set to exception type entry point
|
||||
// NPC = 0x00000x00;
|
||||
|
||||
// TODO(delroth): Exception priority is completely wrong here: depending on
|
||||
// the instruction class, exceptions should be executed in a given order,
|
||||
// which is very different from the one arbitrarily chosen here. See §6.1.5
|
||||
// in 6xx_pem.pdf.
|
||||
// TODO(delroth): Exception priority is completely wrong here: depending on
|
||||
// the instruction class, exceptions should be executed in a given order,
|
||||
// which is very different from the one arbitrarily chosen here. See §6.1.5
|
||||
// in 6xx_pem.pdf.
|
||||
|
||||
if (exceptions & EXCEPTION_ISI)
|
||||
{
|
||||
SRR0 = NPC;
|
||||
// Page fault occurred
|
||||
SRR1 = (MSR & 0x87C0FFFF) | (1 << 30);
|
||||
MSR |= (MSR >> 16) & 1;
|
||||
MSR &= ~0x04EF36;
|
||||
PC = NPC = 0x00000400;
|
||||
if (exceptions & EXCEPTION_ISI)
|
||||
{
|
||||
SRR0 = NPC;
|
||||
// Page fault occurred
|
||||
SRR1 = (MSR & 0x87C0FFFF) | (1 << 30);
|
||||
MSR |= (MSR >> 16) & 1;
|
||||
MSR &= ~0x04EF36;
|
||||
PC = NPC = 0x00000400;
|
||||
|
||||
INFO_LOG(POWERPC, "EXCEPTION_ISI");
|
||||
ppcState.Exceptions &= ~EXCEPTION_ISI;
|
||||
}
|
||||
else if (exceptions & EXCEPTION_PROGRAM)
|
||||
{
|
||||
SRR0 = PC;
|
||||
// say that it's a trap exception
|
||||
SRR1 = (MSR & 0x87C0FFFF) | 0x20000;
|
||||
MSR |= (MSR >> 16) & 1;
|
||||
MSR &= ~0x04EF36;
|
||||
PC = NPC = 0x00000700;
|
||||
INFO_LOG(POWERPC, "EXCEPTION_ISI");
|
||||
ppcState.Exceptions &= ~EXCEPTION_ISI;
|
||||
}
|
||||
else if (exceptions & EXCEPTION_PROGRAM)
|
||||
{
|
||||
SRR0 = PC;
|
||||
// say that it's a trap exception
|
||||
SRR1 = (MSR & 0x87C0FFFF) | 0x20000;
|
||||
MSR |= (MSR >> 16) & 1;
|
||||
MSR &= ~0x04EF36;
|
||||
PC = NPC = 0x00000700;
|
||||
|
||||
INFO_LOG(POWERPC, "EXCEPTION_PROGRAM");
|
||||
ppcState.Exceptions &= ~EXCEPTION_PROGRAM;
|
||||
}
|
||||
else if (exceptions & EXCEPTION_SYSCALL)
|
||||
{
|
||||
SRR0 = NPC;
|
||||
SRR1 = MSR & 0x87C0FFFF;
|
||||
MSR |= (MSR >> 16) & 1;
|
||||
MSR &= ~0x04EF36;
|
||||
PC = NPC = 0x00000C00;
|
||||
INFO_LOG(POWERPC, "EXCEPTION_PROGRAM");
|
||||
ppcState.Exceptions &= ~EXCEPTION_PROGRAM;
|
||||
}
|
||||
else if (exceptions & EXCEPTION_SYSCALL)
|
||||
{
|
||||
SRR0 = NPC;
|
||||
SRR1 = MSR & 0x87C0FFFF;
|
||||
MSR |= (MSR >> 16) & 1;
|
||||
MSR &= ~0x04EF36;
|
||||
PC = NPC = 0x00000C00;
|
||||
|
||||
INFO_LOG(POWERPC, "EXCEPTION_SYSCALL (PC=%08x)", PC);
|
||||
ppcState.Exceptions &= ~EXCEPTION_SYSCALL;
|
||||
}
|
||||
else if (exceptions & EXCEPTION_FPU_UNAVAILABLE)
|
||||
{
|
||||
//This happens a lot - GameCube OS uses deferred FPU context switching
|
||||
SRR0 = PC; // re-execute the instruction
|
||||
SRR1 = MSR & 0x87C0FFFF;
|
||||
MSR |= (MSR >> 16) & 1;
|
||||
MSR &= ~0x04EF36;
|
||||
PC = NPC = 0x00000800;
|
||||
INFO_LOG(POWERPC, "EXCEPTION_SYSCALL (PC=%08x)", PC);
|
||||
ppcState.Exceptions &= ~EXCEPTION_SYSCALL;
|
||||
}
|
||||
else if (exceptions & EXCEPTION_FPU_UNAVAILABLE)
|
||||
{
|
||||
// This happens a lot - GameCube OS uses deferred FPU context switching
|
||||
SRR0 = PC; // re-execute the instruction
|
||||
SRR1 = MSR & 0x87C0FFFF;
|
||||
MSR |= (MSR >> 16) & 1;
|
||||
MSR &= ~0x04EF36;
|
||||
PC = NPC = 0x00000800;
|
||||
|
||||
INFO_LOG(POWERPC, "EXCEPTION_FPU_UNAVAILABLE");
|
||||
ppcState.Exceptions &= ~EXCEPTION_FPU_UNAVAILABLE;
|
||||
}
|
||||
INFO_LOG(POWERPC, "EXCEPTION_FPU_UNAVAILABLE");
|
||||
ppcState.Exceptions &= ~EXCEPTION_FPU_UNAVAILABLE;
|
||||
}
|
||||
#ifdef ENABLE_MEM_CHECK
|
||||
else if (exceptions & EXCEPTION_FAKE_MEMCHECK_HIT)
|
||||
{
|
||||
ppcState.Exceptions &= ~EXCEPTION_DSI & ~EXCEPTION_FAKE_MEMCHECK_HIT;
|
||||
}
|
||||
else if (exceptions & EXCEPTION_FAKE_MEMCHECK_HIT)
|
||||
{
|
||||
ppcState.Exceptions &= ~EXCEPTION_DSI & ~EXCEPTION_FAKE_MEMCHECK_HIT;
|
||||
}
|
||||
#endif
|
||||
else if (exceptions & EXCEPTION_DSI)
|
||||
{
|
||||
SRR0 = PC;
|
||||
SRR1 = MSR & 0x87C0FFFF;
|
||||
MSR |= (MSR >> 16) & 1;
|
||||
MSR &= ~0x04EF36;
|
||||
PC = NPC = 0x00000300;
|
||||
//DSISR and DAR regs are changed in GenerateDSIException()
|
||||
else if (exceptions & EXCEPTION_DSI)
|
||||
{
|
||||
SRR0 = PC;
|
||||
SRR1 = MSR & 0x87C0FFFF;
|
||||
MSR |= (MSR >> 16) & 1;
|
||||
MSR &= ~0x04EF36;
|
||||
PC = NPC = 0x00000300;
|
||||
// DSISR and DAR regs are changed in GenerateDSIException()
|
||||
|
||||
INFO_LOG(POWERPC, "EXCEPTION_DSI");
|
||||
ppcState.Exceptions &= ~EXCEPTION_DSI;
|
||||
}
|
||||
else if (exceptions & EXCEPTION_ALIGNMENT)
|
||||
{
|
||||
//This never happens ATM
|
||||
// perhaps we can get dcb* instructions to use this :p
|
||||
SRR0 = PC;
|
||||
SRR1 = MSR & 0x87C0FFFF;
|
||||
MSR |= (MSR >> 16) & 1;
|
||||
MSR &= ~0x04EF36;
|
||||
PC = NPC = 0x00000600;
|
||||
INFO_LOG(POWERPC, "EXCEPTION_DSI");
|
||||
ppcState.Exceptions &= ~EXCEPTION_DSI;
|
||||
}
|
||||
else if (exceptions & EXCEPTION_ALIGNMENT)
|
||||
{
|
||||
// This never happens ATM
|
||||
// perhaps we can get dcb* instructions to use this :p
|
||||
SRR0 = PC;
|
||||
SRR1 = MSR & 0x87C0FFFF;
|
||||
MSR |= (MSR >> 16) & 1;
|
||||
MSR &= ~0x04EF36;
|
||||
PC = NPC = 0x00000600;
|
||||
|
||||
//TODO crazy amount of DSISR options to check out
|
||||
// TODO crazy amount of DSISR options to check out
|
||||
|
||||
INFO_LOG(POWERPC, "EXCEPTION_ALIGNMENT");
|
||||
ppcState.Exceptions &= ~EXCEPTION_ALIGNMENT;
|
||||
}
|
||||
INFO_LOG(POWERPC, "EXCEPTION_ALIGNMENT");
|
||||
ppcState.Exceptions &= ~EXCEPTION_ALIGNMENT;
|
||||
}
|
||||
|
||||
// EXTERNAL INTERRUPT
|
||||
else if (MSR & 0x0008000) // Handling is delayed until MSR.EE=1.
|
||||
{
|
||||
if (exceptions & EXCEPTION_EXTERNAL_INT)
|
||||
{
|
||||
// Pokemon gets this "too early", it hasn't a handler yet
|
||||
SRR0 = NPC;
|
||||
SRR1 = MSR & 0x87C0FFFF;
|
||||
MSR |= (MSR >> 16) & 1;
|
||||
MSR &= ~0x04EF36;
|
||||
PC = NPC = 0x00000500;
|
||||
// EXTERNAL INTERRUPT
|
||||
else if (MSR & 0x0008000) // Handling is delayed until MSR.EE=1.
|
||||
{
|
||||
if (exceptions & EXCEPTION_EXTERNAL_INT)
|
||||
{
|
||||
// Pokemon gets this "too early", it hasn't a handler yet
|
||||
SRR0 = NPC;
|
||||
SRR1 = MSR & 0x87C0FFFF;
|
||||
MSR |= (MSR >> 16) & 1;
|
||||
MSR &= ~0x04EF36;
|
||||
PC = NPC = 0x00000500;
|
||||
|
||||
INFO_LOG(POWERPC, "EXCEPTION_EXTERNAL_INT");
|
||||
ppcState.Exceptions &= ~EXCEPTION_EXTERNAL_INT;
|
||||
INFO_LOG(POWERPC, "EXCEPTION_EXTERNAL_INT");
|
||||
ppcState.Exceptions &= ~EXCEPTION_EXTERNAL_INT;
|
||||
|
||||
_dbg_assert_msg_(POWERPC, (SRR1 & 0x02) != 0, "EXTERNAL_INT unrecoverable???");
|
||||
}
|
||||
else if (exceptions & EXCEPTION_PERFORMANCE_MONITOR)
|
||||
{
|
||||
SRR0 = NPC;
|
||||
SRR1 = MSR & 0x87C0FFFF;
|
||||
MSR |= (MSR >> 16) & 1;
|
||||
MSR &= ~0x04EF36;
|
||||
PC = NPC = 0x00000F00;
|
||||
_dbg_assert_msg_(POWERPC, (SRR1 & 0x02) != 0, "EXTERNAL_INT unrecoverable???");
|
||||
}
|
||||
else if (exceptions & EXCEPTION_PERFORMANCE_MONITOR)
|
||||
{
|
||||
SRR0 = NPC;
|
||||
SRR1 = MSR & 0x87C0FFFF;
|
||||
MSR |= (MSR >> 16) & 1;
|
||||
MSR &= ~0x04EF36;
|
||||
PC = NPC = 0x00000F00;
|
||||
|
||||
INFO_LOG(POWERPC, "EXCEPTION_PERFORMANCE_MONITOR");
|
||||
ppcState.Exceptions &= ~EXCEPTION_PERFORMANCE_MONITOR;
|
||||
}
|
||||
else if (exceptions & EXCEPTION_DECREMENTER)
|
||||
{
|
||||
SRR0 = NPC;
|
||||
SRR1 = MSR & 0x87C0FFFF;
|
||||
MSR |= (MSR >> 16) & 1;
|
||||
MSR &= ~0x04EF36;
|
||||
PC = NPC = 0x00000900;
|
||||
INFO_LOG(POWERPC, "EXCEPTION_PERFORMANCE_MONITOR");
|
||||
ppcState.Exceptions &= ~EXCEPTION_PERFORMANCE_MONITOR;
|
||||
}
|
||||
else if (exceptions & EXCEPTION_DECREMENTER)
|
||||
{
|
||||
SRR0 = NPC;
|
||||
SRR1 = MSR & 0x87C0FFFF;
|
||||
MSR |= (MSR >> 16) & 1;
|
||||
MSR &= ~0x04EF36;
|
||||
PC = NPC = 0x00000900;
|
||||
|
||||
INFO_LOG(POWERPC, "EXCEPTION_DECREMENTER");
|
||||
ppcState.Exceptions &= ~EXCEPTION_DECREMENTER;
|
||||
}
|
||||
}
|
||||
INFO_LOG(POWERPC, "EXCEPTION_DECREMENTER");
|
||||
ppcState.Exceptions &= ~EXCEPTION_DECREMENTER;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CheckExternalExceptions()
|
||||
{
|
||||
u32 exceptions = ppcState.Exceptions;
|
||||
u32 exceptions = ppcState.Exceptions;
|
||||
|
||||
// EXTERNAL INTERRUPT
|
||||
if (exceptions && (MSR & 0x0008000)) // Handling is delayed until MSR.EE=1.
|
||||
{
|
||||
if (exceptions & EXCEPTION_EXTERNAL_INT)
|
||||
{
|
||||
// Pokemon gets this "too early", it hasn't a handler yet
|
||||
SRR0 = NPC;
|
||||
SRR1 = MSR & 0x87C0FFFF;
|
||||
MSR |= (MSR >> 16) & 1;
|
||||
MSR &= ~0x04EF36;
|
||||
PC = NPC = 0x00000500;
|
||||
// EXTERNAL INTERRUPT
|
||||
if (exceptions && (MSR & 0x0008000)) // Handling is delayed until MSR.EE=1.
|
||||
{
|
||||
if (exceptions & EXCEPTION_EXTERNAL_INT)
|
||||
{
|
||||
// Pokemon gets this "too early", it hasn't a handler yet
|
||||
SRR0 = NPC;
|
||||
SRR1 = MSR & 0x87C0FFFF;
|
||||
MSR |= (MSR >> 16) & 1;
|
||||
MSR &= ~0x04EF36;
|
||||
PC = NPC = 0x00000500;
|
||||
|
||||
INFO_LOG(POWERPC, "EXCEPTION_EXTERNAL_INT");
|
||||
ppcState.Exceptions &= ~EXCEPTION_EXTERNAL_INT;
|
||||
INFO_LOG(POWERPC, "EXCEPTION_EXTERNAL_INT");
|
||||
ppcState.Exceptions &= ~EXCEPTION_EXTERNAL_INT;
|
||||
|
||||
_dbg_assert_msg_(POWERPC, (SRR1 & 0x02) != 0, "EXTERNAL_INT unrecoverable???");
|
||||
}
|
||||
else if (exceptions & EXCEPTION_PERFORMANCE_MONITOR)
|
||||
{
|
||||
SRR0 = NPC;
|
||||
SRR1 = MSR & 0x87C0FFFF;
|
||||
MSR |= (MSR >> 16) & 1;
|
||||
MSR &= ~0x04EF36;
|
||||
PC = NPC = 0x00000F00;
|
||||
_dbg_assert_msg_(POWERPC, (SRR1 & 0x02) != 0, "EXTERNAL_INT unrecoverable???");
|
||||
}
|
||||
else if (exceptions & EXCEPTION_PERFORMANCE_MONITOR)
|
||||
{
|
||||
SRR0 = NPC;
|
||||
SRR1 = MSR & 0x87C0FFFF;
|
||||
MSR |= (MSR >> 16) & 1;
|
||||
MSR &= ~0x04EF36;
|
||||
PC = NPC = 0x00000F00;
|
||||
|
||||
INFO_LOG(POWERPC, "EXCEPTION_PERFORMANCE_MONITOR");
|
||||
ppcState.Exceptions &= ~EXCEPTION_PERFORMANCE_MONITOR;
|
||||
}
|
||||
else if (exceptions & EXCEPTION_DECREMENTER)
|
||||
{
|
||||
SRR0 = NPC;
|
||||
SRR1 = MSR & 0x87C0FFFF;
|
||||
MSR |= (MSR >> 16) & 1;
|
||||
MSR &= ~0x04EF36;
|
||||
PC = NPC = 0x00000900;
|
||||
INFO_LOG(POWERPC, "EXCEPTION_PERFORMANCE_MONITOR");
|
||||
ppcState.Exceptions &= ~EXCEPTION_PERFORMANCE_MONITOR;
|
||||
}
|
||||
else if (exceptions & EXCEPTION_DECREMENTER)
|
||||
{
|
||||
SRR0 = NPC;
|
||||
SRR1 = MSR & 0x87C0FFFF;
|
||||
MSR |= (MSR >> 16) & 1;
|
||||
MSR &= ~0x04EF36;
|
||||
PC = NPC = 0x00000900;
|
||||
|
||||
INFO_LOG(POWERPC, "EXCEPTION_DECREMENTER");
|
||||
ppcState.Exceptions &= ~EXCEPTION_DECREMENTER;
|
||||
}
|
||||
else
|
||||
{
|
||||
_dbg_assert_msg_(POWERPC, 0, "Unknown EXT interrupt: Exceptions == %08x", exceptions);
|
||||
ERROR_LOG(POWERPC, "Unknown EXTERNAL INTERRUPT exception: Exceptions == %08x", exceptions);
|
||||
}
|
||||
}
|
||||
INFO_LOG(POWERPC, "EXCEPTION_DECREMENTER");
|
||||
ppcState.Exceptions &= ~EXCEPTION_DECREMENTER;
|
||||
}
|
||||
else
|
||||
{
|
||||
_dbg_assert_msg_(POWERPC, 0, "Unknown EXT interrupt: Exceptions == %08x", exceptions);
|
||||
ERROR_LOG(POWERPC, "Unknown EXTERNAL INTERRUPT exception: Exceptions == %08x", exceptions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CheckBreakPoints()
|
||||
{
|
||||
if (PowerPC::breakpoints.IsAddressBreakPoint(PC))
|
||||
{
|
||||
CPU::Break();
|
||||
if (PowerPC::breakpoints.IsTempBreakPoint(PC))
|
||||
PowerPC::breakpoints.Remove(PC);
|
||||
}
|
||||
if (PowerPC::breakpoints.IsAddressBreakPoint(PC))
|
||||
{
|
||||
CPU::Break();
|
||||
if (PowerPC::breakpoints.IsTempBreakPoint(PC))
|
||||
PowerPC::breakpoints.Remove(PC);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
// FPSCR update functions
|
||||
|
||||
void UpdateFPRF(double dvalue)
|
||||
{
|
||||
FPSCR.FPRF = MathUtil::ClassifyDouble(dvalue);
|
||||
//if (FPSCR.FPRF == 0x11)
|
||||
// PanicAlert("QNAN alert");
|
||||
FPSCR.FPRF = MathUtil::ClassifyDouble(dvalue);
|
||||
// if (FPSCR.FPRF == 0x11)
|
||||
// PanicAlert("QNAN alert");
|
||||
}
|
||||
|
Reference in New Issue
Block a user