157 changes: 83 additions & 74 deletions Source/Core/Core/Boot/Boot_BS2Emu.cpp
Expand Up @@ -55,80 +55,83 @@ void PresetTimeBaseTicks()
}
} // Anonymous namespace

void CBoot::RunFunction(u32 address)
void CBoot::RunFunction(Core::System& system, u32 address)
{
PC = address;
LR = 0x00;
auto& ppc_state = system.GetPPCState();

while (PC != 0x00)
ppc_state.pc = address;
LR(ppc_state) = 0x00;

while (ppc_state.pc != 0x00)
PowerPC::SingleStep();
}

void CBoot::SetupMSR()
void CBoot::SetupMSR(PowerPC::PowerPCState& ppc_state)
{
// 0x0002032
MSR.RI = 1;
MSR.DR = 1;
MSR.IR = 1;
MSR.FP = 1;
ppc_state.msr.RI = 1;
ppc_state.msr.DR = 1;
ppc_state.msr.IR = 1;
ppc_state.msr.FP = 1;
}

void CBoot::SetupHID(bool is_wii)
void CBoot::SetupHID(PowerPC::PowerPCState& ppc_state, bool is_wii)
{
// HID0 is 0x0011c464 on GC, 0x0011c664 on Wii
HID0.BHT = 1;
HID0.BTIC = 1;
HID0.DCFA = 1;
HID0(ppc_state).BHT = 1;
HID0(ppc_state).BTIC = 1;
HID0(ppc_state).DCFA = 1;
if (is_wii)
HID0.SPD = 1;
HID0.DCFI = 1;
HID0.DCE = 1;
HID0(ppc_state).SPD = 1;
HID0(ppc_state).DCFI = 1;
HID0(ppc_state).DCE = 1;
// Note that Datel titles will fail to boot if the instruction cache is not enabled; see
// https://bugs.dolphin-emu.org/issues/8223
HID0.ICE = 1;
HID0.NHR = 1;
HID0.DPM = 1;
HID0(ppc_state).ICE = 1;
HID0(ppc_state).NHR = 1;
HID0(ppc_state).DPM = 1;

// HID1 is initialized in PowerPC.cpp to 0x80000000
// HID2 is 0xe0000000
HID2.PSE = 1;
HID2.WPE = 1;
HID2.LSQE = 1;
HID2(ppc_state).PSE = 1;
HID2(ppc_state).WPE = 1;
HID2(ppc_state).LSQE = 1;

// HID4 is 0 on GC and 0x83900000 on Wii
if (is_wii)
{
HID4.L2CFI = 1;
HID4.LPE = 1;
HID4.ST0 = 1;
HID4.SBE = 1;
HID4.reserved_3 = 1;
HID4(ppc_state).L2CFI = 1;
HID4(ppc_state).LPE = 1;
HID4(ppc_state).ST0 = 1;
HID4(ppc_state).SBE = 1;
HID4(ppc_state).reserved_3 = 1;
}
}

void CBoot::SetupBAT(bool is_wii)
void CBoot::SetupBAT(Core::System& system, bool is_wii)
{
PowerPC::ppcState.spr[SPR_IBAT0U] = 0x80001fff;
PowerPC::ppcState.spr[SPR_IBAT0L] = 0x00000002;
PowerPC::ppcState.spr[SPR_DBAT0U] = 0x80001fff;
PowerPC::ppcState.spr[SPR_DBAT0L] = 0x00000002;
PowerPC::ppcState.spr[SPR_DBAT1U] = 0xc0001fff;
PowerPC::ppcState.spr[SPR_DBAT1L] = 0x0000002a;
auto& ppc_state = system.GetPPCState();
ppc_state.spr[SPR_IBAT0U] = 0x80001fff;
ppc_state.spr[SPR_IBAT0L] = 0x00000002;
ppc_state.spr[SPR_DBAT0U] = 0x80001fff;
ppc_state.spr[SPR_DBAT0L] = 0x00000002;
ppc_state.spr[SPR_DBAT1U] = 0xc0001fff;
ppc_state.spr[SPR_DBAT1L] = 0x0000002a;
if (is_wii)
{
PowerPC::ppcState.spr[SPR_IBAT4U] = 0x90001fff;
PowerPC::ppcState.spr[SPR_IBAT4L] = 0x10000002;
PowerPC::ppcState.spr[SPR_DBAT4U] = 0x90001fff;
PowerPC::ppcState.spr[SPR_DBAT4L] = 0x10000002;
PowerPC::ppcState.spr[SPR_DBAT5U] = 0xd0001fff;
PowerPC::ppcState.spr[SPR_DBAT5L] = 0x1000002a;
HID4.SBE = 1;
ppc_state.spr[SPR_IBAT4U] = 0x90001fff;
ppc_state.spr[SPR_IBAT4L] = 0x10000002;
ppc_state.spr[SPR_DBAT4U] = 0x90001fff;
ppc_state.spr[SPR_DBAT4L] = 0x10000002;
ppc_state.spr[SPR_DBAT5U] = 0xd0001fff;
ppc_state.spr[SPR_DBAT5L] = 0x1000002a;
HID4(ppc_state).SBE = 1;
}
PowerPC::DBATUpdated();
PowerPC::IBATUpdated();
}

bool CBoot::RunApploader(bool is_wii, const DiscIO::VolumeDisc& volume,
bool CBoot::RunApploader(Core::System& system, bool is_wii, const DiscIO::VolumeDisc& volume,
const std::vector<DiscIO::Riivolution::Patch>& riivolution_patches)
{
const DiscIO::Partition partition = volume.GetGamePartition();
Expand All @@ -148,40 +151,42 @@ bool CBoot::RunApploader(bool is_wii, const DiscIO::VolumeDisc& volume,

// TODO - Make Apploader(or just RunFunction()) debuggable!!!

auto& ppc_state = system.GetPPCState();

// Call iAppLoaderEntry.
DEBUG_LOG_FMT(BOOT, "Call iAppLoaderEntry");
const u32 iAppLoaderFuncAddr = is_wii ? 0x80004000 : 0x80003100;
PowerPC::ppcState.gpr[3] = iAppLoaderFuncAddr + 0;
PowerPC::ppcState.gpr[4] = iAppLoaderFuncAddr + 4;
PowerPC::ppcState.gpr[5] = iAppLoaderFuncAddr + 8;
RunFunction(*entry);
ppc_state.gpr[3] = iAppLoaderFuncAddr + 0;
ppc_state.gpr[4] = iAppLoaderFuncAddr + 4;
ppc_state.gpr[5] = iAppLoaderFuncAddr + 8;
RunFunction(system, *entry);
const u32 iAppLoaderInit = PowerPC::Read_U32(iAppLoaderFuncAddr + 0);
const u32 iAppLoaderMain = PowerPC::Read_U32(iAppLoaderFuncAddr + 4);
const u32 iAppLoaderClose = PowerPC::Read_U32(iAppLoaderFuncAddr + 8);

// iAppLoaderInit
DEBUG_LOG_FMT(BOOT, "Call iAppLoaderInit");
PowerPC::HostWrite_U32(0x4E800020, 0x81300000); // Write BLR
HLE::Patch(0x81300000, "AppLoaderReport"); // HLE OSReport for Apploader
PowerPC::ppcState.gpr[3] = 0x81300000;
RunFunction(iAppLoaderInit);
PowerPC::HostWrite_U32(0x4E800020, 0x81300000); // Write BLR
HLE::Patch(system, 0x81300000, "AppLoaderReport"); // HLE OSReport for Apploader
ppc_state.gpr[3] = 0x81300000;
RunFunction(system, iAppLoaderInit);

// iAppLoaderMain - Here we load the apploader, the DOL (the exe) and the FST (filesystem).
// To give you an idea about where the stuff is located on the disc take a look at yagcd
// ch 13.
DEBUG_LOG_FMT(BOOT, "Call iAppLoaderMain");

PowerPC::ppcState.gpr[3] = 0x81300004;
PowerPC::ppcState.gpr[4] = 0x81300008;
PowerPC::ppcState.gpr[5] = 0x8130000c;
ppc_state.gpr[3] = 0x81300004;
ppc_state.gpr[4] = 0x81300008;
ppc_state.gpr[5] = 0x8130000c;

RunFunction(iAppLoaderMain);
RunFunction(system, iAppLoaderMain);

// iAppLoaderMain returns 1 if the pointers in R3/R4/R5 were filled with values for DVD copy
// Typical behaviour is doing it once for each section defined in the DOL header. Some unlicensed
// titles don't have a properly constructed DOL and maintain a table of these values in apploader.
// iAppLoaderMain returns 0 when there are no more sections to copy.
while (PowerPC::ppcState.gpr[3] != 0x00)
while (ppc_state.gpr[3] != 0x00)
{
const u32 ram_address = PowerPC::Read_U32(0x81300004);
const u32 length = PowerPC::Read_U32(0x81300008);
Expand All @@ -193,20 +198,20 @@ bool CBoot::RunApploader(bool is_wii, const DiscIO::VolumeDisc& volume,

DiscIO::Riivolution::ApplyApploaderMemoryPatches(riivolution_patches, ram_address, length);

PowerPC::ppcState.gpr[3] = 0x81300004;
PowerPC::ppcState.gpr[4] = 0x81300008;
PowerPC::ppcState.gpr[5] = 0x8130000c;
ppc_state.gpr[3] = 0x81300004;
ppc_state.gpr[4] = 0x81300008;
ppc_state.gpr[5] = 0x8130000c;

RunFunction(iAppLoaderMain);
RunFunction(system, iAppLoaderMain);
}

// iAppLoaderClose
DEBUG_LOG_FMT(BOOT, "call iAppLoaderClose");
RunFunction(iAppLoaderClose);
HLE::UnPatch("AppLoaderReport");
RunFunction(system, iAppLoaderClose);
HLE::UnPatch(system, "AppLoaderReport");

// return
PC = PowerPC::ppcState.gpr[3];
ppc_state.pc = ppc_state.gpr[3];

return true;
}
Expand Down Expand Up @@ -255,9 +260,11 @@ bool CBoot::EmulatedBS2_GC(Core::System& system, const DiscIO::VolumeDisc& volum
{
INFO_LOG_FMT(BOOT, "Faking GC BS2...");

SetupMSR();
SetupHID(/*is_wii*/ false);
SetupBAT(/*is_wii*/ false);
auto& ppc_state = system.GetPPCState();

SetupMSR(ppc_state);
SetupHID(ppc_state, /*is_wii*/ false);
SetupBAT(system, /*is_wii*/ false);

SetupGCMemory(system);

Expand Down Expand Up @@ -296,13 +303,13 @@ bool CBoot::EmulatedBS2_GC(Core::System& system, const DiscIO::VolumeDisc& volum
// Setup pointers like real BS2 does

// StackPointer, used to be set to 0x816ffff0
PowerPC::ppcState.gpr[1] = ntsc ? 0x81566550 : 0x815edca8;
ppc_state.gpr[1] = ntsc ? 0x81566550 : 0x815edca8;
// Global pointer to Small Data Area 2 Base (haven't seen anything use it...meh)
PowerPC::ppcState.gpr[2] = ntsc ? 0x81465cc0 : 0x814b5b20;
ppc_state.gpr[2] = ntsc ? 0x81465cc0 : 0x814b5b20;
// Global pointer to Small Data Area Base (Luigi's Mansion's apploader uses it)
PowerPC::ppcState.gpr[13] = ntsc ? 0x81465320 : 0x814b4fc0;
ppc_state.gpr[13] = ntsc ? 0x81465320 : 0x814b4fc0;

return RunApploader(/*is_wii*/ false, volume, riivolution_patches);
return RunApploader(system, /*is_wii*/ false, volume, riivolution_patches);
}

static DiscIO::Region CodeRegion(char c)
Expand Down Expand Up @@ -559,17 +566,19 @@ bool CBoot::EmulatedBS2_Wii(Core::System& system, const DiscIO::VolumeDisc& volu
// after this check during booting.
DVDRead(volume, 0, 0x3180, 4, partition);

SetupMSR();
SetupHID(/*is_wii*/ true);
SetupBAT(/*is_wii*/ true);
auto& ppc_state = system.GetPPCState();

SetupMSR(ppc_state);
SetupHID(ppc_state, /*is_wii*/ true);
SetupBAT(system, /*is_wii*/ true);

memory.Write_U32(0x4c000064, 0x00000300); // Write default DSI Handler: rfi
memory.Write_U32(0x4c000064, 0x00000800); // Write default FPU Handler: rfi
memory.Write_U32(0x4c000064, 0x00000C00); // Write default Syscall Handler: rfi

PowerPC::ppcState.gpr[1] = 0x816ffff0; // StackPointer
ppc_state.gpr[1] = 0x816ffff0; // StackPointer

if (!RunApploader(/*is_wii*/ true, volume, riivolution_patches))
if (!RunApploader(system, /*is_wii*/ true, volume, riivolution_patches))
return false;

// The Apploader probably just overwrote values needed for RAM Override. Run this again!
Expand Down
9 changes: 7 additions & 2 deletions Source/Core/Core/CheatSearch.cpp
Expand Up @@ -20,6 +20,7 @@
#include "Core/HW/Memmap.h"
#include "Core/PowerPC/MMU.h"
#include "Core/PowerPC/PowerPC.h"
#include "Core/System.h"

Cheats::DataType Cheats::GetDataType(const Cheats::SearchValue& value)
{
Expand Down Expand Up @@ -204,7 +205,9 @@ Cheats::NewSearch(const std::vector<Cheats::MemoryRange>& memory_ranges,
return;
}

if (address_space == PowerPC::RequestedAddressSpace::Virtual && !MSR.DR)
auto& system = Core::System::GetInstance();
auto& ppc_state = system.GetPPCState();
if (address_space == PowerPC::RequestedAddressSpace::Virtual && !ppc_state.msr.DR)
{
error_code = Cheats::SearchErrorCode::VirtualAddressesCurrentlyNotAccessible;
return;
Expand Down Expand Up @@ -263,7 +266,9 @@ Cheats::NextSearch(const std::vector<Cheats::SearchResult<T>>& previous_results,
return;
}

if (address_space == PowerPC::RequestedAddressSpace::Virtual && !MSR.DR)
auto& system = Core::System::GetInstance();
auto& ppc_state = system.GetPPCState();
if (address_space == PowerPC::RequestedAddressSpace::Virtual && !ppc_state.msr.DR)
{
error_code = Cheats::SearchErrorCode::VirtualAddressesCurrentlyNotAccessible;
return;
Expand Down
4 changes: 3 additions & 1 deletion Source/Core/Core/ConfigManager.cpp
Expand Up @@ -51,6 +51,7 @@
#include "Core/PatchEngine.h"
#include "Core/PowerPC/PPCSymbolDB.h"
#include "Core/PowerPC/PowerPC.h"
#include "Core/System.h"
#include "Core/TitleDatabase.h"
#include "VideoCommon/HiresTextures.h"

Expand Down Expand Up @@ -202,7 +203,8 @@ void SConfig::OnNewTitleLoad()
Host_NotifyMapLoaded();
}
CBoot::LoadMapFromFilename();
HLE::Reload();
auto& system = Core::System::GetInstance();
HLE::Reload(system);
PatchEngine::Reload();
HiresTexture::Update();
}
Expand Down
33 changes: 20 additions & 13 deletions Source/Core/Core/CoreTiming.cpp
Expand Up @@ -44,6 +44,10 @@ static void EmptyTimedCallback(Core::System& system, u64 userdata, s64 cyclesLat
{
}

CoreTimingManager::CoreTimingManager(Core::System& system) : m_system(system)
{
}

// Changing the CPU speed in Dolphin isn't actually done by changing the physical clock rate,
// but by changing the amount of work done in a particular amount of time. This tends to be more
// compatible because it stops the games from actually knowing directly that the clock rate has
Expand Down Expand Up @@ -90,7 +94,7 @@ void CoreTimingManager::Init()

m_last_oc_factor = m_config_oc_factor;
m_globals.last_OC_factor_inverted = m_config_oc_inv_factor;
PowerPC::ppcState.downcount = CyclesToDowncount(MAX_SLICE_LENGTH);
m_system.GetPPCState().downcount = CyclesToDowncount(MAX_SLICE_LENGTH);
m_globals.slice_length = MAX_SLICE_LENGTH;
m_globals.global_timer = 0;
m_idled_cycles = 0;
Expand Down Expand Up @@ -195,7 +199,7 @@ u64 CoreTimingManager::GetTicks() const
u64 ticks = static_cast<u64>(m_globals.global_timer);
if (!m_is_global_timer_sane)
{
int downcount = DowncountToCycles(PowerPC::ppcState.downcount);
int downcount = DowncountToCycles(m_system.GetPPCState().downcount);
ticks += m_globals.slice_length - downcount;
}
return ticks;
Expand Down Expand Up @@ -277,13 +281,13 @@ void CoreTimingManager::RemoveAllEvents(EventType* event_type)
void CoreTimingManager::ForceExceptionCheck(s64 cycles)
{
cycles = std::max<s64>(0, cycles);
if (DowncountToCycles(PowerPC::ppcState.downcount) > cycles)
auto& ppc_state = m_system.GetPPCState();
if (DowncountToCycles(ppc_state.downcount) > cycles)
{
// downcount is always (much) smaller than MAX_INT so we can safely cast cycles to an int here.
// Account for cycles already executed by adjusting the m_globals.slice_length
m_globals.slice_length -=
DowncountToCycles(PowerPC::ppcState.downcount) - static_cast<int>(cycles);
PowerPC::ppcState.downcount = CyclesToDowncount(static_cast<int>(cycles));
m_globals.slice_length -= DowncountToCycles(ppc_state.downcount) - static_cast<int>(cycles);
ppc_state.downcount = CyclesToDowncount(static_cast<int>(cycles));
}
}

Expand All @@ -299,11 +303,12 @@ void CoreTimingManager::MoveEvents()

void CoreTimingManager::Advance()
{
auto& system = Core::System::GetInstance();
auto& system = m_system;
auto& ppc_state = m_system.GetPPCState();

MoveEvents();

int cyclesExecuted = m_globals.slice_length - DowncountToCycles(PowerPC::ppcState.downcount);
int cyclesExecuted = m_globals.slice_length - DowncountToCycles(ppc_state.downcount);
m_globals.global_timer += cyclesExecuted;
m_last_oc_factor = m_config_oc_factor;
m_globals.last_OC_factor_inverted = m_config_oc_inv_factor;
Expand All @@ -330,7 +335,7 @@ void CoreTimingManager::Advance()
std::min<s64>(m_event_queue.front().time - m_globals.global_timer, MAX_SLICE_LENGTH));
}

PowerPC::ppcState.downcount = CyclesToDowncount(m_globals.slice_length);
ppc_state.downcount = CyclesToDowncount(m_globals.slice_length);

// Check for any external exceptions.
// It's important to do this after processing events otherwise any exceptions will be delayed
Expand Down Expand Up @@ -438,18 +443,20 @@ void CoreTimingManager::AdjustEventQueueTimes(u32 new_ppc_clock, u32 old_ppc_clo

void CoreTimingManager::Idle()
{
auto& system = m_system;
auto& ppc_state = m_system.GetPPCState();

if (m_config_sync_on_skip_idle)
{
// When the FIFO is processing data we must not advance because in this way
// the VI will be desynchronized. So, We are waiting until the FIFO finish and
// while we process only the events required by the FIFO.
auto& system = Core::System::GetInstance();
system.GetFifo().FlushGpu(system);
}

PowerPC::UpdatePerformanceMonitor(PowerPC::ppcState.downcount, 0, 0);
m_idled_cycles += DowncountToCycles(PowerPC::ppcState.downcount);
PowerPC::ppcState.downcount = 0;
PowerPC::UpdatePerformanceMonitor(ppc_state.downcount, 0, 0, ppc_state);
m_idled_cycles += DowncountToCycles(ppc_state.downcount);
ppc_state.downcount = 0;
}

std::string CoreTimingManager::GetScheduledEventsSummary() const
Expand Down
4 changes: 4 additions & 0 deletions Source/Core/Core/CoreTiming.h
Expand Up @@ -75,6 +75,8 @@ void GlobalIdle();
class CoreTimingManager
{
public:
explicit CoreTimingManager(Core::System& system);

// CoreTiming begins at the boundary of timing slice -1. An initial call to Advance() is
// required to end slice -1 and start slice 0 before the first cycle of code is executed.
void Init();
Expand Down Expand Up @@ -151,6 +153,8 @@ class CoreTimingManager
private:
Globals m_globals;

Core::System& m_system;

// unordered_map stores each element separately as a linked list node so pointers to elements
// remain stable regardless of rehashes/resizing.
std::unordered_map<std::string, EventType> m_event_types;
Expand Down
39 changes: 24 additions & 15 deletions Source/Core/Core/Debugger/Debugger_SymbolMap.cpp
Expand Up @@ -16,6 +16,7 @@
#include "Core/PowerPC/MMU.h"
#include "Core/PowerPC/PPCSymbolDB.h"
#include "Core/PowerPC/PowerPC.h"
#include "Core/System.h"

namespace Dolphin_Debugger
{
Expand Down Expand Up @@ -43,11 +44,13 @@ static bool IsStackBottom(u32 addr)
return !addr || !PowerPC::HostIsRAMAddress(addr);
}

static void WalkTheStack(const std::function<void(u32)>& stack_step)
static void WalkTheStack(Core::System& system, const std::function<void(u32)>& stack_step)
{
if (!IsStackBottom(PowerPC::ppcState.gpr[1]))
auto& ppc_state = system.GetPPCState();

if (!IsStackBottom(ppc_state.gpr[1]))
{
u32 addr = PowerPC::HostRead_U32(PowerPC::ppcState.gpr[1]); // SP
u32 addr = PowerPC::HostRead_U32(ppc_state.gpr[1]); // SP

// Walk the stack chain
for (int count = 0; !IsStackBottom(addr + 4) && (count++ < 20); ++count)
Expand All @@ -66,12 +69,14 @@ static void WalkTheStack(const std::function<void(u32)>& stack_step)
// Returns callstack "formatted for debugging" - meaning that it
// includes LR as the last item, and all items are the last step,
// instead of "pointing ahead"
bool GetCallstack(std::vector<CallstackEntry>& output)
bool GetCallstack(Core::System& system, std::vector<CallstackEntry>& output)
{
if (!Core::IsRunning() || !PowerPC::HostIsRAMAddress(PowerPC::ppcState.gpr[1]))
auto& ppc_state = system.GetPPCState();

if (!Core::IsRunning() || !PowerPC::HostIsRAMAddress(ppc_state.gpr[1]))
return false;

if (LR == 0)
if (LR(ppc_state) == 0)
{
CallstackEntry entry;
entry.Name = "(error: LR=0)";
Expand All @@ -81,11 +86,12 @@ bool GetCallstack(std::vector<CallstackEntry>& output)
}

CallstackEntry entry;
entry.Name = fmt::format(" * {} [ LR = {:08x} ]\n", g_symbolDB.GetDescription(LR), LR - 4);
entry.vAddress = LR - 4;
entry.Name = fmt::format(" * {} [ LR = {:08x} ]\n", g_symbolDB.GetDescription(LR(ppc_state)),
LR(ppc_state) - 4);
entry.vAddress = LR(ppc_state) - 4;
output.push_back(entry);

WalkTheStack([&entry, &output](u32 func_addr) {
WalkTheStack(system, [&entry, &output](u32 func_addr) {
std::string func_desc = g_symbolDB.GetDescription(func_addr);
if (func_desc.empty() || func_desc == "Invalid")
func_desc = "(unknown)";
Expand All @@ -97,21 +103,24 @@ bool GetCallstack(std::vector<CallstackEntry>& output)
return true;
}

void PrintCallstack(Common::Log::LogType type, Common::Log::LogLevel level)
void PrintCallstack(Core::System& system, Common::Log::LogType type, Common::Log::LogLevel level)
{
GENERIC_LOG_FMT(type, level, "== STACK TRACE - SP = {:08x} ==", PowerPC::ppcState.gpr[1]);
auto& ppc_state = system.GetPPCState();

GENERIC_LOG_FMT(type, level, "== STACK TRACE - SP = {:08x} ==", ppc_state.gpr[1]);

if (LR == 0)
if (LR(ppc_state) == 0)
{
GENERIC_LOG_FMT(type, level, " LR = 0 - this is bad");
}

if (g_symbolDB.GetDescription(PC) != g_symbolDB.GetDescription(LR))
if (g_symbolDB.GetDescription(ppc_state.pc) != g_symbolDB.GetDescription(LR(ppc_state)))
{
GENERIC_LOG_FMT(type, level, " * {} [ LR = {:08x} ]", g_symbolDB.GetDescription(LR), LR);
GENERIC_LOG_FMT(type, level, " * {} [ LR = {:08x} ]", g_symbolDB.GetDescription(LR(ppc_state)),
LR(ppc_state));
}

WalkTheStack([type, level](u32 func_addr) {
WalkTheStack(system, [type, level](u32 func_addr) {
std::string func_desc = g_symbolDB.GetDescription(func_addr);
if (func_desc.empty() || func_desc == "Invalid")
func_desc = "(unknown)";
Expand Down
9 changes: 7 additions & 2 deletions Source/Core/Core/Debugger/Debugger_SymbolMap.h
Expand Up @@ -10,6 +10,11 @@
#include "Common/CommonTypes.h"
#include "Common/Logging/Log.h"

namespace Core
{
class System;
}

namespace Dolphin_Debugger
{
struct CallstackEntry
Expand All @@ -18,8 +23,8 @@ struct CallstackEntry
u32 vAddress = 0;
};

bool GetCallstack(std::vector<CallstackEntry>& output);
void PrintCallstack(Common::Log::LogType type, Common::Log::LogLevel level);
bool GetCallstack(Core::System& system, std::vector<CallstackEntry>& output);
void PrintCallstack(Core::System& system, Common::Log::LogType type, Common::Log::LogLevel level);
void PrintDataBuffer(Common::Log::LogType type, const u8* data, size_t size,
std::string_view title);
void AddAutoBreakpoints();
Expand Down
14 changes: 9 additions & 5 deletions Source/Core/Core/Debugger/PPCDebugInterface.cpp
Expand Up @@ -23,6 +23,7 @@
#include "Core/PowerPC/MMU.h"
#include "Core/PowerPC/PPCSymbolDB.h"
#include "Core/PowerPC/PowerPC.h"
#include "Core/System.h"

void ApplyMemoryPatch(Common::Debug::MemoryPatch& patch, bool store_existing_value)
{
Expand Down Expand Up @@ -81,7 +82,10 @@ void PPCPatches::UnPatch(std::size_t index)
PatchEngine::RemoveMemoryPatch(index);
}

PPCDebugInterface::PPCDebugInterface() = default;
PPCDebugInterface::PPCDebugInterface(Core::System& system) : m_system(system)
{
}

PPCDebugInterface::~PPCDebugInterface() = default;

std::size_t PPCDebugInterface::SetWatch(u32 address, std::string name)
Expand Down Expand Up @@ -449,7 +453,7 @@ PPCDebugInterface::GetMemoryAddressFromInstruction(const std::string& instructio
if (is_reg == offset_match[0])
{
const int register_index = std::stoi(offset_match.substr(1), nullptr, 10);
offset = (register_index == 0 ? 0 : GPR(register_index));
offset = (register_index == 0 ? 0 : m_system.GetPPCState().gpr[register_index]);
}
else
{
Expand All @@ -468,7 +472,7 @@ PPCDebugInterface::GetMemoryAddressFromInstruction(const std::string& instructio
else
i = std::stoi(register_match, nullptr, 10);

const u32 base_address = GPR(i);
const u32 base_address = m_system.GetPPCState().gpr[i];

if (!match.str(1).empty())
return base_address - offset;
Expand All @@ -478,12 +482,12 @@ PPCDebugInterface::GetMemoryAddressFromInstruction(const std::string& instructio

u32 PPCDebugInterface::GetPC() const
{
return PowerPC::ppcState.pc;
return m_system.GetPPCState().pc;
}

void PPCDebugInterface::SetPC(u32 address)
{
PowerPC::ppcState.pc = address;
m_system.GetPPCState().pc = address;
}

void PPCDebugInterface::RunToBreakpoint()
Expand Down
8 changes: 7 additions & 1 deletion Source/Core/Core/Debugger/PPCDebugInterface.h
Expand Up @@ -12,6 +12,11 @@
#include "Common/DebugInterface.h"
#include "Core/NetworkCaptureLogger.h"

namespace Core
{
class System;
}

void ApplyMemoryPatch(Common::Debug::MemoryPatch& patch, bool store_existing_value = true);

class PPCPatches final : public Common::Debug::MemoryPatches
Expand All @@ -29,7 +34,7 @@ class PPCPatches final : public Common::Debug::MemoryPatches
class PPCDebugInterface final : public Common::DebugInterface
{
public:
PPCDebugInterface();
explicit PPCDebugInterface(Core::System& system);
~PPCDebugInterface() override;

// Watches
Expand Down Expand Up @@ -102,4 +107,5 @@ class PPCDebugInterface final : public Common::DebugInterface
Common::Debug::Watches m_watches;
PPCPatches m_patches;
std::shared_ptr<Core::NetworkCaptureLogger> m_network_logger;
Core::System& m_system;
};
24 changes: 14 additions & 10 deletions Source/Core/Core/FifoPlayer/FifoPlayer.cpp
Expand Up @@ -514,6 +514,7 @@ void FifoPlayer::WriteFifo(const u8* data, u32 start, u32 end)
auto& system = Core::System::GetInstance();
auto& core_timing = system.GetCoreTiming();
auto& gpfifo = system.GetGPFifo();
auto& ppc_state = system.GetPPCState();

// Write up to 256 bytes at a time
while (written < end)
Expand All @@ -528,8 +529,8 @@ void FifoPlayer::WriteFifo(const u8* data, u32 start, u32 end)

u32 burstEnd = std::min(written + 255, lastBurstEnd);

std::copy(data + written, data + burstEnd, PowerPC::ppcState.gather_pipe_ptr);
PowerPC::ppcState.gather_pipe_ptr += burstEnd - written;
std::copy(data + written, data + burstEnd, ppc_state.gather_pipe_ptr);
ppc_state.gather_pipe_ptr += burstEnd - written;
written = burstEnd;

gpfifo.Write8(data[written++]);
Expand All @@ -539,7 +540,7 @@ void FifoPlayer::WriteFifo(const u8* data, u32 start, u32 end)
u32 cyclesUsed = elapsedCycles - m_ElapsedCycles;
m_ElapsedCycles = elapsedCycles;

PowerPC::ppcState.downcount -= cyclesUsed;
ppc_state.downcount -= cyclesUsed;
core_timing.Advance();
}
}
Expand Down Expand Up @@ -629,16 +630,19 @@ void FifoPlayer::ClearEfb()

void FifoPlayer::LoadMemory()
{
auto& system = Core::System::GetInstance();
auto& ppc_state = system.GetPPCState();

UReg_MSR newMSR;
newMSR.DR = 1;
newMSR.IR = 1;
MSR.Hex = newMSR.Hex;
PowerPC::ppcState.spr[SPR_IBAT0U] = 0x80001fff;
PowerPC::ppcState.spr[SPR_IBAT0L] = 0x00000002;
PowerPC::ppcState.spr[SPR_DBAT0U] = 0x80001fff;
PowerPC::ppcState.spr[SPR_DBAT0L] = 0x00000002;
PowerPC::ppcState.spr[SPR_DBAT1U] = 0xc0001fff;
PowerPC::ppcState.spr[SPR_DBAT1L] = 0x0000002a;
ppc_state.msr.Hex = newMSR.Hex;
ppc_state.spr[SPR_IBAT0U] = 0x80001fff;
ppc_state.spr[SPR_IBAT0L] = 0x00000002;
ppc_state.spr[SPR_DBAT0U] = 0x80001fff;
ppc_state.spr[SPR_DBAT0L] = 0x00000002;
ppc_state.spr[SPR_DBAT1U] = 0xc0001fff;
ppc_state.spr[SPR_DBAT1L] = 0x0000002a;
PowerPC::DBATUpdated();
PowerPC::IBATUpdated();

Expand Down
38 changes: 23 additions & 15 deletions Source/Core/Core/GeckoCode.cpp
Expand Up @@ -19,6 +19,7 @@
#include "Core/ConfigManager.h"
#include "Core/PowerPC/MMU.h"
#include "Core/PowerPC/PowerPC.h"
#include "Core/System.h"

namespace Gecko
{
Expand Down Expand Up @@ -204,10 +205,13 @@ static Installation InstallCodeHandlerLocked()
// Turn on codes
PowerPC::HostWrite_U8(1, INSTALLER_BASE_ADDRESS + 7);

auto& system = Core::System::GetInstance();
auto& ppc_state = system.GetPPCState();

// Invalidate the icache and any asm codes
for (unsigned int j = 0; j < (INSTALLER_END_ADDRESS - INSTALLER_BASE_ADDRESS); j += 32)
{
PowerPC::ppcState.iCache.Invalidate(INSTALLER_BASE_ADDRESS + j);
ppc_state.iCache.Invalidate(INSTALLER_BASE_ADDRESS + j);
}
return Installation::Installed;
}
Expand Down Expand Up @@ -253,36 +257,40 @@ void RunCodeHandler()
}
}

auto& system = Core::System::GetInstance();
auto& ppc_state = system.GetPPCState();

// We always do this to avoid problems with the stack since we're branching in random locations.
// Even with function call return hooks (PC == LR), hand coded assembler won't necessarily
// follow the ABI. [Volatile FPR, GPR, CR may not be volatile]
// The codehandler will STMW all of the GPR registers, but we need to fix the Stack's Red
// Zone, the LR, PC (return address) and the volatile floating point registers.
// Build a function call stack frame.
u32 SFP = GPR(1); // Stack Frame Pointer
GPR(1) -= 256; // Stack's Red Zone
GPR(1) -= 16 + 2 * 14 * sizeof(u64); // Our stack frame (HLE_Misc::GeckoReturnTrampoline)
GPR(1) -= 8; // Fake stack frame for codehandler
GPR(1) &= 0xFFFFFFF0; // Align stack to 16bytes
u32 SP = GPR(1); // Stack Pointer
u32 SFP = ppc_state.gpr[1]; // Stack Frame Pointer
ppc_state.gpr[1] -= 256; // Stack's Red Zone
ppc_state.gpr[1] -= 16 + 2 * 14 * sizeof(u64); // Our stack frame
// (HLE_Misc::GeckoReturnTrampoline)
ppc_state.gpr[1] -= 8; // Fake stack frame for codehandler
ppc_state.gpr[1] &= 0xFFFFFFF0; // Align stack to 16bytes
u32 SP = ppc_state.gpr[1]; // Stack Pointer
PowerPC::HostWrite_U32(SP + 8, SP);
// SP + 4 is reserved for the codehandler to save LR to the stack.
PowerPC::HostWrite_U32(SFP, SP + 8); // Real stack frame
PowerPC::HostWrite_U32(PC, SP + 12);
PowerPC::HostWrite_U32(LR, SP + 16);
PowerPC::HostWrite_U32(PowerPC::ppcState.cr.Get(), SP + 20);
PowerPC::HostWrite_U32(ppc_state.pc, SP + 12);
PowerPC::HostWrite_U32(LR(ppc_state), SP + 16);
PowerPC::HostWrite_U32(ppc_state.cr.Get(), SP + 20);
// Registers FPR0->13 are volatile
for (int i = 0; i < 14; ++i)
{
PowerPC::HostWrite_U64(rPS(i).PS0AsU64(), SP + 24 + 2 * i * sizeof(u64));
PowerPC::HostWrite_U64(rPS(i).PS1AsU64(), SP + 24 + (2 * i + 1) * sizeof(u64));
PowerPC::HostWrite_U64(ppc_state.ps[i].PS0AsU64(), SP + 24 + 2 * i * sizeof(u64));
PowerPC::HostWrite_U64(ppc_state.ps[i].PS1AsU64(), SP + 24 + (2 * i + 1) * sizeof(u64));
}
DEBUG_LOG_FMT(ACTIONREPLAY,
"GeckoCodes: Initiating phantom branch-and-link. "
"PC = {:#010x}, SP = {:#010x}, SFP = {:#010x}",
PC, SP, SFP);
LR = HLE_TRAMPOLINE_ADDRESS;
PC = NPC = ENTRY_POINT;
ppc_state.pc, SP, SFP);
LR(ppc_state) = HLE_TRAMPOLINE_ADDRESS;
ppc_state.pc = ppc_state.npc = ENTRY_POINT;
}

} // namespace Gecko
42 changes: 24 additions & 18 deletions Source/Core/Core/HLE/HLE.cpp
Expand Up @@ -63,20 +63,21 @@ constexpr std::array<Hook, 23> os_patches{{
}};
// clang-format on

void Patch(u32 addr, std::string_view func_name)
void Patch(Core::System& system, u32 addr, std::string_view func_name)
{
auto& ppc_state = system.GetPPCState();
for (u32 i = 1; i < os_patches.size(); ++i)
{
if (os_patches[i].name == func_name)
{
s_hooked_addresses[addr] = i;
PowerPC::ppcState.iCache.Invalidate(addr);
ppc_state.iCache.Invalidate(addr);
return;
}
}
}

void PatchFixedFunctions()
void PatchFixedFunctions(Core::System& system)
{
// MIOS puts patch data in low MEM1 (0x1800-0x3000) for its own use.
// Overwriting data in this range can cause the IPL to crash when launching games
Expand All @@ -90,28 +91,29 @@ void PatchFixedFunctions()
// handler
if (!Config::Get(Config::MAIN_ENABLE_CHEATS))
{
Patch(0x80001800, "HBReload");
auto& system = Core::System::GetInstance();
Patch(system, 0x80001800, "HBReload");
auto& memory = system.GetMemory();
memory.CopyToEmu(0x00001804, "STUBHAXX", 8);
}

// Not part of the binary itself, but either we or Gecko OS might insert
// this, and it doesn't clear the icache properly.
Patch(Gecko::ENTRY_POINT, "GeckoCodehandler");
Patch(system, Gecko::ENTRY_POINT, "GeckoCodehandler");
// This has to always be installed even if cheats are not enabled because of the possiblity of
// loading a savestate where PC is inside the code handler while cheats are disabled.
Patch(Gecko::HLE_TRAMPOLINE_ADDRESS, "GeckoHandlerReturnTrampoline");
Patch(system, Gecko::HLE_TRAMPOLINE_ADDRESS, "GeckoHandlerReturnTrampoline");
}

void PatchFunctions()
void PatchFunctions(Core::System& system)
{
auto& ppc_state = system.GetPPCState();

// Remove all hooks that aren't fixed address hooks
for (auto i = s_hooked_addresses.begin(); i != s_hooked_addresses.end();)
{
if (os_patches[i->second].flags != HookFlag::Fixed)
{
PowerPC::ppcState.iCache.Invalidate(i->first);
ppc_state.iCache.Invalidate(i->first);
i = s_hooked_addresses.erase(i);
}
else
Expand All @@ -131,7 +133,7 @@ void PatchFunctions()
for (u32 addr = symbol->address; addr < symbol->address + symbol->size; addr += 4)
{
s_hooked_addresses[addr] = i;
PowerPC::ppcState.iCache.Invalidate(addr);
ppc_state.iCache.Invalidate(addr);
}
INFO_LOG_FMT(OSHLE, "Patching {} {:08x}", os_patches[i].name, symbol->address);
}
Expand All @@ -143,11 +145,11 @@ void Clear()
s_hooked_addresses.clear();
}

void Reload()
void Reload(Core::System& system)
{
Clear();
PatchFixedFunctions();
PatchFunctions();
PatchFixedFunctions(system);
PatchFunctions(system);
}

void Execute(u32 current_pc, u32 hook_index)
Expand Down Expand Up @@ -196,13 +198,15 @@ bool IsEnabled(HookFlag flag)
PowerPC::GetMode() == PowerPC::CoreMode::Interpreter;
}

u32 UnPatch(std::string_view patch_name)
u32 UnPatch(Core::System& system, std::string_view patch_name)
{
const auto patch = std::find_if(std::begin(os_patches), std::end(os_patches),
[&](const Hook& p) { return patch_name == p.name; });
if (patch == std::end(os_patches))
return 0;

auto& ppc_state = system.GetPPCState();

if (patch->flags == HookFlag::Fixed)
{
const u32 patch_idx = static_cast<u32>(std::distance(os_patches.begin(), patch));
Expand All @@ -213,7 +217,7 @@ u32 UnPatch(std::string_view patch_name)
if (i->second == patch_idx)
{
addr = i->first;
PowerPC::ppcState.iCache.Invalidate(i->first);
ppc_state.iCache.Invalidate(i->first);
i = s_hooked_addresses.erase(i);
}
else
Expand All @@ -231,24 +235,26 @@ u32 UnPatch(std::string_view patch_name)
for (u32 addr = symbol->address; addr < symbol->address + symbol->size; addr += 4)
{
s_hooked_addresses.erase(addr);
PowerPC::ppcState.iCache.Invalidate(addr);
ppc_state.iCache.Invalidate(addr);
}
return symbol->address;
}

return 0;
}

u32 UnpatchRange(u32 start_addr, u32 end_addr)
u32 UnpatchRange(Core::System& system, u32 start_addr, u32 end_addr)
{
auto& ppc_state = system.GetPPCState();

u32 count = 0;

auto i = s_hooked_addresses.lower_bound(start_addr);
while (i != s_hooked_addresses.end() && i->first < end_addr)
{
INFO_LOG_FMT(OSHLE, "Unpatch HLE hooks [{:08x};{:08x}): {} at {:08x}", start_addr, end_addr,
os_patches[i->second].name, i->first);
PowerPC::ppcState.iCache.Invalidate(i->first);
ppc_state.iCache.Invalidate(i->first);
i = s_hooked_addresses.erase(i);
count += 1;
}
Expand Down
17 changes: 11 additions & 6 deletions Source/Core/Core/HLE/HLE.h
Expand Up @@ -7,6 +7,11 @@

#include "Common/CommonTypes.h"

namespace Core
{
class System;
}

namespace HLE
{
using HookFunction = void (*)();
Expand All @@ -33,14 +38,14 @@ struct Hook
HookFlag flags;
};

void PatchFixedFunctions();
void PatchFunctions();
void PatchFixedFunctions(Core::System& system);
void PatchFunctions(Core::System& system);
void Clear();
void Reload();
void Reload(Core::System& system);

void Patch(u32 pc, std::string_view func_name);
u32 UnPatch(std::string_view patch_name);
u32 UnpatchRange(u32 start_addr, u32 end_addr);
void Patch(Core::System& system, u32 pc, std::string_view func_name);
u32 UnPatch(Core::System& system, std::string_view patch_name);
u32 UnpatchRange(Core::System& system, u32 start_addr, u32 end_addr);
void Execute(u32 current_pc, u32 hook_index);

// Returns the HLE hook index of the address
Expand Down
27 changes: 18 additions & 9 deletions Source/Core/Core/HLE/HLE_Misc.cpp
Expand Up @@ -10,14 +10,17 @@
#include "Core/Host.h"
#include "Core/PowerPC/MMU.h"
#include "Core/PowerPC/PowerPC.h"
#include "Core/System.h"

namespace HLE_Misc
{
// If you just want to kill a function, one of the three following are usually appropriate.
// According to the PPC ABI, the return value is always in r3.
void UnimplementedFunction()
{
NPC = LR;
auto& system = Core::System::GetInstance();
auto& ppc_state = system.GetPPCState();
ppc_state.npc = LR(ppc_state);
}

void HBReload()
Expand All @@ -29,6 +32,9 @@ void HBReload()

void GeckoCodeHandlerICacheFlush()
{
auto& system = Core::System::GetInstance();
auto& ppc_state = system.GetPPCState();

// Work around the codehandler not properly invalidating the icache, but
// only the first few frames.
// (Project M uses a conditional to only apply patches after something has
Expand All @@ -46,7 +52,7 @@ void GeckoCodeHandlerICacheFlush()
}
PowerPC::HostWrite_U32(gch_gameid + 1, Gecko::INSTALLER_BASE_ADDRESS);

PowerPC::ppcState.iCache.Reset();
ppc_state.iCache.Reset();
}

// Because Dolphin messes around with the CPU state instead of patching the game binary, we
Expand All @@ -55,16 +61,19 @@ void GeckoCodeHandlerICacheFlush()
// and PC before the magic, invisible BL instruction happened.
void GeckoReturnTrampoline()
{
auto& system = Core::System::GetInstance();
auto& ppc_state = system.GetPPCState();

// Stack frame is built in GeckoCode.cpp, Gecko::RunCodeHandler.
u32 SP = GPR(1);
GPR(1) = PowerPC::HostRead_U32(SP + 8);
NPC = PowerPC::HostRead_U32(SP + 12);
LR = PowerPC::HostRead_U32(SP + 16);
PowerPC::ppcState.cr.Set(PowerPC::HostRead_U32(SP + 20));
u32 SP = ppc_state.gpr[1];
ppc_state.gpr[1] = PowerPC::HostRead_U32(SP + 8);
ppc_state.npc = PowerPC::HostRead_U32(SP + 12);
LR(ppc_state) = PowerPC::HostRead_U32(SP + 16);
ppc_state.cr.Set(PowerPC::HostRead_U32(SP + 20));
for (int i = 0; i < 14; ++i)
{
rPS(i).SetBoth(PowerPC::HostRead_U64(SP + 24 + 2 * i * sizeof(u64)),
PowerPC::HostRead_U64(SP + 24 + (2 * i + 1) * sizeof(u64)));
ppc_state.ps[i].SetBoth(PowerPC::HostRead_U64(SP + 24 + 2 * i * sizeof(u64)),
PowerPC::HostRead_U64(SP + 24 + (2 * i + 1) * sizeof(u64)));
}
}
} // namespace HLE_Misc
89 changes: 57 additions & 32 deletions Source/Core/Core/HLE/HLE_OS.cpp
Expand Up @@ -13,6 +13,7 @@
#include "Core/HLE/HLE_VarArgs.h"
#include "Core/PowerPC/MMU.h"
#include "Core/PowerPC/PowerPC.h"
#include "Core/System.h"

namespace HLE_OS
{
Expand All @@ -22,64 +23,72 @@ enum class ParameterType : bool
VariableArgumentList = true
};

std::string GetStringVA(u32 str_reg = 3,
std::string GetStringVA(Core::System& system, u32 str_reg = 3,
ParameterType parameter_type = ParameterType::ParameterList);
void HLE_GeneralDebugPrint(ParameterType parameter_type);
void HLE_LogDPrint(ParameterType parameter_type);
void HLE_LogFPrint(ParameterType parameter_type);

void HLE_OSPanic()
{
std::string error = GetStringVA();
std::string msg = GetStringVA(5);
auto& system = Core::System::GetInstance();
auto& ppc_state = system.GetPPCState();

std::string error = GetStringVA(system);
std::string msg = GetStringVA(system, 5);

StringPopBackIf(&error, '\n');
StringPopBackIf(&msg, '\n');

PanicAlertFmt("OSPanic: {}: {}", error, msg);
ERROR_LOG_FMT(OSREPORT_HLE, "{:08x}->{:08x}| OSPanic: {}: {}", LR, PC, error, msg);
ERROR_LOG_FMT(OSREPORT_HLE, "{:08x}->{:08x}| OSPanic: {}: {}", LR(ppc_state), ppc_state.pc, error,
msg);

NPC = LR;
ppc_state.npc = LR(ppc_state);
}

// Generalized function for printing formatted string.
void HLE_GeneralDebugPrint(ParameterType parameter_type)
{
auto& system = Core::System::GetInstance();
auto& ppc_state = system.GetPPCState();

std::string report_message;

// Is gpr3 pointing to a pointer (including nullptr) rather than an ASCII string
if (PowerPC::HostIsRAMAddress(GPR(3)) &&
(PowerPC::HostIsRAMAddress(PowerPC::HostRead_U32(GPR(3))) ||
PowerPC::HostRead_U32(GPR(3)) == 0))
if (PowerPC::HostIsRAMAddress(ppc_state.gpr[3]) &&
(PowerPC::HostIsRAMAddress(PowerPC::HostRead_U32(ppc_state.gpr[3])) ||
PowerPC::HostRead_U32(ppc_state.gpr[3]) == 0))
{
if (PowerPC::HostIsRAMAddress(GPR(4)))
if (PowerPC::HostIsRAMAddress(ppc_state.gpr[4]))
{
// ___blank(void* this, const char* fmt, ...);
report_message = GetStringVA(4, parameter_type);
report_message = GetStringVA(system, 4, parameter_type);
}
else
{
// ___blank(void* this, int log_type, const char* fmt, ...);
report_message = GetStringVA(5, parameter_type);
report_message = GetStringVA(system, 5, parameter_type);
}
}
else
{
if (PowerPC::HostIsRAMAddress(GPR(3)))
if (PowerPC::HostIsRAMAddress(ppc_state.gpr[3]))
{
// ___blank(const char* fmt, ...);
report_message = GetStringVA(3, parameter_type);
report_message = GetStringVA(system, 3, parameter_type);
}
else
{
// ___blank(int log_type, const char* fmt, ...);
report_message = GetStringVA(4, parameter_type);
report_message = GetStringVA(system, 4, parameter_type);
}
}

StringPopBackIf(&report_message, '\n');

NOTICE_LOG_FMT(OSREPORT_HLE, "{:08x}->{:08x}| {}", LR, PC, SHIFTJISToUTF8(report_message));
NOTICE_LOG_FMT(OSREPORT_HLE, "{:08x}->{:08x}| {}", LR(ppc_state), ppc_state.pc,
SHIFTJISToUTF8(report_message));
}

// Generalized function for printing formatted string using parameter list.
Expand All @@ -97,10 +106,13 @@ void HLE_GeneralDebugVPrint()
// __write_console(int fd, const void* buffer, const u32* size)
void HLE_write_console()
{
std::string report_message = GetStringVA(4);
if (PowerPC::HostIsRAMAddress(GPR(5)))
auto& system = Core::System::GetInstance();
auto& ppc_state = system.GetPPCState();

std::string report_message = GetStringVA(system, 4);
if (PowerPC::HostIsRAMAddress(ppc_state.gpr[5]))
{
const u32 size = PowerPC::Read_U32(GPR(5));
const u32 size = PowerPC::Read_U32(ppc_state.gpr[5]);
if (size > report_message.size())
WARN_LOG_FMT(OSREPORT_HLE, "__write_console uses an invalid size of {:#010x}", size);
else if (size == 0)
Expand All @@ -115,18 +127,23 @@ void HLE_write_console()

StringPopBackIf(&report_message, '\n');

NOTICE_LOG_FMT(OSREPORT_HLE, "{:08x}->{:08x}| {}", LR, PC, SHIFTJISToUTF8(report_message));
NOTICE_LOG_FMT(OSREPORT_HLE, "{:08x}->{:08x}| {}", LR(ppc_state), ppc_state.pc,
SHIFTJISToUTF8(report_message));
}

// Log (v)dprintf message if fd is 1 (stdout) or 2 (stderr)
void HLE_LogDPrint(ParameterType parameter_type)
{
if (GPR(3) != 1 && GPR(3) != 2)
auto& system = Core::System::GetInstance();
auto& ppc_state = system.GetPPCState();

if (ppc_state.gpr[3] != 1 && ppc_state.gpr[3] != 2)
return;

std::string report_message = GetStringVA(4, parameter_type);
std::string report_message = GetStringVA(system, 4, parameter_type);
StringPopBackIf(&report_message, '\n');
NOTICE_LOG_FMT(OSREPORT_HLE, "{:08x}->{:08x}| {}", LR, PC, SHIFTJISToUTF8(report_message));
NOTICE_LOG_FMT(OSREPORT_HLE, "{:08x}->{:08x}| {}", LR(ppc_state), ppc_state.pc,
SHIFTJISToUTF8(report_message));
}

// Log dprintf message
Expand All @@ -146,25 +163,30 @@ void HLE_LogVDPrint()
// Log (v)fprintf message if FILE is stdout or stderr
void HLE_LogFPrint(ParameterType parameter_type)
{
auto& system = Core::System::GetInstance();
auto& ppc_state = system.GetPPCState();

// The structure FILE is implementation defined.
// Both libogc and Dolphin SDK seem to store the fd at the same address.
int fd = -1;
if (PowerPC::HostIsRAMAddress(GPR(3)) && PowerPC::HostIsRAMAddress(GPR(3) + 0xF))
if (PowerPC::HostIsRAMAddress(ppc_state.gpr[3]) &&
PowerPC::HostIsRAMAddress(ppc_state.gpr[3] + 0xF))
{
// The fd is stored as a short at FILE+0xE.
fd = static_cast<short>(PowerPC::HostRead_U16(GPR(3) + 0xE));
fd = static_cast<short>(PowerPC::HostRead_U16(ppc_state.gpr[3] + 0xE));
}
if (fd != 1 && fd != 2)
{
// On RVL SDK it seems stored at FILE+0x2.
fd = static_cast<short>(PowerPC::HostRead_U16(GPR(3) + 0x2));
fd = static_cast<short>(PowerPC::HostRead_U16(ppc_state.gpr[3] + 0x2));
}
if (fd != 1 && fd != 2)
return;

std::string report_message = GetStringVA(4, parameter_type);
std::string report_message = GetStringVA(system, 4, parameter_type);
StringPopBackIf(&report_message, '\n');
NOTICE_LOG_FMT(OSREPORT_HLE, "{:08x}->{:08x}| {}", LR, PC, SHIFTJISToUTF8(report_message));
NOTICE_LOG_FMT(OSREPORT_HLE, "{:08x}->{:08x}| {}", LR(ppc_state), ppc_state.pc,
SHIFTJISToUTF8(report_message));
}

// Log fprintf message
Expand All @@ -181,14 +203,17 @@ void HLE_LogVFPrint()
HLE_LogFPrint(ParameterType::VariableArgumentList);
}

std::string GetStringVA(u32 str_reg, ParameterType parameter_type)
std::string GetStringVA(Core::System& system, u32 str_reg, ParameterType parameter_type)
{
auto& ppc_state = system.GetPPCState();

std::string ArgumentBuffer;
std::string result;
std::string string = PowerPC::HostGetString(GPR(str_reg));
auto ap = parameter_type == ParameterType::VariableArgumentList ?
std::make_unique<HLE::SystemVABI::VAListStruct>(GPR(str_reg + 1)) :
std::make_unique<HLE::SystemVABI::VAList>(GPR(1) + 0x8, str_reg + 1);
std::string string = PowerPC::HostGetString(ppc_state.gpr[str_reg]);
auto ap =
parameter_type == ParameterType::VariableArgumentList ?
std::make_unique<HLE::SystemVABI::VAListStruct>(system, ppc_state.gpr[str_reg + 1]) :
std::make_unique<HLE::SystemVABI::VAList>(system, ppc_state.gpr[1] + 0x8, str_reg + 1);

for (size_t i = 0; i < string.size(); i++)
{
Expand Down
14 changes: 8 additions & 6 deletions Source/Core/Core/HLE/HLE_VarArgs.cpp
Expand Up @@ -2,25 +2,27 @@
// SPDX-License-Identifier: GPL-2.0-or-later

#include "Core/HLE/HLE_VarArgs.h"
#include "Core/System.h"

#include "Common/Logging/Log.h"

HLE::SystemVABI::VAList::~VAList() = default;

u32 HLE::SystemVABI::VAList::GetGPR(u32 gpr) const
{
return GPR(gpr);
return m_system.GetPPCState().gpr[gpr];
}

double HLE::SystemVABI::VAList::GetFPR(u32 fpr) const
{
return rPS(fpr).PS0AsDouble();
return m_system.GetPPCState().ps[fpr].PS0AsDouble();
}

HLE::SystemVABI::VAListStruct::VAListStruct(u32 address)
: VAList(0), m_va_list{PowerPC::HostRead_U8(address), PowerPC::HostRead_U8(address + 1),
PowerPC::HostRead_U32(address + 4), PowerPC::HostRead_U32(address + 8)},
m_address(address), m_has_fpr_area(PowerPC::ppcState.cr.GetBit(6) == 1)
HLE::SystemVABI::VAListStruct::VAListStruct(Core::System& system, u32 address)
: VAList(system, 0), m_va_list{PowerPC::HostRead_U8(address), PowerPC::HostRead_U8(address + 1),
PowerPC::HostRead_U32(address + 4),
PowerPC::HostRead_U32(address + 8)},
m_address(address), m_has_fpr_area(system.GetPPCState().cr.GetBit(6) == 1)
{
m_stack = m_va_list.overflow_arg_area;
m_gpr += m_va_list.gpr;
Expand Down
14 changes: 11 additions & 3 deletions Source/Core/Core/HLE/HLE_VarArgs.h
Expand Up @@ -11,6 +11,11 @@

#include <type_traits>

namespace Core
{
class System;
}

namespace HLE::SystemVABI
{
// SFINAE
Expand All @@ -32,8 +37,10 @@ constexpr bool IS_ARG_REAL = std::is_floating_point<T>();
class VAList
{
public:
explicit VAList(u32 stack, u32 gpr = 3, u32 fpr = 1, u32 gpr_max = 10, u32 fpr_max = 8)
: m_gpr(gpr), m_fpr(fpr), m_gpr_max(gpr_max), m_fpr_max(fpr_max), m_stack(stack)
explicit VAList(Core::System& system, u32 stack, u32 gpr = 3, u32 fpr = 1, u32 gpr_max = 10,
u32 fpr_max = 8)
: m_system(system), m_gpr(gpr), m_fpr(fpr), m_gpr_max(gpr_max), m_fpr_max(fpr_max),
m_stack(stack)
{
}
virtual ~VAList();
Expand Down Expand Up @@ -127,6 +134,7 @@ class VAList
}

protected:
Core::System& m_system;
u32 m_gpr = 3;
u32 m_fpr = 1;
const u32 m_gpr_max = 10;
Expand All @@ -147,7 +155,7 @@ class VAList
class VAListStruct : public VAList
{
public:
explicit VAListStruct(u32 address);
explicit VAListStruct(Core::System& system, u32 address);
~VAListStruct() = default;

private:
Expand Down
12 changes: 7 additions & 5 deletions Source/Core/Core/HW/AudioInterface.cpp
Expand Up @@ -173,16 +173,18 @@ void IncreaseSampleCount(const u32 amount)
if (!IsPlaying())
return;

auto& state = Core::System::GetInstance().GetAudioInterfaceState().GetData();
auto& system = Core::System::GetInstance();
auto& state = system.GetAudioInterfaceState().GetData();

const u32 old_sample_counter = state.sample_counter + 1;
state.sample_counter += amount;

if ((state.interrupt_timing - old_sample_counter) <= (state.sample_counter - old_sample_counter))
{
DEBUG_LOG_FMT(
AUDIO_INTERFACE, "GenerateAudioInterrupt {:08x}:{:08x} at PC {:08x} control.AIINTVLD={}",
state.sample_counter, state.interrupt_timing, PowerPC::ppcState.pc, state.control.AIINTVLD);
DEBUG_LOG_FMT(AUDIO_INTERFACE,
"GenerateAudioInterrupt {:08x}:{:08x} at PC {:08x} control.AIINTVLD={}",
state.sample_counter, state.interrupt_timing, system.GetPPCState().pc,
state.control.AIINTVLD);
GenerateAudioInterrupt();
}
}
Expand Down Expand Up @@ -382,7 +384,7 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
auto& core_timing = system.GetCoreTiming();
auto& state = system.GetAudioInterfaceState().GetData();
DEBUG_LOG_FMT(AUDIO_INTERFACE, "AI_INTERRUPT_TIMING={:08x} at PC: {:08x}", val,
PowerPC::ppcState.pc);
system.GetPPCState().pc);
state.interrupt_timing = val;
core_timing.RemoveEvent(state.event_type_ai);
core_timing.ScheduleEvent(GetAIPeriod(), state.event_type_ai);
Expand Down
5 changes: 4 additions & 1 deletion Source/Core/Core/HW/CPU.cpp
Expand Up @@ -88,6 +88,8 @@ static void ExecutePendingJobs(std::unique_lock<std::mutex>& state_lock)

void Run()
{
auto& system = Core::System::GetInstance();

// Updating the host CPU's rounding mode must be done on the CPU thread.
// We can't rely on PowerPC::Init doing it, since it's called from EmuThread.
PowerPC::RoundingModeUpdated();
Expand All @@ -111,7 +113,8 @@ void Run()
// If watchpoints are enabled, any instruction could be a breakpoint.
if (PowerPC::GetMode() != PowerPC::CoreMode::Interpreter)
{
if (PowerPC::breakpoints.IsAddressBreakPoint(PC) || PowerPC::memchecks.HasAny())
if (PowerPC::breakpoints.IsAddressBreakPoint(system.GetPPCState().pc) ||
PowerPC::memchecks.HasAny())
{
s_state = State::Stepping;
PowerPC::CoreMode old_mode = PowerPC::GetMode();
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/Core/HW/CPU.h
Expand Up @@ -69,7 +69,7 @@ const State* GetStatePtr();

// Locks the CPU Thread (waiting for it to become idle).
// While this lock is held, the CPU Thread will not perform any action so it is safe to access
// PowerPC::ppcState, CoreTiming, etc. without racing the CPU Thread.
// PowerPC, CoreTiming, etc. without racing the CPU Thread.
// Cannot be used recursively. Must be paired as PauseAndLock(true)/PauseAndLock(false).
// Return value for do_lock == true is whether the state was State::Running or not.
// Return value for do_lock == false is whether the state was changed *to* State::Running or not.
Expand Down
6 changes: 4 additions & 2 deletions Source/Core/Core/HW/DSP.cpp
Expand Up @@ -572,7 +572,8 @@ static void Do_ARAM_DMA()
{
// ARAM -> MRAM
DEBUG_LOG_FMT(DSPINTERFACE, "DMA {:08x} bytes from ARAM {:08x} to MRAM {:08x} PC: {:08x}",
state.aram_dma.Cnt.count, state.aram_dma.ARAddr, state.aram_dma.MMAddr, PC);
state.aram_dma.Cnt.count, state.aram_dma.ARAddr, state.aram_dma.MMAddr,
system.GetPPCState().pc);

// Outgoing data from ARAM is mirrored every 64MB (verified on real HW)
state.aram_dma.ARAddr &= 0x3ffffff;
Expand Down Expand Up @@ -620,7 +621,8 @@ static void Do_ARAM_DMA()
{
// MRAM -> ARAM
DEBUG_LOG_FMT(DSPINTERFACE, "DMA {:08x} bytes from MRAM {:08x} to ARAM {:08x} PC: {:08x}",
state.aram_dma.Cnt.count, state.aram_dma.MMAddr, state.aram_dma.ARAddr, PC);
state.aram_dma.Cnt.count, state.aram_dma.MMAddr, state.aram_dma.ARAddr,
system.GetPPCState().pc);

// Incoming data into ARAM is mirrored every 64MB (verified on real HW)
state.aram_dma.ARAddr &= 0x3ffffff;
Expand Down
26 changes: 15 additions & 11 deletions Source/Core/Core/HW/GPFifo.cpp
Expand Up @@ -35,12 +35,12 @@ GPFifoManager::GPFifoManager(Core::System& system) : m_system(system)

size_t GPFifoManager::GetGatherPipeCount()
{
return PowerPC::ppcState.gather_pipe_ptr - m_gather_pipe;
return m_system.GetPPCState().gather_pipe_ptr - m_gather_pipe;
}

void GPFifoManager::SetGatherPipeCount(size_t size)
{
PowerPC::ppcState.gather_pipe_ptr = m_gather_pipe + size;
m_system.GetPPCState().gather_pipe_ptr = m_gather_pipe + size;
}

void GPFifoManager::DoState(PointerWrap& p)
Expand All @@ -54,7 +54,7 @@ void GPFifoManager::DoState(PointerWrap& p)
void GPFifoManager::Init()
{
ResetGatherPipe();
PowerPC::ppcState.gather_pipe_base_ptr = m_gather_pipe;
m_system.GetPPCState().gather_pipe_base_ptr = m_gather_pipe;
memset(m_gather_pipe, 0, sizeof(m_gather_pipe));
}

Expand Down Expand Up @@ -162,29 +162,33 @@ void GPFifoManager::Write64(const u64 value)

void GPFifoManager::FastWrite8(const u8 value)
{
*PowerPC::ppcState.gather_pipe_ptr = value;
PowerPC::ppcState.gather_pipe_ptr += sizeof(u8);
auto& ppc_state = m_system.GetPPCState();
*ppc_state.gather_pipe_ptr = value;
ppc_state.gather_pipe_ptr += sizeof(u8);
}

void GPFifoManager::FastWrite16(u16 value)
{
value = Common::swap16(value);
std::memcpy(PowerPC::ppcState.gather_pipe_ptr, &value, sizeof(u16));
PowerPC::ppcState.gather_pipe_ptr += sizeof(u16);
auto& ppc_state = m_system.GetPPCState();
std::memcpy(ppc_state.gather_pipe_ptr, &value, sizeof(u16));
ppc_state.gather_pipe_ptr += sizeof(u16);
}

void GPFifoManager::FastWrite32(u32 value)
{
value = Common::swap32(value);
std::memcpy(PowerPC::ppcState.gather_pipe_ptr, &value, sizeof(u32));
PowerPC::ppcState.gather_pipe_ptr += sizeof(u32);
auto& ppc_state = m_system.GetPPCState();
std::memcpy(ppc_state.gather_pipe_ptr, &value, sizeof(u32));
ppc_state.gather_pipe_ptr += sizeof(u32);
}

void GPFifoManager::FastWrite64(u64 value)
{
value = Common::swap64(value);
std::memcpy(PowerPC::ppcState.gather_pipe_ptr, &value, sizeof(u64));
PowerPC::ppcState.gather_pipe_ptr += sizeof(u64);
auto& ppc_state = m_system.GetPPCState();
std::memcpy(ppc_state.gather_pipe_ptr, &value, sizeof(u64));
ppc_state.gather_pipe_ptr += sizeof(u64);
}

void UpdateGatherPipe(GPFifoManager& gpfifo)
Expand Down
4 changes: 3 additions & 1 deletion Source/Core/Core/HW/Memmap.cpp
Expand Up @@ -482,7 +482,9 @@ u8* MemoryManager::GetPointer(u32 address) const
return m_exram + (address & GetExRamMask());
}

PanicAlertFmt("Unknown Pointer {:#010x} PC {:#010x} LR {:#010x}", address, PC, LR);
auto& ppc_state = Core::System::GetInstance().GetPPCState();
PanicAlertFmt("Unknown Pointer {:#010x} PC {:#010x} LR {:#010x}", address, ppc_state.pc,
LR(ppc_state));
return nullptr;
}

Expand Down
13 changes: 7 additions & 6 deletions Source/Core/Core/HW/ProcessorInterface.cpp
Expand Up @@ -65,14 +65,14 @@ void ProcessorInterfaceManager::RegisterMMIO(MMIO::Mapping* mmio, u32 base)
MMIO::ComplexWrite<u32>([](Core::System& system, u32, u32 val) {
auto& processor_interface = system.GetProcessorInterface();
processor_interface.m_interrupt_cause &= ~val;
processor_interface.UpdateException();
processor_interface.UpdateException(system);
}));

mmio->Register(base | PI_INTERRUPT_MASK, MMIO::DirectRead<u32>(&m_interrupt_mask),
MMIO::ComplexWrite<u32>([](Core::System& system, u32, u32 val) {
auto& processor_interface = system.GetProcessorInterface();
processor_interface.m_interrupt_mask = val;
processor_interface.UpdateException();
processor_interface.UpdateException(system);
}));

mmio->Register(base | PI_FIFO_BASE, MMIO::DirectRead<u32>(&m_fifo_cpu_base),
Expand Down Expand Up @@ -137,12 +137,13 @@ void ProcessorInterfaceManager::RegisterMMIO(MMIO::Mapping* mmio, u32 base)
}
}

void ProcessorInterfaceManager::UpdateException()
void ProcessorInterfaceManager::UpdateException(Core::System& system)
{
auto& ppc_state = system.GetPPCState();
if ((m_interrupt_cause & m_interrupt_mask) != 0)
PowerPC::ppcState.Exceptions |= EXCEPTION_EXTERNAL_INT;
ppc_state.Exceptions |= EXCEPTION_EXTERNAL_INT;
else
PowerPC::ppcState.Exceptions &= ~EXCEPTION_EXTERNAL_INT;
ppc_state.Exceptions &= ~EXCEPTION_EXTERNAL_INT;
}

static const char* Debug_GetInterruptName(u32 cause_mask)
Expand Down Expand Up @@ -208,7 +209,7 @@ void ProcessorInterfaceManager::SetInterrupt(u32 cause_mask, bool set)
m_interrupt_cause &= ~cause_mask; // is there any reason to have this possibility?
// F|RES: i think the hw devices reset the interrupt in the PI to 0
// if the interrupt cause is eliminated. that isn't done by software (afaik)
UpdateException();
UpdateException(Core::System::GetInstance());
}

void ProcessorInterfaceManager::SetResetButton(bool set)
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/Core/HW/ProcessorInterface.h
Expand Up @@ -87,7 +87,7 @@ class ProcessorInterfaceManager

private:
// Let the PPC know that an external exception is set/cleared
void UpdateException();
void UpdateException(Core::System& system);

void SetResetButton(bool set);

Expand Down
8 changes: 5 additions & 3 deletions Source/Core/Core/HW/SystemTimers.cpp
Expand Up @@ -153,8 +153,9 @@ void VICallback(Core::System& system, u64 userdata, s64 cyclesLate)

void DecrementerCallback(Core::System& system, u64 userdata, s64 cyclesLate)
{
PowerPC::ppcState.spr[SPR_DEC] = 0xFFFFFFFF;
PowerPC::ppcState.Exceptions |= EXCEPTION_DECREMENTER;
auto& ppc_state = system.GetPPCState();
ppc_state.spr[SPR_DEC] = 0xFFFFFFFF;
ppc_state.Exceptions |= EXCEPTION_DECREMENTER;
}

void PatchEngineCallback(Core::System& system, u64 userdata, s64 cycles_late)
Expand Down Expand Up @@ -192,8 +193,9 @@ void DecrementerSet()
{
auto& system = Core::System::GetInstance();
auto& core_timing = system.GetCoreTiming();
auto& ppc_state = system.GetPPCState();

u32 decValue = PowerPC::ppcState.spr[SPR_DEC];
u32 decValue = ppc_state.spr[SPR_DEC];

core_timing.RemoveEvent(et_Dec);
if ((decValue & 0x80000000) == 0)
Expand Down
6 changes: 3 additions & 3 deletions Source/Core/Core/IOS/IOS.cpp
Expand Up @@ -200,7 +200,7 @@ static void ResetAndPausePPC()
auto& memory = system.GetMemory();
memory.Write_U32(0x48000000, 0x00000000); // b 0x0
PowerPC::Reset();
PC = 0;
system.GetPPCState().pc = 0;
}

static void ReleasePPC()
Expand All @@ -212,7 +212,7 @@ static void ReleasePPC()
// NAND titles start with address translation off at 0x3400 (via the PPC bootstub)
// The state of other CPU registers (like the BAT registers) doesn't matter much
// because the realmode code at 0x3400 initializes everything itself anyway.
PC = 0x3400;
system.GetPPCState().pc = 0x3400;
}

static void ReleasePPCAncast()
Expand All @@ -223,7 +223,7 @@ static void ReleasePPCAncast()
// On a real console the Espresso verifies and decrypts the Ancast image,
// then jumps to the decrypted ancast body.
// The Ancast loader already did this, so just jump to the decrypted body.
PC = ESPRESSO_ANCAST_LOCATION_VIRT + sizeof(EspressoAncastHeader);
system.GetPPCState().pc = ESPRESSO_ANCAST_LOCATION_VIRT + sizeof(EspressoAncastHeader);
}

void RAMOverrideForIOSMemoryValues(MemorySetupType setup_type)
Expand Down
7 changes: 4 additions & 3 deletions Source/Core/Core/IOS/MIOS.cpp
Expand Up @@ -72,14 +72,15 @@ bool Load()
if (g_symbolDB.LoadMap(File::GetUserPath(D_MAPS_IDX) + "mios-ipl.map"))
{
::HLE::Clear();
::HLE::PatchFunctions();
::HLE::PatchFunctions(system);
Host_NotifyMapLoaded();
}

auto& ppc_state = system.GetPPCState();
const PowerPC::CoreMode core_mode = PowerPC::GetMode();
PowerPC::SetMode(PowerPC::CoreMode::Interpreter);
MSR.Hex = 0;
PC = 0x3400;
ppc_state.msr.Hex = 0;
ppc_state.pc = 0x3400;
NOTICE_LOG_FMT(IOS, "Loaded MIOS and bootstrapped PPC.");

// IOS writes 0 to 0x30f8 before bootstrapping the PPC. Once started, the IPL eventually writes
Expand Down
15 changes: 11 additions & 4 deletions Source/Core/Core/PatchEngine.cpp
Expand Up @@ -33,6 +33,7 @@
#include "Core/GeckoCodeConfig.h"
#include "Core/PowerPC/MMU.h"
#include "Core/PowerPC/PowerPC.h"
#include "Core/System.h"

namespace PatchEngine
{
Expand Down Expand Up @@ -277,10 +278,13 @@ static void ApplyMemoryPatches(std::span<const std::size_t> memory_patch_indices
// We require at least 2 stack frames, if the stack is shallower than that then it won't work.
static bool IsStackSane()
{
DEBUG_ASSERT(MSR.DR && MSR.IR);
auto& system = Core::System::GetInstance();
auto& ppc_state = system.GetPPCState();

DEBUG_ASSERT(ppc_state.msr.DR && ppc_state.msr.IR);

// Check the stack pointer
u32 SP = GPR(1);
u32 SP = ppc_state.gpr[1];
if (!PowerPC::HostIsRAMAddress(SP))
return false;

Expand Down Expand Up @@ -311,16 +315,19 @@ void RemoveMemoryPatch(std::size_t index)

bool ApplyFramePatches()
{
auto& system = Core::System::GetInstance();
auto& ppc_state = system.GetPPCState();

// Because we're using the VI Interrupt to time this instead of patching the game with a
// callback hook we can end up catching the game in an exception vector.
// We deal with this by returning false so that SystemTimers will reschedule us in a few cycles
// where we can try again after the CPU hopefully returns back to the normal instruction flow.
if (!MSR.DR || !MSR.IR || !IsStackSane())
if (!ppc_state.msr.DR || !ppc_state.msr.IR || !IsStackSane())
{
DEBUG_LOG_FMT(ACTIONREPLAY,
"Need to retry later. CPU configuration is currently incorrect. PC = {:#010x}, "
"MSR = {:#010x}",
PC, MSR.Hex);
ppc_state.pc, ppc_state.msr.Hex);
return false;
}

Expand Down
27 changes: 14 additions & 13 deletions Source/Core/Core/PowerPC/CachedInterpreter/CachedInterpreter.cpp
Expand Up @@ -81,7 +81,7 @@ void CachedInterpreter::ExecuteOneBlock()
const u8* normal_entry = m_block_cache.Dispatch();
if (!normal_entry)
{
Jit(PC);
Jit(PowerPC::ppcState.pc);
return;
}

Expand Down Expand Up @@ -136,35 +136,35 @@ void CachedInterpreter::SingleStep()

static void EndBlock(UGeckoInstruction data)
{
PC = NPC;
PowerPC::ppcState.pc = PowerPC::ppcState.npc;
PowerPC::ppcState.downcount -= data.hex;
PowerPC::UpdatePerformanceMonitor(data.hex, 0, 0);
PowerPC::UpdatePerformanceMonitor(data.hex, 0, 0, PowerPC::ppcState);
}

static void UpdateNumLoadStoreInstructions(UGeckoInstruction data)
{
PowerPC::UpdatePerformanceMonitor(0, data.hex, 0);
PowerPC::UpdatePerformanceMonitor(0, data.hex, 0, PowerPC::ppcState);
}

static void UpdateNumFloatingPointInstructions(UGeckoInstruction data)
{
PowerPC::UpdatePerformanceMonitor(0, 0, data.hex);
PowerPC::UpdatePerformanceMonitor(0, 0, data.hex, PowerPC::ppcState);
}

static void WritePC(UGeckoInstruction data)
{
PC = data.hex;
NPC = data.hex + 4;
PowerPC::ppcState.pc = data.hex;
PowerPC::ppcState.npc = data.hex + 4;
}

static void WriteBrokenBlockNPC(UGeckoInstruction data)
{
NPC = data.hex;
PowerPC::ppcState.npc = data.hex;
}

static bool CheckFPU(u32 data)
{
if (!MSR.FP)
if (!PowerPC::ppcState.msr.FP)
{
PowerPC::ppcState.Exceptions |= EXCEPTION_FPU_UNAVAILABLE;
PowerPC::CheckExceptions();
Expand Down Expand Up @@ -239,20 +239,21 @@ void CachedInterpreter::Jit(u32 address)
ClearCache();
}

const u32 nextPC = analyzer.Analyze(PC, &code_block, &m_code_buffer, m_code_buffer.size());
const u32 nextPC =
analyzer.Analyze(PowerPC::ppcState.pc, &code_block, &m_code_buffer, m_code_buffer.size());
if (code_block.m_memory_exception)
{
// Address of instruction could not be translated
NPC = nextPC;
PowerPC::ppcState.npc = nextPC;
PowerPC::ppcState.Exceptions |= EXCEPTION_ISI;
PowerPC::CheckExceptions();
WARN_LOG_FMT(POWERPC, "ISI exception at {:#010x}", nextPC);
return;
}

JitBlock* b = m_block_cache.AllocateBlock(PC);
JitBlock* b = m_block_cache.AllocateBlock(PowerPC::ppcState.pc);

js.blockStart = PC;
js.blockStart = PowerPC::ppcState.pc;
js.firstFPInstructionFound = false;
js.fifoBytesSinceCheck = 0;
js.downcountAmount = 0;
Expand Down
17 changes: 9 additions & 8 deletions Source/Core/Core/PowerPC/Expression.cpp
Expand Up @@ -20,6 +20,7 @@
#include "Core/Debugger/Debugger_SymbolMap.h"
#include "Core/PowerPC/MMU.h"
#include "Core/PowerPC/PowerPC.h"
#include "Core/System.h"

template <typename T>
static T HostRead(u32 address);
Expand Down Expand Up @@ -109,7 +110,7 @@ static double CallstackFunc(expr_func* f, vec_expr_t* args, void* c)
return 0;

std::vector<Dolphin_Debugger::CallstackEntry> stack;
bool success = Dolphin_Debugger::GetCallstack(stack);
bool success = Dolphin_Debugger::GetCallstack(Core::System::GetInstance(), stack);
if (!success)
return 0;

Expand Down Expand Up @@ -246,25 +247,25 @@ void Expression::SynchronizeBindings(SynchronizeDirection dir) const
break;
case VarBindingType::GPR:
if (dir == SynchronizeDirection::From)
v->value = static_cast<double>(GPR(bind->index));
v->value = static_cast<double>(PowerPC::ppcState.gpr[bind->index]);
else
GPR(bind->index) = static_cast<u32>(static_cast<s64>(v->value));
PowerPC::ppcState.gpr[bind->index] = static_cast<u32>(static_cast<s64>(v->value));
break;
case VarBindingType::FPR:
if (dir == SynchronizeDirection::From)
v->value = rPS(bind->index).PS0AsDouble();
v->value = PowerPC::ppcState.ps[bind->index].PS0AsDouble();
else
rPS(bind->index).SetPS0(v->value);
PowerPC::ppcState.ps[bind->index].SetPS0(v->value);
break;
case VarBindingType::SPR:
if (dir == SynchronizeDirection::From)
v->value = static_cast<double>(rSPR(bind->index));
v->value = static_cast<double>(PowerPC::ppcState.spr[bind->index]);
else
rSPR(bind->index) = static_cast<u32>(static_cast<s64>(v->value));
PowerPC::ppcState.spr[bind->index] = static_cast<u32>(static_cast<s64>(v->value));
break;
case VarBindingType::PCtr:
if (dir == SynchronizeDirection::From)
v->value = static_cast<double>(PC);
v->value = static_cast<double>(PowerPC::ppcState.pc);
break;
}
}
Expand Down
229 changes: 124 additions & 105 deletions Source/Core/Core/PowerPC/GDBStub.cpp

Large diffs are not rendered by default.

60 changes: 35 additions & 25 deletions Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp
Expand Up @@ -64,16 +64,17 @@ bool IsPairedSingleInstruction(UGeckoInstruction inst)
// but HID2.LSQE is not set.
bool IsInvalidPairedSingleExecution(UGeckoInstruction inst)
{
if (!HID2.PSE && IsPairedSingleInstruction(inst))
if (!HID2(PowerPC::ppcState).PSE && IsPairedSingleInstruction(inst))
return true;

return HID2.PSE && !HID2.LSQE && IsPairedSingleQuantizedNonIndexedInstruction(inst);
return HID2(PowerPC::ppcState).PSE && !HID2(PowerPC::ppcState).LSQE &&
IsPairedSingleQuantizedNonIndexedInstruction(inst);
}

void UpdatePC()
{
last_pc = PC;
PC = NPC;
last_pc = PowerPC::ppcState.pc;
PowerPC::ppcState.pc = PowerPC::ppcState.npc;
}
} // Anonymous namespace

Expand Down Expand Up @@ -125,12 +126,14 @@ static void Trace(const UGeckoInstruction& inst)
fregs += fmt::format("f{:02d}: {:08x} {:08x} ", i, ps.PS0AsU64(), ps.PS1AsU64());
}

const std::string ppc_inst = Common::GekkoDisassembler::Disassemble(inst.hex, PC);
const std::string ppc_inst =
Common::GekkoDisassembler::Disassemble(inst.hex, PowerPC::ppcState.pc);
DEBUG_LOG_FMT(POWERPC,
"INTER PC: {:08x} SRR0: {:08x} SRR1: {:08x} CRval: {:016x} "
"FPSCR: {:08x} MSR: {:08x} LR: {:08x} {} {:08x} {}",
PC, SRR0, SRR1, PowerPC::ppcState.cr.fields[0], FPSCR.Hex, MSR.Hex,
PowerPC::ppcState.spr[8], regs, inst.hex, ppc_inst);
PowerPC::ppcState.pc, SRR0(PowerPC::ppcState), SRR1(PowerPC::ppcState),
PowerPC::ppcState.cr.fields[0], PowerPC::ppcState.fpscr.Hex,
PowerPC::ppcState.msr.Hex, PowerPC::ppcState.spr[8], regs, inst.hex, ppc_inst);
}

bool Interpreter::HandleFunctionHooking(u32 address)
Expand All @@ -143,20 +146,25 @@ bool Interpreter::HandleFunctionHooking(u32 address)

int Interpreter::SingleStepInner()
{
if (HandleFunctionHooking(PC))
if (HandleFunctionHooking(PowerPC::ppcState.pc))
{
UpdatePC();
return PPCTables::GetOpInfo(m_prev_inst)->numCycles;
}

NPC = PC + sizeof(UGeckoInstruction);
m_prev_inst.hex = PowerPC::Read_Opcode(PC);
PowerPC::ppcState.npc = PowerPC::ppcState.pc + sizeof(UGeckoInstruction);
m_prev_inst.hex = PowerPC::Read_Opcode(PowerPC::ppcState.pc);

// Uncomment to trace the interpreter
// if ((PC & 0x00FFFFFF) >= 0x000AB54C && (PC & 0x00FFFFFF) <= 0x000AB624)
// if ((PowerPC::ppcState.pc & 0x00FFFFFF) >= 0x000AB54C &&
// (PowerPC::ppcState.pc & 0x00FFFFFF) <= 0x000AB624)
// {
// s_start_trace = true;
// }
// else
// {
// s_start_trace = false;
// }

if (s_start_trace)
{
Expand All @@ -170,7 +178,7 @@ int Interpreter::SingleStepInner()
GenerateProgramException(ProgramExceptionCause::IllegalInstruction);
CheckExceptions();
}
else if (MSR.FP)
else if (PowerPC::ppcState.msr.FP)
{
m_op_table[m_prev_inst.OPCD](m_prev_inst);
if ((PowerPC::ppcState.Exceptions & EXCEPTION_DSI) != 0)
Expand Down Expand Up @@ -206,7 +214,7 @@ int Interpreter::SingleStepInner()

const GekkoOPInfo* opinfo = PPCTables::GetOpInfo(m_prev_inst);
PowerPC::UpdatePerformanceMonitor(opinfo->numCycles, (opinfo->flags & FL_LOADSTORE) != 0,
(opinfo->flags & FL_USE_FPU) != 0);
(opinfo->flags & FL_USE_FPU) != 0, PowerPC::ppcState);
return opinfo->numCycles;
}

Expand All @@ -227,7 +235,7 @@ void Interpreter::SingleStep()
if (PowerPC::ppcState.Exceptions != 0)
{
PowerPC::CheckExceptions();
PC = NPC;
PowerPC::ppcState.pc = PowerPC::ppcState.npc;
}
}

Expand Down Expand Up @@ -255,7 +263,7 @@ void Interpreter::Run()
if (Config::Get(Config::MAIN_ENABLE_DEBUGGING))
{
#ifdef SHOW_HISTORY
s_pc_block_vec.push_back(PC);
s_pc_block_vec.push_back(PowerPC::ppcState.pc);
if (s_pc_block_vec.size() > s_show_blocks)
s_pc_block_vec.erase(s_pc_block_vec.begin());
#endif
Expand All @@ -269,13 +277,13 @@ void Interpreter::Run()
while (!m_end_block)
{
#ifdef SHOW_HISTORY
s_pc_vec.push_back(PC);
s_pc_vec.push_back(PowerPC::ppcState.pc);
if (s_pc_vec.size() > s_show_steps)
s_pc_vec.erase(s_pc_vec.begin());
#endif

// 2: check for breakpoint
if (PowerPC::breakpoints.IsAddressBreakPoint(PC))
if (PowerPC::breakpoints.IsAddressBreakPoint(PowerPC::ppcState.pc))
{
#ifdef SHOW_HISTORY
NOTICE_LOG_FMT(POWERPC, "----------------------------");
Expand All @@ -296,12 +304,12 @@ void Interpreter::Run()
NOTICE_LOG_FMT(POWERPC, "PC: {:#010x}", s_pc_vec[j]);
}
#endif
INFO_LOG_FMT(POWERPC, "Hit Breakpoint - {:08x}", PC);
INFO_LOG_FMT(POWERPC, "Hit Breakpoint - {:08x}", PowerPC::ppcState.pc);
CPU::Break();
if (GDBStub::IsActive())
GDBStub::TakeControl();
if (PowerPC::breakpoints.IsTempBreakPoint(PC))
PowerPC::breakpoints.Remove(PC);
if (PowerPC::breakpoints.IsTempBreakPoint(PowerPC::ppcState.pc))
PowerPC::breakpoints.Remove(PowerPC::ppcState.pc);

Host_UpdateDisasmDialog();
return;
Expand Down Expand Up @@ -334,19 +342,21 @@ void Interpreter::unknown_instruction(UGeckoInstruction inst)
const u32 opcode = PowerPC::HostRead_U32(last_pc);
const std::string disasm = Common::GekkoDisassembler::Disassemble(opcode, last_pc);
NOTICE_LOG_FMT(POWERPC, "Last PC = {:08x} : {}", last_pc, disasm);
Dolphin_Debugger::PrintCallstack(Common::Log::LogType::POWERPC, Common::Log::LogLevel::LNOTICE);
Dolphin_Debugger::PrintCallstack(Core::System::GetInstance(), Common::Log::LogType::POWERPC,
Common::Log::LogLevel::LNOTICE);
NOTICE_LOG_FMT(
POWERPC,
"\nIntCPU: Unknown instruction {:08x} at PC = {:08x} last_PC = {:08x} LR = {:08x}\n",
inst.hex, PC, last_pc, LR);
inst.hex, PowerPC::ppcState.pc, last_pc, LR(PowerPC::ppcState));
for (int i = 0; i < 32; i += 4)
{
NOTICE_LOG_FMT(POWERPC, "r{}: {:#010x} r{}: {:#010x} r{}: {:#010x} r{}: {:#010x}", i, rGPR[i],
i + 1, rGPR[i + 1], i + 2, rGPR[i + 2], i + 3, rGPR[i + 3]);
NOTICE_LOG_FMT(POWERPC, "r{}: {:#010x} r{}: {:#010x} r{}: {:#010x} r{}: {:#010x}", i,
PowerPC::ppcState.gpr[i], i + 1, PowerPC::ppcState.gpr[i + 1], i + 2,
PowerPC::ppcState.gpr[i + 2], i + 3, PowerPC::ppcState.gpr[i + 3]);
}
ASSERT_MSG(POWERPC, 0,
"\nIntCPU: Unknown instruction {:08x} at PC = {:08x} last_PC = {:08x} LR = {:08x}\n",
inst.hex, PC, last_pc, LR);
inst.hex, PowerPC::ppcState.pc, last_pc, LR(PowerPC::ppcState));
if (Core::System::GetInstance().IsPauseOnPanicMode())
CPU::Break();
}
Expand Down
39 changes: 20 additions & 19 deletions Source/Core/Core/PowerPC/Interpreter/Interpreter_Branch.cpp
Expand Up @@ -13,14 +13,14 @@
void Interpreter::bx(UGeckoInstruction inst)
{
if (inst.LK)
LR = PC + 4;
LR(PowerPC::ppcState) = PowerPC::ppcState.pc + 4;

const auto address = u32(SignExt26(inst.LI << 2));

if (inst.AA)
NPC = address;
PowerPC::ppcState.npc = address;
else
NPC = PC + address;
PowerPC::ppcState.npc = PowerPC::ppcState.pc + address;

m_end_block = true;
}
Expand All @@ -29,27 +29,27 @@ void Interpreter::bx(UGeckoInstruction inst)
void Interpreter::bcx(UGeckoInstruction inst)
{
if ((inst.BO & BO_DONT_DECREMENT_FLAG) == 0)
CTR--;
CTR(PowerPC::ppcState)--;

const bool true_false = ((inst.BO >> 3) & 1) != 0;
const bool only_counter_check = ((inst.BO >> 4) & 1) != 0;
const bool only_condition_check = ((inst.BO >> 2) & 1) != 0;
const u32 ctr_check = ((CTR != 0) ^ (inst.BO >> 1)) & 1;
const u32 ctr_check = ((CTR(PowerPC::ppcState) != 0) ^ (inst.BO >> 1)) & 1;
const bool counter = only_condition_check || ctr_check != 0;
const bool condition =
only_counter_check || (PowerPC::ppcState.cr.GetBit(inst.BI) == u32(true_false));

if (counter && condition)
{
if (inst.LK)
LR = PC + 4;
LR(PowerPC::ppcState) = PowerPC::ppcState.pc + 4;

const auto address = u32(SignExt16(s16(inst.BD << 2)));

if (inst.AA)
NPC = address;
PowerPC::ppcState.npc = address;
else
NPC = PC + address;
PowerPC::ppcState.npc = PowerPC::ppcState.pc + address;
}

m_end_block = true;
Expand All @@ -65,9 +65,9 @@ void Interpreter::bcctrx(UGeckoInstruction inst)

if (condition != 0)
{
NPC = CTR & (~3);
PowerPC::ppcState.npc = CTR(PowerPC::ppcState) & (~3);
if (inst.LK_3)
LR = PC + 4;
LR(PowerPC::ppcState) = PowerPC::ppcState.pc + 4;
}

m_end_block = true;
Expand All @@ -76,17 +76,17 @@ void Interpreter::bcctrx(UGeckoInstruction inst)
void Interpreter::bclrx(UGeckoInstruction inst)
{
if ((inst.BO_2 & BO_DONT_DECREMENT_FLAG) == 0)
CTR--;
CTR(PowerPC::ppcState)--;

const u32 counter = ((inst.BO_2 >> 2) | ((CTR != 0) ^ (inst.BO_2 >> 1))) & 1;
const u32 counter = ((inst.BO_2 >> 2) | ((CTR(PowerPC::ppcState) != 0) ^ (inst.BO_2 >> 1))) & 1;
const u32 condition =
((inst.BO_2 >> 4) | (PowerPC::ppcState.cr.GetBit(inst.BI_2) == ((inst.BO_2 >> 3) & 1))) & 1;

if ((counter & condition) != 0)
{
NPC = LR & (~3);
PowerPC::ppcState.npc = LR(PowerPC::ppcState) & (~3);
if (inst.LK_3)
LR = PC + 4;
LR(PowerPC::ppcState) = PowerPC::ppcState.pc + 4;
}

m_end_block = true;
Expand All @@ -95,12 +95,12 @@ void Interpreter::bclrx(UGeckoInstruction inst)
void Interpreter::HLEFunction(UGeckoInstruction inst)
{
m_end_block = true;
HLE::Execute(PC, inst.hex);
HLE::Execute(PowerPC::ppcState.pc, inst.hex);
}

void Interpreter::rfi(UGeckoInstruction inst)
{
if (MSR.PR)
if (PowerPC::ppcState.msr.PR)
{
GenerateProgramException(ProgramExceptionCause::PrivilegedInstruction);
return;
Expand All @@ -109,16 +109,17 @@ void Interpreter::rfi(UGeckoInstruction inst)
// Restore saved bits from SRR1 to MSR.
// Gecko/Broadway can save more bits than explicitly defined in ppc spec
const u32 mask = 0x87C0FFFF;
MSR.Hex = (MSR.Hex & ~mask) | (SRR1 & mask);
PowerPC::ppcState.msr.Hex =
(PowerPC::ppcState.msr.Hex & ~mask) | (SRR1(PowerPC::ppcState) & mask);
// MSR[13] is set to 0.
MSR.Hex &= 0xFFFBFFFF;
PowerPC::ppcState.msr.Hex &= 0xFFFBFFFF;
// Here we should check if there are pending exceptions, and if their corresponding enable bits
// are set
// if above is true, we'd do:
// PowerPC::CheckExceptions();
// else
// set NPC to saved offset and resume
NPC = SRR0;
PowerPC::ppcState.npc = SRR0(PowerPC::ppcState);
m_end_block = true;
}

Expand Down
2 changes: 1 addition & 1 deletion Source/Core/Core/PowerPC/Interpreter/Interpreter_FPUtils.h
Expand Up @@ -27,7 +27,7 @@ enum class FPCC

inline void CheckFPExceptions(UReg_FPSCR fpscr)
{
if (fpscr.FEX && (MSR.FE0 || MSR.FE1))
if (fpscr.FEX && (PowerPC::ppcState.msr.FE0 || PowerPC::ppcState.msr.FE1))
GenerateProgramException(ProgramExceptionCause::FloatingPoint);
}

Expand Down
397 changes: 204 additions & 193 deletions Source/Core/Core/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp

Large diffs are not rendered by default.

321 changes: 165 additions & 156 deletions Source/Core/Core/PowerPC/Interpreter/Interpreter_Integer.cpp

Large diffs are not rendered by default.

202 changes: 101 additions & 101 deletions Source/Core/Core/PowerPC/Interpreter/Interpreter_LoadStore.cpp

Large diffs are not rendered by default.

Expand Up @@ -310,100 +310,102 @@ static void Helper_Dequantize(PowerPC::PowerPCState* ppcs, u32 addr, u32 instI,

void Interpreter::psq_l(UGeckoInstruction inst)
{
if (HID2.LSQE == 0)
if (HID2(PowerPC::ppcState).LSQE == 0)
{
GenerateProgramException(ProgramExceptionCause::IllegalInstruction);
return;
}

const u32 EA = inst.RA ? (rGPR[inst.RA] + u32(inst.SIMM_12)) : u32(inst.SIMM_12);
const u32 EA = inst.RA ? (PowerPC::ppcState.gpr[inst.RA] + u32(inst.SIMM_12)) : u32(inst.SIMM_12);
Helper_Dequantize(&PowerPC::ppcState, EA, inst.I, inst.RD, inst.W);
}

void Interpreter::psq_lu(UGeckoInstruction inst)
{
if (HID2.LSQE == 0)
if (HID2(PowerPC::ppcState).LSQE == 0)
{
GenerateProgramException(ProgramExceptionCause::IllegalInstruction);
return;
}

const u32 EA = rGPR[inst.RA] + u32(inst.SIMM_12);
const u32 EA = PowerPC::ppcState.gpr[inst.RA] + u32(inst.SIMM_12);
Helper_Dequantize(&PowerPC::ppcState, EA, inst.I, inst.RD, inst.W);

if ((PowerPC::ppcState.Exceptions & EXCEPTION_DSI) != 0)
{
return;
}

rGPR[inst.RA] = EA;
PowerPC::ppcState.gpr[inst.RA] = EA;
}

void Interpreter::psq_st(UGeckoInstruction inst)
{
if (HID2.LSQE == 0)
if (HID2(PowerPC::ppcState).LSQE == 0)
{
GenerateProgramException(ProgramExceptionCause::IllegalInstruction);
return;
}

const u32 EA = inst.RA ? (rGPR[inst.RA] + u32(inst.SIMM_12)) : u32(inst.SIMM_12);
const u32 EA = inst.RA ? (PowerPC::ppcState.gpr[inst.RA] + u32(inst.SIMM_12)) : u32(inst.SIMM_12);
Helper_Quantize(&PowerPC::ppcState, EA, inst.I, inst.RS, inst.W);
}

void Interpreter::psq_stu(UGeckoInstruction inst)
{
if (HID2.LSQE == 0)
if (HID2(PowerPC::ppcState).LSQE == 0)
{
GenerateProgramException(ProgramExceptionCause::IllegalInstruction);
return;
}

const u32 EA = rGPR[inst.RA] + u32(inst.SIMM_12);
const u32 EA = PowerPC::ppcState.gpr[inst.RA] + u32(inst.SIMM_12);
Helper_Quantize(&PowerPC::ppcState, EA, inst.I, inst.RS, inst.W);

if ((PowerPC::ppcState.Exceptions & EXCEPTION_DSI) != 0)
{
return;
}

rGPR[inst.RA] = EA;
PowerPC::ppcState.gpr[inst.RA] = EA;
}

void Interpreter::psq_lx(UGeckoInstruction inst)
{
const u32 EA = inst.RA ? (rGPR[inst.RA] + rGPR[inst.RB]) : rGPR[inst.RB];
const u32 EA = inst.RA ? (PowerPC::ppcState.gpr[inst.RA] + PowerPC::ppcState.gpr[inst.RB]) :
PowerPC::ppcState.gpr[inst.RB];
Helper_Dequantize(&PowerPC::ppcState, EA, inst.Ix, inst.RD, inst.Wx);
}

void Interpreter::psq_stx(UGeckoInstruction inst)
{
const u32 EA = inst.RA ? (rGPR[inst.RA] + rGPR[inst.RB]) : rGPR[inst.RB];
const u32 EA = inst.RA ? (PowerPC::ppcState.gpr[inst.RA] + PowerPC::ppcState.gpr[inst.RB]) :
PowerPC::ppcState.gpr[inst.RB];
Helper_Quantize(&PowerPC::ppcState, EA, inst.Ix, inst.RS, inst.Wx);
}

void Interpreter::psq_lux(UGeckoInstruction inst)
{
const u32 EA = rGPR[inst.RA] + rGPR[inst.RB];
const u32 EA = PowerPC::ppcState.gpr[inst.RA] + PowerPC::ppcState.gpr[inst.RB];
Helper_Dequantize(&PowerPC::ppcState, EA, inst.Ix, inst.RD, inst.Wx);

if ((PowerPC::ppcState.Exceptions & EXCEPTION_DSI) != 0)
{
return;
}

rGPR[inst.RA] = EA;
PowerPC::ppcState.gpr[inst.RA] = EA;
}

void Interpreter::psq_stux(UGeckoInstruction inst)
{
const u32 EA = rGPR[inst.RA] + rGPR[inst.RB];
const u32 EA = PowerPC::ppcState.gpr[inst.RA] + PowerPC::ppcState.gpr[inst.RB];
Helper_Quantize(&PowerPC::ppcState, EA, inst.Ix, inst.RS, inst.Wx);

if ((PowerPC::ppcState.Exceptions & EXCEPTION_DSI) != 0)
{
return;
}

rGPR[inst.RA] = EA;
PowerPC::ppcState.gpr[inst.RA] = EA;
}
336 changes: 192 additions & 144 deletions Source/Core/Core/PowerPC/Interpreter/Interpreter_Paired.cpp

Large diffs are not rendered by default.

166 changes: 87 additions & 79 deletions Source/Core/Core/PowerPC/Interpreter/Interpreter_SystemRegisters.cpp

Large diffs are not rendered by default.

27 changes: 15 additions & 12 deletions Source/Core/Core/PowerPC/Jit64/Jit.cpp
Expand Up @@ -504,16 +504,17 @@ static void ImHere()
if (!f)
f.Open("log64.txt", "w");

f.WriteString(fmt::format("{0:08x}\n", PC));
f.WriteString(fmt::format("{0:08x}\n", PowerPC::ppcState.pc));
}
if (been_here.find(PC) != been_here.end())
if (been_here.find(PowerPC::ppcState.pc) != been_here.end())
{
been_here.find(PC)->second++;
if ((been_here.find(PC)->second) & 1023)
been_here.find(PowerPC::ppcState.pc)->second++;
if ((been_here.find(PowerPC::ppcState.pc)->second) & 1023)
return;
}
INFO_LOG_FMT(DYNA_REC, "I'm here - PC = {:08x} , LR = {:08x}", PC, LR);
been_here[PC] = 1;
INFO_LOG_FMT(DYNA_REC, "I'm here - PC = {:08x} , LR = {:08x}", PowerPC::ppcState.pc,
LR(PowerPC::ppcState));
been_here[PowerPC::ppcState.pc] = 1;
}

bool Jit64::Cleanup()
Expand All @@ -534,11 +535,11 @@ bool Jit64::Cleanup()
}

// SPEED HACK: MMCR0/MMCR1 should be checked at run-time, not at compile time.
if (MMCR0.Hex || MMCR1.Hex)
if (MMCR0(PowerPC::ppcState).Hex || MMCR1(PowerPC::ppcState).Hex)
{
ABI_PushRegistersAndAdjustStack({}, 0);
ABI_CallFunctionCCC(PowerPC::UpdatePerformanceMonitor, js.downcountAmount, js.numLoadStoreInst,
js.numFloatingPointInst);
ABI_CallFunctionCCCP(PowerPC::UpdatePerformanceMonitor, js.downcountAmount, js.numLoadStoreInst,
js.numFloatingPointInst, &PowerPC::ppcState);
ABI_PopRegistersAndAdjustStack({}, 0);
did_something = true;
}
Expand Down Expand Up @@ -758,7 +759,9 @@ void Jit64::Trace()
DEBUG_LOG_FMT(DYNA_REC,
"JIT64 PC: {:08x} SRR0: {:08x} SRR1: {:08x} FPSCR: {:08x} "
"MSR: {:08x} LR: {:08x} {} {}",
PC, SRR0, SRR1, FPSCR.Hex, MSR.Hex, PowerPC::ppcState.spr[8], regs, fregs);
PowerPC::ppcState.pc, SRR0(PowerPC::ppcState), SRR1(PowerPC::ppcState),
PowerPC::ppcState.fpscr.Hex, PowerPC::ppcState.msr.Hex, PowerPC::ppcState.spr[8],
regs, fregs);
}

void Jit64::Jit(u32 em_address)
Expand Down Expand Up @@ -829,7 +832,7 @@ void Jit64::Jit(u32 em_address, bool clear_cache_and_retry_on_failure)
if (code_block.m_memory_exception)
{
// Address of instruction could not be translated
NPC = nextPC;
PowerPC::ppcState.npc = nextPC;
PowerPC::ppcState.Exceptions |= EXCEPTION_ISI;
PowerPC::CheckExceptions();
WARN_LOG_FMT(POWERPC, "ISI exception at {:#010x}", nextPC);
Expand Down Expand Up @@ -978,7 +981,7 @@ bool Jit64::DoJit(u32 em_address, JitBlock* b, u32 nextPC)
// the start of the block in case our guess turns out wrong.
for (int gqr : gqr_static)
{
u32 value = GQR(gqr);
u32 value = GQR(PowerPC::ppcState, gqr);
js.constantGqr[gqr] = value;
CMP_or_TEST(32, PPCSTATE(spr[SPR_GQR0 + gqr]), Imm32(value));
J_CC(CC_NZ, target);
Expand Down
6 changes: 3 additions & 3 deletions Source/Core/Core/PowerPC/Jit64/Jit_LoadStore.cpp
Expand Up @@ -320,7 +320,7 @@ void Jit64::dcbx(UGeckoInstruction inst)
FixupBranch bat_lookup_failed;
MOV(32, R(effective_address), R(addr));
const u8* loop_start = GetCodePtr();
if (MSR.IR)
if (PowerPC::ppcState.msr.IR)
{
// Translate effective address to physical address.
bat_lookup_failed = BATAddressLookup(addr, tmp, PowerPC::ibat_table.data());
Expand Down Expand Up @@ -349,7 +349,7 @@ void Jit64::dcbx(UGeckoInstruction inst)

SwitchToFarCode();
SetJumpTarget(invalidate_needed);
if (MSR.IR)
if (PowerPC::ppcState.msr.IR)
SetJumpTarget(bat_lookup_failed);

BitSet32 registersInUse = CallerSavedRegistersInUse();
Expand Down Expand Up @@ -422,7 +422,7 @@ void Jit64::dcbz(UGeckoInstruction inst)
end_dcbz_hack = J_CC(CC_L);
}

bool emit_fast_path = MSR.DR && m_jit.jo.fastmem_arena;
bool emit_fast_path = PowerPC::ppcState.msr.DR && m_jit.jo.fastmem_arena;

if (emit_fast_path)
{
Expand Down
4 changes: 2 additions & 2 deletions Source/Core/Core/PowerPC/Jit64/Jit_LoadStorePaired.cpp
Expand Up @@ -23,7 +23,7 @@ void Jit64::psq_stXX(UGeckoInstruction inst)
JITDISABLE(bJITLoadStorePairedOff);

// For performance, the AsmCommon routines assume address translation is on.
FALLBACK_IF(!MSR.DR);
FALLBACK_IF(!PowerPC::ppcState.msr.DR);

s32 offset = inst.SIMM_12;
bool indexed = inst.OPCD == 4;
Expand Down Expand Up @@ -112,7 +112,7 @@ void Jit64::psq_lXX(UGeckoInstruction inst)
JITDISABLE(bJITLoadStorePairedOff);

// For performance, the AsmCommon routines assume address translation is on.
FALLBACK_IF(!MSR.DR);
FALLBACK_IF(!PowerPC::ppcState.msr.DR);

s32 offset = inst.SIMM_12;
bool indexed = inst.OPCD == 4;
Expand Down
4 changes: 2 additions & 2 deletions Source/Core/Core/PowerPC/Jit64Common/EmuCodeBlock.cpp
Expand Up @@ -367,7 +367,7 @@ void EmuCodeBlock::SafeLoadToReg(X64Reg reg_value, const Gen::OpArg& opAddress,
}

FixupBranch exit;
const bool dr_set = (flags & SAFE_LOADSTORE_DR_ON) || MSR.DR;
const bool dr_set = (flags & SAFE_LOADSTORE_DR_ON) || PowerPC::ppcState.msr.DR;
const bool fast_check_address = !slowmem && dr_set && m_jit.jo.fastmem_arena;
if (fast_check_address)
{
Expand Down Expand Up @@ -537,7 +537,7 @@ void EmuCodeBlock::SafeWriteRegToReg(OpArg reg_value, X64Reg reg_addr, int acces
}

FixupBranch exit;
const bool dr_set = (flags & SAFE_LOADSTORE_DR_ON) || MSR.DR;
const bool dr_set = (flags & SAFE_LOADSTORE_DR_ON) || PowerPC::ppcState.msr.DR;
const bool fast_check_address = !slowmem && dr_set && m_jit.jo.fastmem_arena;
if (fast_check_address)
{
Expand Down
11 changes: 7 additions & 4 deletions Source/Core/Core/PowerPC/JitArm64/Jit.cpp
Expand Up @@ -288,12 +288,13 @@ void JitArm64::Cleanup()
}

// SPEED HACK: MMCR0/MMCR1 should be checked at run-time, not at compile time.
if (MMCR0.Hex || MMCR1.Hex)
if (MMCR0(PowerPC::ppcState).Hex || MMCR1(PowerPC::ppcState).Hex)
{
MOVP2R(ARM64Reg::X8, &PowerPC::UpdatePerformanceMonitor);
MOVI2R(ARM64Reg::X0, js.downcountAmount);
MOVI2R(ARM64Reg::X1, js.numLoadStoreInst);
MOVI2R(ARM64Reg::X2, js.numFloatingPointInst);
MOVP2R(ARM64Reg::X3, &PowerPC::ppcState);
BLR(ARM64Reg::X8);
}
}
Expand Down Expand Up @@ -705,7 +706,9 @@ void JitArm64::Trace()
DEBUG_LOG_FMT(DYNA_REC,
"JitArm64 PC: {:08x} SRR0: {:08x} SRR1: {:08x} FPSCR: {:08x} "
"MSR: {:08x} LR: {:08x} {} {}",
PC, SRR0, SRR1, FPSCR.Hex, MSR.Hex, PowerPC::ppcState.spr[8], regs, fregs);
PowerPC::ppcState.pc, SRR0(PowerPC::ppcState), SRR1(PowerPC::ppcState),
PowerPC::ppcState.fpscr.Hex, PowerPC::ppcState.msr.Hex, PowerPC::ppcState.spr[8],
regs, fregs);
}

void JitArm64::Jit(u32 em_address)
Expand Down Expand Up @@ -779,7 +782,7 @@ void JitArm64::Jit(u32 em_address, bool clear_cache_and_retry_on_failure)
if (code_block.m_memory_exception)
{
// Address of instruction could not be translated
NPC = nextPC;
PowerPC::ppcState.npc = nextPC;
PowerPC::ppcState.Exceptions |= EXCEPTION_ISI;
PowerPC::CheckExceptions();
WARN_LOG_FMT(POWERPC, "ISI exception at {:#010x}", nextPC);
Expand Down Expand Up @@ -895,7 +898,7 @@ bool JitArm64::DoJit(u32 em_address, JitBlock* b, u32 nextPC)
js.pairedQuantizeAddresses.find(js.blockStart) == js.pairedQuantizeAddresses.end())
{
int gqr = *code_block.m_gqr_used.begin();
if (!code_block.m_gqr_modified[gqr] && !GQR(gqr))
if (!code_block.m_gqr_modified[gqr] && !GQR(PowerPC::ppcState, gqr))
{
LDR(IndexType::Unsigned, ARM64Reg::W0, PPC_REG, PPCSTATE_OFF_SPR(SPR_GQR0 + gqr));
FixupBranch no_fail = CBZ(ARM64Reg::W0);
Expand Down
4 changes: 2 additions & 2 deletions Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStore.cpp
Expand Up @@ -731,7 +731,7 @@ void JitArm64::dcbx(UGeckoInstruction inst)
// Translate effective address to physical address.
const u8* loop_start = GetCodePtr();
FixupBranch bat_lookup_failed;
if (MSR.IR)
if (PowerPC::ppcState.msr.IR)
{
bat_lookup_failed =
BATAddressLookup(physical_addr, effective_addr, WA, PowerPC::ibat_table.data());
Expand Down Expand Up @@ -760,7 +760,7 @@ void JitArm64::dcbx(UGeckoInstruction inst)

SwitchToFarCode();
SetJumpTarget(invalidate_needed);
if (MSR.IR)
if (PowerPC::ppcState.msr.IR)
SetJumpTarget(bat_lookup_failed);

BitSet32 gprs_to_push = gpr.GetCallerSavedUsed();
Expand Down
Expand Up @@ -23,7 +23,7 @@ void JitArm64::psq_lXX(UGeckoInstruction inst)
JITDISABLE(bJITLoadStorePairedOff);

// If we have a fastmem arena, the asm routines assume address translation is on.
FALLBACK_IF(!js.assumeNoPairedQuantize && jo.fastmem_arena && !MSR.DR);
FALLBACK_IF(!js.assumeNoPairedQuantize && jo.fastmem_arena && !PowerPC::ppcState.msr.DR);

// X30 is LR
// X0 is the address
Expand Down Expand Up @@ -148,7 +148,7 @@ void JitArm64::psq_stXX(UGeckoInstruction inst)
JITDISABLE(bJITLoadStorePairedOff);

// If we have a fastmem arena, the asm routines assume address translation is on.
FALLBACK_IF(!js.assumeNoPairedQuantize && jo.fastmem_arena && !MSR.DR);
FALLBACK_IF(!js.assumeNoPairedQuantize && jo.fastmem_arena && !PowerPC::ppcState.msr.DR);

// X30 is LR
// X0 contains the scale
Expand Down
3 changes: 2 additions & 1 deletion Source/Core/Core/PowerPC/JitCommon/JitBase.cpp
Expand Up @@ -90,7 +90,8 @@ bool JitBase::CanMergeNextInstructions(int count) const
void JitBase::UpdateMemoryAndExceptionOptions()
{
bool any_watchpoints = PowerPC::memchecks.HasAny();
jo.fastmem = m_fastmem_enabled && jo.fastmem_arena && (MSR.DR || !any_watchpoints);
jo.fastmem =
m_fastmem_enabled && jo.fastmem_arena && (PowerPC::ppcState.msr.DR || !any_watchpoints);
jo.memcheck = m_mmu_enabled || m_pause_on_panic_enabled || any_watchpoints;
jo.fp_exceptions = m_enable_float_exceptions;
jo.div_by_zero_exceptions = m_enable_div_by_zero_exceptions;
Expand Down
12 changes: 8 additions & 4 deletions Source/Core/Core/PowerPC/JitCommon/JitCache.cpp
Expand Up @@ -96,7 +96,7 @@ JitBlock* JitBaseBlockCache::AllocateBlock(u32 em_address)
JitBlock& b = block_map.emplace(physical_address, JitBlock())->second;
b.effectiveAddress = em_address;
b.physicalAddress = physical_address;
b.msrBits = MSR.Hex & JIT_CACHE_MSR_MASK;
b.msrBits = PowerPC::ppcState.msr.Hex & JIT_CACHE_MSR_MASK;
b.linkData.clear();
b.fast_block_map_index = 0;
return &b;
Expand Down Expand Up @@ -168,10 +168,14 @@ JitBlock* JitBaseBlockCache::GetBlockFromStartAddress(u32 addr, u32 msr)

const u8* JitBaseBlockCache::Dispatch()
{
JitBlock* block = fast_block_map[FastLookupIndexForAddress(PC)];
JitBlock* block = fast_block_map[FastLookupIndexForAddress(PowerPC::ppcState.pc)];

if (!block || block->effectiveAddress != PC || block->msrBits != (MSR.Hex & JIT_CACHE_MSR_MASK))
block = MoveBlockIntoFastCache(PC, MSR.Hex & JIT_CACHE_MSR_MASK);
if (!block || block->effectiveAddress != PowerPC::ppcState.pc ||
block->msrBits != (PowerPC::ppcState.msr.Hex & JIT_CACHE_MSR_MASK))
{
block = MoveBlockIntoFastCache(PowerPC::ppcState.pc,
PowerPC::ppcState.msr.Hex & JIT_CACHE_MSR_MASK);
}

if (!block)
return nullptr;
Expand Down
15 changes: 9 additions & 6 deletions Source/Core/Core/PowerPC/JitInterface.cpp
Expand Up @@ -153,12 +153,14 @@ std::variant<GetHostCodeError, GetHostCodeResult> GetHostCode(u32 address)
return GetHostCodeError::NoJitActive;
}

JitBlock* block = g_jit->GetBlockCache()->GetBlockFromStartAddress(address, MSR.Hex);
JitBlock* block =
g_jit->GetBlockCache()->GetBlockFromStartAddress(address, PowerPC::ppcState.msr.Hex);
if (!block)
{
for (int i = 0; i < 500; i++)
{
block = g_jit->GetBlockCache()->GetBlockFromStartAddress(address - 4 * i, MSR.Hex);
block = g_jit->GetBlockCache()->GetBlockFromStartAddress(address - 4 * i,
PowerPC::ppcState.msr.Hex);
if (block)
break;
}
Expand Down Expand Up @@ -264,20 +266,21 @@ void CompileExceptionCheck(ExceptionType type)
break;
}

if (PC != 0 && (exception_addresses->find(PC)) == (exception_addresses->end()))
if (PowerPC::ppcState.pc != 0 &&
(exception_addresses->find(PowerPC::ppcState.pc)) == (exception_addresses->end()))
{
if (type == ExceptionType::FIFOWrite)
{
// Check in case the code has been replaced since: do we need to do this?
const OpType optype = PPCTables::GetOpInfo(PowerPC::HostRead_U32(PC))->type;
const OpType optype = PPCTables::GetOpInfo(PowerPC::HostRead_U32(PowerPC::ppcState.pc))->type;
if (optype != OpType::Store && optype != OpType::StoreFP && optype != OpType::StorePS)
return;
}
exception_addresses->insert(PC);
exception_addresses->insert(PowerPC::ppcState.pc);

// Invalidate the JIT block so that it gets recompiled with the external exception check
// included.
g_jit->GetBlockCache()->InvalidateICache(PC, 4, true);
g_jit->GetBlockCache()->InvalidateICache(PowerPC::ppcState.pc, 4, true);
}
}

Expand Down