Merge pull request #11429 from AdmiralCurtiss/globals-ppc

Reduce usage of ppcState global.
This commit is contained in:
Pierre Bourdon
2023-01-27 19:06:30 +01:00
committed by GitHub
69 changed files with 1717 additions and 1427 deletions

View File

@@ -11,6 +11,7 @@
#include "Core/Debugger/PPCDebugInterface.h" #include "Core/Debugger/PPCDebugInterface.h"
#include "Core/HW/CPU.h" #include "Core/HW/CPU.h"
#include "Core/PowerPC/PowerPC.h" #include "Core/PowerPC/PowerPC.h"
#include "Core/System.h"
namespace namespace
{ {
@@ -56,11 +57,13 @@ void CodeTrace::SetRegTracked(const std::string& reg)
InstructionAttributes CodeTrace::GetInstructionAttributes(const TraceOutput& instruction) const InstructionAttributes CodeTrace::GetInstructionAttributes(const TraceOutput& instruction) const
{ {
auto& system = Core::System::GetInstance();
// Slower process of breaking down saved instruction. Only used when stepping through code if a // Slower process of breaking down saved instruction. Only used when stepping through code if a
// decision has to be made, otherwise used afterwards on a log file. // decision has to be made, otherwise used afterwards on a log file.
InstructionAttributes tmp_attributes; InstructionAttributes tmp_attributes;
tmp_attributes.instruction = instruction.instruction; tmp_attributes.instruction = instruction.instruction;
tmp_attributes.address = PC; tmp_attributes.address = system.GetPPCState().pc;
std::string instr = instruction.instruction; std::string instr = instruction.instruction;
std::smatch match; std::smatch match;
@@ -106,11 +109,14 @@ InstructionAttributes CodeTrace::GetInstructionAttributes(const TraceOutput& ins
TraceOutput CodeTrace::SaveCurrentInstruction() const TraceOutput CodeTrace::SaveCurrentInstruction() const
{ {
auto& system = Core::System::GetInstance();
auto& ppc_state = system.GetPPCState();
// Quickly save instruction and memory target for fast logging. // Quickly save instruction and memory target for fast logging.
TraceOutput output; TraceOutput output;
const std::string instr = PowerPC::debug_interface.Disassemble(PC); const std::string instr = PowerPC::debug_interface.Disassemble(ppc_state.pc);
output.instruction = instr; output.instruction = instr;
output.address = PC; output.address = ppc_state.pc;
if (IsInstructionLoadStore(output.instruction)) if (IsInstructionLoadStore(output.instruction))
output.memory_target = PowerPC::debug_interface.GetMemoryAddressFromInstruction(instr); output.memory_target = PowerPC::debug_interface.GetMemoryAddressFromInstruction(instr);

View File

@@ -458,22 +458,23 @@ bool CBoot::Load_BS2(Core::System& system, const std::string& boot_rom_filename)
memory.CopyToEmu(0x01200000, data.data() + 0x100, 0x700); memory.CopyToEmu(0x01200000, data.data() + 0x100, 0x700);
memory.CopyToEmu(0x01300000, data.data() + 0x820, 0x1AFE00); memory.CopyToEmu(0x01300000, data.data() + 0x820, 0x1AFE00);
PowerPC::ppcState.gpr[3] = 0xfff0001f; auto& ppc_state = system.GetPPCState();
PowerPC::ppcState.gpr[4] = 0x00002030; ppc_state.gpr[3] = 0xfff0001f;
PowerPC::ppcState.gpr[5] = 0x0000009c; ppc_state.gpr[4] = 0x00002030;
ppc_state.gpr[5] = 0x0000009c;
MSR.FP = 1; ppc_state.msr.FP = 1;
MSR.DR = 1; ppc_state.msr.DR = 1;
MSR.IR = 1; ppc_state.msr.IR = 1;
PowerPC::ppcState.spr[SPR_HID0] = 0x0011c464; ppc_state.spr[SPR_HID0] = 0x0011c464;
PowerPC::ppcState.spr[SPR_IBAT3U] = 0xfff0001f; ppc_state.spr[SPR_IBAT3U] = 0xfff0001f;
PowerPC::ppcState.spr[SPR_IBAT3L] = 0xfff00001; ppc_state.spr[SPR_IBAT3L] = 0xfff00001;
PowerPC::ppcState.spr[SPR_DBAT3U] = 0xfff0001f; ppc_state.spr[SPR_DBAT3U] = 0xfff0001f;
PowerPC::ppcState.spr[SPR_DBAT3L] = 0xfff00001; ppc_state.spr[SPR_DBAT3L] = 0xfff00001;
SetupBAT(/*is_wii*/ false); SetupBAT(system, /*is_wii*/ false);
PC = 0x81200150; ppc_state.pc = 0x81200150;
return true; return true;
} }
@@ -543,16 +544,18 @@ bool CBoot::BootUp(Core::System& system, std::unique_ptr<BootParameters> boot)
SetDefaultDisc(); SetDefaultDisc();
SetupMSR(); auto& ppc_state = system.GetPPCState();
SetupHID(config.bWii);
SetupBAT(config.bWii); SetupMSR(ppc_state);
SetupHID(ppc_state, config.bWii);
SetupBAT(system, config.bWii);
CopyDefaultExceptionHandlers(system); CopyDefaultExceptionHandlers(system);
if (config.bWii) if (config.bWii)
{ {
// Set a value for the SP. It doesn't matter where this points to, // Set a value for the SP. It doesn't matter where this points to,
// as long as it is a valid location. This value is taken from a homebrew binary. // as long as it is a valid location. This value is taken from a homebrew binary.
PowerPC::ppcState.gpr[1] = 0x8004d4bc; ppc_state.gpr[1] = 0x8004d4bc;
// Because there is no TMD to get the requested system (IOS) version from, // Because there is no TMD to get the requested system (IOS) version from,
// we default to IOS58, which is the version used by the Homebrew Channel. // we default to IOS58, which is the version used by the Homebrew Channel.
@@ -572,12 +575,12 @@ bool CBoot::BootUp(Core::System& system, std::unique_ptr<BootParameters> boot)
SConfig::OnNewTitleLoad(); SConfig::OnNewTitleLoad();
PC = executable.reader->GetEntryPoint(); ppc_state.pc = executable.reader->GetEntryPoint();
if (executable.reader->LoadSymbols()) if (executable.reader->LoadSymbols())
{ {
UpdateDebugger_MapLoaded(); UpdateDebugger_MapLoaded();
HLE::PatchFunctions(); HLE::PatchFunctions(system);
} }
return true; return true;
} }

View File

@@ -34,6 +34,11 @@ namespace IOS::HLE::FS
class FileSystem; class FileSystem;
} }
namespace PowerPC
{
struct PowerPCState;
}
struct RegionSetting struct RegionSetting
{ {
std::string area; std::string area;
@@ -167,17 +172,17 @@ private:
static bool DVDRead(const DiscIO::VolumeDisc& disc, u64 dvd_offset, u32 output_address, static bool DVDRead(const DiscIO::VolumeDisc& disc, u64 dvd_offset, u32 output_address,
u32 length, const DiscIO::Partition& partition); u32 length, const DiscIO::Partition& partition);
static bool DVDReadDiscID(const DiscIO::VolumeDisc& disc, u32 output_address); static bool DVDReadDiscID(const DiscIO::VolumeDisc& disc, u32 output_address);
static void RunFunction(u32 address); static void RunFunction(Core::System& system, u32 address);
static void UpdateDebugger_MapLoaded(); static void UpdateDebugger_MapLoaded();
static bool Boot_WiiWAD(Core::System& system, const DiscIO::VolumeWAD& wad); static bool Boot_WiiWAD(Core::System& system, const DiscIO::VolumeWAD& wad);
static bool BootNANDTitle(Core::System& system, u64 title_id); static bool BootNANDTitle(Core::System& system, u64 title_id);
static void SetupMSR(); static void SetupMSR(PowerPC::PowerPCState& ppc_state);
static void SetupHID(bool is_wii); static void SetupHID(PowerPC::PowerPCState& ppc_state, bool is_wii);
static void SetupBAT(bool is_wii); static void SetupBAT(Core::System& system, bool is_wii);
static bool RunApploader(bool is_wii, const DiscIO::VolumeDisc& volume, static bool RunApploader(Core::System& system, bool is_wii, const DiscIO::VolumeDisc& volume,
const std::vector<DiscIO::Riivolution::Patch>& riivolution_patches); const std::vector<DiscIO::Riivolution::Patch>& riivolution_patches);
static bool EmulatedBS2_GC(Core::System& system, const DiscIO::VolumeDisc& volume, static bool EmulatedBS2_GC(Core::System& system, const DiscIO::VolumeDisc& volume,
const std::vector<DiscIO::Riivolution::Patch>& riivolution_patches); const std::vector<DiscIO::Riivolution::Patch>& riivolution_patches);

View File

@@ -55,80 +55,83 @@ void PresetTimeBaseTicks()
} }
} // Anonymous namespace } // Anonymous namespace
void CBoot::RunFunction(u32 address) void CBoot::RunFunction(Core::System& system, u32 address)
{ {
PC = address; auto& ppc_state = system.GetPPCState();
LR = 0x00;
while (PC != 0x00) ppc_state.pc = address;
LR(ppc_state) = 0x00;
while (ppc_state.pc != 0x00)
PowerPC::SingleStep(); PowerPC::SingleStep();
} }
void CBoot::SetupMSR() void CBoot::SetupMSR(PowerPC::PowerPCState& ppc_state)
{ {
// 0x0002032 // 0x0002032
MSR.RI = 1; ppc_state.msr.RI = 1;
MSR.DR = 1; ppc_state.msr.DR = 1;
MSR.IR = 1; ppc_state.msr.IR = 1;
MSR.FP = 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 is 0x0011c464 on GC, 0x0011c664 on Wii
HID0.BHT = 1; HID0(ppc_state).BHT = 1;
HID0.BTIC = 1; HID0(ppc_state).BTIC = 1;
HID0.DCFA = 1; HID0(ppc_state).DCFA = 1;
if (is_wii) if (is_wii)
HID0.SPD = 1; HID0(ppc_state).SPD = 1;
HID0.DCFI = 1; HID0(ppc_state).DCFI = 1;
HID0.DCE = 1; HID0(ppc_state).DCE = 1;
// Note that Datel titles will fail to boot if the instruction cache is not enabled; see // Note that Datel titles will fail to boot if the instruction cache is not enabled; see
// https://bugs.dolphin-emu.org/issues/8223 // https://bugs.dolphin-emu.org/issues/8223
HID0.ICE = 1; HID0(ppc_state).ICE = 1;
HID0.NHR = 1; HID0(ppc_state).NHR = 1;
HID0.DPM = 1; HID0(ppc_state).DPM = 1;
// HID1 is initialized in PowerPC.cpp to 0x80000000 // HID1 is initialized in PowerPC.cpp to 0x80000000
// HID2 is 0xe0000000 // HID2 is 0xe0000000
HID2.PSE = 1; HID2(ppc_state).PSE = 1;
HID2.WPE = 1; HID2(ppc_state).WPE = 1;
HID2.LSQE = 1; HID2(ppc_state).LSQE = 1;
// HID4 is 0 on GC and 0x83900000 on Wii // HID4 is 0 on GC and 0x83900000 on Wii
if (is_wii) if (is_wii)
{ {
HID4.L2CFI = 1; HID4(ppc_state).L2CFI = 1;
HID4.LPE = 1; HID4(ppc_state).LPE = 1;
HID4.ST0 = 1; HID4(ppc_state).ST0 = 1;
HID4.SBE = 1; HID4(ppc_state).SBE = 1;
HID4.reserved_3 = 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; auto& ppc_state = system.GetPPCState();
PowerPC::ppcState.spr[SPR_IBAT0L] = 0x00000002; ppc_state.spr[SPR_IBAT0U] = 0x80001fff;
PowerPC::ppcState.spr[SPR_DBAT0U] = 0x80001fff; ppc_state.spr[SPR_IBAT0L] = 0x00000002;
PowerPC::ppcState.spr[SPR_DBAT0L] = 0x00000002; ppc_state.spr[SPR_DBAT0U] = 0x80001fff;
PowerPC::ppcState.spr[SPR_DBAT1U] = 0xc0001fff; ppc_state.spr[SPR_DBAT0L] = 0x00000002;
PowerPC::ppcState.spr[SPR_DBAT1L] = 0x0000002a; ppc_state.spr[SPR_DBAT1U] = 0xc0001fff;
ppc_state.spr[SPR_DBAT1L] = 0x0000002a;
if (is_wii) if (is_wii)
{ {
PowerPC::ppcState.spr[SPR_IBAT4U] = 0x90001fff; ppc_state.spr[SPR_IBAT4U] = 0x90001fff;
PowerPC::ppcState.spr[SPR_IBAT4L] = 0x10000002; ppc_state.spr[SPR_IBAT4L] = 0x10000002;
PowerPC::ppcState.spr[SPR_DBAT4U] = 0x90001fff; ppc_state.spr[SPR_DBAT4U] = 0x90001fff;
PowerPC::ppcState.spr[SPR_DBAT4L] = 0x10000002; ppc_state.spr[SPR_DBAT4L] = 0x10000002;
PowerPC::ppcState.spr[SPR_DBAT5U] = 0xd0001fff; ppc_state.spr[SPR_DBAT5U] = 0xd0001fff;
PowerPC::ppcState.spr[SPR_DBAT5L] = 0x1000002a; ppc_state.spr[SPR_DBAT5L] = 0x1000002a;
HID4.SBE = 1; HID4(ppc_state).SBE = 1;
} }
PowerPC::DBATUpdated(); PowerPC::DBATUpdated();
PowerPC::IBATUpdated(); 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 std::vector<DiscIO::Riivolution::Patch>& riivolution_patches)
{ {
const DiscIO::Partition partition = volume.GetGamePartition(); const DiscIO::Partition partition = volume.GetGamePartition();
@@ -148,40 +151,42 @@ bool CBoot::RunApploader(bool is_wii, const DiscIO::VolumeDisc& volume,
// TODO - Make Apploader(or just RunFunction()) debuggable!!! // TODO - Make Apploader(or just RunFunction()) debuggable!!!
auto& ppc_state = system.GetPPCState();
// Call iAppLoaderEntry. // Call iAppLoaderEntry.
DEBUG_LOG_FMT(BOOT, "Call iAppLoaderEntry"); DEBUG_LOG_FMT(BOOT, "Call iAppLoaderEntry");
const u32 iAppLoaderFuncAddr = is_wii ? 0x80004000 : 0x80003100; const u32 iAppLoaderFuncAddr = is_wii ? 0x80004000 : 0x80003100;
PowerPC::ppcState.gpr[3] = iAppLoaderFuncAddr + 0; ppc_state.gpr[3] = iAppLoaderFuncAddr + 0;
PowerPC::ppcState.gpr[4] = iAppLoaderFuncAddr + 4; ppc_state.gpr[4] = iAppLoaderFuncAddr + 4;
PowerPC::ppcState.gpr[5] = iAppLoaderFuncAddr + 8; ppc_state.gpr[5] = iAppLoaderFuncAddr + 8;
RunFunction(*entry); RunFunction(system, *entry);
const u32 iAppLoaderInit = PowerPC::Read_U32(iAppLoaderFuncAddr + 0); const u32 iAppLoaderInit = PowerPC::Read_U32(iAppLoaderFuncAddr + 0);
const u32 iAppLoaderMain = PowerPC::Read_U32(iAppLoaderFuncAddr + 4); const u32 iAppLoaderMain = PowerPC::Read_U32(iAppLoaderFuncAddr + 4);
const u32 iAppLoaderClose = PowerPC::Read_U32(iAppLoaderFuncAddr + 8); const u32 iAppLoaderClose = PowerPC::Read_U32(iAppLoaderFuncAddr + 8);
// iAppLoaderInit // iAppLoaderInit
DEBUG_LOG_FMT(BOOT, "Call iAppLoaderInit"); DEBUG_LOG_FMT(BOOT, "Call iAppLoaderInit");
PowerPC::HostWrite_U32(0x4E800020, 0x81300000); // Write BLR PowerPC::HostWrite_U32(0x4E800020, 0x81300000); // Write BLR
HLE::Patch(0x81300000, "AppLoaderReport"); // HLE OSReport for Apploader HLE::Patch(system, 0x81300000, "AppLoaderReport"); // HLE OSReport for Apploader
PowerPC::ppcState.gpr[3] = 0x81300000; ppc_state.gpr[3] = 0x81300000;
RunFunction(iAppLoaderInit); RunFunction(system, iAppLoaderInit);
// iAppLoaderMain - Here we load the apploader, the DOL (the exe) and the FST (filesystem). // 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 // To give you an idea about where the stuff is located on the disc take a look at yagcd
// ch 13. // ch 13.
DEBUG_LOG_FMT(BOOT, "Call iAppLoaderMain"); DEBUG_LOG_FMT(BOOT, "Call iAppLoaderMain");
PowerPC::ppcState.gpr[3] = 0x81300004; ppc_state.gpr[3] = 0x81300004;
PowerPC::ppcState.gpr[4] = 0x81300008; ppc_state.gpr[4] = 0x81300008;
PowerPC::ppcState.gpr[5] = 0x8130000c; 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 // 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 // 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. // 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. // 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 ram_address = PowerPC::Read_U32(0x81300004);
const u32 length = PowerPC::Read_U32(0x81300008); const u32 length = PowerPC::Read_U32(0x81300008);
@@ -193,20 +198,20 @@ bool CBoot::RunApploader(bool is_wii, const DiscIO::VolumeDisc& volume,
DiscIO::Riivolution::ApplyApploaderMemoryPatches(riivolution_patches, ram_address, length); DiscIO::Riivolution::ApplyApploaderMemoryPatches(riivolution_patches, ram_address, length);
PowerPC::ppcState.gpr[3] = 0x81300004; ppc_state.gpr[3] = 0x81300004;
PowerPC::ppcState.gpr[4] = 0x81300008; ppc_state.gpr[4] = 0x81300008;
PowerPC::ppcState.gpr[5] = 0x8130000c; ppc_state.gpr[5] = 0x8130000c;
RunFunction(iAppLoaderMain); RunFunction(system, iAppLoaderMain);
} }
// iAppLoaderClose // iAppLoaderClose
DEBUG_LOG_FMT(BOOT, "call iAppLoaderClose"); DEBUG_LOG_FMT(BOOT, "call iAppLoaderClose");
RunFunction(iAppLoaderClose); RunFunction(system, iAppLoaderClose);
HLE::UnPatch("AppLoaderReport"); HLE::UnPatch(system, "AppLoaderReport");
// return // return
PC = PowerPC::ppcState.gpr[3]; ppc_state.pc = ppc_state.gpr[3];
return true; return true;
} }
@@ -255,9 +260,11 @@ bool CBoot::EmulatedBS2_GC(Core::System& system, const DiscIO::VolumeDisc& volum
{ {
INFO_LOG_FMT(BOOT, "Faking GC BS2..."); INFO_LOG_FMT(BOOT, "Faking GC BS2...");
SetupMSR(); auto& ppc_state = system.GetPPCState();
SetupHID(/*is_wii*/ false);
SetupBAT(/*is_wii*/ false); SetupMSR(ppc_state);
SetupHID(ppc_state, /*is_wii*/ false);
SetupBAT(system, /*is_wii*/ false);
SetupGCMemory(system); SetupGCMemory(system);
@@ -296,13 +303,13 @@ bool CBoot::EmulatedBS2_GC(Core::System& system, const DiscIO::VolumeDisc& volum
// Setup pointers like real BS2 does // Setup pointers like real BS2 does
// StackPointer, used to be set to 0x816ffff0 // 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) // 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) // 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) static DiscIO::Region CodeRegion(char c)
@@ -559,17 +566,19 @@ bool CBoot::EmulatedBS2_Wii(Core::System& system, const DiscIO::VolumeDisc& volu
// after this check during booting. // after this check during booting.
DVDRead(volume, 0, 0x3180, 4, partition); DVDRead(volume, 0, 0x3180, 4, partition);
SetupMSR(); auto& ppc_state = system.GetPPCState();
SetupHID(/*is_wii*/ true);
SetupBAT(/*is_wii*/ true); 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, 0x00000300); // Write default DSI Handler: rfi
memory.Write_U32(0x4c000064, 0x00000800); // Write default FPU Handler: rfi memory.Write_U32(0x4c000064, 0x00000800); // Write default FPU Handler: rfi
memory.Write_U32(0x4c000064, 0x00000C00); // Write default Syscall 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; return false;
// The Apploader probably just overwrote values needed for RAM Override. Run this again! // The Apploader probably just overwrote values needed for RAM Override. Run this again!

View File

@@ -20,6 +20,7 @@
#include "Core/HW/Memmap.h" #include "Core/HW/Memmap.h"
#include "Core/PowerPC/MMU.h" #include "Core/PowerPC/MMU.h"
#include "Core/PowerPC/PowerPC.h" #include "Core/PowerPC/PowerPC.h"
#include "Core/System.h"
Cheats::DataType Cheats::GetDataType(const Cheats::SearchValue& value) Cheats::DataType Cheats::GetDataType(const Cheats::SearchValue& value)
{ {
@@ -204,7 +205,9 @@ Cheats::NewSearch(const std::vector<Cheats::MemoryRange>& memory_ranges,
return; 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; error_code = Cheats::SearchErrorCode::VirtualAddressesCurrentlyNotAccessible;
return; return;
@@ -263,7 +266,9 @@ Cheats::NextSearch(const std::vector<Cheats::SearchResult<T>>& previous_results,
return; 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; error_code = Cheats::SearchErrorCode::VirtualAddressesCurrentlyNotAccessible;
return; return;

View File

@@ -51,6 +51,7 @@
#include "Core/PatchEngine.h" #include "Core/PatchEngine.h"
#include "Core/PowerPC/PPCSymbolDB.h" #include "Core/PowerPC/PPCSymbolDB.h"
#include "Core/PowerPC/PowerPC.h" #include "Core/PowerPC/PowerPC.h"
#include "Core/System.h"
#include "Core/TitleDatabase.h" #include "Core/TitleDatabase.h"
#include "VideoCommon/HiresTextures.h" #include "VideoCommon/HiresTextures.h"
@@ -202,7 +203,8 @@ void SConfig::OnNewTitleLoad()
Host_NotifyMapLoaded(); Host_NotifyMapLoaded();
} }
CBoot::LoadMapFromFilename(); CBoot::LoadMapFromFilename();
HLE::Reload(); auto& system = Core::System::GetInstance();
HLE::Reload(system);
PatchEngine::Reload(); PatchEngine::Reload();
HiresTexture::Update(); HiresTexture::Update();
} }

View File

@@ -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, // 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 // 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 // compatible because it stops the games from actually knowing directly that the clock rate has
@@ -90,7 +94,7 @@ void CoreTimingManager::Init()
m_last_oc_factor = m_config_oc_factor; m_last_oc_factor = m_config_oc_factor;
m_globals.last_OC_factor_inverted = m_config_oc_inv_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.slice_length = MAX_SLICE_LENGTH;
m_globals.global_timer = 0; m_globals.global_timer = 0;
m_idled_cycles = 0; m_idled_cycles = 0;
@@ -195,7 +199,7 @@ u64 CoreTimingManager::GetTicks() const
u64 ticks = static_cast<u64>(m_globals.global_timer); u64 ticks = static_cast<u64>(m_globals.global_timer);
if (!m_is_global_timer_sane) 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; ticks += m_globals.slice_length - downcount;
} }
return ticks; return ticks;
@@ -277,13 +281,13 @@ void CoreTimingManager::RemoveAllEvents(EventType* event_type)
void CoreTimingManager::ForceExceptionCheck(s64 cycles) void CoreTimingManager::ForceExceptionCheck(s64 cycles)
{ {
cycles = std::max<s64>(0, 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. // 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 // Account for cycles already executed by adjusting the m_globals.slice_length
m_globals.slice_length -= m_globals.slice_length -= DowncountToCycles(ppc_state.downcount) - static_cast<int>(cycles);
DowncountToCycles(PowerPC::ppcState.downcount) - static_cast<int>(cycles); ppc_state.downcount = CyclesToDowncount(static_cast<int>(cycles));
PowerPC::ppcState.downcount = CyclesToDowncount(static_cast<int>(cycles));
} }
} }
@@ -299,11 +303,12 @@ void CoreTimingManager::MoveEvents()
void CoreTimingManager::Advance() void CoreTimingManager::Advance()
{ {
auto& system = Core::System::GetInstance(); auto& system = m_system;
auto& ppc_state = m_system.GetPPCState();
MoveEvents(); 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_globals.global_timer += cyclesExecuted;
m_last_oc_factor = m_config_oc_factor; m_last_oc_factor = m_config_oc_factor;
m_globals.last_OC_factor_inverted = m_config_oc_inv_factor; m_globals.last_OC_factor_inverted = m_config_oc_inv_factor;
@@ -330,7 +335,7 @@ void CoreTimingManager::Advance()
std::min<s64>(m_event_queue.front().time - m_globals.global_timer, MAX_SLICE_LENGTH)); 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. // Check for any external exceptions.
// It's important to do this after processing events otherwise any exceptions will be delayed // It's important to do this after processing events otherwise any exceptions will be delayed
@@ -438,18 +443,20 @@ void CoreTimingManager::AdjustEventQueueTimes(u32 new_ppc_clock, u32 old_ppc_clo
void CoreTimingManager::Idle() void CoreTimingManager::Idle()
{ {
auto& system = m_system;
auto& ppc_state = m_system.GetPPCState();
if (m_config_sync_on_skip_idle) if (m_config_sync_on_skip_idle)
{ {
// When the FIFO is processing data we must not advance because in this way // 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 // the VI will be desynchronized. So, We are waiting until the FIFO finish and
// while we process only the events required by the FIFO. // while we process only the events required by the FIFO.
auto& system = Core::System::GetInstance();
system.GetFifo().FlushGpu(system); system.GetFifo().FlushGpu(system);
} }
PowerPC::UpdatePerformanceMonitor(PowerPC::ppcState.downcount, 0, 0); PowerPC::UpdatePerformanceMonitor(ppc_state.downcount, 0, 0, ppc_state);
m_idled_cycles += DowncountToCycles(PowerPC::ppcState.downcount); m_idled_cycles += DowncountToCycles(ppc_state.downcount);
PowerPC::ppcState.downcount = 0; ppc_state.downcount = 0;
} }
std::string CoreTimingManager::GetScheduledEventsSummary() const std::string CoreTimingManager::GetScheduledEventsSummary() const

View File

@@ -75,6 +75,8 @@ void GlobalIdle();
class CoreTimingManager class CoreTimingManager
{ {
public: public:
explicit CoreTimingManager(Core::System& system);
// CoreTiming begins at the boundary of timing slice -1. An initial call to Advance() is // 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. // required to end slice -1 and start slice 0 before the first cycle of code is executed.
void Init(); void Init();
@@ -151,6 +153,8 @@ public:
private: private:
Globals m_globals; Globals m_globals;
Core::System& m_system;
// unordered_map stores each element separately as a linked list node so pointers to elements // unordered_map stores each element separately as a linked list node so pointers to elements
// remain stable regardless of rehashes/resizing. // remain stable regardless of rehashes/resizing.
std::unordered_map<std::string, EventType> m_event_types; std::unordered_map<std::string, EventType> m_event_types;

View File

@@ -16,6 +16,7 @@
#include "Core/PowerPC/MMU.h" #include "Core/PowerPC/MMU.h"
#include "Core/PowerPC/PPCSymbolDB.h" #include "Core/PowerPC/PPCSymbolDB.h"
#include "Core/PowerPC/PowerPC.h" #include "Core/PowerPC/PowerPC.h"
#include "Core/System.h"
namespace Dolphin_Debugger namespace Dolphin_Debugger
{ {
@@ -43,11 +44,13 @@ static bool IsStackBottom(u32 addr)
return !addr || !PowerPC::HostIsRAMAddress(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 // Walk the stack chain
for (int count = 0; !IsStackBottom(addr + 4) && (count++ < 20); ++count) for (int count = 0; !IsStackBottom(addr + 4) && (count++ < 20); ++count)
@@ -66,12 +69,14 @@ static void WalkTheStack(const std::function<void(u32)>& stack_step)
// Returns callstack "formatted for debugging" - meaning that it // Returns callstack "formatted for debugging" - meaning that it
// includes LR as the last item, and all items are the last step, // includes LR as the last item, and all items are the last step,
// instead of "pointing ahead" // 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; return false;
if (LR == 0) if (LR(ppc_state) == 0)
{ {
CallstackEntry entry; CallstackEntry entry;
entry.Name = "(error: LR=0)"; entry.Name = "(error: LR=0)";
@@ -81,11 +86,12 @@ bool GetCallstack(std::vector<CallstackEntry>& output)
} }
CallstackEntry entry; CallstackEntry entry;
entry.Name = fmt::format(" * {} [ LR = {:08x} ]\n", g_symbolDB.GetDescription(LR), LR - 4); entry.Name = fmt::format(" * {} [ LR = {:08x} ]\n", g_symbolDB.GetDescription(LR(ppc_state)),
entry.vAddress = LR - 4; LR(ppc_state) - 4);
entry.vAddress = LR(ppc_state) - 4;
output.push_back(entry); 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); std::string func_desc = g_symbolDB.GetDescription(func_addr);
if (func_desc.empty() || func_desc == "Invalid") if (func_desc.empty() || func_desc == "Invalid")
func_desc = "(unknown)"; func_desc = "(unknown)";
@@ -97,21 +103,24 @@ bool GetCallstack(std::vector<CallstackEntry>& output)
return true; 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();
if (LR == 0) GENERIC_LOG_FMT(type, level, "== STACK TRACE - SP = {:08x} ==", ppc_state.gpr[1]);
if (LR(ppc_state) == 0)
{ {
GENERIC_LOG_FMT(type, level, " LR = 0 - this is bad"); 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); std::string func_desc = g_symbolDB.GetDescription(func_addr);
if (func_desc.empty() || func_desc == "Invalid") if (func_desc.empty() || func_desc == "Invalid")
func_desc = "(unknown)"; func_desc = "(unknown)";

View File

@@ -10,6 +10,11 @@
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Common/Logging/Log.h" #include "Common/Logging/Log.h"
namespace Core
{
class System;
}
namespace Dolphin_Debugger namespace Dolphin_Debugger
{ {
struct CallstackEntry struct CallstackEntry
@@ -18,8 +23,8 @@ struct CallstackEntry
u32 vAddress = 0; u32 vAddress = 0;
}; };
bool GetCallstack(std::vector<CallstackEntry>& output); bool GetCallstack(Core::System& system, std::vector<CallstackEntry>& output);
void PrintCallstack(Common::Log::LogType type, Common::Log::LogLevel level); 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, void PrintDataBuffer(Common::Log::LogType type, const u8* data, size_t size,
std::string_view title); std::string_view title);
void AddAutoBreakpoints(); void AddAutoBreakpoints();

View File

@@ -23,6 +23,7 @@
#include "Core/PowerPC/MMU.h" #include "Core/PowerPC/MMU.h"
#include "Core/PowerPC/PPCSymbolDB.h" #include "Core/PowerPC/PPCSymbolDB.h"
#include "Core/PowerPC/PowerPC.h" #include "Core/PowerPC/PowerPC.h"
#include "Core/System.h"
void ApplyMemoryPatch(Common::Debug::MemoryPatch& patch, bool store_existing_value) void ApplyMemoryPatch(Common::Debug::MemoryPatch& patch, bool store_existing_value)
{ {
@@ -81,7 +82,10 @@ void PPCPatches::UnPatch(std::size_t index)
PatchEngine::RemoveMemoryPatch(index); PatchEngine::RemoveMemoryPatch(index);
} }
PPCDebugInterface::PPCDebugInterface() = default; PPCDebugInterface::PPCDebugInterface(Core::System& system) : m_system(system)
{
}
PPCDebugInterface::~PPCDebugInterface() = default; PPCDebugInterface::~PPCDebugInterface() = default;
std::size_t PPCDebugInterface::SetWatch(u32 address, std::string name) std::size_t PPCDebugInterface::SetWatch(u32 address, std::string name)
@@ -449,7 +453,7 @@ PPCDebugInterface::GetMemoryAddressFromInstruction(const std::string& instructio
if (is_reg == offset_match[0]) if (is_reg == offset_match[0])
{ {
const int register_index = std::stoi(offset_match.substr(1), nullptr, 10); 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 else
{ {
@@ -468,7 +472,7 @@ PPCDebugInterface::GetMemoryAddressFromInstruction(const std::string& instructio
else else
i = std::stoi(register_match, nullptr, 10); 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()) if (!match.str(1).empty())
return base_address - offset; return base_address - offset;
@@ -478,12 +482,12 @@ PPCDebugInterface::GetMemoryAddressFromInstruction(const std::string& instructio
u32 PPCDebugInterface::GetPC() const u32 PPCDebugInterface::GetPC() const
{ {
return PowerPC::ppcState.pc; return m_system.GetPPCState().pc;
} }
void PPCDebugInterface::SetPC(u32 address) void PPCDebugInterface::SetPC(u32 address)
{ {
PowerPC::ppcState.pc = address; m_system.GetPPCState().pc = address;
} }
void PPCDebugInterface::RunToBreakpoint() void PPCDebugInterface::RunToBreakpoint()

View File

@@ -12,6 +12,11 @@
#include "Common/DebugInterface.h" #include "Common/DebugInterface.h"
#include "Core/NetworkCaptureLogger.h" #include "Core/NetworkCaptureLogger.h"
namespace Core
{
class System;
}
void ApplyMemoryPatch(Common::Debug::MemoryPatch& patch, bool store_existing_value = true); void ApplyMemoryPatch(Common::Debug::MemoryPatch& patch, bool store_existing_value = true);
class PPCPatches final : public Common::Debug::MemoryPatches class PPCPatches final : public Common::Debug::MemoryPatches
@@ -29,7 +34,7 @@ private:
class PPCDebugInterface final : public Common::DebugInterface class PPCDebugInterface final : public Common::DebugInterface
{ {
public: public:
PPCDebugInterface(); explicit PPCDebugInterface(Core::System& system);
~PPCDebugInterface() override; ~PPCDebugInterface() override;
// Watches // Watches
@@ -102,4 +107,5 @@ private:
Common::Debug::Watches m_watches; Common::Debug::Watches m_watches;
PPCPatches m_patches; PPCPatches m_patches;
std::shared_ptr<Core::NetworkCaptureLogger> m_network_logger; std::shared_ptr<Core::NetworkCaptureLogger> m_network_logger;
Core::System& m_system;
}; };

View File

@@ -514,6 +514,7 @@ void FifoPlayer::WriteFifo(const u8* data, u32 start, u32 end)
auto& system = Core::System::GetInstance(); auto& system = Core::System::GetInstance();
auto& core_timing = system.GetCoreTiming(); auto& core_timing = system.GetCoreTiming();
auto& gpfifo = system.GetGPFifo(); auto& gpfifo = system.GetGPFifo();
auto& ppc_state = system.GetPPCState();
// Write up to 256 bytes at a time // Write up to 256 bytes at a time
while (written < end) while (written < end)
@@ -528,8 +529,8 @@ void FifoPlayer::WriteFifo(const u8* data, u32 start, u32 end)
u32 burstEnd = std::min(written + 255, lastBurstEnd); u32 burstEnd = std::min(written + 255, lastBurstEnd);
std::copy(data + written, data + burstEnd, PowerPC::ppcState.gather_pipe_ptr); std::copy(data + written, data + burstEnd, ppc_state.gather_pipe_ptr);
PowerPC::ppcState.gather_pipe_ptr += burstEnd - written; ppc_state.gather_pipe_ptr += burstEnd - written;
written = burstEnd; written = burstEnd;
gpfifo.Write8(data[written++]); gpfifo.Write8(data[written++]);
@@ -539,7 +540,7 @@ void FifoPlayer::WriteFifo(const u8* data, u32 start, u32 end)
u32 cyclesUsed = elapsedCycles - m_ElapsedCycles; u32 cyclesUsed = elapsedCycles - m_ElapsedCycles;
m_ElapsedCycles = elapsedCycles; m_ElapsedCycles = elapsedCycles;
PowerPC::ppcState.downcount -= cyclesUsed; ppc_state.downcount -= cyclesUsed;
core_timing.Advance(); core_timing.Advance();
} }
} }
@@ -629,16 +630,19 @@ void FifoPlayer::ClearEfb()
void FifoPlayer::LoadMemory() void FifoPlayer::LoadMemory()
{ {
auto& system = Core::System::GetInstance();
auto& ppc_state = system.GetPPCState();
UReg_MSR newMSR; UReg_MSR newMSR;
newMSR.DR = 1; newMSR.DR = 1;
newMSR.IR = 1; newMSR.IR = 1;
MSR.Hex = newMSR.Hex; ppc_state.msr.Hex = newMSR.Hex;
PowerPC::ppcState.spr[SPR_IBAT0U] = 0x80001fff; ppc_state.spr[SPR_IBAT0U] = 0x80001fff;
PowerPC::ppcState.spr[SPR_IBAT0L] = 0x00000002; ppc_state.spr[SPR_IBAT0L] = 0x00000002;
PowerPC::ppcState.spr[SPR_DBAT0U] = 0x80001fff; ppc_state.spr[SPR_DBAT0U] = 0x80001fff;
PowerPC::ppcState.spr[SPR_DBAT0L] = 0x00000002; ppc_state.spr[SPR_DBAT0L] = 0x00000002;
PowerPC::ppcState.spr[SPR_DBAT1U] = 0xc0001fff; ppc_state.spr[SPR_DBAT1U] = 0xc0001fff;
PowerPC::ppcState.spr[SPR_DBAT1L] = 0x0000002a; ppc_state.spr[SPR_DBAT1L] = 0x0000002a;
PowerPC::DBATUpdated(); PowerPC::DBATUpdated();
PowerPC::IBATUpdated(); PowerPC::IBATUpdated();

View File

@@ -19,6 +19,7 @@
#include "Core/ConfigManager.h" #include "Core/ConfigManager.h"
#include "Core/PowerPC/MMU.h" #include "Core/PowerPC/MMU.h"
#include "Core/PowerPC/PowerPC.h" #include "Core/PowerPC/PowerPC.h"
#include "Core/System.h"
namespace Gecko namespace Gecko
{ {
@@ -204,10 +205,13 @@ static Installation InstallCodeHandlerLocked()
// Turn on codes // Turn on codes
PowerPC::HostWrite_U8(1, INSTALLER_BASE_ADDRESS + 7); 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 // Invalidate the icache and any asm codes
for (unsigned int j = 0; j < (INSTALLER_END_ADDRESS - INSTALLER_BASE_ADDRESS); j += 32) 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; return Installation::Installed;
} }
@@ -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. // 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 // 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] // 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 // 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. // Zone, the LR, PC (return address) and the volatile floating point registers.
// Build a function call stack frame. // Build a function call stack frame.
u32 SFP = GPR(1); // Stack Frame Pointer u32 SFP = ppc_state.gpr[1]; // Stack Frame Pointer
GPR(1) -= 256; // Stack's Red Zone ppc_state.gpr[1] -= 256; // Stack's Red Zone
GPR(1) -= 16 + 2 * 14 * sizeof(u64); // Our stack frame (HLE_Misc::GeckoReturnTrampoline) ppc_state.gpr[1] -= 16 + 2 * 14 * sizeof(u64); // Our stack frame
GPR(1) -= 8; // Fake stack frame for codehandler // (HLE_Misc::GeckoReturnTrampoline)
GPR(1) &= 0xFFFFFFF0; // Align stack to 16bytes ppc_state.gpr[1] -= 8; // Fake stack frame for codehandler
u32 SP = GPR(1); // Stack Pointer ppc_state.gpr[1] &= 0xFFFFFFF0; // Align stack to 16bytes
u32 SP = ppc_state.gpr[1]; // Stack Pointer
PowerPC::HostWrite_U32(SP + 8, SP); PowerPC::HostWrite_U32(SP + 8, SP);
// SP + 4 is reserved for the codehandler to save LR to the stack. // 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(SFP, SP + 8); // Real stack frame
PowerPC::HostWrite_U32(PC, SP + 12); PowerPC::HostWrite_U32(ppc_state.pc, SP + 12);
PowerPC::HostWrite_U32(LR, SP + 16); PowerPC::HostWrite_U32(LR(ppc_state), SP + 16);
PowerPC::HostWrite_U32(PowerPC::ppcState.cr.Get(), SP + 20); PowerPC::HostWrite_U32(ppc_state.cr.Get(), SP + 20);
// Registers FPR0->13 are volatile // Registers FPR0->13 are volatile
for (int i = 0; i < 14; ++i) for (int i = 0; i < 14; ++i)
{ {
PowerPC::HostWrite_U64(rPS(i).PS0AsU64(), SP + 24 + 2 * i * sizeof(u64)); PowerPC::HostWrite_U64(ppc_state.ps[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].PS1AsU64(), SP + 24 + (2 * i + 1) * sizeof(u64));
} }
DEBUG_LOG_FMT(ACTIONREPLAY, DEBUG_LOG_FMT(ACTIONREPLAY,
"GeckoCodes: Initiating phantom branch-and-link. " "GeckoCodes: Initiating phantom branch-and-link. "
"PC = {:#010x}, SP = {:#010x}, SFP = {:#010x}", "PC = {:#010x}, SP = {:#010x}, SFP = {:#010x}",
PC, SP, SFP); ppc_state.pc, SP, SFP);
LR = HLE_TRAMPOLINE_ADDRESS; LR(ppc_state) = HLE_TRAMPOLINE_ADDRESS;
PC = NPC = ENTRY_POINT; ppc_state.pc = ppc_state.npc = ENTRY_POINT;
} }
} // namespace Gecko } // namespace Gecko

View File

@@ -63,20 +63,21 @@ constexpr std::array<Hook, 23> os_patches{{
}}; }};
// clang-format on // 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) for (u32 i = 1; i < os_patches.size(); ++i)
{ {
if (os_patches[i].name == func_name) if (os_patches[i].name == func_name)
{ {
s_hooked_addresses[addr] = i; s_hooked_addresses[addr] = i;
PowerPC::ppcState.iCache.Invalidate(addr); ppc_state.iCache.Invalidate(addr);
return; return;
} }
} }
} }
void PatchFixedFunctions() void PatchFixedFunctions(Core::System& system)
{ {
// MIOS puts patch data in low MEM1 (0x1800-0x3000) for its own use. // 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 // Overwriting data in this range can cause the IPL to crash when launching games
@@ -90,28 +91,29 @@ void PatchFixedFunctions()
// handler // handler
if (!Config::Get(Config::MAIN_ENABLE_CHEATS)) if (!Config::Get(Config::MAIN_ENABLE_CHEATS))
{ {
Patch(0x80001800, "HBReload"); Patch(system, 0x80001800, "HBReload");
auto& system = Core::System::GetInstance();
auto& memory = system.GetMemory(); auto& memory = system.GetMemory();
memory.CopyToEmu(0x00001804, "STUBHAXX", 8); memory.CopyToEmu(0x00001804, "STUBHAXX", 8);
} }
// Not part of the binary itself, but either we or Gecko OS might insert // Not part of the binary itself, but either we or Gecko OS might insert
// this, and it doesn't clear the icache properly. // 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 // 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. // 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 // Remove all hooks that aren't fixed address hooks
for (auto i = s_hooked_addresses.begin(); i != s_hooked_addresses.end();) for (auto i = s_hooked_addresses.begin(); i != s_hooked_addresses.end();)
{ {
if (os_patches[i->second].flags != HookFlag::Fixed) 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); i = s_hooked_addresses.erase(i);
} }
else else
@@ -131,7 +133,7 @@ void PatchFunctions()
for (u32 addr = symbol->address; addr < symbol->address + symbol->size; addr += 4) for (u32 addr = symbol->address; addr < symbol->address + symbol->size; addr += 4)
{ {
s_hooked_addresses[addr] = i; 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); INFO_LOG_FMT(OSHLE, "Patching {} {:08x}", os_patches[i].name, symbol->address);
} }
@@ -143,11 +145,11 @@ void Clear()
s_hooked_addresses.clear(); s_hooked_addresses.clear();
} }
void Reload() void Reload(Core::System& system)
{ {
Clear(); Clear();
PatchFixedFunctions(); PatchFixedFunctions(system);
PatchFunctions(); PatchFunctions(system);
} }
void Execute(u32 current_pc, u32 hook_index) void Execute(u32 current_pc, u32 hook_index)
@@ -196,13 +198,15 @@ bool IsEnabled(HookFlag flag)
PowerPC::GetMode() == PowerPC::CoreMode::Interpreter; 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 auto patch = std::find_if(std::begin(os_patches), std::end(os_patches),
[&](const Hook& p) { return patch_name == p.name; }); [&](const Hook& p) { return patch_name == p.name; });
if (patch == std::end(os_patches)) if (patch == std::end(os_patches))
return 0; return 0;
auto& ppc_state = system.GetPPCState();
if (patch->flags == HookFlag::Fixed) if (patch->flags == HookFlag::Fixed)
{ {
const u32 patch_idx = static_cast<u32>(std::distance(os_patches.begin(), patch)); const u32 patch_idx = static_cast<u32>(std::distance(os_patches.begin(), patch));
@@ -213,7 +217,7 @@ u32 UnPatch(std::string_view patch_name)
if (i->second == patch_idx) if (i->second == patch_idx)
{ {
addr = i->first; addr = i->first;
PowerPC::ppcState.iCache.Invalidate(i->first); ppc_state.iCache.Invalidate(i->first);
i = s_hooked_addresses.erase(i); i = s_hooked_addresses.erase(i);
} }
else else
@@ -231,7 +235,7 @@ u32 UnPatch(std::string_view patch_name)
for (u32 addr = symbol->address; addr < symbol->address + symbol->size; addr += 4) for (u32 addr = symbol->address; addr < symbol->address + symbol->size; addr += 4)
{ {
s_hooked_addresses.erase(addr); s_hooked_addresses.erase(addr);
PowerPC::ppcState.iCache.Invalidate(addr); ppc_state.iCache.Invalidate(addr);
} }
return symbol->address; return symbol->address;
} }
@@ -239,8 +243,10 @@ u32 UnPatch(std::string_view patch_name)
return 0; 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; u32 count = 0;
auto i = s_hooked_addresses.lower_bound(start_addr); auto i = s_hooked_addresses.lower_bound(start_addr);
@@ -248,7 +254,7 @@ u32 UnpatchRange(u32 start_addr, u32 end_addr)
{ {
INFO_LOG_FMT(OSHLE, "Unpatch HLE hooks [{:08x};{:08x}): {} at {:08x}", start_addr, end_addr, INFO_LOG_FMT(OSHLE, "Unpatch HLE hooks [{:08x};{:08x}): {} at {:08x}", start_addr, end_addr,
os_patches[i->second].name, i->first); 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); i = s_hooked_addresses.erase(i);
count += 1; count += 1;
} }

View File

@@ -7,6 +7,11 @@
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
namespace Core
{
class System;
}
namespace HLE namespace HLE
{ {
using HookFunction = void (*)(); using HookFunction = void (*)();
@@ -33,14 +38,14 @@ struct Hook
HookFlag flags; HookFlag flags;
}; };
void PatchFixedFunctions(); void PatchFixedFunctions(Core::System& system);
void PatchFunctions(); void PatchFunctions(Core::System& system);
void Clear(); void Clear();
void Reload(); void Reload(Core::System& system);
void Patch(u32 pc, std::string_view func_name); void Patch(Core::System& system, u32 pc, std::string_view func_name);
u32 UnPatch(std::string_view patch_name); u32 UnPatch(Core::System& system, std::string_view patch_name);
u32 UnpatchRange(u32 start_addr, u32 end_addr); u32 UnpatchRange(Core::System& system, u32 start_addr, u32 end_addr);
void Execute(u32 current_pc, u32 hook_index); void Execute(u32 current_pc, u32 hook_index);
// Returns the HLE hook index of the address // Returns the HLE hook index of the address

View File

@@ -10,6 +10,7 @@
#include "Core/Host.h" #include "Core/Host.h"
#include "Core/PowerPC/MMU.h" #include "Core/PowerPC/MMU.h"
#include "Core/PowerPC/PowerPC.h" #include "Core/PowerPC/PowerPC.h"
#include "Core/System.h"
namespace HLE_Misc namespace HLE_Misc
{ {
@@ -17,7 +18,9 @@ namespace HLE_Misc
// According to the PPC ABI, the return value is always in r3. // According to the PPC ABI, the return value is always in r3.
void UnimplementedFunction() void UnimplementedFunction()
{ {
NPC = LR; auto& system = Core::System::GetInstance();
auto& ppc_state = system.GetPPCState();
ppc_state.npc = LR(ppc_state);
} }
void HBReload() void HBReload()
@@ -29,6 +32,9 @@ void HBReload()
void GeckoCodeHandlerICacheFlush() void GeckoCodeHandlerICacheFlush()
{ {
auto& system = Core::System::GetInstance();
auto& ppc_state = system.GetPPCState();
// Work around the codehandler not properly invalidating the icache, but // Work around the codehandler not properly invalidating the icache, but
// only the first few frames. // only the first few frames.
// (Project M uses a conditional to only apply patches after something has // (Project M uses a conditional to only apply patches after something has
@@ -46,7 +52,7 @@ void GeckoCodeHandlerICacheFlush()
} }
PowerPC::HostWrite_U32(gch_gameid + 1, Gecko::INSTALLER_BASE_ADDRESS); 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 // Because Dolphin messes around with the CPU state instead of patching the game binary, we
@@ -55,16 +61,19 @@ void GeckoCodeHandlerICacheFlush()
// and PC before the magic, invisible BL instruction happened. // and PC before the magic, invisible BL instruction happened.
void GeckoReturnTrampoline() void GeckoReturnTrampoline()
{ {
auto& system = Core::System::GetInstance();
auto& ppc_state = system.GetPPCState();
// Stack frame is built in GeckoCode.cpp, Gecko::RunCodeHandler. // Stack frame is built in GeckoCode.cpp, Gecko::RunCodeHandler.
u32 SP = GPR(1); u32 SP = ppc_state.gpr[1];
GPR(1) = PowerPC::HostRead_U32(SP + 8); ppc_state.gpr[1] = PowerPC::HostRead_U32(SP + 8);
NPC = PowerPC::HostRead_U32(SP + 12); ppc_state.npc = PowerPC::HostRead_U32(SP + 12);
LR = PowerPC::HostRead_U32(SP + 16); LR(ppc_state) = PowerPC::HostRead_U32(SP + 16);
PowerPC::ppcState.cr.Set(PowerPC::HostRead_U32(SP + 20)); ppc_state.cr.Set(PowerPC::HostRead_U32(SP + 20));
for (int i = 0; i < 14; ++i) for (int i = 0; i < 14; ++i)
{ {
rPS(i).SetBoth(PowerPC::HostRead_U64(SP + 24 + 2 * i * 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))); PowerPC::HostRead_U64(SP + 24 + (2 * i + 1) * sizeof(u64)));
} }
} }
} // namespace HLE_Misc } // namespace HLE_Misc

View File

@@ -13,6 +13,7 @@
#include "Core/HLE/HLE_VarArgs.h" #include "Core/HLE/HLE_VarArgs.h"
#include "Core/PowerPC/MMU.h" #include "Core/PowerPC/MMU.h"
#include "Core/PowerPC/PowerPC.h" #include "Core/PowerPC/PowerPC.h"
#include "Core/System.h"
namespace HLE_OS namespace HLE_OS
{ {
@@ -22,7 +23,7 @@ enum class ParameterType : bool
VariableArgumentList = true VariableArgumentList = true
}; };
std::string GetStringVA(u32 str_reg = 3, std::string GetStringVA(Core::System& system, u32 str_reg = 3,
ParameterType parameter_type = ParameterType::ParameterList); ParameterType parameter_type = ParameterType::ParameterList);
void HLE_GeneralDebugPrint(ParameterType parameter_type); void HLE_GeneralDebugPrint(ParameterType parameter_type);
void HLE_LogDPrint(ParameterType parameter_type); void HLE_LogDPrint(ParameterType parameter_type);
@@ -30,56 +31,64 @@ void HLE_LogFPrint(ParameterType parameter_type);
void HLE_OSPanic() void HLE_OSPanic()
{ {
std::string error = GetStringVA(); auto& system = Core::System::GetInstance();
std::string msg = GetStringVA(5); auto& ppc_state = system.GetPPCState();
std::string error = GetStringVA(system);
std::string msg = GetStringVA(system, 5);
StringPopBackIf(&error, '\n'); StringPopBackIf(&error, '\n');
StringPopBackIf(&msg, '\n'); StringPopBackIf(&msg, '\n');
PanicAlertFmt("OSPanic: {}: {}", error, msg); 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. // Generalized function for printing formatted string.
void HLE_GeneralDebugPrint(ParameterType parameter_type) void HLE_GeneralDebugPrint(ParameterType parameter_type)
{ {
auto& system = Core::System::GetInstance();
auto& ppc_state = system.GetPPCState();
std::string report_message; std::string report_message;
// Is gpr3 pointing to a pointer (including nullptr) rather than an ASCII string // Is gpr3 pointing to a pointer (including nullptr) rather than an ASCII string
if (PowerPC::HostIsRAMAddress(GPR(3)) && if (PowerPC::HostIsRAMAddress(ppc_state.gpr[3]) &&
(PowerPC::HostIsRAMAddress(PowerPC::HostRead_U32(GPR(3))) || (PowerPC::HostIsRAMAddress(PowerPC::HostRead_U32(ppc_state.gpr[3])) ||
PowerPC::HostRead_U32(GPR(3)) == 0)) 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, ...); // ___blank(void* this, const char* fmt, ...);
report_message = GetStringVA(4, parameter_type); report_message = GetStringVA(system, 4, parameter_type);
} }
else else
{ {
// ___blank(void* this, int log_type, const char* fmt, ...); // ___blank(void* this, int log_type, const char* fmt, ...);
report_message = GetStringVA(5, parameter_type); report_message = GetStringVA(system, 5, parameter_type);
} }
} }
else else
{ {
if (PowerPC::HostIsRAMAddress(GPR(3))) if (PowerPC::HostIsRAMAddress(ppc_state.gpr[3]))
{ {
// ___blank(const char* fmt, ...); // ___blank(const char* fmt, ...);
report_message = GetStringVA(3, parameter_type); report_message = GetStringVA(system, 3, parameter_type);
} }
else else
{ {
// ___blank(int log_type, const char* fmt, ...); // ___blank(int log_type, const char* fmt, ...);
report_message = GetStringVA(4, parameter_type); report_message = GetStringVA(system, 4, parameter_type);
} }
} }
StringPopBackIf(&report_message, '\n'); 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. // Generalized function for printing formatted string using parameter list.
@@ -97,10 +106,13 @@ void HLE_GeneralDebugVPrint()
// __write_console(int fd, const void* buffer, const u32* size) // __write_console(int fd, const void* buffer, const u32* size)
void HLE_write_console() void HLE_write_console()
{ {
std::string report_message = GetStringVA(4); auto& system = Core::System::GetInstance();
if (PowerPC::HostIsRAMAddress(GPR(5))) 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()) if (size > report_message.size())
WARN_LOG_FMT(OSREPORT_HLE, "__write_console uses an invalid size of {:#010x}", size); WARN_LOG_FMT(OSREPORT_HLE, "__write_console uses an invalid size of {:#010x}", size);
else if (size == 0) else if (size == 0)
@@ -115,18 +127,23 @@ void HLE_write_console()
StringPopBackIf(&report_message, '\n'); 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) // Log (v)dprintf message if fd is 1 (stdout) or 2 (stderr)
void HLE_LogDPrint(ParameterType parameter_type) 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; return;
std::string report_message = GetStringVA(4, parameter_type); std::string report_message = GetStringVA(system, 4, parameter_type);
StringPopBackIf(&report_message, '\n'); 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 // Log dprintf message
@@ -146,25 +163,30 @@ void HLE_LogVDPrint()
// Log (v)fprintf message if FILE is stdout or stderr // Log (v)fprintf message if FILE is stdout or stderr
void HLE_LogFPrint(ParameterType parameter_type) void HLE_LogFPrint(ParameterType parameter_type)
{ {
auto& system = Core::System::GetInstance();
auto& ppc_state = system.GetPPCState();
// The structure FILE is implementation defined. // The structure FILE is implementation defined.
// Both libogc and Dolphin SDK seem to store the fd at the same address. // Both libogc and Dolphin SDK seem to store the fd at the same address.
int fd = -1; 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. // 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) if (fd != 1 && fd != 2)
{ {
// On RVL SDK it seems stored at FILE+0x2. // 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) if (fd != 1 && fd != 2)
return; return;
std::string report_message = GetStringVA(4, parameter_type); std::string report_message = GetStringVA(system, 4, parameter_type);
StringPopBackIf(&report_message, '\n'); 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 // Log fprintf message
@@ -181,14 +203,17 @@ void HLE_LogVFPrint()
HLE_LogFPrint(ParameterType::VariableArgumentList); 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 ArgumentBuffer;
std::string result; std::string result;
std::string string = PowerPC::HostGetString(GPR(str_reg)); std::string string = PowerPC::HostGetString(ppc_state.gpr[str_reg]);
auto ap = parameter_type == ParameterType::VariableArgumentList ? auto ap =
std::make_unique<HLE::SystemVABI::VAListStruct>(GPR(str_reg + 1)) : parameter_type == ParameterType::VariableArgumentList ?
std::make_unique<HLE::SystemVABI::VAList>(GPR(1) + 0x8, str_reg + 1); 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++) for (size_t i = 0; i < string.size(); i++)
{ {

View File

@@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "Core/HLE/HLE_VarArgs.h" #include "Core/HLE/HLE_VarArgs.h"
#include "Core/System.h"
#include "Common/Logging/Log.h" #include "Common/Logging/Log.h"
@@ -9,18 +10,19 @@ HLE::SystemVABI::VAList::~VAList() = default;
u32 HLE::SystemVABI::VAList::GetGPR(u32 gpr) const 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 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) HLE::SystemVABI::VAListStruct::VAListStruct(Core::System& system, u32 address)
: VAList(0), m_va_list{PowerPC::HostRead_U8(address), PowerPC::HostRead_U8(address + 1), : 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)}, PowerPC::HostRead_U32(address + 4),
m_address(address), m_has_fpr_area(PowerPC::ppcState.cr.GetBit(6) == 1) 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_stack = m_va_list.overflow_arg_area;
m_gpr += m_va_list.gpr; m_gpr += m_va_list.gpr;

View File

@@ -11,6 +11,11 @@
#include <type_traits> #include <type_traits>
namespace Core
{
class System;
}
namespace HLE::SystemVABI namespace HLE::SystemVABI
{ {
// SFINAE // SFINAE
@@ -32,8 +37,10 @@ constexpr bool IS_ARG_REAL = std::is_floating_point<T>();
class VAList class VAList
{ {
public: public:
explicit VAList(u32 stack, u32 gpr = 3, u32 fpr = 1, u32 gpr_max = 10, u32 fpr_max = 8) explicit VAList(Core::System& system, u32 stack, u32 gpr = 3, u32 fpr = 1, u32 gpr_max = 10,
: m_gpr(gpr), m_fpr(fpr), m_gpr_max(gpr_max), m_fpr_max(fpr_max), m_stack(stack) 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(); virtual ~VAList();
@@ -127,6 +134,7 @@ public:
} }
protected: protected:
Core::System& m_system;
u32 m_gpr = 3; u32 m_gpr = 3;
u32 m_fpr = 1; u32 m_fpr = 1;
const u32 m_gpr_max = 10; const u32 m_gpr_max = 10;
@@ -147,7 +155,7 @@ private:
class VAListStruct : public VAList class VAListStruct : public VAList
{ {
public: public:
explicit VAListStruct(u32 address); explicit VAListStruct(Core::System& system, u32 address);
~VAListStruct() = default; ~VAListStruct() = default;
private: private:

View File

@@ -173,16 +173,18 @@ void IncreaseSampleCount(const u32 amount)
if (!IsPlaying()) if (!IsPlaying())
return; 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; const u32 old_sample_counter = state.sample_counter + 1;
state.sample_counter += amount; state.sample_counter += amount;
if ((state.interrupt_timing - old_sample_counter) <= (state.sample_counter - old_sample_counter)) if ((state.interrupt_timing - old_sample_counter) <= (state.sample_counter - old_sample_counter))
{ {
DEBUG_LOG_FMT( DEBUG_LOG_FMT(AUDIO_INTERFACE,
AUDIO_INTERFACE, "GenerateAudioInterrupt {:08x}:{:08x} at PC {:08x} control.AIINTVLD={}", "GenerateAudioInterrupt {:08x}:{:08x} at PC {:08x} control.AIINTVLD={}",
state.sample_counter, state.interrupt_timing, PowerPC::ppcState.pc, state.control.AIINTVLD); state.sample_counter, state.interrupt_timing, system.GetPPCState().pc,
state.control.AIINTVLD);
GenerateAudioInterrupt(); GenerateAudioInterrupt();
} }
} }
@@ -382,7 +384,7 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
auto& core_timing = system.GetCoreTiming(); auto& core_timing = system.GetCoreTiming();
auto& state = system.GetAudioInterfaceState().GetData(); auto& state = system.GetAudioInterfaceState().GetData();
DEBUG_LOG_FMT(AUDIO_INTERFACE, "AI_INTERRUPT_TIMING={:08x} at PC: {:08x}", val, DEBUG_LOG_FMT(AUDIO_INTERFACE, "AI_INTERRUPT_TIMING={:08x} at PC: {:08x}", val,
PowerPC::ppcState.pc); system.GetPPCState().pc);
state.interrupt_timing = val; state.interrupt_timing = val;
core_timing.RemoveEvent(state.event_type_ai); core_timing.RemoveEvent(state.event_type_ai);
core_timing.ScheduleEvent(GetAIPeriod(), state.event_type_ai); core_timing.ScheduleEvent(GetAIPeriod(), state.event_type_ai);

View File

@@ -88,6 +88,8 @@ static void ExecutePendingJobs(std::unique_lock<std::mutex>& state_lock)
void Run() void Run()
{ {
auto& system = Core::System::GetInstance();
// Updating the host CPU's rounding mode must be done on the CPU thread. // 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. // We can't rely on PowerPC::Init doing it, since it's called from EmuThread.
PowerPC::RoundingModeUpdated(); PowerPC::RoundingModeUpdated();
@@ -111,7 +113,8 @@ void Run()
// If watchpoints are enabled, any instruction could be a breakpoint. // If watchpoints are enabled, any instruction could be a breakpoint.
if (PowerPC::GetMode() != PowerPC::CoreMode::Interpreter) 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; s_state = State::Stepping;
PowerPC::CoreMode old_mode = PowerPC::GetMode(); PowerPC::CoreMode old_mode = PowerPC::GetMode();

View File

@@ -69,7 +69,7 @@ const State* GetStatePtr();
// Locks the CPU Thread (waiting for it to become idle). // 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 // 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). // 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 == 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. // Return value for do_lock == false is whether the state was changed *to* State::Running or not.

View File

@@ -572,7 +572,8 @@ static void Do_ARAM_DMA()
{ {
// ARAM -> MRAM // ARAM -> MRAM
DEBUG_LOG_FMT(DSPINTERFACE, "DMA {:08x} bytes from ARAM {:08x} to MRAM {:08x} PC: {:08x}", 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) // Outgoing data from ARAM is mirrored every 64MB (verified on real HW)
state.aram_dma.ARAddr &= 0x3ffffff; state.aram_dma.ARAddr &= 0x3ffffff;
@@ -620,7 +621,8 @@ static void Do_ARAM_DMA()
{ {
// MRAM -> ARAM // MRAM -> ARAM
DEBUG_LOG_FMT(DSPINTERFACE, "DMA {:08x} bytes from MRAM {:08x} to ARAM {:08x} PC: {:08x}", 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) // Incoming data into ARAM is mirrored every 64MB (verified on real HW)
state.aram_dma.ARAddr &= 0x3ffffff; state.aram_dma.ARAddr &= 0x3ffffff;

View File

@@ -35,12 +35,12 @@ GPFifoManager::GPFifoManager(Core::System& system) : m_system(system)
size_t GPFifoManager::GetGatherPipeCount() 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) 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) void GPFifoManager::DoState(PointerWrap& p)
@@ -54,7 +54,7 @@ void GPFifoManager::DoState(PointerWrap& p)
void GPFifoManager::Init() void GPFifoManager::Init()
{ {
ResetGatherPipe(); 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)); memset(m_gather_pipe, 0, sizeof(m_gather_pipe));
} }
@@ -162,29 +162,33 @@ void GPFifoManager::Write64(const u64 value)
void GPFifoManager::FastWrite8(const u8 value) void GPFifoManager::FastWrite8(const u8 value)
{ {
*PowerPC::ppcState.gather_pipe_ptr = value; auto& ppc_state = m_system.GetPPCState();
PowerPC::ppcState.gather_pipe_ptr += sizeof(u8); *ppc_state.gather_pipe_ptr = value;
ppc_state.gather_pipe_ptr += sizeof(u8);
} }
void GPFifoManager::FastWrite16(u16 value) void GPFifoManager::FastWrite16(u16 value)
{ {
value = Common::swap16(value); value = Common::swap16(value);
std::memcpy(PowerPC::ppcState.gather_pipe_ptr, &value, sizeof(u16)); auto& ppc_state = m_system.GetPPCState();
PowerPC::ppcState.gather_pipe_ptr += sizeof(u16); std::memcpy(ppc_state.gather_pipe_ptr, &value, sizeof(u16));
ppc_state.gather_pipe_ptr += sizeof(u16);
} }
void GPFifoManager::FastWrite32(u32 value) void GPFifoManager::FastWrite32(u32 value)
{ {
value = Common::swap32(value); value = Common::swap32(value);
std::memcpy(PowerPC::ppcState.gather_pipe_ptr, &value, sizeof(u32)); auto& ppc_state = m_system.GetPPCState();
PowerPC::ppcState.gather_pipe_ptr += sizeof(u32); std::memcpy(ppc_state.gather_pipe_ptr, &value, sizeof(u32));
ppc_state.gather_pipe_ptr += sizeof(u32);
} }
void GPFifoManager::FastWrite64(u64 value) void GPFifoManager::FastWrite64(u64 value)
{ {
value = Common::swap64(value); value = Common::swap64(value);
std::memcpy(PowerPC::ppcState.gather_pipe_ptr, &value, sizeof(u64)); auto& ppc_state = m_system.GetPPCState();
PowerPC::ppcState.gather_pipe_ptr += sizeof(u64); std::memcpy(ppc_state.gather_pipe_ptr, &value, sizeof(u64));
ppc_state.gather_pipe_ptr += sizeof(u64);
} }
void UpdateGatherPipe(GPFifoManager& gpfifo) void UpdateGatherPipe(GPFifoManager& gpfifo)

View File

@@ -482,7 +482,9 @@ u8* MemoryManager::GetPointer(u32 address) const
return m_exram + (address & GetExRamMask()); 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; return nullptr;
} }

View File

@@ -65,14 +65,14 @@ void ProcessorInterfaceManager::RegisterMMIO(MMIO::Mapping* mmio, u32 base)
MMIO::ComplexWrite<u32>([](Core::System& system, u32, u32 val) { MMIO::ComplexWrite<u32>([](Core::System& system, u32, u32 val) {
auto& processor_interface = system.GetProcessorInterface(); auto& processor_interface = system.GetProcessorInterface();
processor_interface.m_interrupt_cause &= ~val; 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->Register(base | PI_INTERRUPT_MASK, MMIO::DirectRead<u32>(&m_interrupt_mask),
MMIO::ComplexWrite<u32>([](Core::System& system, u32, u32 val) { MMIO::ComplexWrite<u32>([](Core::System& system, u32, u32 val) {
auto& processor_interface = system.GetProcessorInterface(); auto& processor_interface = system.GetProcessorInterface();
processor_interface.m_interrupt_mask = val; 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), mmio->Register(base | PI_FIFO_BASE, MMIO::DirectRead<u32>(&m_fifo_cpu_base),
@@ -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) if ((m_interrupt_cause & m_interrupt_mask) != 0)
PowerPC::ppcState.Exceptions |= EXCEPTION_EXTERNAL_INT; ppc_state.Exceptions |= EXCEPTION_EXTERNAL_INT;
else else
PowerPC::ppcState.Exceptions &= ~EXCEPTION_EXTERNAL_INT; ppc_state.Exceptions &= ~EXCEPTION_EXTERNAL_INT;
} }
static const char* Debug_GetInterruptName(u32 cause_mask) static const char* Debug_GetInterruptName(u32 cause_mask)
@@ -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? 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 // 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) // if the interrupt cause is eliminated. that isn't done by software (afaik)
UpdateException(); UpdateException(Core::System::GetInstance());
} }
void ProcessorInterfaceManager::SetResetButton(bool set) void ProcessorInterfaceManager::SetResetButton(bool set)

View File

@@ -87,7 +87,7 @@ public:
private: private:
// Let the PPC know that an external exception is set/cleared // Let the PPC know that an external exception is set/cleared
void UpdateException(); void UpdateException(Core::System& system);
void SetResetButton(bool set); void SetResetButton(bool set);

View File

@@ -153,8 +153,9 @@ void VICallback(Core::System& system, u64 userdata, s64 cyclesLate)
void DecrementerCallback(Core::System& system, u64 userdata, s64 cyclesLate) void DecrementerCallback(Core::System& system, u64 userdata, s64 cyclesLate)
{ {
PowerPC::ppcState.spr[SPR_DEC] = 0xFFFFFFFF; auto& ppc_state = system.GetPPCState();
PowerPC::ppcState.Exceptions |= EXCEPTION_DECREMENTER; ppc_state.spr[SPR_DEC] = 0xFFFFFFFF;
ppc_state.Exceptions |= EXCEPTION_DECREMENTER;
} }
void PatchEngineCallback(Core::System& system, u64 userdata, s64 cycles_late) void PatchEngineCallback(Core::System& system, u64 userdata, s64 cycles_late)
@@ -192,8 +193,9 @@ void DecrementerSet()
{ {
auto& system = Core::System::GetInstance(); auto& system = Core::System::GetInstance();
auto& core_timing = system.GetCoreTiming(); 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); core_timing.RemoveEvent(et_Dec);
if ((decValue & 0x80000000) == 0) if ((decValue & 0x80000000) == 0)

View File

@@ -200,7 +200,7 @@ static void ResetAndPausePPC()
auto& memory = system.GetMemory(); auto& memory = system.GetMemory();
memory.Write_U32(0x48000000, 0x00000000); // b 0x0 memory.Write_U32(0x48000000, 0x00000000); // b 0x0
PowerPC::Reset(); PowerPC::Reset();
PC = 0; system.GetPPCState().pc = 0;
} }
static void ReleasePPC() static void ReleasePPC()
@@ -212,7 +212,7 @@ static void ReleasePPC()
// NAND titles start with address translation off at 0x3400 (via the PPC bootstub) // 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 // The state of other CPU registers (like the BAT registers) doesn't matter much
// because the realmode code at 0x3400 initializes everything itself anyway. // because the realmode code at 0x3400 initializes everything itself anyway.
PC = 0x3400; system.GetPPCState().pc = 0x3400;
} }
static void ReleasePPCAncast() static void ReleasePPCAncast()
@@ -223,7 +223,7 @@ static void ReleasePPCAncast()
// On a real console the Espresso verifies and decrypts the Ancast image, // On a real console the Espresso verifies and decrypts the Ancast image,
// then jumps to the decrypted ancast body. // then jumps to the decrypted ancast body.
// The Ancast loader already did this, so just jump to the decrypted 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) void RAMOverrideForIOSMemoryValues(MemorySetupType setup_type)

View File

@@ -72,14 +72,15 @@ bool Load()
if (g_symbolDB.LoadMap(File::GetUserPath(D_MAPS_IDX) + "mios-ipl.map")) if (g_symbolDB.LoadMap(File::GetUserPath(D_MAPS_IDX) + "mios-ipl.map"))
{ {
::HLE::Clear(); ::HLE::Clear();
::HLE::PatchFunctions(); ::HLE::PatchFunctions(system);
Host_NotifyMapLoaded(); Host_NotifyMapLoaded();
} }
auto& ppc_state = system.GetPPCState();
const PowerPC::CoreMode core_mode = PowerPC::GetMode(); const PowerPC::CoreMode core_mode = PowerPC::GetMode();
PowerPC::SetMode(PowerPC::CoreMode::Interpreter); PowerPC::SetMode(PowerPC::CoreMode::Interpreter);
MSR.Hex = 0; ppc_state.msr.Hex = 0;
PC = 0x3400; ppc_state.pc = 0x3400;
NOTICE_LOG_FMT(IOS, "Loaded MIOS and bootstrapped PPC."); NOTICE_LOG_FMT(IOS, "Loaded MIOS and bootstrapped PPC.");
// IOS writes 0 to 0x30f8 before bootstrapping the PPC. Once started, the IPL eventually writes // IOS writes 0 to 0x30f8 before bootstrapping the PPC. Once started, the IPL eventually writes

View File

@@ -33,6 +33,7 @@
#include "Core/GeckoCodeConfig.h" #include "Core/GeckoCodeConfig.h"
#include "Core/PowerPC/MMU.h" #include "Core/PowerPC/MMU.h"
#include "Core/PowerPC/PowerPC.h" #include "Core/PowerPC/PowerPC.h"
#include "Core/System.h"
namespace PatchEngine namespace PatchEngine
{ {
@@ -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. // We require at least 2 stack frames, if the stack is shallower than that then it won't work.
static bool IsStackSane() 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 // Check the stack pointer
u32 SP = GPR(1); u32 SP = ppc_state.gpr[1];
if (!PowerPC::HostIsRAMAddress(SP)) if (!PowerPC::HostIsRAMAddress(SP))
return false; return false;
@@ -311,16 +315,19 @@ void RemoveMemoryPatch(std::size_t index)
bool ApplyFramePatches() 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 // 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. // 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 // 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. // 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, DEBUG_LOG_FMT(ACTIONREPLAY,
"Need to retry later. CPU configuration is currently incorrect. PC = {:#010x}, " "Need to retry later. CPU configuration is currently incorrect. PC = {:#010x}, "
"MSR = {:#010x}", "MSR = {:#010x}",
PC, MSR.Hex); ppc_state.pc, ppc_state.msr.Hex);
return false; return false;
} }

View File

@@ -81,7 +81,7 @@ void CachedInterpreter::ExecuteOneBlock()
const u8* normal_entry = m_block_cache.Dispatch(); const u8* normal_entry = m_block_cache.Dispatch();
if (!normal_entry) if (!normal_entry)
{ {
Jit(PC); Jit(PowerPC::ppcState.pc);
return; return;
} }
@@ -136,35 +136,35 @@ void CachedInterpreter::SingleStep()
static void EndBlock(UGeckoInstruction data) static void EndBlock(UGeckoInstruction data)
{ {
PC = NPC; PowerPC::ppcState.pc = PowerPC::ppcState.npc;
PowerPC::ppcState.downcount -= data.hex; PowerPC::ppcState.downcount -= data.hex;
PowerPC::UpdatePerformanceMonitor(data.hex, 0, 0); PowerPC::UpdatePerformanceMonitor(data.hex, 0, 0, PowerPC::ppcState);
} }
static void UpdateNumLoadStoreInstructions(UGeckoInstruction data) static void UpdateNumLoadStoreInstructions(UGeckoInstruction data)
{ {
PowerPC::UpdatePerformanceMonitor(0, data.hex, 0); PowerPC::UpdatePerformanceMonitor(0, data.hex, 0, PowerPC::ppcState);
} }
static void UpdateNumFloatingPointInstructions(UGeckoInstruction data) static void UpdateNumFloatingPointInstructions(UGeckoInstruction data)
{ {
PowerPC::UpdatePerformanceMonitor(0, 0, data.hex); PowerPC::UpdatePerformanceMonitor(0, 0, data.hex, PowerPC::ppcState);
} }
static void WritePC(UGeckoInstruction data) static void WritePC(UGeckoInstruction data)
{ {
PC = data.hex; PowerPC::ppcState.pc = data.hex;
NPC = data.hex + 4; PowerPC::ppcState.npc = data.hex + 4;
} }
static void WriteBrokenBlockNPC(UGeckoInstruction data) static void WriteBrokenBlockNPC(UGeckoInstruction data)
{ {
NPC = data.hex; PowerPC::ppcState.npc = data.hex;
} }
static bool CheckFPU(u32 data) static bool CheckFPU(u32 data)
{ {
if (!MSR.FP) if (!PowerPC::ppcState.msr.FP)
{ {
PowerPC::ppcState.Exceptions |= EXCEPTION_FPU_UNAVAILABLE; PowerPC::ppcState.Exceptions |= EXCEPTION_FPU_UNAVAILABLE;
PowerPC::CheckExceptions(); PowerPC::CheckExceptions();
@@ -239,20 +239,21 @@ void CachedInterpreter::Jit(u32 address)
ClearCache(); 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) if (code_block.m_memory_exception)
{ {
// Address of instruction could not be translated // Address of instruction could not be translated
NPC = nextPC; PowerPC::ppcState.npc = nextPC;
PowerPC::ppcState.Exceptions |= EXCEPTION_ISI; PowerPC::ppcState.Exceptions |= EXCEPTION_ISI;
PowerPC::CheckExceptions(); PowerPC::CheckExceptions();
WARN_LOG_FMT(POWERPC, "ISI exception at {:#010x}", nextPC); WARN_LOG_FMT(POWERPC, "ISI exception at {:#010x}", nextPC);
return; 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.firstFPInstructionFound = false;
js.fifoBytesSinceCheck = 0; js.fifoBytesSinceCheck = 0;
js.downcountAmount = 0; js.downcountAmount = 0;

View File

@@ -20,6 +20,7 @@
#include "Core/Debugger/Debugger_SymbolMap.h" #include "Core/Debugger/Debugger_SymbolMap.h"
#include "Core/PowerPC/MMU.h" #include "Core/PowerPC/MMU.h"
#include "Core/PowerPC/PowerPC.h" #include "Core/PowerPC/PowerPC.h"
#include "Core/System.h"
template <typename T> template <typename T>
static T HostRead(u32 address); static T HostRead(u32 address);
@@ -109,7 +110,7 @@ static double CallstackFunc(expr_func* f, vec_expr_t* args, void* c)
return 0; return 0;
std::vector<Dolphin_Debugger::CallstackEntry> stack; std::vector<Dolphin_Debugger::CallstackEntry> stack;
bool success = Dolphin_Debugger::GetCallstack(stack); bool success = Dolphin_Debugger::GetCallstack(Core::System::GetInstance(), stack);
if (!success) if (!success)
return 0; return 0;
@@ -246,25 +247,25 @@ void Expression::SynchronizeBindings(SynchronizeDirection dir) const
break; break;
case VarBindingType::GPR: case VarBindingType::GPR:
if (dir == SynchronizeDirection::From) if (dir == SynchronizeDirection::From)
v->value = static_cast<double>(GPR(bind->index)); v->value = static_cast<double>(PowerPC::ppcState.gpr[bind->index]);
else 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; break;
case VarBindingType::FPR: case VarBindingType::FPR:
if (dir == SynchronizeDirection::From) if (dir == SynchronizeDirection::From)
v->value = rPS(bind->index).PS0AsDouble(); v->value = PowerPC::ppcState.ps[bind->index].PS0AsDouble();
else else
rPS(bind->index).SetPS0(v->value); PowerPC::ppcState.ps[bind->index].SetPS0(v->value);
break; break;
case VarBindingType::SPR: case VarBindingType::SPR:
if (dir == SynchronizeDirection::From) if (dir == SynchronizeDirection::From)
v->value = static_cast<double>(rSPR(bind->index)); v->value = static_cast<double>(PowerPC::ppcState.spr[bind->index]);
else 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; break;
case VarBindingType::PCtr: case VarBindingType::PCtr:
if (dir == SynchronizeDirection::From) if (dir == SynchronizeDirection::From)
v->value = static_cast<double>(PC); v->value = static_cast<double>(PowerPC::ppcState.pc);
break; break;
} }
} }

View File

@@ -397,6 +397,9 @@ static u64 re64hex(u8* p)
static void ReadRegister() static void ReadRegister()
{ {
auto& system = Core::System::GetInstance();
auto& ppc_state = system.GetPPCState();
static u8 reply[64]; static u8 reply[64];
u32 id; u32 id;
@@ -410,161 +413,161 @@ static void ReadRegister()
if (id < 32) if (id < 32)
{ {
wbe32hex(reply, GPR(id)); wbe32hex(reply, ppc_state.gpr[id]);
} }
else if (id >= 32 && id < 64) else if (id >= 32 && id < 64)
{ {
wbe64hex(reply, rPS(id - 32).PS0AsU64()); wbe64hex(reply, ppc_state.ps[id - 32].PS0AsU64());
} }
else if (id >= 71 && id < 87) else if (id >= 71 && id < 87)
{ {
wbe32hex(reply, PowerPC::ppcState.sr[id - 71]); wbe32hex(reply, ppc_state.sr[id - 71]);
} }
else if (id >= 88 && id < 104) else if (id >= 88 && id < 104)
{ {
wbe32hex(reply, PowerPC::ppcState.spr[SPR_IBAT0U + id - 88]); wbe32hex(reply, ppc_state.spr[SPR_IBAT0U + id - 88]);
} }
else else
{ {
switch (id) switch (id)
{ {
case 64: case 64:
wbe32hex(reply, PC); wbe32hex(reply, ppc_state.pc);
break; break;
case 65: case 65:
wbe32hex(reply, MSR.Hex); wbe32hex(reply, ppc_state.msr.Hex);
break; break;
case 66: case 66:
wbe32hex(reply, PowerPC::ppcState.cr.Get()); wbe32hex(reply, ppc_state.cr.Get());
break; break;
case 67: case 67:
wbe32hex(reply, LR); wbe32hex(reply, LR(ppc_state));
break; break;
case 68: case 68:
wbe32hex(reply, CTR); wbe32hex(reply, CTR(ppc_state));
break; break;
case 69: case 69:
wbe32hex(reply, PowerPC::ppcState.spr[SPR_XER]); wbe32hex(reply, ppc_state.spr[SPR_XER]);
break; break;
case 70: case 70:
wbe32hex(reply, FPSCR.Hex); wbe32hex(reply, ppc_state.fpscr.Hex);
break; break;
case 87: case 87:
wbe32hex(reply, PowerPC::ppcState.spr[SPR_PVR]); wbe32hex(reply, ppc_state.spr[SPR_PVR]);
break; break;
case 104: case 104:
wbe32hex(reply, PowerPC::ppcState.spr[SPR_SDR]); wbe32hex(reply, ppc_state.spr[SPR_SDR]);
break; break;
case 105: case 105:
wbe64hex(reply, PowerPC::ppcState.spr[SPR_ASR]); wbe64hex(reply, ppc_state.spr[SPR_ASR]);
break; break;
case 106: case 106:
wbe32hex(reply, PowerPC::ppcState.spr[SPR_DAR]); wbe32hex(reply, ppc_state.spr[SPR_DAR]);
break; break;
case 107: case 107:
wbe32hex(reply, PowerPC::ppcState.spr[SPR_DSISR]); wbe32hex(reply, ppc_state.spr[SPR_DSISR]);
break; break;
case 108: case 108:
wbe32hex(reply, PowerPC::ppcState.spr[SPR_SPRG0]); wbe32hex(reply, ppc_state.spr[SPR_SPRG0]);
break; break;
case 109: case 109:
wbe32hex(reply, PowerPC::ppcState.spr[SPR_SPRG1]); wbe32hex(reply, ppc_state.spr[SPR_SPRG1]);
break; break;
case 110: case 110:
wbe32hex(reply, PowerPC::ppcState.spr[SPR_SPRG2]); wbe32hex(reply, ppc_state.spr[SPR_SPRG2]);
break; break;
case 111: case 111:
wbe32hex(reply, PowerPC::ppcState.spr[SPR_SPRG3]); wbe32hex(reply, ppc_state.spr[SPR_SPRG3]);
break; break;
case 112: case 112:
wbe32hex(reply, PowerPC::ppcState.spr[SPR_SRR0]); wbe32hex(reply, ppc_state.spr[SPR_SRR0]);
break; break;
case 113: case 113:
wbe32hex(reply, PowerPC::ppcState.spr[SPR_SRR1]); wbe32hex(reply, ppc_state.spr[SPR_SRR1]);
break; break;
case 114: case 114:
wbe32hex(reply, PowerPC::ppcState.spr[SPR_TL]); wbe32hex(reply, ppc_state.spr[SPR_TL]);
break; break;
case 115: case 115:
wbe32hex(reply, PowerPC::ppcState.spr[SPR_TU]); wbe32hex(reply, ppc_state.spr[SPR_TU]);
break; break;
case 116: case 116:
wbe32hex(reply, PowerPC::ppcState.spr[SPR_DEC]); wbe32hex(reply, ppc_state.spr[SPR_DEC]);
break; break;
case 117: case 117:
wbe32hex(reply, PowerPC::ppcState.spr[SPR_DABR]); wbe32hex(reply, ppc_state.spr[SPR_DABR]);
break; break;
case 118: case 118:
wbe32hex(reply, PowerPC::ppcState.spr[SPR_EAR]); wbe32hex(reply, ppc_state.spr[SPR_EAR]);
break; break;
case 119: case 119:
wbe32hex(reply, PowerPC::ppcState.spr[SPR_HID0]); wbe32hex(reply, ppc_state.spr[SPR_HID0]);
break; break;
case 120: case 120:
wbe32hex(reply, PowerPC::ppcState.spr[SPR_HID1]); wbe32hex(reply, ppc_state.spr[SPR_HID1]);
break; break;
case 121: case 121:
wbe32hex(reply, PowerPC::ppcState.spr[SPR_IABR]); wbe32hex(reply, ppc_state.spr[SPR_IABR]);
break; break;
case 122: case 122:
wbe32hex(reply, PowerPC::ppcState.spr[SPR_DABR]); wbe32hex(reply, ppc_state.spr[SPR_DABR]);
break; break;
case 124: case 124:
wbe32hex(reply, PowerPC::ppcState.spr[SPR_UMMCR0]); wbe32hex(reply, ppc_state.spr[SPR_UMMCR0]);
break; break;
case 125: case 125:
wbe32hex(reply, PowerPC::ppcState.spr[SPR_UPMC1]); wbe32hex(reply, ppc_state.spr[SPR_UPMC1]);
break; break;
case 126: case 126:
wbe32hex(reply, PowerPC::ppcState.spr[SPR_UPMC2]); wbe32hex(reply, ppc_state.spr[SPR_UPMC2]);
break; break;
case 127: case 127:
wbe32hex(reply, PowerPC::ppcState.spr[SPR_USIA]); wbe32hex(reply, ppc_state.spr[SPR_USIA]);
break; break;
case 128: case 128:
wbe32hex(reply, PowerPC::ppcState.spr[SPR_UMMCR1]); wbe32hex(reply, ppc_state.spr[SPR_UMMCR1]);
break; break;
case 129: case 129:
wbe32hex(reply, PowerPC::ppcState.spr[SPR_UPMC3]); wbe32hex(reply, ppc_state.spr[SPR_UPMC3]);
break; break;
case 130: case 130:
wbe32hex(reply, PowerPC::ppcState.spr[SPR_UPMC4]); wbe32hex(reply, ppc_state.spr[SPR_UPMC4]);
break; break;
case 131: case 131:
wbe32hex(reply, PowerPC::ppcState.spr[SPR_MMCR0]); wbe32hex(reply, ppc_state.spr[SPR_MMCR0]);
break; break;
case 132: case 132:
wbe32hex(reply, PowerPC::ppcState.spr[SPR_PMC1]); wbe32hex(reply, ppc_state.spr[SPR_PMC1]);
break; break;
case 133: case 133:
wbe32hex(reply, PowerPC::ppcState.spr[SPR_PMC2]); wbe32hex(reply, ppc_state.spr[SPR_PMC2]);
break; break;
case 134: case 134:
wbe32hex(reply, PowerPC::ppcState.spr[SPR_SIA]); wbe32hex(reply, ppc_state.spr[SPR_SIA]);
break; break;
case 135: case 135:
wbe32hex(reply, PowerPC::ppcState.spr[SPR_MMCR1]); wbe32hex(reply, ppc_state.spr[SPR_MMCR1]);
break; break;
case 136: case 136:
wbe32hex(reply, PowerPC::ppcState.spr[SPR_PMC3]); wbe32hex(reply, ppc_state.spr[SPR_PMC3]);
break; break;
case 137: case 137:
wbe32hex(reply, PowerPC::ppcState.spr[SPR_PMC4]); wbe32hex(reply, ppc_state.spr[SPR_PMC4]);
break; break;
case 138: case 138:
wbe32hex(reply, PowerPC::ppcState.spr[SPR_L2CR]); wbe32hex(reply, ppc_state.spr[SPR_L2CR]);
break; break;
case 139: case 139:
wbe32hex(reply, PowerPC::ppcState.spr[SPR_ICTC]); wbe32hex(reply, ppc_state.spr[SPR_ICTC]);
break; break;
case 140: case 140:
wbe32hex(reply, PowerPC::ppcState.spr[SPR_THRM1]); wbe32hex(reply, ppc_state.spr[SPR_THRM1]);
break; break;
case 141: case 141:
wbe32hex(reply, PowerPC::ppcState.spr[SPR_THRM2]); wbe32hex(reply, ppc_state.spr[SPR_THRM2]);
break; break;
case 142: case 142:
wbe32hex(reply, PowerPC::ppcState.spr[SPR_THRM3]); wbe32hex(reply, ppc_state.spr[SPR_THRM3]);
break; break;
default: default:
return SendReply("E01"); return SendReply("E01");
@@ -577,6 +580,9 @@ static void ReadRegister()
static void ReadRegisters() static void ReadRegisters()
{ {
auto& system = Core::System::GetInstance();
auto& ppc_state = system.GetPPCState();
static u8 bfr[GDB_BFR_MAX - 4]; static u8 bfr[GDB_BFR_MAX - 4];
u8* bufptr = bfr; u8* bufptr = bfr;
u32 i; u32 i;
@@ -585,7 +591,7 @@ static void ReadRegisters()
for (i = 0; i < 32; i++) for (i = 0; i < 32; i++)
{ {
wbe32hex(bufptr + i * 8, GPR(i)); wbe32hex(bufptr + i * 8, ppc_state.gpr[i]);
} }
bufptr += 32 * 8; bufptr += 32 * 8;
@@ -594,12 +600,15 @@ static void ReadRegisters()
static void WriteRegisters() static void WriteRegisters()
{ {
auto& system = Core::System::GetInstance();
auto& ppc_state = system.GetPPCState();
u32 i; u32 i;
u8* bufptr = s_cmd_bfr; u8* bufptr = s_cmd_bfr;
for (i = 0; i < 32; i++) for (i = 0; i < 32; i++)
{ {
GPR(i) = re32hex(bufptr + i * 8); ppc_state.gpr[i] = re32hex(bufptr + i * 8);
} }
bufptr += 32 * 8; bufptr += 32 * 8;
@@ -608,6 +617,9 @@ static void WriteRegisters()
static void WriteRegister() static void WriteRegister()
{ {
auto& system = Core::System::GetInstance();
auto& ppc_state = system.GetPPCState();
u32 id; u32 id;
u8* bufptr = s_cmd_bfr + 3; u8* bufptr = s_cmd_bfr + 3;
@@ -622,161 +634,161 @@ static void WriteRegister()
if (id < 32) if (id < 32)
{ {
GPR(id) = re32hex(bufptr); ppc_state.gpr[id] = re32hex(bufptr);
} }
else if (id >= 32 && id < 64) else if (id >= 32 && id < 64)
{ {
rPS(id - 32).SetPS0(re64hex(bufptr)); ppc_state.ps[id - 32].SetPS0(re64hex(bufptr));
} }
else if (id >= 71 && id < 87) else if (id >= 71 && id < 87)
{ {
PowerPC::ppcState.sr[id - 71] = re32hex(bufptr); ppc_state.sr[id - 71] = re32hex(bufptr);
} }
else if (id >= 88 && id < 104) else if (id >= 88 && id < 104)
{ {
PowerPC::ppcState.spr[SPR_IBAT0U + id - 88] = re32hex(bufptr); ppc_state.spr[SPR_IBAT0U + id - 88] = re32hex(bufptr);
} }
else else
{ {
switch (id) switch (id)
{ {
case 64: case 64:
PC = re32hex(bufptr); ppc_state.pc = re32hex(bufptr);
break; break;
case 65: case 65:
MSR.Hex = re32hex(bufptr); ppc_state.msr.Hex = re32hex(bufptr);
break; break;
case 66: case 66:
PowerPC::ppcState.cr.Set(re32hex(bufptr)); ppc_state.cr.Set(re32hex(bufptr));
break; break;
case 67: case 67:
LR = re32hex(bufptr); LR(ppc_state) = re32hex(bufptr);
break; break;
case 68: case 68:
CTR = re32hex(bufptr); CTR(ppc_state) = re32hex(bufptr);
break; break;
case 69: case 69:
PowerPC::ppcState.spr[SPR_XER] = re32hex(bufptr); ppc_state.spr[SPR_XER] = re32hex(bufptr);
break; break;
case 70: case 70:
FPSCR.Hex = re32hex(bufptr); ppc_state.fpscr.Hex = re32hex(bufptr);
break; break;
case 87: case 87:
PowerPC::ppcState.spr[SPR_PVR] = re32hex(bufptr); ppc_state.spr[SPR_PVR] = re32hex(bufptr);
break; break;
case 104: case 104:
PowerPC::ppcState.spr[SPR_SDR] = re32hex(bufptr); ppc_state.spr[SPR_SDR] = re32hex(bufptr);
break; break;
case 105: case 105:
PowerPC::ppcState.spr[SPR_ASR] = re64hex(bufptr); ppc_state.spr[SPR_ASR] = re64hex(bufptr);
break; break;
case 106: case 106:
PowerPC::ppcState.spr[SPR_DAR] = re32hex(bufptr); ppc_state.spr[SPR_DAR] = re32hex(bufptr);
break; break;
case 107: case 107:
PowerPC::ppcState.spr[SPR_DSISR] = re32hex(bufptr); ppc_state.spr[SPR_DSISR] = re32hex(bufptr);
break; break;
case 108: case 108:
PowerPC::ppcState.spr[SPR_SPRG0] = re32hex(bufptr); ppc_state.spr[SPR_SPRG0] = re32hex(bufptr);
break; break;
case 109: case 109:
PowerPC::ppcState.spr[SPR_SPRG1] = re32hex(bufptr); ppc_state.spr[SPR_SPRG1] = re32hex(bufptr);
break; break;
case 110: case 110:
PowerPC::ppcState.spr[SPR_SPRG2] = re32hex(bufptr); ppc_state.spr[SPR_SPRG2] = re32hex(bufptr);
break; break;
case 111: case 111:
PowerPC::ppcState.spr[SPR_SPRG3] = re32hex(bufptr); ppc_state.spr[SPR_SPRG3] = re32hex(bufptr);
break; break;
case 112: case 112:
PowerPC::ppcState.spr[SPR_SRR0] = re32hex(bufptr); ppc_state.spr[SPR_SRR0] = re32hex(bufptr);
break; break;
case 113: case 113:
PowerPC::ppcState.spr[SPR_SRR1] = re32hex(bufptr); ppc_state.spr[SPR_SRR1] = re32hex(bufptr);
break; break;
case 114: case 114:
PowerPC::ppcState.spr[SPR_TL] = re32hex(bufptr); ppc_state.spr[SPR_TL] = re32hex(bufptr);
break; break;
case 115: case 115:
PowerPC::ppcState.spr[SPR_TU] = re32hex(bufptr); ppc_state.spr[SPR_TU] = re32hex(bufptr);
break; break;
case 116: case 116:
PowerPC::ppcState.spr[SPR_DEC] = re32hex(bufptr); ppc_state.spr[SPR_DEC] = re32hex(bufptr);
break; break;
case 117: case 117:
PowerPC::ppcState.spr[SPR_DABR] = re32hex(bufptr); ppc_state.spr[SPR_DABR] = re32hex(bufptr);
break; break;
case 118: case 118:
PowerPC::ppcState.spr[SPR_EAR] = re32hex(bufptr); ppc_state.spr[SPR_EAR] = re32hex(bufptr);
break; break;
case 119: case 119:
PowerPC::ppcState.spr[SPR_HID0] = re32hex(bufptr); ppc_state.spr[SPR_HID0] = re32hex(bufptr);
break; break;
case 120: case 120:
PowerPC::ppcState.spr[SPR_HID1] = re32hex(bufptr); ppc_state.spr[SPR_HID1] = re32hex(bufptr);
break; break;
case 121: case 121:
PowerPC::ppcState.spr[SPR_IABR] = re32hex(bufptr); ppc_state.spr[SPR_IABR] = re32hex(bufptr);
break; break;
case 122: case 122:
PowerPC::ppcState.spr[SPR_DABR] = re32hex(bufptr); ppc_state.spr[SPR_DABR] = re32hex(bufptr);
break; break;
case 124: case 124:
PowerPC::ppcState.spr[SPR_UMMCR0] = re32hex(bufptr); ppc_state.spr[SPR_UMMCR0] = re32hex(bufptr);
break; break;
case 125: case 125:
PowerPC::ppcState.spr[SPR_UPMC1] = re32hex(bufptr); ppc_state.spr[SPR_UPMC1] = re32hex(bufptr);
break; break;
case 126: case 126:
PowerPC::ppcState.spr[SPR_UPMC2] = re32hex(bufptr); ppc_state.spr[SPR_UPMC2] = re32hex(bufptr);
break; break;
case 127: case 127:
PowerPC::ppcState.spr[SPR_USIA] = re32hex(bufptr); ppc_state.spr[SPR_USIA] = re32hex(bufptr);
break; break;
case 128: case 128:
PowerPC::ppcState.spr[SPR_UMMCR1] = re32hex(bufptr); ppc_state.spr[SPR_UMMCR1] = re32hex(bufptr);
break; break;
case 129: case 129:
PowerPC::ppcState.spr[SPR_UPMC3] = re32hex(bufptr); ppc_state.spr[SPR_UPMC3] = re32hex(bufptr);
break; break;
case 130: case 130:
PowerPC::ppcState.spr[SPR_UPMC4] = re32hex(bufptr); ppc_state.spr[SPR_UPMC4] = re32hex(bufptr);
break; break;
case 131: case 131:
PowerPC::ppcState.spr[SPR_MMCR0] = re32hex(bufptr); ppc_state.spr[SPR_MMCR0] = re32hex(bufptr);
break; break;
case 132: case 132:
PowerPC::ppcState.spr[SPR_PMC1] = re32hex(bufptr); ppc_state.spr[SPR_PMC1] = re32hex(bufptr);
break; break;
case 133: case 133:
PowerPC::ppcState.spr[SPR_PMC2] = re32hex(bufptr); ppc_state.spr[SPR_PMC2] = re32hex(bufptr);
break; break;
case 134: case 134:
PowerPC::ppcState.spr[SPR_SIA] = re32hex(bufptr); ppc_state.spr[SPR_SIA] = re32hex(bufptr);
break; break;
case 135: case 135:
PowerPC::ppcState.spr[SPR_MMCR1] = re32hex(bufptr); ppc_state.spr[SPR_MMCR1] = re32hex(bufptr);
break; break;
case 136: case 136:
PowerPC::ppcState.spr[SPR_PMC3] = re32hex(bufptr); ppc_state.spr[SPR_PMC3] = re32hex(bufptr);
break; break;
case 137: case 137:
PowerPC::ppcState.spr[SPR_PMC4] = re32hex(bufptr); ppc_state.spr[SPR_PMC4] = re32hex(bufptr);
break; break;
case 138: case 138:
PowerPC::ppcState.spr[SPR_L2CR] = re32hex(bufptr); ppc_state.spr[SPR_L2CR] = re32hex(bufptr);
break; break;
case 139: case 139:
PowerPC::ppcState.spr[SPR_ICTC] = re32hex(bufptr); ppc_state.spr[SPR_ICTC] = re32hex(bufptr);
break; break;
case 140: case 140:
PowerPC::ppcState.spr[SPR_THRM1] = re32hex(bufptr); ppc_state.spr[SPR_THRM1] = re32hex(bufptr);
break; break;
case 141: case 141:
PowerPC::ppcState.spr[SPR_THRM2] = re32hex(bufptr); ppc_state.spr[SPR_THRM2] = re32hex(bufptr);
break; break;
case 142: case 142:
PowerPC::ppcState.spr[SPR_THRM3] = re32hex(bufptr); ppc_state.spr[SPR_THRM3] = re32hex(bufptr);
break; break;
default: default:
return SendReply("E01"); return SendReply("E01");
@@ -981,10 +993,14 @@ void ProcessCommands(bool loop_until_continue)
ReadMemory(); ReadMemory();
break; break;
case 'M': case 'M':
{
WriteMemory(); WriteMemory();
PowerPC::ppcState.iCache.Reset(); auto& system = Core::System::GetInstance();
auto& ppc_state = system.GetPPCState();
ppc_state.iCache.Reset();
Host_UpdateDisasmDialog(); Host_UpdateDisasmDialog();
break; break;
}
case 's': case 's':
Step(); Step();
return; return;
@@ -1121,9 +1137,12 @@ bool JustConnected()
void SendSignal(Signal signal) void SendSignal(Signal signal)
{ {
auto& system = Core::System::GetInstance();
auto& ppc_state = system.GetPPCState();
char bfr[128] = {}; char bfr[128] = {};
fmt::format_to(bfr, "T{:02x}{:02x}:{:08x};{:02x}:{:08x};", static_cast<u8>(signal), 64, PC, 1, fmt::format_to(bfr, "T{:02x}{:02x}:{:08x};{:02x}:{:08x};", static_cast<u8>(signal), 64,
GPR(1)); ppc_state.pc, 1, ppc_state.gpr[1]);
SendReply(bfr); SendReply(bfr);
} }
} // namespace GDBStub } // namespace GDBStub

View File

@@ -64,16 +64,17 @@ bool IsPairedSingleInstruction(UGeckoInstruction inst)
// but HID2.LSQE is not set. // but HID2.LSQE is not set.
bool IsInvalidPairedSingleExecution(UGeckoInstruction inst) bool IsInvalidPairedSingleExecution(UGeckoInstruction inst)
{ {
if (!HID2.PSE && IsPairedSingleInstruction(inst)) if (!HID2(PowerPC::ppcState).PSE && IsPairedSingleInstruction(inst))
return true; return true;
return HID2.PSE && !HID2.LSQE && IsPairedSingleQuantizedNonIndexedInstruction(inst); return HID2(PowerPC::ppcState).PSE && !HID2(PowerPC::ppcState).LSQE &&
IsPairedSingleQuantizedNonIndexedInstruction(inst);
} }
void UpdatePC() void UpdatePC()
{ {
last_pc = PC; last_pc = PowerPC::ppcState.pc;
PC = NPC; PowerPC::ppcState.pc = PowerPC::ppcState.npc;
} }
} // Anonymous namespace } // Anonymous namespace
@@ -125,12 +126,14 @@ static void Trace(const UGeckoInstruction& inst)
fregs += fmt::format("f{:02d}: {:08x} {:08x} ", i, ps.PS0AsU64(), ps.PS1AsU64()); 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, DEBUG_LOG_FMT(POWERPC,
"INTER PC: {:08x} SRR0: {:08x} SRR1: {:08x} CRval: {:016x} " "INTER PC: {:08x} SRR0: {:08x} SRR1: {:08x} CRval: {:016x} "
"FPSCR: {:08x} MSR: {:08x} LR: {:08x} {} {:08x} {}", "FPSCR: {:08x} MSR: {:08x} LR: {:08x} {} {:08x} {}",
PC, SRR0, SRR1, PowerPC::ppcState.cr.fields[0], FPSCR.Hex, MSR.Hex, PowerPC::ppcState.pc, SRR0(PowerPC::ppcState), SRR1(PowerPC::ppcState),
PowerPC::ppcState.spr[8], regs, inst.hex, ppc_inst); 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) bool Interpreter::HandleFunctionHooking(u32 address)
@@ -143,20 +146,25 @@ bool Interpreter::HandleFunctionHooking(u32 address)
int Interpreter::SingleStepInner() int Interpreter::SingleStepInner()
{ {
if (HandleFunctionHooking(PC)) if (HandleFunctionHooking(PowerPC::ppcState.pc))
{ {
UpdatePC(); UpdatePC();
return PPCTables::GetOpInfo(m_prev_inst)->numCycles; return PPCTables::GetOpInfo(m_prev_inst)->numCycles;
} }
NPC = PC + sizeof(UGeckoInstruction); PowerPC::ppcState.npc = PowerPC::ppcState.pc + sizeof(UGeckoInstruction);
m_prev_inst.hex = PowerPC::Read_Opcode(PC); m_prev_inst.hex = PowerPC::Read_Opcode(PowerPC::ppcState.pc);
// Uncomment to trace the interpreter // 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; // s_start_trace = true;
// }
// else // else
// {
// s_start_trace = false; // s_start_trace = false;
// }
if (s_start_trace) if (s_start_trace)
{ {
@@ -170,7 +178,7 @@ int Interpreter::SingleStepInner()
GenerateProgramException(ProgramExceptionCause::IllegalInstruction); GenerateProgramException(ProgramExceptionCause::IllegalInstruction);
CheckExceptions(); CheckExceptions();
} }
else if (MSR.FP) else if (PowerPC::ppcState.msr.FP)
{ {
m_op_table[m_prev_inst.OPCD](m_prev_inst); m_op_table[m_prev_inst.OPCD](m_prev_inst);
if ((PowerPC::ppcState.Exceptions & EXCEPTION_DSI) != 0) if ((PowerPC::ppcState.Exceptions & EXCEPTION_DSI) != 0)
@@ -206,7 +214,7 @@ int Interpreter::SingleStepInner()
const GekkoOPInfo* opinfo = PPCTables::GetOpInfo(m_prev_inst); const GekkoOPInfo* opinfo = PPCTables::GetOpInfo(m_prev_inst);
PowerPC::UpdatePerformanceMonitor(opinfo->numCycles, (opinfo->flags & FL_LOADSTORE) != 0, 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; return opinfo->numCycles;
} }
@@ -227,7 +235,7 @@ void Interpreter::SingleStep()
if (PowerPC::ppcState.Exceptions != 0) if (PowerPC::ppcState.Exceptions != 0)
{ {
PowerPC::CheckExceptions(); PowerPC::CheckExceptions();
PC = NPC; PowerPC::ppcState.pc = PowerPC::ppcState.npc;
} }
} }
@@ -255,7 +263,7 @@ void Interpreter::Run()
if (Config::Get(Config::MAIN_ENABLE_DEBUGGING)) if (Config::Get(Config::MAIN_ENABLE_DEBUGGING))
{ {
#ifdef SHOW_HISTORY #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) if (s_pc_block_vec.size() > s_show_blocks)
s_pc_block_vec.erase(s_pc_block_vec.begin()); s_pc_block_vec.erase(s_pc_block_vec.begin());
#endif #endif
@@ -269,13 +277,13 @@ void Interpreter::Run()
while (!m_end_block) while (!m_end_block)
{ {
#ifdef SHOW_HISTORY #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) if (s_pc_vec.size() > s_show_steps)
s_pc_vec.erase(s_pc_vec.begin()); s_pc_vec.erase(s_pc_vec.begin());
#endif #endif
// 2: check for breakpoint // 2: check for breakpoint
if (PowerPC::breakpoints.IsAddressBreakPoint(PC)) if (PowerPC::breakpoints.IsAddressBreakPoint(PowerPC::ppcState.pc))
{ {
#ifdef SHOW_HISTORY #ifdef SHOW_HISTORY
NOTICE_LOG_FMT(POWERPC, "----------------------------"); NOTICE_LOG_FMT(POWERPC, "----------------------------");
@@ -296,12 +304,12 @@ void Interpreter::Run()
NOTICE_LOG_FMT(POWERPC, "PC: {:#010x}", s_pc_vec[j]); NOTICE_LOG_FMT(POWERPC, "PC: {:#010x}", s_pc_vec[j]);
} }
#endif #endif
INFO_LOG_FMT(POWERPC, "Hit Breakpoint - {:08x}", PC); INFO_LOG_FMT(POWERPC, "Hit Breakpoint - {:08x}", PowerPC::ppcState.pc);
CPU::Break(); CPU::Break();
if (GDBStub::IsActive()) if (GDBStub::IsActive())
GDBStub::TakeControl(); GDBStub::TakeControl();
if (PowerPC::breakpoints.IsTempBreakPoint(PC)) if (PowerPC::breakpoints.IsTempBreakPoint(PowerPC::ppcState.pc))
PowerPC::breakpoints.Remove(PC); PowerPC::breakpoints.Remove(PowerPC::ppcState.pc);
Host_UpdateDisasmDialog(); Host_UpdateDisasmDialog();
return; return;
@@ -334,19 +342,21 @@ void Interpreter::unknown_instruction(UGeckoInstruction inst)
const u32 opcode = PowerPC::HostRead_U32(last_pc); const u32 opcode = PowerPC::HostRead_U32(last_pc);
const std::string disasm = Common::GekkoDisassembler::Disassemble(opcode, last_pc); const std::string disasm = Common::GekkoDisassembler::Disassemble(opcode, last_pc);
NOTICE_LOG_FMT(POWERPC, "Last PC = {:08x} : {}", last_pc, disasm); 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( NOTICE_LOG_FMT(
POWERPC, POWERPC,
"\nIntCPU: Unknown instruction {:08x} at PC = {:08x} last_PC = {:08x} LR = {:08x}\n", "\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) for (int i = 0; i < 32; i += 4)
{ {
NOTICE_LOG_FMT(POWERPC, "r{}: {:#010x} r{}: {:#010x} r{}: {:#010x} r{}: {:#010x}", i, rGPR[i], NOTICE_LOG_FMT(POWERPC, "r{}: {:#010x} r{}: {:#010x} r{}: {:#010x} r{}: {:#010x}", i,
i + 1, rGPR[i + 1], i + 2, rGPR[i + 2], i + 3, rGPR[i + 3]); 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, ASSERT_MSG(POWERPC, 0,
"\nIntCPU: Unknown instruction {:08x} at PC = {:08x} last_PC = {:08x} LR = {:08x}\n", "\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()) if (Core::System::GetInstance().IsPauseOnPanicMode())
CPU::Break(); CPU::Break();
} }

View File

@@ -13,14 +13,14 @@
void Interpreter::bx(UGeckoInstruction inst) void Interpreter::bx(UGeckoInstruction inst)
{ {
if (inst.LK) if (inst.LK)
LR = PC + 4; LR(PowerPC::ppcState) = PowerPC::ppcState.pc + 4;
const auto address = u32(SignExt26(inst.LI << 2)); const auto address = u32(SignExt26(inst.LI << 2));
if (inst.AA) if (inst.AA)
NPC = address; PowerPC::ppcState.npc = address;
else else
NPC = PC + address; PowerPC::ppcState.npc = PowerPC::ppcState.pc + address;
m_end_block = true; m_end_block = true;
} }
@@ -29,12 +29,12 @@ void Interpreter::bx(UGeckoInstruction inst)
void Interpreter::bcx(UGeckoInstruction inst) void Interpreter::bcx(UGeckoInstruction inst)
{ {
if ((inst.BO & BO_DONT_DECREMENT_FLAG) == 0) if ((inst.BO & BO_DONT_DECREMENT_FLAG) == 0)
CTR--; CTR(PowerPC::ppcState)--;
const bool true_false = ((inst.BO >> 3) & 1) != 0; const bool true_false = ((inst.BO >> 3) & 1) != 0;
const bool only_counter_check = ((inst.BO >> 4) & 1) != 0; const bool only_counter_check = ((inst.BO >> 4) & 1) != 0;
const bool only_condition_check = ((inst.BO >> 2) & 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 counter = only_condition_check || ctr_check != 0;
const bool condition = const bool condition =
only_counter_check || (PowerPC::ppcState.cr.GetBit(inst.BI) == u32(true_false)); only_counter_check || (PowerPC::ppcState.cr.GetBit(inst.BI) == u32(true_false));
@@ -42,14 +42,14 @@ void Interpreter::bcx(UGeckoInstruction inst)
if (counter && condition) if (counter && condition)
{ {
if (inst.LK) if (inst.LK)
LR = PC + 4; LR(PowerPC::ppcState) = PowerPC::ppcState.pc + 4;
const auto address = u32(SignExt16(s16(inst.BD << 2))); const auto address = u32(SignExt16(s16(inst.BD << 2)));
if (inst.AA) if (inst.AA)
NPC = address; PowerPC::ppcState.npc = address;
else else
NPC = PC + address; PowerPC::ppcState.npc = PowerPC::ppcState.pc + address;
} }
m_end_block = true; m_end_block = true;
@@ -65,9 +65,9 @@ void Interpreter::bcctrx(UGeckoInstruction inst)
if (condition != 0) if (condition != 0)
{ {
NPC = CTR & (~3); PowerPC::ppcState.npc = CTR(PowerPC::ppcState) & (~3);
if (inst.LK_3) if (inst.LK_3)
LR = PC + 4; LR(PowerPC::ppcState) = PowerPC::ppcState.pc + 4;
} }
m_end_block = true; m_end_block = true;
@@ -76,17 +76,17 @@ void Interpreter::bcctrx(UGeckoInstruction inst)
void Interpreter::bclrx(UGeckoInstruction inst) void Interpreter::bclrx(UGeckoInstruction inst)
{ {
if ((inst.BO_2 & BO_DONT_DECREMENT_FLAG) == 0) 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 = const u32 condition =
((inst.BO_2 >> 4) | (PowerPC::ppcState.cr.GetBit(inst.BI_2) == ((inst.BO_2 >> 3) & 1))) & 1; ((inst.BO_2 >> 4) | (PowerPC::ppcState.cr.GetBit(inst.BI_2) == ((inst.BO_2 >> 3) & 1))) & 1;
if ((counter & condition) != 0) if ((counter & condition) != 0)
{ {
NPC = LR & (~3); PowerPC::ppcState.npc = LR(PowerPC::ppcState) & (~3);
if (inst.LK_3) if (inst.LK_3)
LR = PC + 4; LR(PowerPC::ppcState) = PowerPC::ppcState.pc + 4;
} }
m_end_block = true; m_end_block = true;
@@ -95,12 +95,12 @@ void Interpreter::bclrx(UGeckoInstruction inst)
void Interpreter::HLEFunction(UGeckoInstruction inst) void Interpreter::HLEFunction(UGeckoInstruction inst)
{ {
m_end_block = true; m_end_block = true;
HLE::Execute(PC, inst.hex); HLE::Execute(PowerPC::ppcState.pc, inst.hex);
} }
void Interpreter::rfi(UGeckoInstruction inst) void Interpreter::rfi(UGeckoInstruction inst)
{ {
if (MSR.PR) if (PowerPC::ppcState.msr.PR)
{ {
GenerateProgramException(ProgramExceptionCause::PrivilegedInstruction); GenerateProgramException(ProgramExceptionCause::PrivilegedInstruction);
return; return;
@@ -109,16 +109,17 @@ void Interpreter::rfi(UGeckoInstruction inst)
// Restore saved bits from SRR1 to MSR. // Restore saved bits from SRR1 to MSR.
// Gecko/Broadway can save more bits than explicitly defined in ppc spec // Gecko/Broadway can save more bits than explicitly defined in ppc spec
const u32 mask = 0x87C0FFFF; 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[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 // Here we should check if there are pending exceptions, and if their corresponding enable bits
// are set // are set
// if above is true, we'd do: // if above is true, we'd do:
// PowerPC::CheckExceptions(); // PowerPC::CheckExceptions();
// else // else
// set NPC to saved offset and resume // set NPC to saved offset and resume
NPC = SRR0; PowerPC::ppcState.npc = SRR0(PowerPC::ppcState);
m_end_block = true; m_end_block = true;
} }

View File

@@ -27,7 +27,7 @@ enum class FPCC
inline void CheckFPExceptions(UReg_FPSCR fpscr) 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); GenerateProgramException(ProgramExceptionCause::FloatingPoint);
} }

View File

@@ -37,31 +37,31 @@ void SetFI(UReg_FPSCR* fpscr, u32 FI)
// The Programming Environments Manual for 32 and 64-bit Microprocessors // The Programming Environments Manual for 32 and 64-bit Microprocessors
void ConvertToInteger(UGeckoInstruction inst, RoundingMode rounding_mode) void ConvertToInteger(UGeckoInstruction inst, RoundingMode rounding_mode)
{ {
const double b = rPS(inst.FB).PS0AsDouble(); const double b = PowerPC::ppcState.ps[inst.FB].PS0AsDouble();
u32 value; u32 value;
bool exception_occurred = false; bool exception_occurred = false;
if (std::isnan(b)) if (std::isnan(b))
{ {
if (Common::IsSNAN(b)) if (Common::IsSNAN(b))
SetFPException(&FPSCR, FPSCR_VXSNAN); SetFPException(&PowerPC::ppcState.fpscr, FPSCR_VXSNAN);
value = 0x80000000; value = 0x80000000;
SetFPException(&FPSCR, FPSCR_VXCVI); SetFPException(&PowerPC::ppcState.fpscr, FPSCR_VXCVI);
exception_occurred = true; exception_occurred = true;
} }
else if (b > static_cast<double>(0x7fffffff)) else if (b > static_cast<double>(0x7fffffff))
{ {
// Positive large operand or +inf // Positive large operand or +inf
value = 0x7fffffff; value = 0x7fffffff;
SetFPException(&FPSCR, FPSCR_VXCVI); SetFPException(&PowerPC::ppcState.fpscr, FPSCR_VXCVI);
exception_occurred = true; exception_occurred = true;
} }
else if (b < -static_cast<double>(0x80000000)) else if (b < -static_cast<double>(0x80000000))
{ {
// Negative large operand or -inf // Negative large operand or -inf
value = 0x80000000; value = 0x80000000;
SetFPException(&FPSCR, FPSCR_VXCVI); SetFPException(&PowerPC::ppcState.fpscr, FPSCR_VXCVI);
exception_occurred = true; exception_occurred = true;
} }
else else
@@ -103,22 +103,22 @@ void ConvertToInteger(UGeckoInstruction inst, RoundingMode rounding_mode)
const double di = i; const double di = i;
if (di == b) if (di == b)
{ {
FPSCR.ClearFIFR(); PowerPC::ppcState.fpscr.ClearFIFR();
} }
else else
{ {
// Also sets FPSCR[XX] // Also sets FPSCR[XX]
SetFI(&FPSCR, 1); SetFI(&PowerPC::ppcState.fpscr, 1);
FPSCR.FR = fabs(di) > fabs(b); PowerPC::ppcState.fpscr.FR = fabs(di) > fabs(b);
} }
} }
if (exception_occurred) if (exception_occurred)
{ {
FPSCR.ClearFIFR(); PowerPC::ppcState.fpscr.ClearFIFR();
} }
if (!exception_occurred || FPSCR.VE == 0) if (!exception_occurred || PowerPC::ppcState.fpscr.VE == 0)
{ {
// Based on HW tests // Based on HW tests
// FPRF is not affected // FPRF is not affected
@@ -126,7 +126,7 @@ void ConvertToInteger(UGeckoInstruction inst, RoundingMode rounding_mode)
if (value == 0 && std::signbit(b)) if (value == 0 && std::signbit(b))
result |= 0x100000000ull; result |= 0x100000000ull;
rPS(inst.FD).SetPS0(result); PowerPC::ppcState.ps[inst.FD].SetPS0(result);
} }
if (inst.Rc) if (inst.Rc)
@@ -143,15 +143,15 @@ void Interpreter::Helper_FloatCompareOrdered(UGeckoInstruction inst, double fa,
compare_result = FPCC::FU; compare_result = FPCC::FU;
if (Common::IsSNAN(fa) || Common::IsSNAN(fb)) if (Common::IsSNAN(fa) || Common::IsSNAN(fb))
{ {
SetFPException(&FPSCR, FPSCR_VXSNAN); SetFPException(&PowerPC::ppcState.fpscr, FPSCR_VXSNAN);
if (FPSCR.VE == 0) if (PowerPC::ppcState.fpscr.VE == 0)
{ {
SetFPException(&FPSCR, FPSCR_VXVC); SetFPException(&PowerPC::ppcState.fpscr, FPSCR_VXVC);
} }
} }
else // QNaN else // QNaN
{ {
SetFPException(&FPSCR, FPSCR_VXVC); SetFPException(&PowerPC::ppcState.fpscr, FPSCR_VXVC);
} }
} }
else if (fa < fb) else if (fa < fb)
@@ -170,7 +170,7 @@ void Interpreter::Helper_FloatCompareOrdered(UGeckoInstruction inst, double fa,
const u32 compare_value = static_cast<u32>(compare_result); const u32 compare_value = static_cast<u32>(compare_result);
// Clear and set the FPCC bits accordingly. // Clear and set the FPCC bits accordingly.
FPSCR.FPRF = (FPSCR.FPRF & ~FPCC_MASK) | compare_value; PowerPC::ppcState.fpscr.FPRF = (PowerPC::ppcState.fpscr.FPRF & ~FPCC_MASK) | compare_value;
PowerPC::ppcState.cr.SetField(inst.CRFD, compare_value); PowerPC::ppcState.cr.SetField(inst.CRFD, compare_value);
} }
@@ -185,7 +185,7 @@ void Interpreter::Helper_FloatCompareUnordered(UGeckoInstruction inst, double fa
if (Common::IsSNAN(fa) || Common::IsSNAN(fb)) if (Common::IsSNAN(fa) || Common::IsSNAN(fb))
{ {
SetFPException(&FPSCR, FPSCR_VXSNAN); SetFPException(&PowerPC::ppcState.fpscr, FPSCR_VXSNAN);
} }
} }
else if (fa < fb) else if (fa < fb)
@@ -204,30 +204,30 @@ void Interpreter::Helper_FloatCompareUnordered(UGeckoInstruction inst, double fa
const u32 compare_value = static_cast<u32>(compare_result); const u32 compare_value = static_cast<u32>(compare_result);
// Clear and set the FPCC bits accordingly. // Clear and set the FPCC bits accordingly.
FPSCR.FPRF = (FPSCR.FPRF & ~FPCC_MASK) | compare_value; PowerPC::ppcState.fpscr.FPRF = (PowerPC::ppcState.fpscr.FPRF & ~FPCC_MASK) | compare_value;
PowerPC::ppcState.cr.SetField(inst.CRFD, compare_value); PowerPC::ppcState.cr.SetField(inst.CRFD, compare_value);
} }
void Interpreter::fcmpo(UGeckoInstruction inst) void Interpreter::fcmpo(UGeckoInstruction inst)
{ {
const auto& a = rPS(inst.FA); const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = rPS(inst.FB); const auto& b = PowerPC::ppcState.ps[inst.FB];
Helper_FloatCompareOrdered(inst, a.PS0AsDouble(), b.PS0AsDouble()); Helper_FloatCompareOrdered(inst, a.PS0AsDouble(), b.PS0AsDouble());
} }
void Interpreter::fcmpu(UGeckoInstruction inst) void Interpreter::fcmpu(UGeckoInstruction inst)
{ {
const auto& a = rPS(inst.FA); const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = rPS(inst.FB); const auto& b = PowerPC::ppcState.ps[inst.FB];
Helper_FloatCompareUnordered(inst, a.PS0AsDouble(), b.PS0AsDouble()); Helper_FloatCompareUnordered(inst, a.PS0AsDouble(), b.PS0AsDouble());
} }
void Interpreter::fctiwx(UGeckoInstruction inst) void Interpreter::fctiwx(UGeckoInstruction inst)
{ {
ConvertToInteger(inst, static_cast<RoundingMode>(FPSCR.RN.Value())); ConvertToInteger(inst, static_cast<RoundingMode>(PowerPC::ppcState.fpscr.RN.Value()));
} }
void Interpreter::fctiwzx(UGeckoInstruction inst) void Interpreter::fctiwzx(UGeckoInstruction inst)
@@ -237,7 +237,7 @@ void Interpreter::fctiwzx(UGeckoInstruction inst)
void Interpreter::fmrx(UGeckoInstruction inst) void Interpreter::fmrx(UGeckoInstruction inst)
{ {
rPS(inst.FD).SetPS0(rPS(inst.FB).PS0AsU64()); PowerPC::ppcState.ps[inst.FD].SetPS0(PowerPC::ppcState.ps[inst.FB].PS0AsU64());
// This is a binary instruction. Does not alter FPSCR // This is a binary instruction. Does not alter FPSCR
if (inst.Rc) if (inst.Rc)
@@ -246,7 +246,7 @@ void Interpreter::fmrx(UGeckoInstruction inst)
void Interpreter::fabsx(UGeckoInstruction inst) void Interpreter::fabsx(UGeckoInstruction inst)
{ {
rPS(inst.FD).SetPS0(fabs(rPS(inst.FB).PS0AsDouble())); PowerPC::ppcState.ps[inst.FD].SetPS0(fabs(PowerPC::ppcState.ps[inst.FB].PS0AsDouble()));
// This is a binary instruction. Does not alter FPSCR // This is a binary instruction. Does not alter FPSCR
if (inst.Rc) if (inst.Rc)
@@ -255,7 +255,8 @@ void Interpreter::fabsx(UGeckoInstruction inst)
void Interpreter::fnabsx(UGeckoInstruction inst) void Interpreter::fnabsx(UGeckoInstruction inst)
{ {
rPS(inst.FD).SetPS0(rPS(inst.FB).PS0AsU64() | (UINT64_C(1) << 63)); PowerPC::ppcState.ps[inst.FD].SetPS0(PowerPC::ppcState.ps[inst.FB].PS0AsU64() |
(UINT64_C(1) << 63));
// This is a binary instruction. Does not alter FPSCR // This is a binary instruction. Does not alter FPSCR
if (inst.Rc) if (inst.Rc)
@@ -264,7 +265,8 @@ void Interpreter::fnabsx(UGeckoInstruction inst)
void Interpreter::fnegx(UGeckoInstruction inst) void Interpreter::fnegx(UGeckoInstruction inst)
{ {
rPS(inst.FD).SetPS0(rPS(inst.FB).PS0AsU64() ^ (UINT64_C(1) << 63)); PowerPC::ppcState.ps[inst.FD].SetPS0(PowerPC::ppcState.ps[inst.FB].PS0AsU64() ^
(UINT64_C(1) << 63));
// This is a binary instruction. Does not alter FPSCR // This is a binary instruction. Does not alter FPSCR
if (inst.Rc) if (inst.Rc)
@@ -273,11 +275,12 @@ void Interpreter::fnegx(UGeckoInstruction inst)
void Interpreter::fselx(UGeckoInstruction inst) void Interpreter::fselx(UGeckoInstruction inst)
{ {
const auto& a = rPS(inst.FA); const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = rPS(inst.FB); const auto& b = PowerPC::ppcState.ps[inst.FB];
const auto& c = rPS(inst.FC); const auto& c = PowerPC::ppcState.ps[inst.FC];
rPS(inst.FD).SetPS0((a.PS0AsDouble() >= -0.0) ? c.PS0AsDouble() : b.PS0AsDouble()); PowerPC::ppcState.ps[inst.FD].SetPS0((a.PS0AsDouble() >= -0.0) ? c.PS0AsDouble() :
b.PS0AsDouble());
// This is a binary instruction. Does not alter FPSCR // This is a binary instruction. Does not alter FPSCR
if (inst.Rc) if (inst.Rc)
@@ -289,30 +292,30 @@ void Interpreter::fselx(UGeckoInstruction inst)
// PS1 is said to be undefined // PS1 is said to be undefined
void Interpreter::frspx(UGeckoInstruction inst) // round to single void Interpreter::frspx(UGeckoInstruction inst) // round to single
{ {
const double b = rPS(inst.FB).PS0AsDouble(); const double b = PowerPC::ppcState.ps[inst.FB].PS0AsDouble();
const float rounded = ForceSingle(FPSCR, b); const float rounded = ForceSingle(PowerPC::ppcState.fpscr, b);
if (std::isnan(b)) if (std::isnan(b))
{ {
const bool is_snan = Common::IsSNAN(b); const bool is_snan = Common::IsSNAN(b);
if (is_snan) if (is_snan)
SetFPException(&FPSCR, FPSCR_VXSNAN); SetFPException(&PowerPC::ppcState.fpscr, FPSCR_VXSNAN);
if (!is_snan || FPSCR.VE == 0) if (!is_snan || PowerPC::ppcState.fpscr.VE == 0)
{ {
rPS(inst.FD).Fill(rounded); PowerPC::ppcState.ps[inst.FD].Fill(rounded);
PowerPC::UpdateFPRFSingle(rounded); PowerPC::ppcState.UpdateFPRFSingle(rounded);
} }
FPSCR.ClearFIFR(); PowerPC::ppcState.fpscr.ClearFIFR();
} }
else else
{ {
SetFI(&FPSCR, b != rounded); SetFI(&PowerPC::ppcState.fpscr, b != rounded);
FPSCR.FR = fabs(rounded) > fabs(b); PowerPC::ppcState.fpscr.FR = fabs(rounded) > fabs(b);
PowerPC::UpdateFPRFSingle(rounded); PowerPC::ppcState.UpdateFPRFSingle(rounded);
rPS(inst.FD).Fill(rounded); PowerPC::ppcState.ps[inst.FD].Fill(rounded);
} }
if (inst.Rc) if (inst.Rc)
@@ -321,19 +324,19 @@ void Interpreter::frspx(UGeckoInstruction inst) // round to single
void Interpreter::fmulx(UGeckoInstruction inst) void Interpreter::fmulx(UGeckoInstruction inst)
{ {
const auto& a = rPS(inst.FA); const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& c = rPS(inst.FC); const auto& c = PowerPC::ppcState.ps[inst.FC];
const FPResult product = NI_mul(&FPSCR, a.PS0AsDouble(), c.PS0AsDouble()); const FPResult product = NI_mul(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), c.PS0AsDouble());
if (FPSCR.VE == 0 || product.HasNoInvalidExceptions()) if (PowerPC::ppcState.fpscr.VE == 0 || product.HasNoInvalidExceptions())
{ {
const double result = ForceDouble(FPSCR, product.value); const double result = ForceDouble(PowerPC::ppcState.fpscr, product.value);
rPS(inst.FD).SetPS0(result); PowerPC::ppcState.ps[inst.FD].SetPS0(result);
FPSCR.FI = 0; // are these flags important? PowerPC::ppcState.fpscr.FI = 0; // are these flags important?
FPSCR.FR = 0; PowerPC::ppcState.fpscr.FR = 0;
PowerPC::UpdateFPRFDouble(result); PowerPC::ppcState.UpdateFPRFDouble(result);
} }
if (inst.Rc) if (inst.Rc)
@@ -341,20 +344,20 @@ void Interpreter::fmulx(UGeckoInstruction inst)
} }
void Interpreter::fmulsx(UGeckoInstruction inst) void Interpreter::fmulsx(UGeckoInstruction inst)
{ {
const auto& a = rPS(inst.FA); const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& c = rPS(inst.FC); const auto& c = PowerPC::ppcState.ps[inst.FC];
const double c_value = Force25Bit(c.PS0AsDouble()); const double c_value = Force25Bit(c.PS0AsDouble());
const FPResult d_value = NI_mul(&FPSCR, a.PS0AsDouble(), c_value); const FPResult d_value = NI_mul(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), c_value);
if (FPSCR.VE == 0 || d_value.HasNoInvalidExceptions()) if (PowerPC::ppcState.fpscr.VE == 0 || d_value.HasNoInvalidExceptions())
{ {
const float result = ForceSingle(FPSCR, d_value.value); const float result = ForceSingle(PowerPC::ppcState.fpscr, d_value.value);
rPS(inst.FD).Fill(result); PowerPC::ppcState.ps[inst.FD].Fill(result);
FPSCR.FI = 0; PowerPC::ppcState.fpscr.FI = 0;
FPSCR.FR = 0; PowerPC::ppcState.fpscr.FR = 0;
PowerPC::UpdateFPRFSingle(result); PowerPC::ppcState.UpdateFPRFSingle(result);
} }
if (inst.Rc) if (inst.Rc)
@@ -363,16 +366,17 @@ void Interpreter::fmulsx(UGeckoInstruction inst)
void Interpreter::fmaddx(UGeckoInstruction inst) void Interpreter::fmaddx(UGeckoInstruction inst)
{ {
const auto& a = rPS(inst.FA); const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = rPS(inst.FB); const auto& b = PowerPC::ppcState.ps[inst.FB];
const auto& c = rPS(inst.FC); const auto& c = PowerPC::ppcState.ps[inst.FC];
const FPResult product = NI_madd(&FPSCR, a.PS0AsDouble(), c.PS0AsDouble(), b.PS0AsDouble()); const FPResult product =
NI_madd(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), c.PS0AsDouble(), b.PS0AsDouble());
if (FPSCR.VE == 0 || product.HasNoInvalidExceptions()) if (PowerPC::ppcState.fpscr.VE == 0 || product.HasNoInvalidExceptions())
{ {
const double result = ForceDouble(FPSCR, product.value); const double result = ForceDouble(PowerPC::ppcState.fpscr, product.value);
rPS(inst.FD).SetPS0(result); PowerPC::ppcState.ps[inst.FD].SetPS0(result);
PowerPC::UpdateFPRFDouble(result); PowerPC::ppcState.UpdateFPRFDouble(result);
} }
if (inst.Rc) if (inst.Rc)
@@ -381,21 +385,22 @@ void Interpreter::fmaddx(UGeckoInstruction inst)
void Interpreter::fmaddsx(UGeckoInstruction inst) void Interpreter::fmaddsx(UGeckoInstruction inst)
{ {
const auto& a = rPS(inst.FA); const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = rPS(inst.FB); const auto& b = PowerPC::ppcState.ps[inst.FB];
const auto& c = rPS(inst.FC); const auto& c = PowerPC::ppcState.ps[inst.FC];
const double c_value = Force25Bit(c.PS0AsDouble()); const double c_value = Force25Bit(c.PS0AsDouble());
const FPResult d_value = NI_madd(&FPSCR, a.PS0AsDouble(), c_value, b.PS0AsDouble()); const FPResult d_value =
NI_madd(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), c_value, b.PS0AsDouble());
if (FPSCR.VE == 0 || d_value.HasNoInvalidExceptions()) if (PowerPC::ppcState.fpscr.VE == 0 || d_value.HasNoInvalidExceptions())
{ {
const float result = ForceSingle(FPSCR, d_value.value); const float result = ForceSingle(PowerPC::ppcState.fpscr, d_value.value);
rPS(inst.FD).Fill(result); PowerPC::ppcState.ps[inst.FD].Fill(result);
FPSCR.FI = d_value.value != result; PowerPC::ppcState.fpscr.FI = d_value.value != result;
FPSCR.FR = 0; PowerPC::ppcState.fpscr.FR = 0;
PowerPC::UpdateFPRFSingle(result); PowerPC::ppcState.UpdateFPRFSingle(result);
} }
if (inst.Rc) if (inst.Rc)
@@ -404,16 +409,16 @@ void Interpreter::fmaddsx(UGeckoInstruction inst)
void Interpreter::faddx(UGeckoInstruction inst) void Interpreter::faddx(UGeckoInstruction inst)
{ {
const auto& a = rPS(inst.FA); const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = rPS(inst.FB); const auto& b = PowerPC::ppcState.ps[inst.FB];
const FPResult sum = NI_add(&FPSCR, a.PS0AsDouble(), b.PS0AsDouble()); const FPResult sum = NI_add(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), b.PS0AsDouble());
if (FPSCR.VE == 0 || sum.HasNoInvalidExceptions()) if (PowerPC::ppcState.fpscr.VE == 0 || sum.HasNoInvalidExceptions())
{ {
const double result = ForceDouble(FPSCR, sum.value); const double result = ForceDouble(PowerPC::ppcState.fpscr, sum.value);
rPS(inst.FD).SetPS0(result); PowerPC::ppcState.ps[inst.FD].SetPS0(result);
PowerPC::UpdateFPRFDouble(result); PowerPC::ppcState.UpdateFPRFDouble(result);
} }
if (inst.Rc) if (inst.Rc)
@@ -421,16 +426,16 @@ void Interpreter::faddx(UGeckoInstruction inst)
} }
void Interpreter::faddsx(UGeckoInstruction inst) void Interpreter::faddsx(UGeckoInstruction inst)
{ {
const auto& a = rPS(inst.FA); const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = rPS(inst.FB); const auto& b = PowerPC::ppcState.ps[inst.FB];
const FPResult sum = NI_add(&FPSCR, a.PS0AsDouble(), b.PS0AsDouble()); const FPResult sum = NI_add(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), b.PS0AsDouble());
if (FPSCR.VE == 0 || sum.HasNoInvalidExceptions()) if (PowerPC::ppcState.fpscr.VE == 0 || sum.HasNoInvalidExceptions())
{ {
const float result = ForceSingle(FPSCR, sum.value); const float result = ForceSingle(PowerPC::ppcState.fpscr, sum.value);
rPS(inst.FD).Fill(result); PowerPC::ppcState.ps[inst.FD].Fill(result);
PowerPC::UpdateFPRFSingle(result); PowerPC::ppcState.UpdateFPRFSingle(result);
} }
if (inst.Rc) if (inst.Rc)
@@ -439,18 +444,18 @@ void Interpreter::faddsx(UGeckoInstruction inst)
void Interpreter::fdivx(UGeckoInstruction inst) void Interpreter::fdivx(UGeckoInstruction inst)
{ {
const auto& a = rPS(inst.FA); const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = rPS(inst.FB); const auto& b = PowerPC::ppcState.ps[inst.FB];
const FPResult quotient = NI_div(&FPSCR, a.PS0AsDouble(), b.PS0AsDouble()); const FPResult quotient = NI_div(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), b.PS0AsDouble());
const bool not_divide_by_zero = FPSCR.ZE == 0 || quotient.exception != FPSCR_ZX; const bool not_divide_by_zero = PowerPC::ppcState.fpscr.ZE == 0 || quotient.exception != FPSCR_ZX;
const bool not_invalid = FPSCR.VE == 0 || quotient.HasNoInvalidExceptions(); const bool not_invalid = PowerPC::ppcState.fpscr.VE == 0 || quotient.HasNoInvalidExceptions();
if (not_divide_by_zero && not_invalid) if (not_divide_by_zero && not_invalid)
{ {
const double result = ForceDouble(FPSCR, quotient.value); const double result = ForceDouble(PowerPC::ppcState.fpscr, quotient.value);
rPS(inst.FD).SetPS0(result); PowerPC::ppcState.ps[inst.FD].SetPS0(result);
PowerPC::UpdateFPRFDouble(result); PowerPC::ppcState.UpdateFPRFDouble(result);
} }
// FR,FI,OX,UX??? // FR,FI,OX,UX???
@@ -459,18 +464,18 @@ void Interpreter::fdivx(UGeckoInstruction inst)
} }
void Interpreter::fdivsx(UGeckoInstruction inst) void Interpreter::fdivsx(UGeckoInstruction inst)
{ {
const auto& a = rPS(inst.FA); const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = rPS(inst.FB); const auto& b = PowerPC::ppcState.ps[inst.FB];
const FPResult quotient = NI_div(&FPSCR, a.PS0AsDouble(), b.PS0AsDouble()); const FPResult quotient = NI_div(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), b.PS0AsDouble());
const bool not_divide_by_zero = FPSCR.ZE == 0 || quotient.exception != FPSCR_ZX; const bool not_divide_by_zero = PowerPC::ppcState.fpscr.ZE == 0 || quotient.exception != FPSCR_ZX;
const bool not_invalid = FPSCR.VE == 0 || quotient.HasNoInvalidExceptions(); const bool not_invalid = PowerPC::ppcState.fpscr.VE == 0 || quotient.HasNoInvalidExceptions();
if (not_divide_by_zero && not_invalid) if (not_divide_by_zero && not_invalid)
{ {
const float result = ForceSingle(FPSCR, quotient.value); const float result = ForceSingle(PowerPC::ppcState.fpscr, quotient.value);
rPS(inst.FD).Fill(result); PowerPC::ppcState.ps[inst.FD].Fill(result);
PowerPC::UpdateFPRFSingle(result); PowerPC::ppcState.UpdateFPRFSingle(result);
} }
if (inst.Rc) if (inst.Rc)
@@ -480,34 +485,34 @@ void Interpreter::fdivsx(UGeckoInstruction inst)
// Single precision only. // Single precision only.
void Interpreter::fresx(UGeckoInstruction inst) void Interpreter::fresx(UGeckoInstruction inst)
{ {
const double b = rPS(inst.FB).PS0AsDouble(); const double b = PowerPC::ppcState.ps[inst.FB].PS0AsDouble();
const auto compute_result = [inst](double value) { const auto compute_result = [inst](double value) {
const double result = Common::ApproximateReciprocal(value); const double result = Common::ApproximateReciprocal(value);
rPS(inst.FD).Fill(result); PowerPC::ppcState.ps[inst.FD].Fill(result);
PowerPC::UpdateFPRFSingle(float(result)); PowerPC::ppcState.UpdateFPRFSingle(float(result));
}; };
if (b == 0.0) if (b == 0.0)
{ {
SetFPException(&FPSCR, FPSCR_ZX); SetFPException(&PowerPC::ppcState.fpscr, FPSCR_ZX);
FPSCR.ClearFIFR(); PowerPC::ppcState.fpscr.ClearFIFR();
if (FPSCR.ZE == 0) if (PowerPC::ppcState.fpscr.ZE == 0)
compute_result(b); compute_result(b);
} }
else if (Common::IsSNAN(b)) else if (Common::IsSNAN(b))
{ {
SetFPException(&FPSCR, FPSCR_VXSNAN); SetFPException(&PowerPC::ppcState.fpscr, FPSCR_VXSNAN);
FPSCR.ClearFIFR(); PowerPC::ppcState.fpscr.ClearFIFR();
if (FPSCR.VE == 0) if (PowerPC::ppcState.fpscr.VE == 0)
compute_result(b); compute_result(b);
} }
else else
{ {
if (std::isnan(b) || std::isinf(b)) if (std::isnan(b) || std::isinf(b))
FPSCR.ClearFIFR(); PowerPC::ppcState.fpscr.ClearFIFR();
compute_result(b); compute_result(b);
} }
@@ -518,42 +523,42 @@ void Interpreter::fresx(UGeckoInstruction inst)
void Interpreter::frsqrtex(UGeckoInstruction inst) void Interpreter::frsqrtex(UGeckoInstruction inst)
{ {
const double b = rPS(inst.FB).PS0AsDouble(); const double b = PowerPC::ppcState.ps[inst.FB].PS0AsDouble();
const auto compute_result = [inst](double value) { const auto compute_result = [inst](double value) {
const double result = Common::ApproximateReciprocalSquareRoot(value); const double result = Common::ApproximateReciprocalSquareRoot(value);
rPS(inst.FD).SetPS0(result); PowerPC::ppcState.ps[inst.FD].SetPS0(result);
PowerPC::UpdateFPRFDouble(result); PowerPC::ppcState.UpdateFPRFDouble(result);
}; };
if (b < 0.0) if (b < 0.0)
{ {
SetFPException(&FPSCR, FPSCR_VXSQRT); SetFPException(&PowerPC::ppcState.fpscr, FPSCR_VXSQRT);
FPSCR.ClearFIFR(); PowerPC::ppcState.fpscr.ClearFIFR();
if (FPSCR.VE == 0) if (PowerPC::ppcState.fpscr.VE == 0)
compute_result(b); compute_result(b);
} }
else if (b == 0.0) else if (b == 0.0)
{ {
SetFPException(&FPSCR, FPSCR_ZX); SetFPException(&PowerPC::ppcState.fpscr, FPSCR_ZX);
FPSCR.ClearFIFR(); PowerPC::ppcState.fpscr.ClearFIFR();
if (FPSCR.ZE == 0) if (PowerPC::ppcState.fpscr.ZE == 0)
compute_result(b); compute_result(b);
} }
else if (Common::IsSNAN(b)) else if (Common::IsSNAN(b))
{ {
SetFPException(&FPSCR, FPSCR_VXSNAN); SetFPException(&PowerPC::ppcState.fpscr, FPSCR_VXSNAN);
FPSCR.ClearFIFR(); PowerPC::ppcState.fpscr.ClearFIFR();
if (FPSCR.VE == 0) if (PowerPC::ppcState.fpscr.VE == 0)
compute_result(b); compute_result(b);
} }
else else
{ {
if (std::isnan(b) || std::isinf(b)) if (std::isnan(b) || std::isinf(b))
FPSCR.ClearFIFR(); PowerPC::ppcState.fpscr.ClearFIFR();
compute_result(b); compute_result(b);
} }
@@ -564,17 +569,18 @@ void Interpreter::frsqrtex(UGeckoInstruction inst)
void Interpreter::fmsubx(UGeckoInstruction inst) void Interpreter::fmsubx(UGeckoInstruction inst)
{ {
const auto& a = rPS(inst.FA); const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = rPS(inst.FB); const auto& b = PowerPC::ppcState.ps[inst.FB];
const auto& c = rPS(inst.FC); const auto& c = PowerPC::ppcState.ps[inst.FC];
const FPResult product = NI_msub(&FPSCR, a.PS0AsDouble(), c.PS0AsDouble(), b.PS0AsDouble()); const FPResult product =
NI_msub(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), c.PS0AsDouble(), b.PS0AsDouble());
if (FPSCR.VE == 0 || product.HasNoInvalidExceptions()) if (PowerPC::ppcState.fpscr.VE == 0 || product.HasNoInvalidExceptions())
{ {
const double result = ForceDouble(FPSCR, product.value); const double result = ForceDouble(PowerPC::ppcState.fpscr, product.value);
rPS(inst.FD).SetPS0(result); PowerPC::ppcState.ps[inst.FD].SetPS0(result);
PowerPC::UpdateFPRFDouble(result); PowerPC::ppcState.UpdateFPRFDouble(result);
} }
if (inst.Rc) if (inst.Rc)
@@ -583,18 +589,19 @@ void Interpreter::fmsubx(UGeckoInstruction inst)
void Interpreter::fmsubsx(UGeckoInstruction inst) void Interpreter::fmsubsx(UGeckoInstruction inst)
{ {
const auto& a = rPS(inst.FA); const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = rPS(inst.FB); const auto& b = PowerPC::ppcState.ps[inst.FB];
const auto& c = rPS(inst.FC); const auto& c = PowerPC::ppcState.ps[inst.FC];
const double c_value = Force25Bit(c.PS0AsDouble()); const double c_value = Force25Bit(c.PS0AsDouble());
const FPResult product = NI_msub(&FPSCR, a.PS0AsDouble(), c_value, b.PS0AsDouble()); const FPResult product =
NI_msub(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), c_value, b.PS0AsDouble());
if (FPSCR.VE == 0 || product.HasNoInvalidExceptions()) if (PowerPC::ppcState.fpscr.VE == 0 || product.HasNoInvalidExceptions())
{ {
const float result = ForceSingle(FPSCR, product.value); const float result = ForceSingle(PowerPC::ppcState.fpscr, product.value);
rPS(inst.FD).Fill(result); PowerPC::ppcState.ps[inst.FD].Fill(result);
PowerPC::UpdateFPRFSingle(result); PowerPC::ppcState.UpdateFPRFSingle(result);
} }
if (inst.Rc) if (inst.Rc)
@@ -603,19 +610,20 @@ void Interpreter::fmsubsx(UGeckoInstruction inst)
void Interpreter::fnmaddx(UGeckoInstruction inst) void Interpreter::fnmaddx(UGeckoInstruction inst)
{ {
const auto& a = rPS(inst.FA); const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = rPS(inst.FB); const auto& b = PowerPC::ppcState.ps[inst.FB];
const auto& c = rPS(inst.FC); const auto& c = PowerPC::ppcState.ps[inst.FC];
const FPResult product = NI_madd(&FPSCR, a.PS0AsDouble(), c.PS0AsDouble(), b.PS0AsDouble()); const FPResult product =
NI_madd(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), c.PS0AsDouble(), b.PS0AsDouble());
if (FPSCR.VE == 0 || product.HasNoInvalidExceptions()) if (PowerPC::ppcState.fpscr.VE == 0 || product.HasNoInvalidExceptions())
{ {
const double tmp = ForceDouble(FPSCR, product.value); const double tmp = ForceDouble(PowerPC::ppcState.fpscr, product.value);
const double result = std::isnan(tmp) ? tmp : -tmp; const double result = std::isnan(tmp) ? tmp : -tmp;
rPS(inst.FD).SetPS0(result); PowerPC::ppcState.ps[inst.FD].SetPS0(result);
PowerPC::UpdateFPRFDouble(result); PowerPC::ppcState.UpdateFPRFDouble(result);
} }
if (inst.Rc) if (inst.Rc)
@@ -624,20 +632,21 @@ void Interpreter::fnmaddx(UGeckoInstruction inst)
void Interpreter::fnmaddsx(UGeckoInstruction inst) void Interpreter::fnmaddsx(UGeckoInstruction inst)
{ {
const auto& a = rPS(inst.FA); const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = rPS(inst.FB); const auto& b = PowerPC::ppcState.ps[inst.FB];
const auto& c = rPS(inst.FC); const auto& c = PowerPC::ppcState.ps[inst.FC];
const double c_value = Force25Bit(c.PS0AsDouble()); const double c_value = Force25Bit(c.PS0AsDouble());
const FPResult product = NI_madd(&FPSCR, a.PS0AsDouble(), c_value, b.PS0AsDouble()); const FPResult product =
NI_madd(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), c_value, b.PS0AsDouble());
if (FPSCR.VE == 0 || product.HasNoInvalidExceptions()) if (PowerPC::ppcState.fpscr.VE == 0 || product.HasNoInvalidExceptions())
{ {
const float tmp = ForceSingle(FPSCR, product.value); const float tmp = ForceSingle(PowerPC::ppcState.fpscr, product.value);
const float result = std::isnan(tmp) ? tmp : -tmp; const float result = std::isnan(tmp) ? tmp : -tmp;
rPS(inst.FD).Fill(result); PowerPC::ppcState.ps[inst.FD].Fill(result);
PowerPC::UpdateFPRFSingle(result); PowerPC::ppcState.UpdateFPRFSingle(result);
} }
if (inst.Rc) if (inst.Rc)
@@ -646,19 +655,20 @@ void Interpreter::fnmaddsx(UGeckoInstruction inst)
void Interpreter::fnmsubx(UGeckoInstruction inst) void Interpreter::fnmsubx(UGeckoInstruction inst)
{ {
const auto& a = rPS(inst.FA); const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = rPS(inst.FB); const auto& b = PowerPC::ppcState.ps[inst.FB];
const auto& c = rPS(inst.FC); const auto& c = PowerPC::ppcState.ps[inst.FC];
const FPResult product = NI_msub(&FPSCR, a.PS0AsDouble(), c.PS0AsDouble(), b.PS0AsDouble()); const FPResult product =
NI_msub(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), c.PS0AsDouble(), b.PS0AsDouble());
if (FPSCR.VE == 0 || product.HasNoInvalidExceptions()) if (PowerPC::ppcState.fpscr.VE == 0 || product.HasNoInvalidExceptions())
{ {
const double tmp = ForceDouble(FPSCR, product.value); const double tmp = ForceDouble(PowerPC::ppcState.fpscr, product.value);
const double result = std::isnan(tmp) ? tmp : -tmp; const double result = std::isnan(tmp) ? tmp : -tmp;
rPS(inst.FD).SetPS0(result); PowerPC::ppcState.ps[inst.FD].SetPS0(result);
PowerPC::UpdateFPRFDouble(result); PowerPC::ppcState.UpdateFPRFDouble(result);
} }
if (inst.Rc) if (inst.Rc)
@@ -667,20 +677,21 @@ void Interpreter::fnmsubx(UGeckoInstruction inst)
void Interpreter::fnmsubsx(UGeckoInstruction inst) void Interpreter::fnmsubsx(UGeckoInstruction inst)
{ {
const auto& a = rPS(inst.FA); const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = rPS(inst.FB); const auto& b = PowerPC::ppcState.ps[inst.FB];
const auto& c = rPS(inst.FC); const auto& c = PowerPC::ppcState.ps[inst.FC];
const double c_value = Force25Bit(c.PS0AsDouble()); const double c_value = Force25Bit(c.PS0AsDouble());
const FPResult product = NI_msub(&FPSCR, a.PS0AsDouble(), c_value, b.PS0AsDouble()); const FPResult product =
NI_msub(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), c_value, b.PS0AsDouble());
if (FPSCR.VE == 0 || product.HasNoInvalidExceptions()) if (PowerPC::ppcState.fpscr.VE == 0 || product.HasNoInvalidExceptions())
{ {
const float tmp = ForceSingle(FPSCR, product.value); const float tmp = ForceSingle(PowerPC::ppcState.fpscr, product.value);
const float result = std::isnan(tmp) ? tmp : -tmp; const float result = std::isnan(tmp) ? tmp : -tmp;
rPS(inst.FD).Fill(result); PowerPC::ppcState.ps[inst.FD].Fill(result);
PowerPC::UpdateFPRFSingle(result); PowerPC::ppcState.UpdateFPRFSingle(result);
} }
if (inst.Rc) if (inst.Rc)
@@ -689,16 +700,16 @@ void Interpreter::fnmsubsx(UGeckoInstruction inst)
void Interpreter::fsubx(UGeckoInstruction inst) void Interpreter::fsubx(UGeckoInstruction inst)
{ {
const auto& a = rPS(inst.FA); const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = rPS(inst.FB); const auto& b = PowerPC::ppcState.ps[inst.FB];
const FPResult difference = NI_sub(&FPSCR, a.PS0AsDouble(), b.PS0AsDouble()); const FPResult difference = NI_sub(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), b.PS0AsDouble());
if (FPSCR.VE == 0 || difference.HasNoInvalidExceptions()) if (PowerPC::ppcState.fpscr.VE == 0 || difference.HasNoInvalidExceptions())
{ {
const double result = ForceDouble(FPSCR, difference.value); const double result = ForceDouble(PowerPC::ppcState.fpscr, difference.value);
rPS(inst.FD).SetPS0(result); PowerPC::ppcState.ps[inst.FD].SetPS0(result);
PowerPC::UpdateFPRFDouble(result); PowerPC::ppcState.UpdateFPRFDouble(result);
} }
if (inst.Rc) if (inst.Rc)
@@ -707,16 +718,16 @@ void Interpreter::fsubx(UGeckoInstruction inst)
void Interpreter::fsubsx(UGeckoInstruction inst) void Interpreter::fsubsx(UGeckoInstruction inst)
{ {
const auto& a = rPS(inst.FA); const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = rPS(inst.FB); const auto& b = PowerPC::ppcState.ps[inst.FB];
const FPResult difference = NI_sub(&FPSCR, a.PS0AsDouble(), b.PS0AsDouble()); const FPResult difference = NI_sub(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), b.PS0AsDouble());
if (FPSCR.VE == 0 || difference.HasNoInvalidExceptions()) if (PowerPC::ppcState.fpscr.VE == 0 || difference.HasNoInvalidExceptions())
{ {
const float result = ForceSingle(FPSCR, difference.value); const float result = ForceSingle(PowerPC::ppcState.fpscr, difference.value);
rPS(inst.FD).Fill(result); PowerPC::ppcState.ps[inst.FD].Fill(result);
PowerPC::UpdateFPRFSingle(result); PowerPC::ppcState.UpdateFPRFSingle(result);
} }
if (inst.Rc) if (inst.Rc)

View File

@@ -16,7 +16,7 @@ void Interpreter::Helper_UpdateCR0(u32 value)
const s64 sign_extended = s64{s32(value)}; const s64 sign_extended = s64{s32(value)};
u64 cr_val = u64(sign_extended); u64 cr_val = u64(sign_extended);
cr_val = (cr_val & ~(1ULL << PowerPC::CR_EMU_SO_BIT)) | cr_val = (cr_val & ~(1ULL << PowerPC::CR_EMU_SO_BIT)) |
(u64{PowerPC::GetXER_SO()} << PowerPC::CR_EMU_SO_BIT); (u64{PowerPC::ppcState.GetXER_SO()} << PowerPC::CR_EMU_SO_BIT);
PowerPC::ppcState.cr.fields[0] = cr_val; PowerPC::ppcState.cr.fields[0] = cr_val;
} }
@@ -29,44 +29,44 @@ u32 Interpreter::Helper_Carry(u32 value1, u32 value2)
void Interpreter::addi(UGeckoInstruction inst) void Interpreter::addi(UGeckoInstruction inst)
{ {
if (inst.RA) if (inst.RA)
rGPR[inst.RD] = rGPR[inst.RA] + u32(inst.SIMM_16); PowerPC::ppcState.gpr[inst.RD] = PowerPC::ppcState.gpr[inst.RA] + u32(inst.SIMM_16);
else else
rGPR[inst.RD] = u32(inst.SIMM_16); PowerPC::ppcState.gpr[inst.RD] = u32(inst.SIMM_16);
} }
void Interpreter::addic(UGeckoInstruction inst) void Interpreter::addic(UGeckoInstruction inst)
{ {
const u32 a = rGPR[inst.RA]; const u32 a = PowerPC::ppcState.gpr[inst.RA];
const u32 imm = u32(s32{inst.SIMM_16}); const u32 imm = u32(s32{inst.SIMM_16});
rGPR[inst.RD] = a + imm; PowerPC::ppcState.gpr[inst.RD] = a + imm;
PowerPC::SetCarry(Helper_Carry(a, imm)); PowerPC::ppcState.SetCarry(Helper_Carry(a, imm));
} }
void Interpreter::addic_rc(UGeckoInstruction inst) void Interpreter::addic_rc(UGeckoInstruction inst)
{ {
addic(inst); addic(inst);
Helper_UpdateCR0(rGPR[inst.RD]); Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RD]);
} }
void Interpreter::addis(UGeckoInstruction inst) void Interpreter::addis(UGeckoInstruction inst)
{ {
if (inst.RA) if (inst.RA)
rGPR[inst.RD] = rGPR[inst.RA] + u32(inst.SIMM_16 << 16); PowerPC::ppcState.gpr[inst.RD] = PowerPC::ppcState.gpr[inst.RA] + u32(inst.SIMM_16 << 16);
else else
rGPR[inst.RD] = u32(inst.SIMM_16 << 16); PowerPC::ppcState.gpr[inst.RD] = u32(inst.SIMM_16 << 16);
} }
void Interpreter::andi_rc(UGeckoInstruction inst) void Interpreter::andi_rc(UGeckoInstruction inst)
{ {
rGPR[inst.RA] = rGPR[inst.RS] & inst.UIMM; PowerPC::ppcState.gpr[inst.RA] = PowerPC::ppcState.gpr[inst.RS] & inst.UIMM;
Helper_UpdateCR0(rGPR[inst.RA]); Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
} }
void Interpreter::andis_rc(UGeckoInstruction inst) void Interpreter::andis_rc(UGeckoInstruction inst)
{ {
rGPR[inst.RA] = rGPR[inst.RS] & (u32{inst.UIMM} << 16); PowerPC::ppcState.gpr[inst.RA] = PowerPC::ppcState.gpr[inst.RS] & (u32{inst.UIMM} << 16);
Helper_UpdateCR0(rGPR[inst.RA]); Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
} }
template <typename T> template <typename T>
@@ -81,7 +81,7 @@ void Interpreter::Helper_IntCompare(UGeckoInstruction inst, T a, T b)
else else
cr_field = PowerPC::CR_EQ; cr_field = PowerPC::CR_EQ;
if (PowerPC::GetXER_SO()) if (PowerPC::ppcState.GetXER_SO())
cr_field |= PowerPC::CR_SO; cr_field |= PowerPC::CR_SO;
PowerPC::ppcState.cr.SetField(inst.CRFD, cr_field); PowerPC::ppcState.cr.SetField(inst.CRFD, cr_field);
@@ -89,43 +89,44 @@ void Interpreter::Helper_IntCompare(UGeckoInstruction inst, T a, T b)
void Interpreter::cmpi(UGeckoInstruction inst) void Interpreter::cmpi(UGeckoInstruction inst)
{ {
const s32 a = static_cast<s32>(rGPR[inst.RA]); const s32 a = static_cast<s32>(PowerPC::ppcState.gpr[inst.RA]);
const s32 b = inst.SIMM_16; const s32 b = inst.SIMM_16;
Helper_IntCompare(inst, a, b); Helper_IntCompare(inst, a, b);
} }
void Interpreter::cmpli(UGeckoInstruction inst) void Interpreter::cmpli(UGeckoInstruction inst)
{ {
const u32 a = rGPR[inst.RA]; const u32 a = PowerPC::ppcState.gpr[inst.RA];
const u32 b = inst.UIMM; const u32 b = inst.UIMM;
Helper_IntCompare(inst, a, b); Helper_IntCompare(inst, a, b);
} }
void Interpreter::mulli(UGeckoInstruction inst) void Interpreter::mulli(UGeckoInstruction inst)
{ {
rGPR[inst.RD] = u32(s32(rGPR[inst.RA]) * inst.SIMM_16); PowerPC::ppcState.gpr[inst.RD] = u32(s32(PowerPC::ppcState.gpr[inst.RA]) * inst.SIMM_16);
} }
void Interpreter::ori(UGeckoInstruction inst) void Interpreter::ori(UGeckoInstruction inst)
{ {
rGPR[inst.RA] = rGPR[inst.RS] | inst.UIMM; PowerPC::ppcState.gpr[inst.RA] = PowerPC::ppcState.gpr[inst.RS] | inst.UIMM;
} }
void Interpreter::oris(UGeckoInstruction inst) void Interpreter::oris(UGeckoInstruction inst)
{ {
rGPR[inst.RA] = rGPR[inst.RS] | (u32{inst.UIMM} << 16); PowerPC::ppcState.gpr[inst.RA] = PowerPC::ppcState.gpr[inst.RS] | (u32{inst.UIMM} << 16);
} }
void Interpreter::subfic(UGeckoInstruction inst) void Interpreter::subfic(UGeckoInstruction inst)
{ {
const s32 immediate = inst.SIMM_16; const s32 immediate = inst.SIMM_16;
rGPR[inst.RD] = u32(immediate - s32(rGPR[inst.RA])); PowerPC::ppcState.gpr[inst.RD] = u32(immediate - s32(PowerPC::ppcState.gpr[inst.RA]));
PowerPC::SetCarry((rGPR[inst.RA] == 0) || (Helper_Carry(0 - rGPR[inst.RA], u32(immediate)))); PowerPC::ppcState.SetCarry((PowerPC::ppcState.gpr[inst.RA] == 0) ||
(Helper_Carry(0 - PowerPC::ppcState.gpr[inst.RA], u32(immediate))));
} }
void Interpreter::twi(UGeckoInstruction inst) void Interpreter::twi(UGeckoInstruction inst)
{ {
const s32 a = s32(rGPR[inst.RA]); const s32 a = s32(PowerPC::ppcState.gpr[inst.RA]);
const s32 b = inst.SIMM_16; const s32 b = inst.SIMM_16;
const u32 TO = inst.TO; const u32 TO = inst.TO;
@@ -142,199 +143,207 @@ void Interpreter::twi(UGeckoInstruction inst)
void Interpreter::xori(UGeckoInstruction inst) void Interpreter::xori(UGeckoInstruction inst)
{ {
rGPR[inst.RA] = rGPR[inst.RS] ^ inst.UIMM; PowerPC::ppcState.gpr[inst.RA] = PowerPC::ppcState.gpr[inst.RS] ^ inst.UIMM;
} }
void Interpreter::xoris(UGeckoInstruction inst) void Interpreter::xoris(UGeckoInstruction inst)
{ {
rGPR[inst.RA] = rGPR[inst.RS] ^ (u32{inst.UIMM} << 16); PowerPC::ppcState.gpr[inst.RA] = PowerPC::ppcState.gpr[inst.RS] ^ (u32{inst.UIMM} << 16);
} }
void Interpreter::rlwimix(UGeckoInstruction inst) void Interpreter::rlwimix(UGeckoInstruction inst)
{ {
const u32 mask = MakeRotationMask(inst.MB, inst.ME); const u32 mask = MakeRotationMask(inst.MB, inst.ME);
rGPR[inst.RA] = (rGPR[inst.RA] & ~mask) | (std::rotl(rGPR[inst.RS], inst.SH) & mask); PowerPC::ppcState.gpr[inst.RA] = (PowerPC::ppcState.gpr[inst.RA] & ~mask) |
(std::rotl(PowerPC::ppcState.gpr[inst.RS], inst.SH) & mask);
if (inst.Rc) if (inst.Rc)
Helper_UpdateCR0(rGPR[inst.RA]); Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
} }
void Interpreter::rlwinmx(UGeckoInstruction inst) void Interpreter::rlwinmx(UGeckoInstruction inst)
{ {
const u32 mask = MakeRotationMask(inst.MB, inst.ME); const u32 mask = MakeRotationMask(inst.MB, inst.ME);
rGPR[inst.RA] = std::rotl(rGPR[inst.RS], inst.SH) & mask; PowerPC::ppcState.gpr[inst.RA] = std::rotl(PowerPC::ppcState.gpr[inst.RS], inst.SH) & mask;
if (inst.Rc) if (inst.Rc)
Helper_UpdateCR0(rGPR[inst.RA]); Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
} }
void Interpreter::rlwnmx(UGeckoInstruction inst) void Interpreter::rlwnmx(UGeckoInstruction inst)
{ {
const u32 mask = MakeRotationMask(inst.MB, inst.ME); const u32 mask = MakeRotationMask(inst.MB, inst.ME);
rGPR[inst.RA] = std::rotl(rGPR[inst.RS], rGPR[inst.RB] & 0x1F) & mask; PowerPC::ppcState.gpr[inst.RA] =
std::rotl(PowerPC::ppcState.gpr[inst.RS], PowerPC::ppcState.gpr[inst.RB] & 0x1F) & mask;
if (inst.Rc) if (inst.Rc)
Helper_UpdateCR0(rGPR[inst.RA]); Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
} }
void Interpreter::andx(UGeckoInstruction inst) void Interpreter::andx(UGeckoInstruction inst)
{ {
rGPR[inst.RA] = rGPR[inst.RS] & rGPR[inst.RB]; PowerPC::ppcState.gpr[inst.RA] = PowerPC::ppcState.gpr[inst.RS] & PowerPC::ppcState.gpr[inst.RB];
if (inst.Rc) if (inst.Rc)
Helper_UpdateCR0(rGPR[inst.RA]); Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
} }
void Interpreter::andcx(UGeckoInstruction inst) void Interpreter::andcx(UGeckoInstruction inst)
{ {
rGPR[inst.RA] = rGPR[inst.RS] & ~rGPR[inst.RB]; PowerPC::ppcState.gpr[inst.RA] = PowerPC::ppcState.gpr[inst.RS] & ~PowerPC::ppcState.gpr[inst.RB];
if (inst.Rc) if (inst.Rc)
Helper_UpdateCR0(rGPR[inst.RA]); Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
} }
void Interpreter::cmp(UGeckoInstruction inst) void Interpreter::cmp(UGeckoInstruction inst)
{ {
const s32 a = static_cast<s32>(rGPR[inst.RA]); const s32 a = static_cast<s32>(PowerPC::ppcState.gpr[inst.RA]);
const s32 b = static_cast<s32>(rGPR[inst.RB]); const s32 b = static_cast<s32>(PowerPC::ppcState.gpr[inst.RB]);
Helper_IntCompare(inst, a, b); Helper_IntCompare(inst, a, b);
} }
void Interpreter::cmpl(UGeckoInstruction inst) void Interpreter::cmpl(UGeckoInstruction inst)
{ {
const u32 a = rGPR[inst.RA]; const u32 a = PowerPC::ppcState.gpr[inst.RA];
const u32 b = rGPR[inst.RB]; const u32 b = PowerPC::ppcState.gpr[inst.RB];
Helper_IntCompare(inst, a, b); Helper_IntCompare(inst, a, b);
} }
void Interpreter::cntlzwx(UGeckoInstruction inst) void Interpreter::cntlzwx(UGeckoInstruction inst)
{ {
rGPR[inst.RA] = u32(std::countl_zero(rGPR[inst.RS])); PowerPC::ppcState.gpr[inst.RA] = u32(std::countl_zero(PowerPC::ppcState.gpr[inst.RS]));
if (inst.Rc) if (inst.Rc)
Helper_UpdateCR0(rGPR[inst.RA]); Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
} }
void Interpreter::eqvx(UGeckoInstruction inst) void Interpreter::eqvx(UGeckoInstruction inst)
{ {
rGPR[inst.RA] = ~(rGPR[inst.RS] ^ rGPR[inst.RB]); PowerPC::ppcState.gpr[inst.RA] =
~(PowerPC::ppcState.gpr[inst.RS] ^ PowerPC::ppcState.gpr[inst.RB]);
if (inst.Rc) if (inst.Rc)
Helper_UpdateCR0(rGPR[inst.RA]); Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
} }
void Interpreter::extsbx(UGeckoInstruction inst) void Interpreter::extsbx(UGeckoInstruction inst)
{ {
rGPR[inst.RA] = u32(s32(s8(rGPR[inst.RS]))); PowerPC::ppcState.gpr[inst.RA] = u32(s32(s8(PowerPC::ppcState.gpr[inst.RS])));
if (inst.Rc) if (inst.Rc)
Helper_UpdateCR0(rGPR[inst.RA]); Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
} }
void Interpreter::extshx(UGeckoInstruction inst) void Interpreter::extshx(UGeckoInstruction inst)
{ {
rGPR[inst.RA] = u32(s32(s16(rGPR[inst.RS]))); PowerPC::ppcState.gpr[inst.RA] = u32(s32(s16(PowerPC::ppcState.gpr[inst.RS])));
if (inst.Rc) if (inst.Rc)
Helper_UpdateCR0(rGPR[inst.RA]); Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
} }
void Interpreter::nandx(UGeckoInstruction inst) void Interpreter::nandx(UGeckoInstruction inst)
{ {
rGPR[inst.RA] = ~(rGPR[inst.RS] & rGPR[inst.RB]); PowerPC::ppcState.gpr[inst.RA] =
~(PowerPC::ppcState.gpr[inst.RS] & PowerPC::ppcState.gpr[inst.RB]);
if (inst.Rc) if (inst.Rc)
Helper_UpdateCR0(rGPR[inst.RA]); Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
} }
void Interpreter::norx(UGeckoInstruction inst) void Interpreter::norx(UGeckoInstruction inst)
{ {
rGPR[inst.RA] = ~(rGPR[inst.RS] | rGPR[inst.RB]); PowerPC::ppcState.gpr[inst.RA] =
~(PowerPC::ppcState.gpr[inst.RS] | PowerPC::ppcState.gpr[inst.RB]);
if (inst.Rc) if (inst.Rc)
Helper_UpdateCR0(rGPR[inst.RA]); Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
} }
void Interpreter::orx(UGeckoInstruction inst) void Interpreter::orx(UGeckoInstruction inst)
{ {
rGPR[inst.RA] = rGPR[inst.RS] | rGPR[inst.RB]; PowerPC::ppcState.gpr[inst.RA] = PowerPC::ppcState.gpr[inst.RS] | PowerPC::ppcState.gpr[inst.RB];
if (inst.Rc) if (inst.Rc)
Helper_UpdateCR0(rGPR[inst.RA]); Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
} }
void Interpreter::orcx(UGeckoInstruction inst) void Interpreter::orcx(UGeckoInstruction inst)
{ {
rGPR[inst.RA] = rGPR[inst.RS] | (~rGPR[inst.RB]); PowerPC::ppcState.gpr[inst.RA] =
PowerPC::ppcState.gpr[inst.RS] | (~PowerPC::ppcState.gpr[inst.RB]);
if (inst.Rc) if (inst.Rc)
Helper_UpdateCR0(rGPR[inst.RA]); Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
} }
void Interpreter::slwx(UGeckoInstruction inst) void Interpreter::slwx(UGeckoInstruction inst)
{ {
const u32 amount = rGPR[inst.RB]; const u32 amount = PowerPC::ppcState.gpr[inst.RB];
rGPR[inst.RA] = (amount & 0x20) != 0 ? 0 : rGPR[inst.RS] << (amount & 0x1f); PowerPC::ppcState.gpr[inst.RA] =
(amount & 0x20) != 0 ? 0 : PowerPC::ppcState.gpr[inst.RS] << (amount & 0x1f);
if (inst.Rc) if (inst.Rc)
Helper_UpdateCR0(rGPR[inst.RA]); Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
} }
void Interpreter::srawx(UGeckoInstruction inst) void Interpreter::srawx(UGeckoInstruction inst)
{ {
const u32 rb = rGPR[inst.RB]; const u32 rb = PowerPC::ppcState.gpr[inst.RB];
if ((rb & 0x20) != 0) if ((rb & 0x20) != 0)
{ {
if ((rGPR[inst.RS] & 0x80000000) != 0) if ((PowerPC::ppcState.gpr[inst.RS] & 0x80000000) != 0)
{ {
rGPR[inst.RA] = 0xFFFFFFFF; PowerPC::ppcState.gpr[inst.RA] = 0xFFFFFFFF;
PowerPC::SetCarry(1); PowerPC::ppcState.SetCarry(1);
} }
else else
{ {
rGPR[inst.RA] = 0x00000000; PowerPC::ppcState.gpr[inst.RA] = 0x00000000;
PowerPC::SetCarry(0); PowerPC::ppcState.SetCarry(0);
} }
} }
else else
{ {
const u32 amount = rb & 0x1f; const u32 amount = rb & 0x1f;
const s32 rrs = s32(rGPR[inst.RS]); const s32 rrs = s32(PowerPC::ppcState.gpr[inst.RS]);
rGPR[inst.RA] = u32(rrs >> amount); PowerPC::ppcState.gpr[inst.RA] = u32(rrs >> amount);
PowerPC::SetCarry(rrs < 0 && amount > 0 && (u32(rrs) << (32 - amount)) != 0); PowerPC::ppcState.SetCarry(rrs < 0 && amount > 0 && (u32(rrs) << (32 - amount)) != 0);
} }
if (inst.Rc) if (inst.Rc)
Helper_UpdateCR0(rGPR[inst.RA]); Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
} }
void Interpreter::srawix(UGeckoInstruction inst) void Interpreter::srawix(UGeckoInstruction inst)
{ {
const u32 amount = inst.SH; const u32 amount = inst.SH;
const s32 rrs = s32(rGPR[inst.RS]); const s32 rrs = s32(PowerPC::ppcState.gpr[inst.RS]);
rGPR[inst.RA] = u32(rrs >> amount); PowerPC::ppcState.gpr[inst.RA] = u32(rrs >> amount);
PowerPC::SetCarry(rrs < 0 && amount > 0 && (u32(rrs) << (32 - amount)) != 0); PowerPC::ppcState.SetCarry(rrs < 0 && amount > 0 && (u32(rrs) << (32 - amount)) != 0);
if (inst.Rc) if (inst.Rc)
Helper_UpdateCR0(rGPR[inst.RA]); Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
} }
void Interpreter::srwx(UGeckoInstruction inst) void Interpreter::srwx(UGeckoInstruction inst)
{ {
const u32 amount = rGPR[inst.RB]; const u32 amount = PowerPC::ppcState.gpr[inst.RB];
rGPR[inst.RA] = (amount & 0x20) != 0 ? 0 : (rGPR[inst.RS] >> (amount & 0x1f)); PowerPC::ppcState.gpr[inst.RA] =
(amount & 0x20) != 0 ? 0 : (PowerPC::ppcState.gpr[inst.RS] >> (amount & 0x1f));
if (inst.Rc) if (inst.Rc)
Helper_UpdateCR0(rGPR[inst.RA]); Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
} }
void Interpreter::tw(UGeckoInstruction inst) void Interpreter::tw(UGeckoInstruction inst)
{ {
const s32 a = s32(rGPR[inst.RA]); const s32 a = s32(PowerPC::ppcState.gpr[inst.RA]);
const s32 b = s32(rGPR[inst.RB]); const s32 b = s32(PowerPC::ppcState.gpr[inst.RB]);
const u32 TO = inst.TO; const u32 TO = inst.TO;
DEBUG_LOG_FMT(POWERPC, "tw rA {:x} rB {:x} TO {:x}", a, b, TO); DEBUG_LOG_FMT(POWERPC, "tw rA {:x} rB {:x} TO {:x}", a, b, TO);
@@ -350,10 +359,10 @@ void Interpreter::tw(UGeckoInstruction inst)
void Interpreter::xorx(UGeckoInstruction inst) void Interpreter::xorx(UGeckoInstruction inst)
{ {
rGPR[inst.RA] = rGPR[inst.RS] ^ rGPR[inst.RB]; PowerPC::ppcState.gpr[inst.RA] = PowerPC::ppcState.gpr[inst.RS] ^ PowerPC::ppcState.gpr[inst.RB];
if (inst.Rc) if (inst.Rc)
Helper_UpdateCR0(rGPR[inst.RA]); Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
} }
static bool HasAddOverflowed(u32 x, u32 y, u32 result) static bool HasAddOverflowed(u32 x, u32 y, u32 result)
@@ -365,14 +374,14 @@ static bool HasAddOverflowed(u32 x, u32 y, u32 result)
void Interpreter::addx(UGeckoInstruction inst) void Interpreter::addx(UGeckoInstruction inst)
{ {
const u32 a = rGPR[inst.RA]; const u32 a = PowerPC::ppcState.gpr[inst.RA];
const u32 b = rGPR[inst.RB]; const u32 b = PowerPC::ppcState.gpr[inst.RB];
const u32 result = a + b; const u32 result = a + b;
rGPR[inst.RD] = result; PowerPC::ppcState.gpr[inst.RD] = result;
if (inst.OE) if (inst.OE)
PowerPC::SetXER_OV(HasAddOverflowed(a, b, result)); PowerPC::ppcState.SetXER_OV(HasAddOverflowed(a, b, result));
if (inst.Rc) if (inst.Rc)
Helper_UpdateCR0(result); Helper_UpdateCR0(result);
@@ -380,15 +389,15 @@ void Interpreter::addx(UGeckoInstruction inst)
void Interpreter::addcx(UGeckoInstruction inst) void Interpreter::addcx(UGeckoInstruction inst)
{ {
const u32 a = rGPR[inst.RA]; const u32 a = PowerPC::ppcState.gpr[inst.RA];
const u32 b = rGPR[inst.RB]; const u32 b = PowerPC::ppcState.gpr[inst.RB];
const u32 result = a + b; const u32 result = a + b;
rGPR[inst.RD] = result; PowerPC::ppcState.gpr[inst.RD] = result;
PowerPC::SetCarry(Helper_Carry(a, b)); PowerPC::ppcState.SetCarry(Helper_Carry(a, b));
if (inst.OE) if (inst.OE)
PowerPC::SetXER_OV(HasAddOverflowed(a, b, result)); PowerPC::ppcState.SetXER_OV(HasAddOverflowed(a, b, result));
if (inst.Rc) if (inst.Rc)
Helper_UpdateCR0(result); Helper_UpdateCR0(result);
@@ -396,16 +405,16 @@ void Interpreter::addcx(UGeckoInstruction inst)
void Interpreter::addex(UGeckoInstruction inst) void Interpreter::addex(UGeckoInstruction inst)
{ {
const u32 carry = PowerPC::GetCarry(); const u32 carry = PowerPC::ppcState.GetCarry();
const u32 a = rGPR[inst.RA]; const u32 a = PowerPC::ppcState.gpr[inst.RA];
const u32 b = rGPR[inst.RB]; const u32 b = PowerPC::ppcState.gpr[inst.RB];
const u32 result = a + b + carry; const u32 result = a + b + carry;
rGPR[inst.RD] = result; PowerPC::ppcState.gpr[inst.RD] = result;
PowerPC::SetCarry(Helper_Carry(a, b) || (carry != 0 && Helper_Carry(a + b, carry))); PowerPC::ppcState.SetCarry(Helper_Carry(a, b) || (carry != 0 && Helper_Carry(a + b, carry)));
if (inst.OE) if (inst.OE)
PowerPC::SetXER_OV(HasAddOverflowed(a, b, result)); PowerPC::ppcState.SetXER_OV(HasAddOverflowed(a, b, result));
if (inst.Rc) if (inst.Rc)
Helper_UpdateCR0(result); Helper_UpdateCR0(result);
@@ -413,16 +422,16 @@ void Interpreter::addex(UGeckoInstruction inst)
void Interpreter::addmex(UGeckoInstruction inst) void Interpreter::addmex(UGeckoInstruction inst)
{ {
const u32 carry = PowerPC::GetCarry(); const u32 carry = PowerPC::ppcState.GetCarry();
const u32 a = rGPR[inst.RA]; const u32 a = PowerPC::ppcState.gpr[inst.RA];
const u32 b = 0xFFFFFFFF; const u32 b = 0xFFFFFFFF;
const u32 result = a + b + carry; const u32 result = a + b + carry;
rGPR[inst.RD] = result; PowerPC::ppcState.gpr[inst.RD] = result;
PowerPC::SetCarry(Helper_Carry(a, carry - 1)); PowerPC::ppcState.SetCarry(Helper_Carry(a, carry - 1));
if (inst.OE) if (inst.OE)
PowerPC::SetXER_OV(HasAddOverflowed(a, b, result)); PowerPC::ppcState.SetXER_OV(HasAddOverflowed(a, b, result));
if (inst.Rc) if (inst.Rc)
Helper_UpdateCR0(result); Helper_UpdateCR0(result);
@@ -430,15 +439,15 @@ void Interpreter::addmex(UGeckoInstruction inst)
void Interpreter::addzex(UGeckoInstruction inst) void Interpreter::addzex(UGeckoInstruction inst)
{ {
const u32 carry = PowerPC::GetCarry(); const u32 carry = PowerPC::ppcState.GetCarry();
const u32 a = rGPR[inst.RA]; const u32 a = PowerPC::ppcState.gpr[inst.RA];
const u32 result = a + carry; const u32 result = a + carry;
rGPR[inst.RD] = result; PowerPC::ppcState.gpr[inst.RD] = result;
PowerPC::SetCarry(Helper_Carry(a, carry)); PowerPC::ppcState.SetCarry(Helper_Carry(a, carry));
if (inst.OE) if (inst.OE)
PowerPC::SetXER_OV(HasAddOverflowed(a, 0, result)); PowerPC::ppcState.SetXER_OV(HasAddOverflowed(a, 0, result));
if (inst.Rc) if (inst.Rc)
Helper_UpdateCR0(result); Helper_UpdateCR0(result);
@@ -446,58 +455,58 @@ void Interpreter::addzex(UGeckoInstruction inst)
void Interpreter::divwx(UGeckoInstruction inst) void Interpreter::divwx(UGeckoInstruction inst)
{ {
const auto a = s32(rGPR[inst.RA]); const auto a = s32(PowerPC::ppcState.gpr[inst.RA]);
const auto b = s32(rGPR[inst.RB]); const auto b = s32(PowerPC::ppcState.gpr[inst.RB]);
const bool overflow = b == 0 || (static_cast<u32>(a) == 0x80000000 && b == -1); const bool overflow = b == 0 || (static_cast<u32>(a) == 0x80000000 && b == -1);
if (overflow) if (overflow)
{ {
if (a < 0) if (a < 0)
rGPR[inst.RD] = UINT32_MAX; PowerPC::ppcState.gpr[inst.RD] = UINT32_MAX;
else else
rGPR[inst.RD] = 0; PowerPC::ppcState.gpr[inst.RD] = 0;
} }
else else
{ {
rGPR[inst.RD] = static_cast<u32>(a / b); PowerPC::ppcState.gpr[inst.RD] = static_cast<u32>(a / b);
} }
if (inst.OE) if (inst.OE)
PowerPC::SetXER_OV(overflow); PowerPC::ppcState.SetXER_OV(overflow);
if (inst.Rc) if (inst.Rc)
Helper_UpdateCR0(rGPR[inst.RD]); Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RD]);
} }
void Interpreter::divwux(UGeckoInstruction inst) void Interpreter::divwux(UGeckoInstruction inst)
{ {
const u32 a = rGPR[inst.RA]; const u32 a = PowerPC::ppcState.gpr[inst.RA];
const u32 b = rGPR[inst.RB]; const u32 b = PowerPC::ppcState.gpr[inst.RB];
const bool overflow = b == 0; const bool overflow = b == 0;
if (overflow) if (overflow)
{ {
rGPR[inst.RD] = 0; PowerPC::ppcState.gpr[inst.RD] = 0;
} }
else else
{ {
rGPR[inst.RD] = a / b; PowerPC::ppcState.gpr[inst.RD] = a / b;
} }
if (inst.OE) if (inst.OE)
PowerPC::SetXER_OV(overflow); PowerPC::ppcState.SetXER_OV(overflow);
if (inst.Rc) if (inst.Rc)
Helper_UpdateCR0(rGPR[inst.RD]); Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RD]);
} }
void Interpreter::mulhwx(UGeckoInstruction inst) void Interpreter::mulhwx(UGeckoInstruction inst)
{ {
const s64 a = static_cast<s32>(rGPR[inst.RA]); const s64 a = static_cast<s32>(PowerPC::ppcState.gpr[inst.RA]);
const s64 b = static_cast<s32>(rGPR[inst.RB]); const s64 b = static_cast<s32>(PowerPC::ppcState.gpr[inst.RB]);
const u32 d = static_cast<u32>((a * b) >> 32); const u32 d = static_cast<u32>((a * b) >> 32);
rGPR[inst.RD] = d; PowerPC::ppcState.gpr[inst.RD] = d;
if (inst.Rc) if (inst.Rc)
Helper_UpdateCR0(d); Helper_UpdateCR0(d);
@@ -505,11 +514,11 @@ void Interpreter::mulhwx(UGeckoInstruction inst)
void Interpreter::mulhwux(UGeckoInstruction inst) void Interpreter::mulhwux(UGeckoInstruction inst)
{ {
const u64 a = rGPR[inst.RA]; const u64 a = PowerPC::ppcState.gpr[inst.RA];
const u64 b = rGPR[inst.RB]; const u64 b = PowerPC::ppcState.gpr[inst.RB];
const u32 d = static_cast<u32>((a * b) >> 32); const u32 d = static_cast<u32>((a * b) >> 32);
rGPR[inst.RD] = d; PowerPC::ppcState.gpr[inst.RD] = d;
if (inst.Rc) if (inst.Rc)
Helper_UpdateCR0(d); Helper_UpdateCR0(d);
@@ -517,42 +526,42 @@ void Interpreter::mulhwux(UGeckoInstruction inst)
void Interpreter::mullwx(UGeckoInstruction inst) void Interpreter::mullwx(UGeckoInstruction inst)
{ {
const s64 a = static_cast<s32>(rGPR[inst.RA]); const s64 a = static_cast<s32>(PowerPC::ppcState.gpr[inst.RA]);
const s64 b = static_cast<s32>(rGPR[inst.RB]); const s64 b = static_cast<s32>(PowerPC::ppcState.gpr[inst.RB]);
const s64 result = a * b; const s64 result = a * b;
rGPR[inst.RD] = static_cast<u32>(result); PowerPC::ppcState.gpr[inst.RD] = static_cast<u32>(result);
if (inst.OE) if (inst.OE)
PowerPC::SetXER_OV(result < -0x80000000LL || result > 0x7FFFFFFFLL); PowerPC::ppcState.SetXER_OV(result < -0x80000000LL || result > 0x7FFFFFFFLL);
if (inst.Rc) if (inst.Rc)
Helper_UpdateCR0(rGPR[inst.RD]); Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RD]);
} }
void Interpreter::negx(UGeckoInstruction inst) void Interpreter::negx(UGeckoInstruction inst)
{ {
const u32 a = rGPR[inst.RA]; const u32 a = PowerPC::ppcState.gpr[inst.RA];
rGPR[inst.RD] = (~a) + 1; PowerPC::ppcState.gpr[inst.RD] = (~a) + 1;
if (inst.OE) if (inst.OE)
PowerPC::SetXER_OV(a == 0x80000000); PowerPC::ppcState.SetXER_OV(a == 0x80000000);
if (inst.Rc) if (inst.Rc)
Helper_UpdateCR0(rGPR[inst.RD]); Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RD]);
} }
void Interpreter::subfx(UGeckoInstruction inst) void Interpreter::subfx(UGeckoInstruction inst)
{ {
const u32 a = ~rGPR[inst.RA]; const u32 a = ~PowerPC::ppcState.gpr[inst.RA];
const u32 b = rGPR[inst.RB]; const u32 b = PowerPC::ppcState.gpr[inst.RB];
const u32 result = a + b + 1; const u32 result = a + b + 1;
rGPR[inst.RD] = result; PowerPC::ppcState.gpr[inst.RD] = result;
if (inst.OE) if (inst.OE)
PowerPC::SetXER_OV(HasAddOverflowed(a, b, result)); PowerPC::ppcState.SetXER_OV(HasAddOverflowed(a, b, result));
if (inst.Rc) if (inst.Rc)
Helper_UpdateCR0(result); Helper_UpdateCR0(result);
@@ -560,15 +569,15 @@ void Interpreter::subfx(UGeckoInstruction inst)
void Interpreter::subfcx(UGeckoInstruction inst) void Interpreter::subfcx(UGeckoInstruction inst)
{ {
const u32 a = ~rGPR[inst.RA]; const u32 a = ~PowerPC::ppcState.gpr[inst.RA];
const u32 b = rGPR[inst.RB]; const u32 b = PowerPC::ppcState.gpr[inst.RB];
const u32 result = a + b + 1; const u32 result = a + b + 1;
rGPR[inst.RD] = result; PowerPC::ppcState.gpr[inst.RD] = result;
PowerPC::SetCarry(a == 0xFFFFFFFF || Helper_Carry(b, a + 1)); PowerPC::ppcState.SetCarry(a == 0xFFFFFFFF || Helper_Carry(b, a + 1));
if (inst.OE) if (inst.OE)
PowerPC::SetXER_OV(HasAddOverflowed(a, b, result)); PowerPC::ppcState.SetXER_OV(HasAddOverflowed(a, b, result));
if (inst.Rc) if (inst.Rc)
Helper_UpdateCR0(result); Helper_UpdateCR0(result);
@@ -576,16 +585,16 @@ void Interpreter::subfcx(UGeckoInstruction inst)
void Interpreter::subfex(UGeckoInstruction inst) void Interpreter::subfex(UGeckoInstruction inst)
{ {
const u32 a = ~rGPR[inst.RA]; const u32 a = ~PowerPC::ppcState.gpr[inst.RA];
const u32 b = rGPR[inst.RB]; const u32 b = PowerPC::ppcState.gpr[inst.RB];
const u32 carry = PowerPC::GetCarry(); const u32 carry = PowerPC::ppcState.GetCarry();
const u32 result = a + b + carry; const u32 result = a + b + carry;
rGPR[inst.RD] = result; PowerPC::ppcState.gpr[inst.RD] = result;
PowerPC::SetCarry(Helper_Carry(a, b) || Helper_Carry(a + b, carry)); PowerPC::ppcState.SetCarry(Helper_Carry(a, b) || Helper_Carry(a + b, carry));
if (inst.OE) if (inst.OE)
PowerPC::SetXER_OV(HasAddOverflowed(a, b, result)); PowerPC::ppcState.SetXER_OV(HasAddOverflowed(a, b, result));
if (inst.Rc) if (inst.Rc)
Helper_UpdateCR0(result); Helper_UpdateCR0(result);
@@ -594,16 +603,16 @@ void Interpreter::subfex(UGeckoInstruction inst)
// sub from minus one // sub from minus one
void Interpreter::subfmex(UGeckoInstruction inst) void Interpreter::subfmex(UGeckoInstruction inst)
{ {
const u32 a = ~rGPR[inst.RA]; const u32 a = ~PowerPC::ppcState.gpr[inst.RA];
const u32 b = 0xFFFFFFFF; const u32 b = 0xFFFFFFFF;
const u32 carry = PowerPC::GetCarry(); const u32 carry = PowerPC::ppcState.GetCarry();
const u32 result = a + b + carry; const u32 result = a + b + carry;
rGPR[inst.RD] = result; PowerPC::ppcState.gpr[inst.RD] = result;
PowerPC::SetCarry(Helper_Carry(a, carry - 1)); PowerPC::ppcState.SetCarry(Helper_Carry(a, carry - 1));
if (inst.OE) if (inst.OE)
PowerPC::SetXER_OV(HasAddOverflowed(a, b, result)); PowerPC::ppcState.SetXER_OV(HasAddOverflowed(a, b, result));
if (inst.Rc) if (inst.Rc)
Helper_UpdateCR0(result); Helper_UpdateCR0(result);
@@ -612,15 +621,15 @@ void Interpreter::subfmex(UGeckoInstruction inst)
// sub from zero // sub from zero
void Interpreter::subfzex(UGeckoInstruction inst) void Interpreter::subfzex(UGeckoInstruction inst)
{ {
const u32 a = ~rGPR[inst.RA]; const u32 a = ~PowerPC::ppcState.gpr[inst.RA];
const u32 carry = PowerPC::GetCarry(); const u32 carry = PowerPC::ppcState.GetCarry();
const u32 result = a + carry; const u32 result = a + carry;
rGPR[inst.RD] = result; PowerPC::ppcState.gpr[inst.RD] = result;
PowerPC::SetCarry(Helper_Carry(a, carry)); PowerPC::ppcState.SetCarry(Helper_Carry(a, carry));
if (inst.OE) if (inst.OE)
PowerPC::SetXER_OV(HasAddOverflowed(a, 0, result)); PowerPC::ppcState.SetXER_OV(HasAddOverflowed(a, 0, result));
if (inst.Rc) if (inst.Rc)
Helper_UpdateCR0(result); Helper_UpdateCR0(result);

View File

@@ -42,7 +42,7 @@ void Interpreter::lbz(UGeckoInstruction inst)
const u32 temp = PowerPC::Read_U8(Helper_Get_EA(PowerPC::ppcState, inst)); const u32 temp = PowerPC::Read_U8(Helper_Get_EA(PowerPC::ppcState, inst));
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
rGPR[inst.RD] = temp; PowerPC::ppcState.gpr[inst.RD] = temp;
} }
void Interpreter::lbzu(UGeckoInstruction inst) void Interpreter::lbzu(UGeckoInstruction inst)
@@ -52,8 +52,8 @@ void Interpreter::lbzu(UGeckoInstruction inst)
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{ {
rGPR[inst.RD] = temp; PowerPC::ppcState.gpr[inst.RD] = temp;
rGPR[inst.RA] = address; PowerPC::ppcState.gpr[inst.RA] = address;
} }
} }
@@ -70,7 +70,7 @@ void Interpreter::lfd(UGeckoInstruction inst)
const u64 temp = PowerPC::Read_U64(address); const u64 temp = PowerPC::Read_U64(address);
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
rPS(inst.FD).SetPS0(temp); PowerPC::ppcState.ps[inst.FD].SetPS0(temp);
} }
void Interpreter::lfdu(UGeckoInstruction inst) void Interpreter::lfdu(UGeckoInstruction inst)
@@ -87,8 +87,8 @@ void Interpreter::lfdu(UGeckoInstruction inst)
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{ {
rPS(inst.FD).SetPS0(temp); PowerPC::ppcState.ps[inst.FD].SetPS0(temp);
rGPR[inst.RA] = address; PowerPC::ppcState.gpr[inst.RA] = address;
} }
} }
@@ -106,8 +106,8 @@ void Interpreter::lfdux(UGeckoInstruction inst)
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{ {
rPS(inst.FD).SetPS0(temp); PowerPC::ppcState.ps[inst.FD].SetPS0(temp);
rGPR[inst.RA] = address; PowerPC::ppcState.gpr[inst.RA] = address;
} }
} }
@@ -124,7 +124,7 @@ void Interpreter::lfdx(UGeckoInstruction inst)
const u64 temp = PowerPC::Read_U64(address); const u64 temp = PowerPC::Read_U64(address);
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
rPS(inst.FD).SetPS0(temp); PowerPC::ppcState.ps[inst.FD].SetPS0(temp);
} }
void Interpreter::lfs(UGeckoInstruction inst) void Interpreter::lfs(UGeckoInstruction inst)
@@ -142,7 +142,7 @@ void Interpreter::lfs(UGeckoInstruction inst)
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{ {
const u64 value = ConvertToDouble(temp); const u64 value = ConvertToDouble(temp);
rPS(inst.FD).Fill(value); PowerPC::ppcState.ps[inst.FD].Fill(value);
} }
} }
@@ -161,8 +161,8 @@ void Interpreter::lfsu(UGeckoInstruction inst)
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{ {
const u64 value = ConvertToDouble(temp); const u64 value = ConvertToDouble(temp);
rPS(inst.FD).Fill(value); PowerPC::ppcState.ps[inst.FD].Fill(value);
rGPR[inst.RA] = address; PowerPC::ppcState.gpr[inst.RA] = address;
} }
} }
@@ -181,8 +181,8 @@ void Interpreter::lfsux(UGeckoInstruction inst)
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{ {
const u64 value = ConvertToDouble(temp); const u64 value = ConvertToDouble(temp);
rPS(inst.FD).Fill(value); PowerPC::ppcState.ps[inst.FD].Fill(value);
rGPR[inst.RA] = address; PowerPC::ppcState.gpr[inst.RA] = address;
} }
} }
@@ -201,7 +201,7 @@ void Interpreter::lfsx(UGeckoInstruction inst)
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{ {
const u64 value = ConvertToDouble(temp); const u64 value = ConvertToDouble(temp);
rPS(inst.FD).Fill(value); PowerPC::ppcState.ps[inst.FD].Fill(value);
} }
} }
@@ -211,7 +211,7 @@ void Interpreter::lha(UGeckoInstruction inst)
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{ {
rGPR[inst.RD] = temp; PowerPC::ppcState.gpr[inst.RD] = temp;
} }
} }
@@ -222,8 +222,8 @@ void Interpreter::lhau(UGeckoInstruction inst)
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{ {
rGPR[inst.RD] = temp; PowerPC::ppcState.gpr[inst.RD] = temp;
rGPR[inst.RA] = address; PowerPC::ppcState.gpr[inst.RA] = address;
} }
} }
@@ -233,7 +233,7 @@ void Interpreter::lhz(UGeckoInstruction inst)
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{ {
rGPR[inst.RD] = temp; PowerPC::ppcState.gpr[inst.RD] = temp;
} }
} }
@@ -244,8 +244,8 @@ void Interpreter::lhzu(UGeckoInstruction inst)
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{ {
rGPR[inst.RD] = temp; PowerPC::ppcState.gpr[inst.RD] = temp;
rGPR[inst.RA] = address; PowerPC::ppcState.gpr[inst.RA] = address;
} }
} }
@@ -254,7 +254,7 @@ void Interpreter::lmw(UGeckoInstruction inst)
{ {
u32 address = Helper_Get_EA(PowerPC::ppcState, inst); u32 address = Helper_Get_EA(PowerPC::ppcState, inst);
if ((address & 0b11) != 0 || MSR.LE) if ((address & 0b11) != 0 || PowerPC::ppcState.msr.LE)
{ {
GenerateAlignmentException(address); GenerateAlignmentException(address);
return; return;
@@ -272,7 +272,7 @@ void Interpreter::lmw(UGeckoInstruction inst)
} }
else else
{ {
rGPR[i] = temp_reg; PowerPC::ppcState.gpr[i] = temp_reg;
} }
} }
} }
@@ -282,7 +282,7 @@ void Interpreter::stmw(UGeckoInstruction inst)
{ {
u32 address = Helper_Get_EA(PowerPC::ppcState, inst); u32 address = Helper_Get_EA(PowerPC::ppcState, inst);
if ((address & 0b11) != 0 || MSR.LE) if ((address & 0b11) != 0 || PowerPC::ppcState.msr.LE)
{ {
GenerateAlignmentException(address); GenerateAlignmentException(address);
return; return;
@@ -290,7 +290,7 @@ void Interpreter::stmw(UGeckoInstruction inst)
for (u32 i = inst.RS; i <= 31; i++, address += 4) for (u32 i = inst.RS; i <= 31; i++, address += 4)
{ {
PowerPC::Write_U32(rGPR[i], address); PowerPC::Write_U32(PowerPC::ppcState.gpr[i], address);
if ((PowerPC::ppcState.Exceptions & EXCEPTION_DSI) != 0) if ((PowerPC::ppcState.Exceptions & EXCEPTION_DSI) != 0)
{ {
PanicAlertFmt("DSI exception in stmw"); PanicAlertFmt("DSI exception in stmw");
@@ -307,7 +307,7 @@ void Interpreter::lwz(UGeckoInstruction inst)
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{ {
rGPR[inst.RD] = temp; PowerPC::ppcState.gpr[inst.RD] = temp;
} }
} }
@@ -318,24 +318,24 @@ void Interpreter::lwzu(UGeckoInstruction inst)
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{ {
rGPR[inst.RD] = temp; PowerPC::ppcState.gpr[inst.RD] = temp;
rGPR[inst.RA] = address; PowerPC::ppcState.gpr[inst.RA] = address;
} }
} }
void Interpreter::stb(UGeckoInstruction inst) void Interpreter::stb(UGeckoInstruction inst)
{ {
PowerPC::Write_U8(rGPR[inst.RS], Helper_Get_EA(PowerPC::ppcState, inst)); PowerPC::Write_U8(PowerPC::ppcState.gpr[inst.RS], Helper_Get_EA(PowerPC::ppcState, inst));
} }
void Interpreter::stbu(UGeckoInstruction inst) void Interpreter::stbu(UGeckoInstruction inst)
{ {
const u32 address = Helper_Get_EA_U(PowerPC::ppcState, inst); const u32 address = Helper_Get_EA_U(PowerPC::ppcState, inst);
PowerPC::Write_U8(rGPR[inst.RS], address); PowerPC::Write_U8(PowerPC::ppcState.gpr[inst.RS], address);
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{ {
rGPR[inst.RA] = address; PowerPC::ppcState.gpr[inst.RA] = address;
} }
} }
@@ -349,7 +349,7 @@ void Interpreter::stfd(UGeckoInstruction inst)
return; return;
} }
PowerPC::Write_U64(rPS(inst.FS).PS0AsU64(), address); PowerPC::Write_U64(PowerPC::ppcState.ps[inst.FS].PS0AsU64(), address);
} }
void Interpreter::stfdu(UGeckoInstruction inst) void Interpreter::stfdu(UGeckoInstruction inst)
@@ -362,10 +362,10 @@ void Interpreter::stfdu(UGeckoInstruction inst)
return; return;
} }
PowerPC::Write_U64(rPS(inst.FS).PS0AsU64(), address); PowerPC::Write_U64(PowerPC::ppcState.ps[inst.FS].PS0AsU64(), address);
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{ {
rGPR[inst.RA] = address; PowerPC::ppcState.gpr[inst.RA] = address;
} }
} }
@@ -379,7 +379,7 @@ void Interpreter::stfs(UGeckoInstruction inst)
return; return;
} }
PowerPC::Write_U32(ConvertToSingle(rPS(inst.FS).PS0AsU64()), address); PowerPC::Write_U32(ConvertToSingle(PowerPC::ppcState.ps[inst.FS].PS0AsU64()), address);
} }
void Interpreter::stfsu(UGeckoInstruction inst) void Interpreter::stfsu(UGeckoInstruction inst)
@@ -392,42 +392,42 @@ void Interpreter::stfsu(UGeckoInstruction inst)
return; return;
} }
PowerPC::Write_U32(ConvertToSingle(rPS(inst.FS).PS0AsU64()), address); PowerPC::Write_U32(ConvertToSingle(PowerPC::ppcState.ps[inst.FS].PS0AsU64()), address);
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{ {
rGPR[inst.RA] = address; PowerPC::ppcState.gpr[inst.RA] = address;
} }
} }
void Interpreter::sth(UGeckoInstruction inst) void Interpreter::sth(UGeckoInstruction inst)
{ {
PowerPC::Write_U16(rGPR[inst.RS], Helper_Get_EA(PowerPC::ppcState, inst)); PowerPC::Write_U16(PowerPC::ppcState.gpr[inst.RS], Helper_Get_EA(PowerPC::ppcState, inst));
} }
void Interpreter::sthu(UGeckoInstruction inst) void Interpreter::sthu(UGeckoInstruction inst)
{ {
const u32 address = Helper_Get_EA_U(PowerPC::ppcState, inst); const u32 address = Helper_Get_EA_U(PowerPC::ppcState, inst);
PowerPC::Write_U16(rGPR[inst.RS], address); PowerPC::Write_U16(PowerPC::ppcState.gpr[inst.RS], address);
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{ {
rGPR[inst.RA] = address; PowerPC::ppcState.gpr[inst.RA] = address;
} }
} }
void Interpreter::stw(UGeckoInstruction inst) void Interpreter::stw(UGeckoInstruction inst)
{ {
PowerPC::Write_U32(rGPR[inst.RS], Helper_Get_EA(PowerPC::ppcState, inst)); PowerPC::Write_U32(PowerPC::ppcState.gpr[inst.RS], Helper_Get_EA(PowerPC::ppcState, inst));
} }
void Interpreter::stwu(UGeckoInstruction inst) void Interpreter::stwu(UGeckoInstruction inst)
{ {
const u32 address = Helper_Get_EA_U(PowerPC::ppcState, inst); const u32 address = Helper_Get_EA_U(PowerPC::ppcState, inst);
PowerPC::Write_U32(rGPR[inst.RS], address); PowerPC::Write_U32(PowerPC::ppcState.gpr[inst.RS], address);
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{ {
rGPR[inst.RA] = address; PowerPC::ppcState.gpr[inst.RA] = address;
} }
} }
@@ -453,7 +453,7 @@ void Interpreter::dcbf(UGeckoInstruction inst)
void Interpreter::dcbi(UGeckoInstruction inst) void Interpreter::dcbi(UGeckoInstruction inst)
{ {
if (MSR.PR) if (PowerPC::ppcState.msr.PR)
{ {
GenerateProgramException(ProgramExceptionCause::PrivilegedInstruction); GenerateProgramException(ProgramExceptionCause::PrivilegedInstruction);
return; return;
@@ -503,7 +503,7 @@ void Interpreter::dcbz(UGeckoInstruction inst)
{ {
const u32 dcbz_addr = Helper_Get_EA_X(PowerPC::ppcState, inst); const u32 dcbz_addr = Helper_Get_EA_X(PowerPC::ppcState, inst);
if (!HID0.DCE) if (!HID0(PowerPC::ppcState).DCE)
{ {
GenerateAlignmentException(dcbz_addr); GenerateAlignmentException(dcbz_addr);
return; return;
@@ -525,7 +525,7 @@ void Interpreter::dcbz(UGeckoInstruction inst)
void Interpreter::dcbz_l(UGeckoInstruction inst) void Interpreter::dcbz_l(UGeckoInstruction inst)
{ {
if (!HID2.LCE) if (!HID2(PowerPC::ppcState).LCE)
{ {
GenerateProgramException(ProgramExceptionCause::IllegalInstruction); GenerateProgramException(ProgramExceptionCause::IllegalInstruction);
return; return;
@@ -533,7 +533,7 @@ void Interpreter::dcbz_l(UGeckoInstruction inst)
const u32 address = Helper_Get_EA_X(PowerPC::ppcState, inst); const u32 address = Helper_Get_EA_X(PowerPC::ppcState, inst);
if (!HID0.DCE) if (!HID0(PowerPC::ppcState).DCE)
{ {
GenerateAlignmentException(address); GenerateAlignmentException(address);
return; return;
@@ -560,7 +560,7 @@ void Interpreter::eciwx(UGeckoInstruction inst)
return; return;
} }
rGPR[inst.RD] = PowerPC::Read_U32(EA); PowerPC::ppcState.gpr[inst.RD] = PowerPC::Read_U32(EA);
} }
void Interpreter::ecowx(UGeckoInstruction inst) void Interpreter::ecowx(UGeckoInstruction inst)
@@ -579,7 +579,7 @@ void Interpreter::ecowx(UGeckoInstruction inst)
return; return;
} }
PowerPC::Write_U32(rGPR[inst.RS], EA); PowerPC::Write_U32(PowerPC::ppcState.gpr[inst.RS], EA);
} }
void Interpreter::eieio(UGeckoInstruction inst) void Interpreter::eieio(UGeckoInstruction inst)
@@ -604,8 +604,8 @@ void Interpreter::lbzux(UGeckoInstruction inst)
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{ {
rGPR[inst.RD] = temp; PowerPC::ppcState.gpr[inst.RD] = temp;
rGPR[inst.RA] = address; PowerPC::ppcState.gpr[inst.RA] = address;
} }
} }
@@ -615,7 +615,7 @@ void Interpreter::lbzx(UGeckoInstruction inst)
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{ {
rGPR[inst.RD] = temp; PowerPC::ppcState.gpr[inst.RD] = temp;
} }
} }
@@ -626,8 +626,8 @@ void Interpreter::lhaux(UGeckoInstruction inst)
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{ {
rGPR[inst.RD] = u32(temp); PowerPC::ppcState.gpr[inst.RD] = u32(temp);
rGPR[inst.RA] = address; PowerPC::ppcState.gpr[inst.RA] = address;
} }
} }
@@ -637,7 +637,7 @@ void Interpreter::lhax(UGeckoInstruction inst)
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{ {
rGPR[inst.RD] = u32(temp); PowerPC::ppcState.gpr[inst.RD] = u32(temp);
} }
} }
@@ -647,7 +647,7 @@ void Interpreter::lhbrx(UGeckoInstruction inst)
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{ {
rGPR[inst.RD] = temp; PowerPC::ppcState.gpr[inst.RD] = temp;
} }
} }
@@ -658,8 +658,8 @@ void Interpreter::lhzux(UGeckoInstruction inst)
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{ {
rGPR[inst.RD] = temp; PowerPC::ppcState.gpr[inst.RD] = temp;
rGPR[inst.RA] = address; PowerPC::ppcState.gpr[inst.RA] = address;
} }
} }
@@ -669,7 +669,7 @@ void Interpreter::lhzx(UGeckoInstruction inst)
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{ {
rGPR[inst.RD] = temp; PowerPC::ppcState.gpr[inst.RD] = temp;
} }
} }
@@ -678,20 +678,20 @@ void Interpreter::lswx(UGeckoInstruction inst)
{ {
u32 EA = Helper_Get_EA_X(PowerPC::ppcState, inst); u32 EA = Helper_Get_EA_X(PowerPC::ppcState, inst);
if (MSR.LE) if (PowerPC::ppcState.msr.LE)
{ {
GenerateAlignmentException(EA); GenerateAlignmentException(EA);
return; return;
} }
// Confirmed by hardware test that the zero case doesn't zero rGPR[r] // Confirmed by hardware test that the zero case doesn't zero gpr[r]
for (u32 n = 0; n < static_cast<u8>(PowerPC::ppcState.xer_stringctrl); n++) for (u32 n = 0; n < static_cast<u8>(PowerPC::ppcState.xer_stringctrl); n++)
{ {
const u32 reg = (inst.RD + (n >> 2)) & 0x1f; const u32 reg = (inst.RD + (n >> 2)) & 0x1f;
const u32 offset = (n & 3) << 3; const u32 offset = (n & 3) << 3;
if ((n & 0b11) == 0) if ((n & 0b11) == 0)
rGPR[reg] = 0; PowerPC::ppcState.gpr[reg] = 0;
const u32 temp_value = PowerPC::Read_U8(EA) << (24 - offset); const u32 temp_value = PowerPC::Read_U8(EA) << (24 - offset);
// Not64 (Homebrew N64 Emulator for Wii) triggers the following case. // Not64 (Homebrew N64 Emulator for Wii) triggers the following case.
@@ -700,7 +700,7 @@ void Interpreter::lswx(UGeckoInstruction inst)
NOTICE_LOG_FMT(POWERPC, "DSI exception in lswx"); NOTICE_LOG_FMT(POWERPC, "DSI exception in lswx");
return; return;
} }
rGPR[reg] |= temp_value; PowerPC::ppcState.gpr[reg] |= temp_value;
EA++; EA++;
} }
@@ -712,7 +712,7 @@ void Interpreter::lwbrx(UGeckoInstruction inst)
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{ {
rGPR[inst.RD] = temp; PowerPC::ppcState.gpr[inst.RD] = temp;
} }
} }
@@ -723,8 +723,8 @@ void Interpreter::lwzux(UGeckoInstruction inst)
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{ {
rGPR[inst.RD] = temp; PowerPC::ppcState.gpr[inst.RD] = temp;
rGPR[inst.RA] = address; PowerPC::ppcState.gpr[inst.RA] = address;
} }
} }
@@ -735,7 +735,7 @@ void Interpreter::lwzx(UGeckoInstruction inst)
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{ {
rGPR[inst.RD] = temp; PowerPC::ppcState.gpr[inst.RD] = temp;
} }
} }
@@ -743,16 +743,16 @@ void Interpreter::stbux(UGeckoInstruction inst)
{ {
const u32 address = Helper_Get_EA_UX(PowerPC::ppcState, inst); const u32 address = Helper_Get_EA_UX(PowerPC::ppcState, inst);
PowerPC::Write_U8(rGPR[inst.RS], address); PowerPC::Write_U8(PowerPC::ppcState.gpr[inst.RS], address);
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{ {
rGPR[inst.RA] = address; PowerPC::ppcState.gpr[inst.RA] = address;
} }
} }
void Interpreter::stbx(UGeckoInstruction inst) void Interpreter::stbx(UGeckoInstruction inst)
{ {
PowerPC::Write_U8(rGPR[inst.RS], Helper_Get_EA_X(PowerPC::ppcState, inst)); PowerPC::Write_U8(PowerPC::ppcState.gpr[inst.RS], Helper_Get_EA_X(PowerPC::ppcState, inst));
} }
void Interpreter::stfdux(UGeckoInstruction inst) void Interpreter::stfdux(UGeckoInstruction inst)
@@ -765,10 +765,10 @@ void Interpreter::stfdux(UGeckoInstruction inst)
return; return;
} }
PowerPC::Write_U64(rPS(inst.FS).PS0AsU64(), address); PowerPC::Write_U64(PowerPC::ppcState.ps[inst.FS].PS0AsU64(), address);
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{ {
rGPR[inst.RA] = address; PowerPC::ppcState.gpr[inst.RA] = address;
} }
} }
@@ -782,7 +782,7 @@ void Interpreter::stfdx(UGeckoInstruction inst)
return; return;
} }
PowerPC::Write_U64(rPS(inst.FS).PS0AsU64(), address); PowerPC::Write_U64(PowerPC::ppcState.ps[inst.FS].PS0AsU64(), address);
} }
// Stores Floating points into Integers indeXed // Stores Floating points into Integers indeXed
@@ -796,7 +796,7 @@ void Interpreter::stfiwx(UGeckoInstruction inst)
return; return;
} }
PowerPC::Write_U32(rPS(inst.FS).PS0AsU32(), address); PowerPC::Write_U32(PowerPC::ppcState.ps[inst.FS].PS0AsU32(), address);
} }
void Interpreter::stfsux(UGeckoInstruction inst) void Interpreter::stfsux(UGeckoInstruction inst)
@@ -809,10 +809,10 @@ void Interpreter::stfsux(UGeckoInstruction inst)
return; return;
} }
PowerPC::Write_U32(ConvertToSingle(rPS(inst.FS).PS0AsU64()), address); PowerPC::Write_U32(ConvertToSingle(PowerPC::ppcState.ps[inst.FS].PS0AsU64()), address);
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{ {
rGPR[inst.RA] = address; PowerPC::ppcState.gpr[inst.RA] = address;
} }
} }
@@ -826,28 +826,28 @@ void Interpreter::stfsx(UGeckoInstruction inst)
return; return;
} }
PowerPC::Write_U32(ConvertToSingle(rPS(inst.FS).PS0AsU64()), address); PowerPC::Write_U32(ConvertToSingle(PowerPC::ppcState.ps[inst.FS].PS0AsU64()), address);
} }
void Interpreter::sthbrx(UGeckoInstruction inst) void Interpreter::sthbrx(UGeckoInstruction inst)
{ {
PowerPC::Write_U16_Swap(rGPR[inst.RS], Helper_Get_EA_X(PowerPC::ppcState, inst)); PowerPC::Write_U16_Swap(PowerPC::ppcState.gpr[inst.RS], Helper_Get_EA_X(PowerPC::ppcState, inst));
} }
void Interpreter::sthux(UGeckoInstruction inst) void Interpreter::sthux(UGeckoInstruction inst)
{ {
const u32 address = Helper_Get_EA_UX(PowerPC::ppcState, inst); const u32 address = Helper_Get_EA_UX(PowerPC::ppcState, inst);
PowerPC::Write_U16(rGPR[inst.RS], address); PowerPC::Write_U16(PowerPC::ppcState.gpr[inst.RS], address);
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{ {
rGPR[inst.RA] = address; PowerPC::ppcState.gpr[inst.RA] = address;
} }
} }
void Interpreter::sthx(UGeckoInstruction inst) void Interpreter::sthx(UGeckoInstruction inst)
{ {
PowerPC::Write_U16(rGPR[inst.RS], Helper_Get_EA_X(PowerPC::ppcState, inst)); PowerPC::Write_U16(PowerPC::ppcState.gpr[inst.RS], Helper_Get_EA_X(PowerPC::ppcState, inst));
} }
// lswi - bizarro string instruction // lswi - bizarro string instruction
@@ -856,9 +856,9 @@ void Interpreter::lswi(UGeckoInstruction inst)
{ {
u32 EA = 0; u32 EA = 0;
if (inst.RA != 0) if (inst.RA != 0)
EA = rGPR[inst.RA]; EA = PowerPC::ppcState.gpr[inst.RA];
if (MSR.LE) if (PowerPC::ppcState.msr.LE)
{ {
GenerateAlignmentException(EA); GenerateAlignmentException(EA);
return; return;
@@ -876,7 +876,7 @@ void Interpreter::lswi(UGeckoInstruction inst)
{ {
r++; r++;
r &= 31; r &= 31;
rGPR[r] = 0; PowerPC::ppcState.gpr[r] = 0;
} }
const u32 temp_value = PowerPC::Read_U8(EA) << (24 - i); const u32 temp_value = PowerPC::Read_U8(EA) << (24 - i);
@@ -886,7 +886,7 @@ void Interpreter::lswi(UGeckoInstruction inst)
return; return;
} }
rGPR[r] |= temp_value; PowerPC::ppcState.gpr[r] |= temp_value;
i += 8; i += 8;
if (i == 32) if (i == 32)
@@ -903,9 +903,9 @@ void Interpreter::stswi(UGeckoInstruction inst)
{ {
u32 EA = 0; u32 EA = 0;
if (inst.RA != 0) if (inst.RA != 0)
EA = rGPR[inst.RA]; EA = PowerPC::ppcState.gpr[inst.RA];
if (MSR.LE) if (PowerPC::ppcState.msr.LE)
{ {
GenerateAlignmentException(EA); GenerateAlignmentException(EA);
return; return;
@@ -924,7 +924,7 @@ void Interpreter::stswi(UGeckoInstruction inst)
r++; r++;
r &= 31; r &= 31;
} }
PowerPC::Write_U8((rGPR[r] >> (24 - i)) & 0xFF, EA); PowerPC::Write_U8((PowerPC::ppcState.gpr[r] >> (24 - i)) & 0xFF, EA);
if ((PowerPC::ppcState.Exceptions & EXCEPTION_DSI) != 0) if ((PowerPC::ppcState.Exceptions & EXCEPTION_DSI) != 0)
{ {
return; return;
@@ -943,7 +943,7 @@ void Interpreter::stswx(UGeckoInstruction inst)
{ {
u32 EA = Helper_Get_EA_X(PowerPC::ppcState, inst); u32 EA = Helper_Get_EA_X(PowerPC::ppcState, inst);
if (MSR.LE) if (PowerPC::ppcState.msr.LE)
{ {
GenerateAlignmentException(EA); GenerateAlignmentException(EA);
return; return;
@@ -955,7 +955,7 @@ void Interpreter::stswx(UGeckoInstruction inst)
while (n > 0) while (n > 0)
{ {
PowerPC::Write_U8((rGPR[r] >> (24 - i)) & 0xFF, EA); PowerPC::Write_U8((PowerPC::ppcState.gpr[r] >> (24 - i)) & 0xFF, EA);
EA++; EA++;
n--; n--;
@@ -972,7 +972,7 @@ void Interpreter::stwbrx(UGeckoInstruction inst)
{ {
const u32 address = Helper_Get_EA_X(PowerPC::ppcState, inst); const u32 address = Helper_Get_EA_X(PowerPC::ppcState, inst);
PowerPC::Write_U32_Swap(rGPR[inst.RS], address); PowerPC::Write_U32_Swap(PowerPC::ppcState.gpr[inst.RS], address);
} }
// The following two instructions are for SMP communications. On a single // The following two instructions are for SMP communications. On a single
@@ -992,7 +992,7 @@ void Interpreter::lwarx(UGeckoInstruction inst)
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{ {
rGPR[inst.RD] = temp; PowerPC::ppcState.gpr[inst.RD] = temp;
PowerPC::ppcState.reserve = true; PowerPC::ppcState.reserve = true;
PowerPC::ppcState.reserve_address = address; PowerPC::ppcState.reserve_address = address;
} }
@@ -1013,27 +1013,27 @@ void Interpreter::stwcxd(UGeckoInstruction inst)
{ {
if (address == PowerPC::ppcState.reserve_address) if (address == PowerPC::ppcState.reserve_address)
{ {
PowerPC::Write_U32(rGPR[inst.RS], address); PowerPC::Write_U32(PowerPC::ppcState.gpr[inst.RS], address);
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{ {
PowerPC::ppcState.reserve = false; PowerPC::ppcState.reserve = false;
PowerPC::ppcState.cr.SetField(0, 2 | PowerPC::GetXER_SO()); PowerPC::ppcState.cr.SetField(0, 2 | PowerPC::ppcState.GetXER_SO());
return; return;
} }
} }
} }
PowerPC::ppcState.cr.SetField(0, PowerPC::GetXER_SO()); PowerPC::ppcState.cr.SetField(0, PowerPC::ppcState.GetXER_SO());
} }
void Interpreter::stwux(UGeckoInstruction inst) void Interpreter::stwux(UGeckoInstruction inst)
{ {
const u32 address = Helper_Get_EA_UX(PowerPC::ppcState, inst); const u32 address = Helper_Get_EA_UX(PowerPC::ppcState, inst);
PowerPC::Write_U32(rGPR[inst.RS], address); PowerPC::Write_U32(PowerPC::ppcState.gpr[inst.RS], address);
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{ {
rGPR[inst.RA] = address; PowerPC::ppcState.gpr[inst.RA] = address;
} }
} }
@@ -1041,7 +1041,7 @@ void Interpreter::stwx(UGeckoInstruction inst)
{ {
const u32 address = Helper_Get_EA_X(PowerPC::ppcState, inst); const u32 address = Helper_Get_EA_X(PowerPC::ppcState, inst);
PowerPC::Write_U32(rGPR[inst.RS], address); PowerPC::Write_U32(PowerPC::ppcState.gpr[inst.RS], address);
} }
void Interpreter::sync(UGeckoInstruction inst) void Interpreter::sync(UGeckoInstruction inst)
@@ -1051,21 +1051,21 @@ void Interpreter::sync(UGeckoInstruction inst)
void Interpreter::tlbie(UGeckoInstruction inst) void Interpreter::tlbie(UGeckoInstruction inst)
{ {
if (MSR.PR) if (PowerPC::ppcState.msr.PR)
{ {
GenerateProgramException(ProgramExceptionCause::PrivilegedInstruction); GenerateProgramException(ProgramExceptionCause::PrivilegedInstruction);
return; return;
} }
// Invalidate TLB entry // Invalidate TLB entry
const u32 address = rGPR[inst.RB]; const u32 address = PowerPC::ppcState.gpr[inst.RB];
PowerPC::InvalidateTLBEntry(address); PowerPC::InvalidateTLBEntry(address);
} }
void Interpreter::tlbsync(UGeckoInstruction inst) void Interpreter::tlbsync(UGeckoInstruction inst)
{ {
if (MSR.PR) if (PowerPC::ppcState.msr.PR)
{ {
GenerateProgramException(ProgramExceptionCause::PrivilegedInstruction); GenerateProgramException(ProgramExceptionCause::PrivilegedInstruction);
} }

View File

@@ -310,25 +310,25 @@ static void Helper_Dequantize(PowerPC::PowerPCState* ppcs, u32 addr, u32 instI,
void Interpreter::psq_l(UGeckoInstruction inst) void Interpreter::psq_l(UGeckoInstruction inst)
{ {
if (HID2.LSQE == 0) if (HID2(PowerPC::ppcState).LSQE == 0)
{ {
GenerateProgramException(ProgramExceptionCause::IllegalInstruction); GenerateProgramException(ProgramExceptionCause::IllegalInstruction);
return; 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); Helper_Dequantize(&PowerPC::ppcState, EA, inst.I, inst.RD, inst.W);
} }
void Interpreter::psq_lu(UGeckoInstruction inst) void Interpreter::psq_lu(UGeckoInstruction inst)
{ {
if (HID2.LSQE == 0) if (HID2(PowerPC::ppcState).LSQE == 0)
{ {
GenerateProgramException(ProgramExceptionCause::IllegalInstruction); GenerateProgramException(ProgramExceptionCause::IllegalInstruction);
return; 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); Helper_Dequantize(&PowerPC::ppcState, EA, inst.I, inst.RD, inst.W);
if ((PowerPC::ppcState.Exceptions & EXCEPTION_DSI) != 0) if ((PowerPC::ppcState.Exceptions & EXCEPTION_DSI) != 0)
@@ -336,30 +336,30 @@ void Interpreter::psq_lu(UGeckoInstruction inst)
return; return;
} }
rGPR[inst.RA] = EA; PowerPC::ppcState.gpr[inst.RA] = EA;
} }
void Interpreter::psq_st(UGeckoInstruction inst) void Interpreter::psq_st(UGeckoInstruction inst)
{ {
if (HID2.LSQE == 0) if (HID2(PowerPC::ppcState).LSQE == 0)
{ {
GenerateProgramException(ProgramExceptionCause::IllegalInstruction); GenerateProgramException(ProgramExceptionCause::IllegalInstruction);
return; 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); Helper_Quantize(&PowerPC::ppcState, EA, inst.I, inst.RS, inst.W);
} }
void Interpreter::psq_stu(UGeckoInstruction inst) void Interpreter::psq_stu(UGeckoInstruction inst)
{ {
if (HID2.LSQE == 0) if (HID2(PowerPC::ppcState).LSQE == 0)
{ {
GenerateProgramException(ProgramExceptionCause::IllegalInstruction); GenerateProgramException(ProgramExceptionCause::IllegalInstruction);
return; 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); Helper_Quantize(&PowerPC::ppcState, EA, inst.I, inst.RS, inst.W);
if ((PowerPC::ppcState.Exceptions & EXCEPTION_DSI) != 0) if ((PowerPC::ppcState.Exceptions & EXCEPTION_DSI) != 0)
@@ -367,24 +367,26 @@ void Interpreter::psq_stu(UGeckoInstruction inst)
return; return;
} }
rGPR[inst.RA] = EA; PowerPC::ppcState.gpr[inst.RA] = EA;
} }
void Interpreter::psq_lx(UGeckoInstruction inst) 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); Helper_Dequantize(&PowerPC::ppcState, EA, inst.Ix, inst.RD, inst.Wx);
} }
void Interpreter::psq_stx(UGeckoInstruction inst) 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); Helper_Quantize(&PowerPC::ppcState, EA, inst.Ix, inst.RS, inst.Wx);
} }
void Interpreter::psq_lux(UGeckoInstruction inst) 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); Helper_Dequantize(&PowerPC::ppcState, EA, inst.Ix, inst.RD, inst.Wx);
if ((PowerPC::ppcState.Exceptions & EXCEPTION_DSI) != 0) if ((PowerPC::ppcState.Exceptions & EXCEPTION_DSI) != 0)
@@ -392,12 +394,12 @@ void Interpreter::psq_lux(UGeckoInstruction inst)
return; return;
} }
rGPR[inst.RA] = EA; PowerPC::ppcState.gpr[inst.RA] = EA;
} }
void Interpreter::psq_stux(UGeckoInstruction inst) 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); Helper_Quantize(&PowerPC::ppcState, EA, inst.Ix, inst.RS, inst.Wx);
if ((PowerPC::ppcState.Exceptions & EXCEPTION_DSI) != 0) if ((PowerPC::ppcState.Exceptions & EXCEPTION_DSI) != 0)
@@ -405,5 +407,5 @@ void Interpreter::psq_stux(UGeckoInstruction inst)
return; return;
} }
rGPR[inst.RA] = EA; PowerPC::ppcState.gpr[inst.RA] = EA;
} }

View File

@@ -13,12 +13,13 @@
// These "binary instructions" do not alter FPSCR. // These "binary instructions" do not alter FPSCR.
void Interpreter::ps_sel(UGeckoInstruction inst) void Interpreter::ps_sel(UGeckoInstruction inst)
{ {
const auto& a = rPS(inst.FA); const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = rPS(inst.FB); const auto& b = PowerPC::ppcState.ps[inst.FB];
const auto& c = rPS(inst.FC); const auto& c = PowerPC::ppcState.ps[inst.FC];
rPS(inst.FD).SetBoth(a.PS0AsDouble() >= -0.0 ? c.PS0AsDouble() : b.PS0AsDouble(), PowerPC::ppcState.ps[inst.FD].SetBoth(a.PS0AsDouble() >= -0.0 ? c.PS0AsDouble() : b.PS0AsDouble(),
a.PS1AsDouble() >= -0.0 ? c.PS1AsDouble() : b.PS1AsDouble()); a.PS1AsDouble() >= -0.0 ? c.PS1AsDouble() :
b.PS1AsDouble());
if (inst.Rc) if (inst.Rc)
PowerPC::ppcState.UpdateCR1(); PowerPC::ppcState.UpdateCR1();
@@ -26,9 +27,10 @@ void Interpreter::ps_sel(UGeckoInstruction inst)
void Interpreter::ps_neg(UGeckoInstruction inst) void Interpreter::ps_neg(UGeckoInstruction inst)
{ {
const auto& b = rPS(inst.FB); const auto& b = PowerPC::ppcState.ps[inst.FB];
rPS(inst.FD).SetBoth(b.PS0AsU64() ^ (UINT64_C(1) << 63), b.PS1AsU64() ^ (UINT64_C(1) << 63)); PowerPC::ppcState.ps[inst.FD].SetBoth(b.PS0AsU64() ^ (UINT64_C(1) << 63),
b.PS1AsU64() ^ (UINT64_C(1) << 63));
if (inst.Rc) if (inst.Rc)
PowerPC::ppcState.UpdateCR1(); PowerPC::ppcState.UpdateCR1();
@@ -36,7 +38,7 @@ void Interpreter::ps_neg(UGeckoInstruction inst)
void Interpreter::ps_mr(UGeckoInstruction inst) void Interpreter::ps_mr(UGeckoInstruction inst)
{ {
rPS(inst.FD) = rPS(inst.FB); PowerPC::ppcState.ps[inst.FD] = PowerPC::ppcState.ps[inst.FB];
if (inst.Rc) if (inst.Rc)
PowerPC::ppcState.UpdateCR1(); PowerPC::ppcState.UpdateCR1();
@@ -44,9 +46,10 @@ void Interpreter::ps_mr(UGeckoInstruction inst)
void Interpreter::ps_nabs(UGeckoInstruction inst) void Interpreter::ps_nabs(UGeckoInstruction inst)
{ {
const auto& b = rPS(inst.FB); const auto& b = PowerPC::ppcState.ps[inst.FB];
rPS(inst.FD).SetBoth(b.PS0AsU64() | (UINT64_C(1) << 63), b.PS1AsU64() | (UINT64_C(1) << 63)); PowerPC::ppcState.ps[inst.FD].SetBoth(b.PS0AsU64() | (UINT64_C(1) << 63),
b.PS1AsU64() | (UINT64_C(1) << 63));
if (inst.Rc) if (inst.Rc)
PowerPC::ppcState.UpdateCR1(); PowerPC::ppcState.UpdateCR1();
@@ -54,9 +57,10 @@ void Interpreter::ps_nabs(UGeckoInstruction inst)
void Interpreter::ps_abs(UGeckoInstruction inst) void Interpreter::ps_abs(UGeckoInstruction inst)
{ {
const auto& b = rPS(inst.FB); const auto& b = PowerPC::ppcState.ps[inst.FB];
rPS(inst.FD).SetBoth(b.PS0AsU64() & ~(UINT64_C(1) << 63), b.PS1AsU64() & ~(UINT64_C(1) << 63)); PowerPC::ppcState.ps[inst.FD].SetBoth(b.PS0AsU64() & ~(UINT64_C(1) << 63),
b.PS1AsU64() & ~(UINT64_C(1) << 63));
if (inst.Rc) if (inst.Rc)
PowerPC::ppcState.UpdateCR1(); PowerPC::ppcState.UpdateCR1();
@@ -65,10 +69,10 @@ void Interpreter::ps_abs(UGeckoInstruction inst)
// These are just moves, double is OK. // These are just moves, double is OK.
void Interpreter::ps_merge00(UGeckoInstruction inst) void Interpreter::ps_merge00(UGeckoInstruction inst)
{ {
const auto& a = rPS(inst.FA); const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = rPS(inst.FB); const auto& b = PowerPC::ppcState.ps[inst.FB];
rPS(inst.FD).SetBoth(a.PS0AsDouble(), b.PS0AsDouble()); PowerPC::ppcState.ps[inst.FD].SetBoth(a.PS0AsDouble(), b.PS0AsDouble());
if (inst.Rc) if (inst.Rc)
PowerPC::ppcState.UpdateCR1(); PowerPC::ppcState.UpdateCR1();
@@ -76,10 +80,10 @@ void Interpreter::ps_merge00(UGeckoInstruction inst)
void Interpreter::ps_merge01(UGeckoInstruction inst) void Interpreter::ps_merge01(UGeckoInstruction inst)
{ {
const auto& a = rPS(inst.FA); const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = rPS(inst.FB); const auto& b = PowerPC::ppcState.ps[inst.FB];
rPS(inst.FD).SetBoth(a.PS0AsDouble(), b.PS1AsDouble()); PowerPC::ppcState.ps[inst.FD].SetBoth(a.PS0AsDouble(), b.PS1AsDouble());
if (inst.Rc) if (inst.Rc)
PowerPC::ppcState.UpdateCR1(); PowerPC::ppcState.UpdateCR1();
@@ -87,10 +91,10 @@ void Interpreter::ps_merge01(UGeckoInstruction inst)
void Interpreter::ps_merge10(UGeckoInstruction inst) void Interpreter::ps_merge10(UGeckoInstruction inst)
{ {
const auto& a = rPS(inst.FA); const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = rPS(inst.FB); const auto& b = PowerPC::ppcState.ps[inst.FB];
rPS(inst.FD).SetBoth(a.PS1AsDouble(), b.PS0AsDouble()); PowerPC::ppcState.ps[inst.FD].SetBoth(a.PS1AsDouble(), b.PS0AsDouble());
if (inst.Rc) if (inst.Rc)
PowerPC::ppcState.UpdateCR1(); PowerPC::ppcState.UpdateCR1();
@@ -98,10 +102,10 @@ void Interpreter::ps_merge10(UGeckoInstruction inst)
void Interpreter::ps_merge11(UGeckoInstruction inst) void Interpreter::ps_merge11(UGeckoInstruction inst)
{ {
const auto& a = rPS(inst.FA); const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = rPS(inst.FB); const auto& b = PowerPC::ppcState.ps[inst.FB];
rPS(inst.FD).SetBoth(a.PS1AsDouble(), b.PS1AsDouble()); PowerPC::ppcState.ps[inst.FD].SetBoth(a.PS1AsDouble(), b.PS1AsDouble());
if (inst.Rc) if (inst.Rc)
PowerPC::ppcState.UpdateCR1(); PowerPC::ppcState.UpdateCR1();
@@ -110,14 +114,18 @@ void Interpreter::ps_merge11(UGeckoInstruction inst)
// From here on, the real deal. // From here on, the real deal.
void Interpreter::ps_div(UGeckoInstruction inst) void Interpreter::ps_div(UGeckoInstruction inst)
{ {
const auto& a = rPS(inst.FA); const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = rPS(inst.FB); const auto& b = PowerPC::ppcState.ps[inst.FB];
const float ps0 = ForceSingle(FPSCR, NI_div(&FPSCR, a.PS0AsDouble(), b.PS0AsDouble()).value); const float ps0 =
const float ps1 = ForceSingle(FPSCR, NI_div(&FPSCR, a.PS1AsDouble(), b.PS1AsDouble()).value); ForceSingle(PowerPC::ppcState.fpscr,
NI_div(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), b.PS0AsDouble()).value);
const float ps1 =
ForceSingle(PowerPC::ppcState.fpscr,
NI_div(&PowerPC::ppcState.fpscr, a.PS1AsDouble(), b.PS1AsDouble()).value);
rPS(inst.FD).SetBoth(ps0, ps1); PowerPC::ppcState.ps[inst.FD].SetBoth(ps0, ps1);
PowerPC::UpdateFPRFSingle(ps0); PowerPC::ppcState.UpdateFPRFSingle(ps0);
if (inst.Rc) if (inst.Rc)
PowerPC::ppcState.UpdateCR1(); PowerPC::ppcState.UpdateCR1();
@@ -126,26 +134,26 @@ void Interpreter::ps_div(UGeckoInstruction inst)
void Interpreter::ps_res(UGeckoInstruction inst) void Interpreter::ps_res(UGeckoInstruction inst)
{ {
// this code is based on the real hardware tests // this code is based on the real hardware tests
const double a = rPS(inst.FB).PS0AsDouble(); const double a = PowerPC::ppcState.ps[inst.FB].PS0AsDouble();
const double b = rPS(inst.FB).PS1AsDouble(); const double b = PowerPC::ppcState.ps[inst.FB].PS1AsDouble();
if (a == 0.0 || b == 0.0) if (a == 0.0 || b == 0.0)
{ {
SetFPException(&FPSCR, FPSCR_ZX); SetFPException(&PowerPC::ppcState.fpscr, FPSCR_ZX);
FPSCR.ClearFIFR(); PowerPC::ppcState.fpscr.ClearFIFR();
} }
if (std::isnan(a) || std::isinf(a) || std::isnan(b) || std::isinf(b)) if (std::isnan(a) || std::isinf(a) || std::isnan(b) || std::isinf(b))
FPSCR.ClearFIFR(); PowerPC::ppcState.fpscr.ClearFIFR();
if (Common::IsSNAN(a) || Common::IsSNAN(b)) if (Common::IsSNAN(a) || Common::IsSNAN(b))
SetFPException(&FPSCR, FPSCR_VXSNAN); SetFPException(&PowerPC::ppcState.fpscr, FPSCR_VXSNAN);
const double ps0 = Common::ApproximateReciprocal(a); const double ps0 = Common::ApproximateReciprocal(a);
const double ps1 = Common::ApproximateReciprocal(b); const double ps1 = Common::ApproximateReciprocal(b);
rPS(inst.FD).SetBoth(ps0, ps1); PowerPC::ppcState.ps[inst.FD].SetBoth(ps0, ps1);
PowerPC::UpdateFPRFSingle(float(ps0)); PowerPC::ppcState.UpdateFPRFSingle(float(ps0));
if (inst.Rc) if (inst.Rc)
PowerPC::ppcState.UpdateCR1(); PowerPC::ppcState.UpdateCR1();
@@ -153,32 +161,34 @@ void Interpreter::ps_res(UGeckoInstruction inst)
void Interpreter::ps_rsqrte(UGeckoInstruction inst) void Interpreter::ps_rsqrte(UGeckoInstruction inst)
{ {
const double ps0 = rPS(inst.FB).PS0AsDouble(); const double ps0 = PowerPC::ppcState.ps[inst.FB].PS0AsDouble();
const double ps1 = rPS(inst.FB).PS1AsDouble(); const double ps1 = PowerPC::ppcState.ps[inst.FB].PS1AsDouble();
if (ps0 == 0.0 || ps1 == 0.0) if (ps0 == 0.0 || ps1 == 0.0)
{ {
SetFPException(&FPSCR, FPSCR_ZX); SetFPException(&PowerPC::ppcState.fpscr, FPSCR_ZX);
FPSCR.ClearFIFR(); PowerPC::ppcState.fpscr.ClearFIFR();
} }
if (ps0 < 0.0 || ps1 < 0.0) if (ps0 < 0.0 || ps1 < 0.0)
{ {
SetFPException(&FPSCR, FPSCR_VXSQRT); SetFPException(&PowerPC::ppcState.fpscr, FPSCR_VXSQRT);
FPSCR.ClearFIFR(); PowerPC::ppcState.fpscr.ClearFIFR();
} }
if (std::isnan(ps0) || std::isinf(ps0) || std::isnan(ps1) || std::isinf(ps1)) if (std::isnan(ps0) || std::isinf(ps0) || std::isnan(ps1) || std::isinf(ps1))
FPSCR.ClearFIFR(); PowerPC::ppcState.fpscr.ClearFIFR();
if (Common::IsSNAN(ps0) || Common::IsSNAN(ps1)) if (Common::IsSNAN(ps0) || Common::IsSNAN(ps1))
SetFPException(&FPSCR, FPSCR_VXSNAN); SetFPException(&PowerPC::ppcState.fpscr, FPSCR_VXSNAN);
const float dst_ps0 = ForceSingle(FPSCR, Common::ApproximateReciprocalSquareRoot(ps0)); const float dst_ps0 =
const float dst_ps1 = ForceSingle(FPSCR, Common::ApproximateReciprocalSquareRoot(ps1)); ForceSingle(PowerPC::ppcState.fpscr, Common::ApproximateReciprocalSquareRoot(ps0));
const float dst_ps1 =
ForceSingle(PowerPC::ppcState.fpscr, Common::ApproximateReciprocalSquareRoot(ps1));
rPS(inst.FD).SetBoth(dst_ps0, dst_ps1); PowerPC::ppcState.ps[inst.FD].SetBoth(dst_ps0, dst_ps1);
PowerPC::UpdateFPRFSingle(dst_ps0); PowerPC::ppcState.UpdateFPRFSingle(dst_ps0);
if (inst.Rc) if (inst.Rc)
PowerPC::ppcState.UpdateCR1(); PowerPC::ppcState.UpdateCR1();
@@ -186,14 +196,18 @@ void Interpreter::ps_rsqrte(UGeckoInstruction inst)
void Interpreter::ps_sub(UGeckoInstruction inst) void Interpreter::ps_sub(UGeckoInstruction inst)
{ {
const auto& a = rPS(inst.FA); const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = rPS(inst.FB); const auto& b = PowerPC::ppcState.ps[inst.FB];
const float ps0 = ForceSingle(FPSCR, NI_sub(&FPSCR, a.PS0AsDouble(), b.PS0AsDouble()).value); const float ps0 =
const float ps1 = ForceSingle(FPSCR, NI_sub(&FPSCR, a.PS1AsDouble(), b.PS1AsDouble()).value); ForceSingle(PowerPC::ppcState.fpscr,
NI_sub(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), b.PS0AsDouble()).value);
const float ps1 =
ForceSingle(PowerPC::ppcState.fpscr,
NI_sub(&PowerPC::ppcState.fpscr, a.PS1AsDouble(), b.PS1AsDouble()).value);
rPS(inst.FD).SetBoth(ps0, ps1); PowerPC::ppcState.ps[inst.FD].SetBoth(ps0, ps1);
PowerPC::UpdateFPRFSingle(ps0); PowerPC::ppcState.UpdateFPRFSingle(ps0);
if (inst.Rc) if (inst.Rc)
PowerPC::ppcState.UpdateCR1(); PowerPC::ppcState.UpdateCR1();
@@ -201,14 +215,18 @@ void Interpreter::ps_sub(UGeckoInstruction inst)
void Interpreter::ps_add(UGeckoInstruction inst) void Interpreter::ps_add(UGeckoInstruction inst)
{ {
const auto& a = rPS(inst.FA); const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = rPS(inst.FB); const auto& b = PowerPC::ppcState.ps[inst.FB];
const float ps0 = ForceSingle(FPSCR, NI_add(&FPSCR, a.PS0AsDouble(), b.PS0AsDouble()).value); const float ps0 =
const float ps1 = ForceSingle(FPSCR, NI_add(&FPSCR, a.PS1AsDouble(), b.PS1AsDouble()).value); ForceSingle(PowerPC::ppcState.fpscr,
NI_add(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), b.PS0AsDouble()).value);
const float ps1 =
ForceSingle(PowerPC::ppcState.fpscr,
NI_add(&PowerPC::ppcState.fpscr, a.PS1AsDouble(), b.PS1AsDouble()).value);
rPS(inst.FD).SetBoth(ps0, ps1); PowerPC::ppcState.ps[inst.FD].SetBoth(ps0, ps1);
PowerPC::UpdateFPRFSingle(ps0); PowerPC::ppcState.UpdateFPRFSingle(ps0);
if (inst.Rc) if (inst.Rc)
PowerPC::ppcState.UpdateCR1(); PowerPC::ppcState.UpdateCR1();
@@ -216,17 +234,19 @@ void Interpreter::ps_add(UGeckoInstruction inst)
void Interpreter::ps_mul(UGeckoInstruction inst) void Interpreter::ps_mul(UGeckoInstruction inst)
{ {
const auto& a = rPS(inst.FA); const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& c = rPS(inst.FC); const auto& c = PowerPC::ppcState.ps[inst.FC];
const double c0 = Force25Bit(c.PS0AsDouble()); const double c0 = Force25Bit(c.PS0AsDouble());
const double c1 = Force25Bit(c.PS1AsDouble()); const double c1 = Force25Bit(c.PS1AsDouble());
const float ps0 = ForceSingle(FPSCR, NI_mul(&FPSCR, a.PS0AsDouble(), c0).value); const float ps0 = ForceSingle(PowerPC::ppcState.fpscr,
const float ps1 = ForceSingle(FPSCR, NI_mul(&FPSCR, a.PS1AsDouble(), c1).value); NI_mul(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), c0).value);
const float ps1 = ForceSingle(PowerPC::ppcState.fpscr,
NI_mul(&PowerPC::ppcState.fpscr, a.PS1AsDouble(), c1).value);
rPS(inst.FD).SetBoth(ps0, ps1); PowerPC::ppcState.ps[inst.FD].SetBoth(ps0, ps1);
PowerPC::UpdateFPRFSingle(ps0); PowerPC::ppcState.UpdateFPRFSingle(ps0);
if (inst.Rc) if (inst.Rc)
PowerPC::ppcState.UpdateCR1(); PowerPC::ppcState.UpdateCR1();
@@ -234,18 +254,22 @@ void Interpreter::ps_mul(UGeckoInstruction inst)
void Interpreter::ps_msub(UGeckoInstruction inst) void Interpreter::ps_msub(UGeckoInstruction inst)
{ {
const auto& a = rPS(inst.FA); const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = rPS(inst.FB); const auto& b = PowerPC::ppcState.ps[inst.FB];
const auto& c = rPS(inst.FC); const auto& c = PowerPC::ppcState.ps[inst.FC];
const double c0 = Force25Bit(c.PS0AsDouble()); const double c0 = Force25Bit(c.PS0AsDouble());
const double c1 = Force25Bit(c.PS1AsDouble()); const double c1 = Force25Bit(c.PS1AsDouble());
const float ps0 = ForceSingle(FPSCR, NI_msub(&FPSCR, a.PS0AsDouble(), c0, b.PS0AsDouble()).value); const float ps0 =
const float ps1 = ForceSingle(FPSCR, NI_msub(&FPSCR, a.PS1AsDouble(), c1, b.PS1AsDouble()).value); ForceSingle(PowerPC::ppcState.fpscr,
NI_msub(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), c0, b.PS0AsDouble()).value);
const float ps1 =
ForceSingle(PowerPC::ppcState.fpscr,
NI_msub(&PowerPC::ppcState.fpscr, a.PS1AsDouble(), c1, b.PS1AsDouble()).value);
rPS(inst.FD).SetBoth(ps0, ps1); PowerPC::ppcState.ps[inst.FD].SetBoth(ps0, ps1);
PowerPC::UpdateFPRFSingle(ps0); PowerPC::ppcState.UpdateFPRFSingle(ps0);
if (inst.Rc) if (inst.Rc)
PowerPC::ppcState.UpdateCR1(); PowerPC::ppcState.UpdateCR1();
@@ -253,18 +277,22 @@ void Interpreter::ps_msub(UGeckoInstruction inst)
void Interpreter::ps_madd(UGeckoInstruction inst) void Interpreter::ps_madd(UGeckoInstruction inst)
{ {
const auto& a = rPS(inst.FA); const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = rPS(inst.FB); const auto& b = PowerPC::ppcState.ps[inst.FB];
const auto& c = rPS(inst.FC); const auto& c = PowerPC::ppcState.ps[inst.FC];
const double c0 = Force25Bit(c.PS0AsDouble()); const double c0 = Force25Bit(c.PS0AsDouble());
const double c1 = Force25Bit(c.PS1AsDouble()); const double c1 = Force25Bit(c.PS1AsDouble());
const float ps0 = ForceSingle(FPSCR, NI_madd(&FPSCR, a.PS0AsDouble(), c0, b.PS0AsDouble()).value); const float ps0 =
const float ps1 = ForceSingle(FPSCR, NI_madd(&FPSCR, a.PS1AsDouble(), c1, b.PS1AsDouble()).value); ForceSingle(PowerPC::ppcState.fpscr,
NI_madd(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), c0, b.PS0AsDouble()).value);
const float ps1 =
ForceSingle(PowerPC::ppcState.fpscr,
NI_madd(&PowerPC::ppcState.fpscr, a.PS1AsDouble(), c1, b.PS1AsDouble()).value);
rPS(inst.FD).SetBoth(ps0, ps1); PowerPC::ppcState.ps[inst.FD].SetBoth(ps0, ps1);
PowerPC::UpdateFPRFSingle(ps0); PowerPC::ppcState.UpdateFPRFSingle(ps0);
if (inst.Rc) if (inst.Rc)
PowerPC::ppcState.UpdateCR1(); PowerPC::ppcState.UpdateCR1();
@@ -272,23 +300,25 @@ void Interpreter::ps_madd(UGeckoInstruction inst)
void Interpreter::ps_nmsub(UGeckoInstruction inst) void Interpreter::ps_nmsub(UGeckoInstruction inst)
{ {
const auto& a = rPS(inst.FA); const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = rPS(inst.FB); const auto& b = PowerPC::ppcState.ps[inst.FB];
const auto& c = rPS(inst.FC); const auto& c = PowerPC::ppcState.ps[inst.FC];
const double c0 = Force25Bit(c.PS0AsDouble()); const double c0 = Force25Bit(c.PS0AsDouble());
const double c1 = Force25Bit(c.PS1AsDouble()); const double c1 = Force25Bit(c.PS1AsDouble());
const float tmp0 = const float tmp0 =
ForceSingle(FPSCR, NI_msub(&FPSCR, a.PS0AsDouble(), c0, b.PS0AsDouble()).value); ForceSingle(PowerPC::ppcState.fpscr,
NI_msub(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), c0, b.PS0AsDouble()).value);
const float tmp1 = const float tmp1 =
ForceSingle(FPSCR, NI_msub(&FPSCR, a.PS1AsDouble(), c1, b.PS1AsDouble()).value); ForceSingle(PowerPC::ppcState.fpscr,
NI_msub(&PowerPC::ppcState.fpscr, a.PS1AsDouble(), c1, b.PS1AsDouble()).value);
const float ps0 = std::isnan(tmp0) ? tmp0 : -tmp0; const float ps0 = std::isnan(tmp0) ? tmp0 : -tmp0;
const float ps1 = std::isnan(tmp1) ? tmp1 : -tmp1; const float ps1 = std::isnan(tmp1) ? tmp1 : -tmp1;
rPS(inst.FD).SetBoth(ps0, ps1); PowerPC::ppcState.ps[inst.FD].SetBoth(ps0, ps1);
PowerPC::UpdateFPRFSingle(ps0); PowerPC::ppcState.UpdateFPRFSingle(ps0);
if (inst.Rc) if (inst.Rc)
PowerPC::ppcState.UpdateCR1(); PowerPC::ppcState.UpdateCR1();
@@ -296,23 +326,25 @@ void Interpreter::ps_nmsub(UGeckoInstruction inst)
void Interpreter::ps_nmadd(UGeckoInstruction inst) void Interpreter::ps_nmadd(UGeckoInstruction inst)
{ {
const auto& a = rPS(inst.FA); const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = rPS(inst.FB); const auto& b = PowerPC::ppcState.ps[inst.FB];
const auto& c = rPS(inst.FC); const auto& c = PowerPC::ppcState.ps[inst.FC];
const double c0 = Force25Bit(c.PS0AsDouble()); const double c0 = Force25Bit(c.PS0AsDouble());
const double c1 = Force25Bit(c.PS1AsDouble()); const double c1 = Force25Bit(c.PS1AsDouble());
const float tmp0 = const float tmp0 =
ForceSingle(FPSCR, NI_madd(&FPSCR, a.PS0AsDouble(), c0, b.PS0AsDouble()).value); ForceSingle(PowerPC::ppcState.fpscr,
NI_madd(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), c0, b.PS0AsDouble()).value);
const float tmp1 = const float tmp1 =
ForceSingle(FPSCR, NI_madd(&FPSCR, a.PS1AsDouble(), c1, b.PS1AsDouble()).value); ForceSingle(PowerPC::ppcState.fpscr,
NI_madd(&PowerPC::ppcState.fpscr, a.PS1AsDouble(), c1, b.PS1AsDouble()).value);
const float ps0 = std::isnan(tmp0) ? tmp0 : -tmp0; const float ps0 = std::isnan(tmp0) ? tmp0 : -tmp0;
const float ps1 = std::isnan(tmp1) ? tmp1 : -tmp1; const float ps1 = std::isnan(tmp1) ? tmp1 : -tmp1;
rPS(inst.FD).SetBoth(ps0, ps1); PowerPC::ppcState.ps[inst.FD].SetBoth(ps0, ps1);
PowerPC::UpdateFPRFSingle(ps0); PowerPC::ppcState.UpdateFPRFSingle(ps0);
if (inst.Rc) if (inst.Rc)
PowerPC::ppcState.UpdateCR1(); PowerPC::ppcState.UpdateCR1();
@@ -320,15 +352,17 @@ void Interpreter::ps_nmadd(UGeckoInstruction inst)
void Interpreter::ps_sum0(UGeckoInstruction inst) void Interpreter::ps_sum0(UGeckoInstruction inst)
{ {
const auto& a = rPS(inst.FA); const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = rPS(inst.FB); const auto& b = PowerPC::ppcState.ps[inst.FB];
const auto& c = rPS(inst.FC); const auto& c = PowerPC::ppcState.ps[inst.FC];
const float ps0 = ForceSingle(FPSCR, NI_add(&FPSCR, a.PS0AsDouble(), b.PS1AsDouble()).value); const float ps0 =
const float ps1 = ForceSingle(FPSCR, c.PS1AsDouble()); ForceSingle(PowerPC::ppcState.fpscr,
NI_add(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), b.PS1AsDouble()).value);
const float ps1 = ForceSingle(PowerPC::ppcState.fpscr, c.PS1AsDouble());
rPS(inst.FD).SetBoth(ps0, ps1); PowerPC::ppcState.ps[inst.FD].SetBoth(ps0, ps1);
PowerPC::UpdateFPRFSingle(ps0); PowerPC::ppcState.UpdateFPRFSingle(ps0);
if (inst.Rc) if (inst.Rc)
PowerPC::ppcState.UpdateCR1(); PowerPC::ppcState.UpdateCR1();
@@ -336,15 +370,17 @@ void Interpreter::ps_sum0(UGeckoInstruction inst)
void Interpreter::ps_sum1(UGeckoInstruction inst) void Interpreter::ps_sum1(UGeckoInstruction inst)
{ {
const auto& a = rPS(inst.FA); const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = rPS(inst.FB); const auto& b = PowerPC::ppcState.ps[inst.FB];
const auto& c = rPS(inst.FC); const auto& c = PowerPC::ppcState.ps[inst.FC];
const float ps0 = ForceSingle(FPSCR, c.PS0AsDouble()); const float ps0 = ForceSingle(PowerPC::ppcState.fpscr, c.PS0AsDouble());
const float ps1 = ForceSingle(FPSCR, NI_add(&FPSCR, a.PS0AsDouble(), b.PS1AsDouble()).value); const float ps1 =
ForceSingle(PowerPC::ppcState.fpscr,
NI_add(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), b.PS1AsDouble()).value);
rPS(inst.FD).SetBoth(ps0, ps1); PowerPC::ppcState.ps[inst.FD].SetBoth(ps0, ps1);
PowerPC::UpdateFPRFSingle(ps1); PowerPC::ppcState.UpdateFPRFSingle(ps1);
if (inst.Rc) if (inst.Rc)
PowerPC::ppcState.UpdateCR1(); PowerPC::ppcState.UpdateCR1();
@@ -352,15 +388,17 @@ void Interpreter::ps_sum1(UGeckoInstruction inst)
void Interpreter::ps_muls0(UGeckoInstruction inst) void Interpreter::ps_muls0(UGeckoInstruction inst)
{ {
const auto& a = rPS(inst.FA); const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& c = rPS(inst.FC); const auto& c = PowerPC::ppcState.ps[inst.FC];
const double c0 = Force25Bit(c.PS0AsDouble()); const double c0 = Force25Bit(c.PS0AsDouble());
const float ps0 = ForceSingle(FPSCR, NI_mul(&FPSCR, a.PS0AsDouble(), c0).value); const float ps0 = ForceSingle(PowerPC::ppcState.fpscr,
const float ps1 = ForceSingle(FPSCR, NI_mul(&FPSCR, a.PS1AsDouble(), c0).value); NI_mul(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), c0).value);
const float ps1 = ForceSingle(PowerPC::ppcState.fpscr,
NI_mul(&PowerPC::ppcState.fpscr, a.PS1AsDouble(), c0).value);
rPS(inst.FD).SetBoth(ps0, ps1); PowerPC::ppcState.ps[inst.FD].SetBoth(ps0, ps1);
PowerPC::UpdateFPRFSingle(ps0); PowerPC::ppcState.UpdateFPRFSingle(ps0);
if (inst.Rc) if (inst.Rc)
PowerPC::ppcState.UpdateCR1(); PowerPC::ppcState.UpdateCR1();
@@ -368,15 +406,17 @@ void Interpreter::ps_muls0(UGeckoInstruction inst)
void Interpreter::ps_muls1(UGeckoInstruction inst) void Interpreter::ps_muls1(UGeckoInstruction inst)
{ {
const auto& a = rPS(inst.FA); const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& c = rPS(inst.FC); const auto& c = PowerPC::ppcState.ps[inst.FC];
const double c1 = Force25Bit(c.PS1AsDouble()); const double c1 = Force25Bit(c.PS1AsDouble());
const float ps0 = ForceSingle(FPSCR, NI_mul(&FPSCR, a.PS0AsDouble(), c1).value); const float ps0 = ForceSingle(PowerPC::ppcState.fpscr,
const float ps1 = ForceSingle(FPSCR, NI_mul(&FPSCR, a.PS1AsDouble(), c1).value); NI_mul(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), c1).value);
const float ps1 = ForceSingle(PowerPC::ppcState.fpscr,
NI_mul(&PowerPC::ppcState.fpscr, a.PS1AsDouble(), c1).value);
rPS(inst.FD).SetBoth(ps0, ps1); PowerPC::ppcState.ps[inst.FD].SetBoth(ps0, ps1);
PowerPC::UpdateFPRFSingle(ps0); PowerPC::ppcState.UpdateFPRFSingle(ps0);
if (inst.Rc) if (inst.Rc)
PowerPC::ppcState.UpdateCR1(); PowerPC::ppcState.UpdateCR1();
@@ -384,16 +424,20 @@ void Interpreter::ps_muls1(UGeckoInstruction inst)
void Interpreter::ps_madds0(UGeckoInstruction inst) void Interpreter::ps_madds0(UGeckoInstruction inst)
{ {
const auto& a = rPS(inst.FA); const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = rPS(inst.FB); const auto& b = PowerPC::ppcState.ps[inst.FB];
const auto& c = rPS(inst.FC); const auto& c = PowerPC::ppcState.ps[inst.FC];
const double c0 = Force25Bit(c.PS0AsDouble()); const double c0 = Force25Bit(c.PS0AsDouble());
const float ps0 = ForceSingle(FPSCR, NI_madd(&FPSCR, a.PS0AsDouble(), c0, b.PS0AsDouble()).value); const float ps0 =
const float ps1 = ForceSingle(FPSCR, NI_madd(&FPSCR, a.PS1AsDouble(), c0, b.PS1AsDouble()).value); ForceSingle(PowerPC::ppcState.fpscr,
NI_madd(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), c0, b.PS0AsDouble()).value);
const float ps1 =
ForceSingle(PowerPC::ppcState.fpscr,
NI_madd(&PowerPC::ppcState.fpscr, a.PS1AsDouble(), c0, b.PS1AsDouble()).value);
rPS(inst.FD).SetBoth(ps0, ps1); PowerPC::ppcState.ps[inst.FD].SetBoth(ps0, ps1);
PowerPC::UpdateFPRFSingle(ps0); PowerPC::ppcState.UpdateFPRFSingle(ps0);
if (inst.Rc) if (inst.Rc)
PowerPC::ppcState.UpdateCR1(); PowerPC::ppcState.UpdateCR1();
@@ -401,16 +445,20 @@ void Interpreter::ps_madds0(UGeckoInstruction inst)
void Interpreter::ps_madds1(UGeckoInstruction inst) void Interpreter::ps_madds1(UGeckoInstruction inst)
{ {
const auto& a = rPS(inst.FA); const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = rPS(inst.FB); const auto& b = PowerPC::ppcState.ps[inst.FB];
const auto& c = rPS(inst.FC); const auto& c = PowerPC::ppcState.ps[inst.FC];
const double c1 = Force25Bit(c.PS1AsDouble()); const double c1 = Force25Bit(c.PS1AsDouble());
const float ps0 = ForceSingle(FPSCR, NI_madd(&FPSCR, a.PS0AsDouble(), c1, b.PS0AsDouble()).value); const float ps0 =
const float ps1 = ForceSingle(FPSCR, NI_madd(&FPSCR, a.PS1AsDouble(), c1, b.PS1AsDouble()).value); ForceSingle(PowerPC::ppcState.fpscr,
NI_madd(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), c1, b.PS0AsDouble()).value);
const float ps1 =
ForceSingle(PowerPC::ppcState.fpscr,
NI_madd(&PowerPC::ppcState.fpscr, a.PS1AsDouble(), c1, b.PS1AsDouble()).value);
rPS(inst.FD).SetBoth(ps0, ps1); PowerPC::ppcState.ps[inst.FD].SetBoth(ps0, ps1);
PowerPC::UpdateFPRFSingle(ps0); PowerPC::ppcState.UpdateFPRFSingle(ps0);
if (inst.Rc) if (inst.Rc)
PowerPC::ppcState.UpdateCR1(); PowerPC::ppcState.UpdateCR1();
@@ -418,32 +466,32 @@ void Interpreter::ps_madds1(UGeckoInstruction inst)
void Interpreter::ps_cmpu0(UGeckoInstruction inst) void Interpreter::ps_cmpu0(UGeckoInstruction inst)
{ {
const auto& a = rPS(inst.FA); const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = rPS(inst.FB); const auto& b = PowerPC::ppcState.ps[inst.FB];
Helper_FloatCompareUnordered(inst, a.PS0AsDouble(), b.PS0AsDouble()); Helper_FloatCompareUnordered(inst, a.PS0AsDouble(), b.PS0AsDouble());
} }
void Interpreter::ps_cmpo0(UGeckoInstruction inst) void Interpreter::ps_cmpo0(UGeckoInstruction inst)
{ {
const auto& a = rPS(inst.FA); const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = rPS(inst.FB); const auto& b = PowerPC::ppcState.ps[inst.FB];
Helper_FloatCompareOrdered(inst, a.PS0AsDouble(), b.PS0AsDouble()); Helper_FloatCompareOrdered(inst, a.PS0AsDouble(), b.PS0AsDouble());
} }
void Interpreter::ps_cmpu1(UGeckoInstruction inst) void Interpreter::ps_cmpu1(UGeckoInstruction inst)
{ {
const auto& a = rPS(inst.FA); const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = rPS(inst.FB); const auto& b = PowerPC::ppcState.ps[inst.FB];
Helper_FloatCompareUnordered(inst, a.PS1AsDouble(), b.PS1AsDouble()); Helper_FloatCompareUnordered(inst, a.PS1AsDouble(), b.PS1AsDouble());
} }
void Interpreter::ps_cmpo1(UGeckoInstruction inst) void Interpreter::ps_cmpo1(UGeckoInstruction inst)
{ {
const auto& a = rPS(inst.FA); const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = rPS(inst.FB); const auto& b = PowerPC::ppcState.ps[inst.FB];
Helper_FloatCompareOrdered(inst, a.PS1AsDouble(), b.PS1AsDouble()); Helper_FloatCompareOrdered(inst, a.PS1AsDouble(), b.PS1AsDouble());
} }

View File

@@ -36,8 +36,8 @@ void Interpreter::mtfsb0x(UGeckoInstruction inst)
{ {
u32 b = 0x80000000 >> inst.CRBD; u32 b = 0x80000000 >> inst.CRBD;
FPSCR.Hex &= ~b; PowerPC::ppcState.fpscr.Hex &= ~b;
FPSCRUpdated(&FPSCR); FPSCRUpdated(&PowerPC::ppcState.fpscr);
if (inst.Rc) if (inst.Rc)
PowerPC::ppcState.UpdateCR1(); PowerPC::ppcState.UpdateCR1();
@@ -50,11 +50,11 @@ void Interpreter::mtfsb1x(UGeckoInstruction inst)
const u32 b = 0x80000000 >> bit; const u32 b = 0x80000000 >> bit;
if ((b & FPSCR_ANY_X) != 0) if ((b & FPSCR_ANY_X) != 0)
SetFPException(&FPSCR, b); SetFPException(&PowerPC::ppcState.fpscr, b);
else else
FPSCR |= b; PowerPC::ppcState.fpscr |= b;
FPSCRUpdated(&FPSCR); FPSCRUpdated(&PowerPC::ppcState.fpscr);
if (inst.Rc) if (inst.Rc)
PowerPC::ppcState.UpdateCR1(); PowerPC::ppcState.UpdateCR1();
@@ -67,9 +67,9 @@ void Interpreter::mtfsfix(UGeckoInstruction inst)
const u32 mask = (pre_shifted_mask >> (4 * field)); const u32 mask = (pre_shifted_mask >> (4 * field));
const u32 imm = (inst.hex << 16) & pre_shifted_mask; const u32 imm = (inst.hex << 16) & pre_shifted_mask;
FPSCR = (FPSCR.Hex & ~mask) | (imm >> (4 * field)); PowerPC::ppcState.fpscr = (PowerPC::ppcState.fpscr.Hex & ~mask) | (imm >> (4 * field));
FPSCRUpdated(&FPSCR); FPSCRUpdated(&PowerPC::ppcState.fpscr);
if (inst.Rc) if (inst.Rc)
PowerPC::ppcState.UpdateCR1(); PowerPC::ppcState.UpdateCR1();
@@ -85,8 +85,9 @@ void Interpreter::mtfsfx(UGeckoInstruction inst)
m |= (0xFU << (i * 4)); m |= (0xFU << (i * 4));
} }
FPSCR = (FPSCR.Hex & ~m) | (static_cast<u32>(rPS(inst.FB).PS0AsU64()) & m); PowerPC::ppcState.fpscr = (PowerPC::ppcState.fpscr.Hex & ~m) |
FPSCRUpdated(&FPSCR); (static_cast<u32>(PowerPC::ppcState.ps[inst.FB].PS0AsU64()) & m);
FPSCRUpdated(&PowerPC::ppcState.fpscr);
if (inst.Rc) if (inst.Rc)
PowerPC::ppcState.UpdateCR1(); PowerPC::ppcState.UpdateCR1();
@@ -94,14 +95,14 @@ void Interpreter::mtfsfx(UGeckoInstruction inst)
void Interpreter::mcrxr(UGeckoInstruction inst) void Interpreter::mcrxr(UGeckoInstruction inst)
{ {
PowerPC::ppcState.cr.SetField(inst.CRFD, PowerPC::GetXER().Hex >> 28); PowerPC::ppcState.cr.SetField(inst.CRFD, PowerPC::ppcState.GetXER().Hex >> 28);
PowerPC::ppcState.xer_ca = 0; PowerPC::ppcState.xer_ca = 0;
PowerPC::ppcState.xer_so_ov = 0; PowerPC::ppcState.xer_so_ov = 0;
} }
void Interpreter::mfcr(UGeckoInstruction inst) void Interpreter::mfcr(UGeckoInstruction inst)
{ {
rGPR[inst.RD] = PowerPC::ppcState.cr.Get(); PowerPC::ppcState.gpr[inst.RD] = PowerPC::ppcState.cr.Get();
} }
void Interpreter::mtcrf(UGeckoInstruction inst) void Interpreter::mtcrf(UGeckoInstruction inst)
@@ -109,7 +110,7 @@ void Interpreter::mtcrf(UGeckoInstruction inst)
const u32 crm = inst.CRM; const u32 crm = inst.CRM;
if (crm == 0xFF) if (crm == 0xFF)
{ {
PowerPC::ppcState.cr.Set(rGPR[inst.RS]); PowerPC::ppcState.cr.Set(PowerPC::ppcState.gpr[inst.RS]);
} }
else else
{ {
@@ -121,56 +122,57 @@ void Interpreter::mtcrf(UGeckoInstruction inst)
mask |= 0xFU << (i * 4); mask |= 0xFU << (i * 4);
} }
PowerPC::ppcState.cr.Set((PowerPC::ppcState.cr.Get() & ~mask) | (rGPR[inst.RS] & mask)); PowerPC::ppcState.cr.Set((PowerPC::ppcState.cr.Get() & ~mask) |
(PowerPC::ppcState.gpr[inst.RS] & mask));
} }
} }
void Interpreter::mfmsr(UGeckoInstruction inst) void Interpreter::mfmsr(UGeckoInstruction inst)
{ {
if (MSR.PR) if (PowerPC::ppcState.msr.PR)
{ {
GenerateProgramException(ProgramExceptionCause::PrivilegedInstruction); GenerateProgramException(ProgramExceptionCause::PrivilegedInstruction);
return; return;
} }
rGPR[inst.RD] = MSR.Hex; PowerPC::ppcState.gpr[inst.RD] = PowerPC::ppcState.msr.Hex;
} }
void Interpreter::mfsr(UGeckoInstruction inst) void Interpreter::mfsr(UGeckoInstruction inst)
{ {
if (MSR.PR) if (PowerPC::ppcState.msr.PR)
{ {
GenerateProgramException(ProgramExceptionCause::PrivilegedInstruction); GenerateProgramException(ProgramExceptionCause::PrivilegedInstruction);
return; return;
} }
rGPR[inst.RD] = PowerPC::ppcState.sr[inst.SR]; PowerPC::ppcState.gpr[inst.RD] = PowerPC::ppcState.sr[inst.SR];
} }
void Interpreter::mfsrin(UGeckoInstruction inst) void Interpreter::mfsrin(UGeckoInstruction inst)
{ {
if (MSR.PR) if (PowerPC::ppcState.msr.PR)
{ {
GenerateProgramException(ProgramExceptionCause::PrivilegedInstruction); GenerateProgramException(ProgramExceptionCause::PrivilegedInstruction);
return; return;
} }
const u32 index = (rGPR[inst.RB] >> 28) & 0xF; const u32 index = (PowerPC::ppcState.gpr[inst.RB] >> 28) & 0xF;
rGPR[inst.RD] = PowerPC::ppcState.sr[index]; PowerPC::ppcState.gpr[inst.RD] = PowerPC::ppcState.sr[index];
} }
void Interpreter::mtmsr(UGeckoInstruction inst) void Interpreter::mtmsr(UGeckoInstruction inst)
{ {
if (MSR.PR) if (PowerPC::ppcState.msr.PR)
{ {
GenerateProgramException(ProgramExceptionCause::PrivilegedInstruction); GenerateProgramException(ProgramExceptionCause::PrivilegedInstruction);
return; return;
} }
MSR.Hex = rGPR[inst.RS]; PowerPC::ppcState.msr.Hex = PowerPC::ppcState.gpr[inst.RS];
// FE0/FE1 may have been set // FE0/FE1 may have been set
CheckFPExceptions(FPSCR); CheckFPExceptions(PowerPC::ppcState.fpscr);
PowerPC::CheckExceptions(); PowerPC::CheckExceptions();
m_end_block = true; m_end_block = true;
@@ -180,27 +182,27 @@ void Interpreter::mtmsr(UGeckoInstruction inst)
void Interpreter::mtsr(UGeckoInstruction inst) void Interpreter::mtsr(UGeckoInstruction inst)
{ {
if (MSR.PR) if (PowerPC::ppcState.msr.PR)
{ {
GenerateProgramException(ProgramExceptionCause::PrivilegedInstruction); GenerateProgramException(ProgramExceptionCause::PrivilegedInstruction);
return; return;
} }
const u32 index = inst.SR; const u32 index = inst.SR;
const u32 value = rGPR[inst.RS]; const u32 value = PowerPC::ppcState.gpr[inst.RS];
PowerPC::ppcState.SetSR(index, value); PowerPC::ppcState.SetSR(index, value);
} }
void Interpreter::mtsrin(UGeckoInstruction inst) void Interpreter::mtsrin(UGeckoInstruction inst)
{ {
if (MSR.PR) if (PowerPC::ppcState.msr.PR)
{ {
GenerateProgramException(ProgramExceptionCause::PrivilegedInstruction); GenerateProgramException(ProgramExceptionCause::PrivilegedInstruction);
return; return;
} }
const u32 index = (rGPR[inst.RB] >> 28) & 0xF; const u32 index = (PowerPC::ppcState.gpr[inst.RB] >> 28) & 0xF;
const u32 value = rGPR[inst.RS]; const u32 value = PowerPC::ppcState.gpr[inst.RS];
PowerPC::ppcState.SetSR(index, value); PowerPC::ppcState.SetSR(index, value);
} }
@@ -216,8 +218,8 @@ void Interpreter::mfspr(UGeckoInstruction inst)
const u32 index = ((inst.SPR & 0x1F) << 5) + ((inst.SPR >> 5) & 0x1F); const u32 index = ((inst.SPR & 0x1F) << 5) + ((inst.SPR >> 5) & 0x1F);
// XER, LR, CTR, and timebase halves are the only ones available in user mode. // XER, LR, CTR, and timebase halves are the only ones available in user mode.
if (MSR.PR && index != SPR_XER && index != SPR_LR && index != SPR_CTR && index != SPR_TL && if (PowerPC::ppcState.msr.PR && index != SPR_XER && index != SPR_LR && index != SPR_CTR &&
index != SPR_TU) index != SPR_TL && index != SPR_TU)
{ {
GenerateProgramException(ProgramExceptionCause::PrivilegedInstruction); GenerateProgramException(ProgramExceptionCause::PrivilegedInstruction);
return; return;
@@ -226,9 +228,9 @@ void Interpreter::mfspr(UGeckoInstruction inst)
switch (index) switch (index)
{ {
case SPR_DEC: case SPR_DEC:
if ((rSPR(index) & 0x80000000) == 0) // We are still decrementing if ((PowerPC::ppcState.spr[index] & 0x80000000) == 0) // We are still decrementing
{ {
rSPR(index) = SystemTimers::GetFakeDecrementer(); PowerPC::ppcState.spr[index] = SystemTimers::GetFakeDecrementer();
} }
break; break;
@@ -246,40 +248,40 @@ void Interpreter::mfspr(UGeckoInstruction inst)
// Currently, we always treat the buffer as not empty, as the exact behavior is unclear // Currently, we always treat the buffer as not empty, as the exact behavior is unclear
// (and games that use display lists will hang if the bit doesn't eventually become zero). // (and games that use display lists will hang if the bit doesn't eventually become zero).
if (Core::System::GetInstance().GetGPFifo().IsBNE()) if (Core::System::GetInstance().GetGPFifo().IsBNE())
rSPR(index) |= 1; PowerPC::ppcState.spr[index] |= 1;
else else
rSPR(index) &= ~1; PowerPC::ppcState.spr[index] &= ~1;
} }
break; break;
case SPR_XER: case SPR_XER:
rSPR(index) = PowerPC::GetXER().Hex; PowerPC::ppcState.spr[index] = PowerPC::ppcState.GetXER().Hex;
break; break;
case SPR_UPMC1: case SPR_UPMC1:
rSPR(index) = rSPR(SPR_PMC1); PowerPC::ppcState.spr[index] = PowerPC::ppcState.spr[SPR_PMC1];
break; break;
case SPR_UPMC2: case SPR_UPMC2:
rSPR(index) = rSPR(SPR_PMC2); PowerPC::ppcState.spr[index] = PowerPC::ppcState.spr[SPR_PMC2];
break; break;
case SPR_UPMC3: case SPR_UPMC3:
rSPR(index) = rSPR(SPR_PMC3); PowerPC::ppcState.spr[index] = PowerPC::ppcState.spr[SPR_PMC3];
break; break;
case SPR_UPMC4: case SPR_UPMC4:
rSPR(index) = rSPR(SPR_PMC4); PowerPC::ppcState.spr[index] = PowerPC::ppcState.spr[SPR_PMC4];
break; break;
case SPR_IABR: case SPR_IABR:
// A strange quirk: reading back this register on hardware will always have the TE (Translation // A strange quirk: reading back this register on hardware will always have the TE (Translation
// enabled) bit set to 0 (despite the bit appearing to function normally when set). This does // enabled) bit set to 0 (despite the bit appearing to function normally when set). This does
// not apply to the DABR. // not apply to the DABR.
rGPR[inst.RD] = rSPR(index) & ~1; PowerPC::ppcState.gpr[inst.RD] = PowerPC::ppcState.spr[index] & ~1;
return; return;
} }
rGPR[inst.RD] = rSPR(index); PowerPC::ppcState.gpr[inst.RD] = PowerPC::ppcState.spr[index];
} }
void Interpreter::mtspr(UGeckoInstruction inst) void Interpreter::mtspr(UGeckoInstruction inst)
@@ -287,14 +289,14 @@ void Interpreter::mtspr(UGeckoInstruction inst)
const u32 index = (inst.SPRU << 5) | (inst.SPRL & 0x1F); const u32 index = (inst.SPRU << 5) | (inst.SPRL & 0x1F);
// XER, LR, and CTR are the only ones available to be written to in user mode // XER, LR, and CTR are the only ones available to be written to in user mode
if (MSR.PR && index != SPR_XER && index != SPR_LR && index != SPR_CTR) if (PowerPC::ppcState.msr.PR && index != SPR_XER && index != SPR_LR && index != SPR_CTR)
{ {
GenerateProgramException(ProgramExceptionCause::PrivilegedInstruction); GenerateProgramException(ProgramExceptionCause::PrivilegedInstruction);
return; return;
} }
const u32 old_value = rSPR(index); const u32 old_value = PowerPC::ppcState.spr[index];
rSPR(index) = rGPR[inst.RD]; PowerPC::ppcState.spr[index] = PowerPC::ppcState.gpr[inst.RD];
// Our DMA emulation is highly inaccurate - instead of properly emulating the queue // Our DMA emulation is highly inaccurate - instead of properly emulating the queue
// and so on, we simply make all DMA:s complete instantaneously. // and so on, we simply make all DMA:s complete instantaneously.
@@ -307,36 +309,38 @@ void Interpreter::mtspr(UGeckoInstruction inst)
break; break;
case SPR_TL_W: case SPR_TL_W:
TL = rGPR[inst.RD]; TL(PowerPC::ppcState) = PowerPC::ppcState.gpr[inst.RD];
SystemTimers::TimeBaseSet(); SystemTimers::TimeBaseSet();
break; break;
case SPR_TU_W: case SPR_TU_W:
TU = rGPR[inst.RD]; TU(PowerPC::ppcState) = PowerPC::ppcState.gpr[inst.RD];
SystemTimers::TimeBaseSet(); SystemTimers::TimeBaseSet();
break; break;
case SPR_PVR: case SPR_PVR:
// PVR is a read-only register so maintain its value. // PVR is a read-only register so maintain its value.
rSPR(index) = old_value; PowerPC::ppcState.spr[index] = old_value;
break; break;
case SPR_HID0: // HID0 case SPR_HID0: // HID0
{ {
UReg_HID0 old_hid0; UReg_HID0 old_hid0;
old_hid0.Hex = old_value; old_hid0.Hex = old_value;
if (HID0.ICE != old_hid0.ICE) if (HID0(PowerPC::ppcState).ICE != old_hid0.ICE)
{ {
INFO_LOG_FMT(POWERPC, "Instruction Cache Enable (HID0.ICE) = {}", HID0.ICE); INFO_LOG_FMT(POWERPC, "Instruction Cache Enable (HID0.ICE) = {}",
HID0(PowerPC::ppcState).ICE);
} }
if (HID0.ILOCK != old_hid0.ILOCK) if (HID0(PowerPC::ppcState).ILOCK != old_hid0.ILOCK)
{ {
INFO_LOG_FMT(POWERPC, "Instruction Cache Lock (HID0.ILOCK) = {}", HID0.ILOCK); INFO_LOG_FMT(POWERPC, "Instruction Cache Lock (HID0.ILOCK) = {}",
HID0(PowerPC::ppcState).ILOCK);
} }
if (HID0.ICFI) if (HID0(PowerPC::ppcState).ICFI)
{ {
HID0.ICFI = 0; HID0(PowerPC::ppcState).ICFI = 0;
INFO_LOG_FMT(POWERPC, "Flush Instruction Cache! ICE={}", HID0.ICE); INFO_LOG_FMT(POWERPC, "Flush Instruction Cache! ICE={}", HID0(PowerPC::ppcState).ICE);
// this is rather slow // this is rather slow
// most games do it only once during initialization // most games do it only once during initialization
PowerPC::ppcState.iCache.Reset(); PowerPC::ppcState.iCache.Reset();
@@ -348,7 +352,7 @@ void Interpreter::mtspr(UGeckoInstruction inst)
// Despite being documented as a read-only register, it actually isn't. Bits // Despite being documented as a read-only register, it actually isn't. Bits
// 0-4 (27-31 from a little endian perspective) are modifiable. The rest are not // 0-4 (27-31 from a little endian perspective) are modifiable. The rest are not
// affected, as those bits are reserved and ignore writes to them. // affected, as those bits are reserved and ignore writes to them.
rSPR(index) &= 0xF8000000; PowerPC::ppcState.spr[index] &= 0xF8000000;
break; break;
case SPR_HID2: case SPR_HID2:
@@ -356,21 +360,23 @@ void Interpreter::mtspr(UGeckoInstruction inst)
// TODO: emulate locked cache and DMA bits. // TODO: emulate locked cache and DMA bits.
// Only the lower half of the register (upper half from a little endian perspective) // Only the lower half of the register (upper half from a little endian perspective)
// is modifiable, except for the DMAQL field. // is modifiable, except for the DMAQL field.
rSPR(index) = (rSPR(index) & 0xF0FF0000) | (old_value & 0x0F000000); PowerPC::ppcState.spr[index] =
(PowerPC::ppcState.spr[index] & 0xF0FF0000) | (old_value & 0x0F000000);
break; break;
case SPR_HID4: case SPR_HID4:
if (old_value != rSPR(index)) if (old_value != PowerPC::ppcState.spr[index])
{ {
INFO_LOG_FMT(POWERPC, "HID4 updated {:x} {:x}", old_value, rSPR(index)); INFO_LOG_FMT(POWERPC, "HID4 updated {:x} {:x}", old_value, PowerPC::ppcState.spr[index]);
PowerPC::IBATUpdated(); PowerPC::IBATUpdated();
PowerPC::DBATUpdated(); PowerPC::DBATUpdated();
} }
break; break;
case SPR_WPAR: case SPR_WPAR:
ASSERT_MSG(POWERPC, rSPR(SPR_WPAR) == GPFifo::GATHER_PIPE_PHYSICAL_ADDRESS, ASSERT_MSG(POWERPC, PowerPC::ppcState.spr[SPR_WPAR] == GPFifo::GATHER_PIPE_PHYSICAL_ADDRESS,
"Gather pipe changed to unexpected address {:08x} @ PC {:08x}", rSPR(SPR_WPAR), PC); "Gather pipe changed to unexpected address {:08x} @ PC {:08x}",
PowerPC::ppcState.spr[SPR_WPAR], PowerPC::ppcState.pc);
Core::System::GetInstance().GetGPFifo().ResetGatherPipe(); Core::System::GetInstance().GetGPFifo().ResetGatherPipe();
break; break;
@@ -388,20 +394,20 @@ void Interpreter::mtspr(UGeckoInstruction inst)
case SPR_DMAL: case SPR_DMAL:
// Locked cache<->Memory DMA // Locked cache<->Memory DMA
// Total fake, we ignore that DMAs take time. // Total fake, we ignore that DMAs take time.
if (DMAL.DMA_T) if (DMAL(PowerPC::ppcState).DMA_T)
{ {
const u32 mem_address = DMAU.MEM_ADDR << 5; const u32 mem_address = DMAU(PowerPC::ppcState).MEM_ADDR << 5;
const u32 cache_address = DMAL.LC_ADDR << 5; const u32 cache_address = DMAL(PowerPC::ppcState).LC_ADDR << 5;
u32 length = ((DMAU.DMA_LEN_U << 2) | DMAL.DMA_LEN_L); u32 length = ((DMAU(PowerPC::ppcState).DMA_LEN_U << 2) | DMAL(PowerPC::ppcState).DMA_LEN_L);
if (length == 0) if (length == 0)
length = 128; length = 128;
if (DMAL.DMA_LD) if (DMAL(PowerPC::ppcState).DMA_LD)
PowerPC::DMA_MemoryToLC(cache_address, mem_address, length); PowerPC::DMA_MemoryToLC(cache_address, mem_address, length);
else else
PowerPC::DMA_LCToMemory(mem_address, cache_address, length); PowerPC::DMA_LCToMemory(mem_address, cache_address, length);
} }
DMAL.DMA_T = 0; DMAL(PowerPC::ppcState).DMA_T = 0;
break; break;
case SPR_L2CR: case SPR_L2CR:
@@ -409,7 +415,7 @@ void Interpreter::mtspr(UGeckoInstruction inst)
case SPR_DEC: case SPR_DEC:
// Top bit from 0 to 1 // Top bit from 0 to 1
if ((old_value >> 31) == 0 && (rGPR[inst.RD] >> 31) != 0) if ((old_value >> 31) == 0 && (PowerPC::ppcState.gpr[inst.RD] >> 31) != 0)
{ {
INFO_LOG_FMT(POWERPC, "Software triggered Decrementer exception"); INFO_LOG_FMT(POWERPC, "Software triggered Decrementer exception");
PowerPC::ppcState.Exceptions |= EXCEPTION_DECREMENTER; PowerPC::ppcState.Exceptions |= EXCEPTION_DECREMENTER;
@@ -423,7 +429,7 @@ void Interpreter::mtspr(UGeckoInstruction inst)
break; break;
case SPR_XER: case SPR_XER:
PowerPC::SetXER(UReg_XER{rSPR(index)}); PowerPC::ppcState.SetXER(UReg_XER{PowerPC::ppcState.spr[index]});
break; break;
case SPR_DBAT0L: case SPR_DBAT0L:
@@ -442,9 +448,10 @@ void Interpreter::mtspr(UGeckoInstruction inst)
case SPR_DBAT6U: case SPR_DBAT6U:
case SPR_DBAT7L: case SPR_DBAT7L:
case SPR_DBAT7U: case SPR_DBAT7U:
if (old_value != rSPR(index)) if (old_value != PowerPC::ppcState.spr[index])
{ {
INFO_LOG_FMT(POWERPC, "DBAT updated {} {:x} {:x}", index, old_value, rSPR(index)); INFO_LOG_FMT(POWERPC, "DBAT updated {} {:x} {:x}", index, old_value,
PowerPC::ppcState.spr[index]);
PowerPC::DBATUpdated(); PowerPC::DBATUpdated();
} }
break; break;
@@ -465,9 +472,10 @@ void Interpreter::mtspr(UGeckoInstruction inst)
case SPR_IBAT6U: case SPR_IBAT6U:
case SPR_IBAT7L: case SPR_IBAT7L:
case SPR_IBAT7U: case SPR_IBAT7U:
if (old_value != rSPR(index)) if (old_value != PowerPC::ppcState.spr[index])
{ {
INFO_LOG_FMT(POWERPC, "IBAT updated {} {:x} {:x}", index, old_value, rSPR(index)); INFO_LOG_FMT(POWERPC, "IBAT updated {} {:x} {:x}", index, old_value,
PowerPC::ppcState.spr[index]);
PowerPC::IBATUpdated(); PowerPC::IBATUpdated();
} }
break; break;
@@ -484,7 +492,7 @@ void Interpreter::mtspr(UGeckoInstruction inst)
constexpr u32 SIMULATED_TEMP = 42; // °C constexpr u32 SIMULATED_TEMP = 42; // °C
auto UpdateThermalReg = [](UReg_THRM12* reg) { auto UpdateThermalReg = [](UReg_THRM12* reg) {
if (!THRM3.E || !reg->V) if (!THRM3(PowerPC::ppcState).E || !reg->V)
{ {
reg->TIV = 0; reg->TIV = 0;
} }
@@ -498,8 +506,8 @@ void Interpreter::mtspr(UGeckoInstruction inst)
} }
}; };
UpdateThermalReg(&THRM1); UpdateThermalReg(&THRM1(PowerPC::ppcState));
UpdateThermalReg(&THRM2); UpdateThermalReg(&THRM2(PowerPC::ppcState));
break; break;
} }
} }
@@ -585,18 +593,18 @@ void Interpreter::isync(UGeckoInstruction inst)
void Interpreter::mcrfs(UGeckoInstruction inst) void Interpreter::mcrfs(UGeckoInstruction inst)
{ {
const u32 shift = 4 * (7 - inst.CRFS); const u32 shift = 4 * (7 - inst.CRFS);
const u32 fpflags = (FPSCR.Hex >> shift) & 0xF; const u32 fpflags = (PowerPC::ppcState.fpscr.Hex >> shift) & 0xF;
// If any exception bits were read, clear them // If any exception bits were read, clear them
FPSCR.Hex &= ~((0xF << shift) & (FPSCR_FX | FPSCR_ANY_X)); PowerPC::ppcState.fpscr.Hex &= ~((0xF << shift) & (FPSCR_FX | FPSCR_ANY_X));
FPSCRUpdated(&FPSCR); FPSCRUpdated(&PowerPC::ppcState.fpscr);
PowerPC::ppcState.cr.SetField(inst.CRFD, fpflags); PowerPC::ppcState.cr.SetField(inst.CRFD, fpflags);
} }
void Interpreter::mffsx(UGeckoInstruction inst) void Interpreter::mffsx(UGeckoInstruction inst)
{ {
rPS(inst.FD).SetPS0(UINT64_C(0xFFF8000000000000) | FPSCR.Hex); PowerPC::ppcState.ps[inst.FD].SetPS0(UINT64_C(0xFFF8000000000000) | PowerPC::ppcState.fpscr.Hex);
if (inst.Rc) if (inst.Rc)
PowerPC::ppcState.UpdateCR1(); PowerPC::ppcState.UpdateCR1();

View File

@@ -504,16 +504,17 @@ static void ImHere()
if (!f) if (!f)
f.Open("log64.txt", "w"); 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++; been_here.find(PowerPC::ppcState.pc)->second++;
if ((been_here.find(PC)->second) & 1023) if ((been_here.find(PowerPC::ppcState.pc)->second) & 1023)
return; return;
} }
INFO_LOG_FMT(DYNA_REC, "I'm here - PC = {:08x} , LR = {:08x}", PC, LR); INFO_LOG_FMT(DYNA_REC, "I'm here - PC = {:08x} , LR = {:08x}", PowerPC::ppcState.pc,
been_here[PC] = 1; LR(PowerPC::ppcState));
been_here[PowerPC::ppcState.pc] = 1;
} }
bool Jit64::Cleanup() bool Jit64::Cleanup()
@@ -534,11 +535,11 @@ bool Jit64::Cleanup()
} }
// SPEED HACK: MMCR0/MMCR1 should be checked at run-time, not at compile time. // 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_PushRegistersAndAdjustStack({}, 0);
ABI_CallFunctionCCC(PowerPC::UpdatePerformanceMonitor, js.downcountAmount, js.numLoadStoreInst, ABI_CallFunctionCCCP(PowerPC::UpdatePerformanceMonitor, js.downcountAmount, js.numLoadStoreInst,
js.numFloatingPointInst); js.numFloatingPointInst, &PowerPC::ppcState);
ABI_PopRegistersAndAdjustStack({}, 0); ABI_PopRegistersAndAdjustStack({}, 0);
did_something = true; did_something = true;
} }
@@ -758,7 +759,9 @@ void Jit64::Trace()
DEBUG_LOG_FMT(DYNA_REC, DEBUG_LOG_FMT(DYNA_REC,
"JIT64 PC: {:08x} SRR0: {:08x} SRR1: {:08x} FPSCR: {:08x} " "JIT64 PC: {:08x} SRR0: {:08x} SRR1: {:08x} FPSCR: {:08x} "
"MSR: {:08x} LR: {: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) void Jit64::Jit(u32 em_address)
@@ -829,7 +832,7 @@ void Jit64::Jit(u32 em_address, bool clear_cache_and_retry_on_failure)
if (code_block.m_memory_exception) if (code_block.m_memory_exception)
{ {
// Address of instruction could not be translated // Address of instruction could not be translated
NPC = nextPC; PowerPC::ppcState.npc = nextPC;
PowerPC::ppcState.Exceptions |= EXCEPTION_ISI; PowerPC::ppcState.Exceptions |= EXCEPTION_ISI;
PowerPC::CheckExceptions(); PowerPC::CheckExceptions();
WARN_LOG_FMT(POWERPC, "ISI exception at {:#010x}", nextPC); WARN_LOG_FMT(POWERPC, "ISI exception at {:#010x}", nextPC);
@@ -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. // the start of the block in case our guess turns out wrong.
for (int gqr : gqr_static) for (int gqr : gqr_static)
{ {
u32 value = GQR(gqr); u32 value = GQR(PowerPC::ppcState, gqr);
js.constantGqr[gqr] = value; js.constantGqr[gqr] = value;
CMP_or_TEST(32, PPCSTATE(spr[SPR_GQR0 + gqr]), Imm32(value)); CMP_or_TEST(32, PPCSTATE(spr[SPR_GQR0 + gqr]), Imm32(value));
J_CC(CC_NZ, target); J_CC(CC_NZ, target);

View File

@@ -320,7 +320,7 @@ void Jit64::dcbx(UGeckoInstruction inst)
FixupBranch bat_lookup_failed; FixupBranch bat_lookup_failed;
MOV(32, R(effective_address), R(addr)); MOV(32, R(effective_address), R(addr));
const u8* loop_start = GetCodePtr(); const u8* loop_start = GetCodePtr();
if (MSR.IR) if (PowerPC::ppcState.msr.IR)
{ {
// Translate effective address to physical address. // Translate effective address to physical address.
bat_lookup_failed = BATAddressLookup(addr, tmp, PowerPC::ibat_table.data()); bat_lookup_failed = BATAddressLookup(addr, tmp, PowerPC::ibat_table.data());
@@ -349,7 +349,7 @@ void Jit64::dcbx(UGeckoInstruction inst)
SwitchToFarCode(); SwitchToFarCode();
SetJumpTarget(invalidate_needed); SetJumpTarget(invalidate_needed);
if (MSR.IR) if (PowerPC::ppcState.msr.IR)
SetJumpTarget(bat_lookup_failed); SetJumpTarget(bat_lookup_failed);
BitSet32 registersInUse = CallerSavedRegistersInUse(); BitSet32 registersInUse = CallerSavedRegistersInUse();
@@ -422,7 +422,7 @@ void Jit64::dcbz(UGeckoInstruction inst)
end_dcbz_hack = J_CC(CC_L); 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) if (emit_fast_path)
{ {

View File

@@ -23,7 +23,7 @@ void Jit64::psq_stXX(UGeckoInstruction inst)
JITDISABLE(bJITLoadStorePairedOff); JITDISABLE(bJITLoadStorePairedOff);
// For performance, the AsmCommon routines assume address translation is on. // 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; s32 offset = inst.SIMM_12;
bool indexed = inst.OPCD == 4; bool indexed = inst.OPCD == 4;
@@ -112,7 +112,7 @@ void Jit64::psq_lXX(UGeckoInstruction inst)
JITDISABLE(bJITLoadStorePairedOff); JITDISABLE(bJITLoadStorePairedOff);
// For performance, the AsmCommon routines assume address translation is on. // 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; s32 offset = inst.SIMM_12;
bool indexed = inst.OPCD == 4; bool indexed = inst.OPCD == 4;

View File

@@ -367,7 +367,7 @@ void EmuCodeBlock::SafeLoadToReg(X64Reg reg_value, const Gen::OpArg& opAddress,
} }
FixupBranch exit; 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; const bool fast_check_address = !slowmem && dr_set && m_jit.jo.fastmem_arena;
if (fast_check_address) if (fast_check_address)
{ {
@@ -537,7 +537,7 @@ void EmuCodeBlock::SafeWriteRegToReg(OpArg reg_value, X64Reg reg_addr, int acces
} }
FixupBranch exit; 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; const bool fast_check_address = !slowmem && dr_set && m_jit.jo.fastmem_arena;
if (fast_check_address) if (fast_check_address)
{ {

View File

@@ -288,12 +288,13 @@ void JitArm64::Cleanup()
} }
// SPEED HACK: MMCR0/MMCR1 should be checked at run-time, not at compile time. // 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); MOVP2R(ARM64Reg::X8, &PowerPC::UpdatePerformanceMonitor);
MOVI2R(ARM64Reg::X0, js.downcountAmount); MOVI2R(ARM64Reg::X0, js.downcountAmount);
MOVI2R(ARM64Reg::X1, js.numLoadStoreInst); MOVI2R(ARM64Reg::X1, js.numLoadStoreInst);
MOVI2R(ARM64Reg::X2, js.numFloatingPointInst); MOVI2R(ARM64Reg::X2, js.numFloatingPointInst);
MOVP2R(ARM64Reg::X3, &PowerPC::ppcState);
BLR(ARM64Reg::X8); BLR(ARM64Reg::X8);
} }
} }
@@ -705,7 +706,9 @@ void JitArm64::Trace()
DEBUG_LOG_FMT(DYNA_REC, DEBUG_LOG_FMT(DYNA_REC,
"JitArm64 PC: {:08x} SRR0: {:08x} SRR1: {:08x} FPSCR: {:08x} " "JitArm64 PC: {:08x} SRR0: {:08x} SRR1: {:08x} FPSCR: {:08x} "
"MSR: {:08x} LR: {: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) void JitArm64::Jit(u32 em_address)
@@ -779,7 +782,7 @@ void JitArm64::Jit(u32 em_address, bool clear_cache_and_retry_on_failure)
if (code_block.m_memory_exception) if (code_block.m_memory_exception)
{ {
// Address of instruction could not be translated // Address of instruction could not be translated
NPC = nextPC; PowerPC::ppcState.npc = nextPC;
PowerPC::ppcState.Exceptions |= EXCEPTION_ISI; PowerPC::ppcState.Exceptions |= EXCEPTION_ISI;
PowerPC::CheckExceptions(); PowerPC::CheckExceptions();
WARN_LOG_FMT(POWERPC, "ISI exception at {:#010x}", nextPC); WARN_LOG_FMT(POWERPC, "ISI exception at {:#010x}", nextPC);
@@ -895,7 +898,7 @@ bool JitArm64::DoJit(u32 em_address, JitBlock* b, u32 nextPC)
js.pairedQuantizeAddresses.find(js.blockStart) == js.pairedQuantizeAddresses.end()) js.pairedQuantizeAddresses.find(js.blockStart) == js.pairedQuantizeAddresses.end())
{ {
int gqr = *code_block.m_gqr_used.begin(); 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)); LDR(IndexType::Unsigned, ARM64Reg::W0, PPC_REG, PPCSTATE_OFF_SPR(SPR_GQR0 + gqr));
FixupBranch no_fail = CBZ(ARM64Reg::W0); FixupBranch no_fail = CBZ(ARM64Reg::W0);

View File

@@ -731,7 +731,7 @@ void JitArm64::dcbx(UGeckoInstruction inst)
// Translate effective address to physical address. // Translate effective address to physical address.
const u8* loop_start = GetCodePtr(); const u8* loop_start = GetCodePtr();
FixupBranch bat_lookup_failed; FixupBranch bat_lookup_failed;
if (MSR.IR) if (PowerPC::ppcState.msr.IR)
{ {
bat_lookup_failed = bat_lookup_failed =
BATAddressLookup(physical_addr, effective_addr, WA, PowerPC::ibat_table.data()); BATAddressLookup(physical_addr, effective_addr, WA, PowerPC::ibat_table.data());
@@ -760,7 +760,7 @@ void JitArm64::dcbx(UGeckoInstruction inst)
SwitchToFarCode(); SwitchToFarCode();
SetJumpTarget(invalidate_needed); SetJumpTarget(invalidate_needed);
if (MSR.IR) if (PowerPC::ppcState.msr.IR)
SetJumpTarget(bat_lookup_failed); SetJumpTarget(bat_lookup_failed);
BitSet32 gprs_to_push = gpr.GetCallerSavedUsed(); BitSet32 gprs_to_push = gpr.GetCallerSavedUsed();

View File

@@ -23,7 +23,7 @@ void JitArm64::psq_lXX(UGeckoInstruction inst)
JITDISABLE(bJITLoadStorePairedOff); JITDISABLE(bJITLoadStorePairedOff);
// If we have a fastmem arena, the asm routines assume address translation is on. // 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 // X30 is LR
// X0 is the address // X0 is the address
@@ -148,7 +148,7 @@ void JitArm64::psq_stXX(UGeckoInstruction inst)
JITDISABLE(bJITLoadStorePairedOff); JITDISABLE(bJITLoadStorePairedOff);
// If we have a fastmem arena, the asm routines assume address translation is on. // 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 // X30 is LR
// X0 contains the scale // X0 contains the scale

View File

@@ -90,7 +90,8 @@ bool JitBase::CanMergeNextInstructions(int count) const
void JitBase::UpdateMemoryAndExceptionOptions() void JitBase::UpdateMemoryAndExceptionOptions()
{ {
bool any_watchpoints = PowerPC::memchecks.HasAny(); 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.memcheck = m_mmu_enabled || m_pause_on_panic_enabled || any_watchpoints;
jo.fp_exceptions = m_enable_float_exceptions; jo.fp_exceptions = m_enable_float_exceptions;
jo.div_by_zero_exceptions = m_enable_div_by_zero_exceptions; jo.div_by_zero_exceptions = m_enable_div_by_zero_exceptions;

View File

@@ -96,7 +96,7 @@ JitBlock* JitBaseBlockCache::AllocateBlock(u32 em_address)
JitBlock& b = block_map.emplace(physical_address, JitBlock())->second; JitBlock& b = block_map.emplace(physical_address, JitBlock())->second;
b.effectiveAddress = em_address; b.effectiveAddress = em_address;
b.physicalAddress = physical_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.linkData.clear();
b.fast_block_map_index = 0; b.fast_block_map_index = 0;
return &b; return &b;
@@ -168,10 +168,14 @@ JitBlock* JitBaseBlockCache::GetBlockFromStartAddress(u32 addr, u32 msr)
const u8* JitBaseBlockCache::Dispatch() 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)) if (!block || block->effectiveAddress != PowerPC::ppcState.pc ||
block = MoveBlockIntoFastCache(PC, MSR.Hex & JIT_CACHE_MSR_MASK); 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) if (!block)
return nullptr; return nullptr;

View File

@@ -153,12 +153,14 @@ std::variant<GetHostCodeError, GetHostCodeResult> GetHostCode(u32 address)
return GetHostCodeError::NoJitActive; 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) if (!block)
{ {
for (int i = 0; i < 500; i++) 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) if (block)
break; break;
} }
@@ -264,20 +266,21 @@ void CompileExceptionCheck(ExceptionType type)
break; 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) if (type == ExceptionType::FIFOWrite)
{ {
// Check in case the code has been replaced since: do we need to do this? // 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) if (optype != OpType::Store && optype != OpType::StoreFP && optype != OpType::StorePS)
return; 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 // Invalidate the JIT block so that it gets recompiled with the external exception check
// included. // included.
g_jit->GetBlockCache()->InvalidateICache(PC, 4, true); g_jit->GetBlockCache()->InvalidateICache(PowerPC::ppcState.pc, 4, true);
} }
} }

View File

@@ -191,7 +191,7 @@ static T ReadFromHardware(Memory::MemoryManager& memory, u32 em_address)
bool wi = false; bool wi = false;
if (!never_translate && MSR.DR) if (!never_translate && PowerPC::ppcState.msr.DR)
{ {
auto translated_addr = TranslateAddress<flag>(em_address); auto translated_addr = TranslateAddress<flag>(em_address);
if (!translated_addr.Success()) if (!translated_addr.Success())
@@ -235,7 +235,7 @@ static T ReadFromHardware(Memory::MemoryManager& memory, u32 em_address)
else else
{ {
ppcState.dCache.Read(em_address, &value, sizeof(T), ppcState.dCache.Read(em_address, &value, sizeof(T),
HID0.DLOCK || flag != XCheckTLBFlag::Read); HID0(PowerPC::ppcState).DLOCK || flag != XCheckTLBFlag::Read);
} }
return bswap(value); return bswap(value);
@@ -254,7 +254,7 @@ static T ReadFromHardware(Memory::MemoryManager& memory, u32 em_address)
else else
{ {
ppcState.dCache.Read(em_address + 0x10000000, &value, sizeof(T), ppcState.dCache.Read(em_address + 0x10000000, &value, sizeof(T),
HID0.DLOCK || flag != XCheckTLBFlag::Read); HID0(PowerPC::ppcState).DLOCK || flag != XCheckTLBFlag::Read);
} }
return bswap(value); return bswap(value);
@@ -270,7 +270,7 @@ static T ReadFromHardware(Memory::MemoryManager& memory, u32 em_address)
return bswap(value); return bswap(value);
} }
PanicAlertFmt("Unable to resolve read address {:x} PC {:x}", em_address, PC); PanicAlertFmt("Unable to resolve read address {:x} PC {:x}", em_address, PowerPC::ppcState.pc);
if (Core::System::GetInstance().IsPauseOnPanicMode()) if (Core::System::GetInstance().IsPauseOnPanicMode())
{ {
CPU::Break(); CPU::Break();
@@ -303,7 +303,7 @@ static void WriteToHardware(Core::System& system, Memory::MemoryManager& memory,
bool wi = false; bool wi = false;
if (!never_translate && MSR.DR) if (!never_translate && PowerPC::ppcState.msr.DR)
{ {
auto translated_addr = TranslateAddress<flag>(em_address); auto translated_addr = TranslateAddress<flag>(em_address);
if (!translated_addr.Success()) if (!translated_addr.Success())
@@ -425,7 +425,7 @@ static void WriteToHardware(Core::System& system, Memory::MemoryManager& memory,
em_address &= memory.GetRamMask(); em_address &= memory.GetRamMask();
if (ppcState.m_enable_dcache && !wi) if (ppcState.m_enable_dcache && !wi)
ppcState.dCache.Write(em_address, &swapped_data, size, HID0.DLOCK); ppcState.dCache.Write(em_address, &swapped_data, size, HID0(PowerPC::ppcState).DLOCK);
if (!ppcState.m_enable_dcache || wi || flag != XCheckTLBFlag::Write) if (!ppcState.m_enable_dcache || wi || flag != XCheckTLBFlag::Write)
std::memcpy(&memory.GetRAM()[em_address], &swapped_data, size); std::memcpy(&memory.GetRAM()[em_address], &swapped_data, size);
@@ -439,7 +439,10 @@ static void WriteToHardware(Core::System& system, Memory::MemoryManager& memory,
em_address &= 0x0FFFFFFF; em_address &= 0x0FFFFFFF;
if (ppcState.m_enable_dcache && !wi) if (ppcState.m_enable_dcache && !wi)
ppcState.dCache.Write(em_address + 0x10000000, &swapped_data, size, HID0.DLOCK); {
ppcState.dCache.Write(em_address + 0x10000000, &swapped_data, size,
HID0(PowerPC::ppcState).DLOCK);
}
if (!ppcState.m_enable_dcache || wi || flag != XCheckTLBFlag::Write) if (!ppcState.m_enable_dcache || wi || flag != XCheckTLBFlag::Write)
std::memcpy(&memory.GetEXRAM()[em_address], &swapped_data, size); std::memcpy(&memory.GetEXRAM()[em_address], &swapped_data, size);
@@ -456,7 +459,7 @@ static void WriteToHardware(Core::System& system, Memory::MemoryManager& memory,
return; return;
} }
PanicAlertFmt("Unable to resolve write address {:x} PC {:x}", em_address, PC); PanicAlertFmt("Unable to resolve write address {:x} PC {:x}", em_address, PowerPC::ppcState.pc);
if (Core::System::GetInstance().IsPauseOnPanicMode()) if (Core::System::GetInstance().IsPauseOnPanicMode())
{ {
CPU::Break(); CPU::Break();
@@ -486,7 +489,7 @@ u32 Read_Opcode(u32 address)
TryReadInstResult TryReadInstruction(u32 address) TryReadInstResult TryReadInstruction(u32 address)
{ {
bool from_bat = true; bool from_bat = true;
if (MSR.IR) if (PowerPC::ppcState.msr.IR)
{ {
auto tlb_addr = TranslateAddress<XCheckTLBFlag::Opcode>(address); auto tlb_addr = TranslateAddress<XCheckTLBFlag::Opcode>(address);
if (!tlb_addr.Success()) if (!tlb_addr.Success())
@@ -537,7 +540,7 @@ std::optional<ReadResult<u32>> HostTryReadInstruction(const u32 address,
case RequestedAddressSpace::Effective: case RequestedAddressSpace::Effective:
{ {
const u32 value = ReadFromHardware<XCheckTLBFlag::OpcodeNoException, u32>(memory, address); const u32 value = ReadFromHardware<XCheckTLBFlag::OpcodeNoException, u32>(memory, address);
return ReadResult<u32>(!!MSR.DR, value); return ReadResult<u32>(!!PowerPC::ppcState.msr.DR, value);
} }
case RequestedAddressSpace::Physical: case RequestedAddressSpace::Physical:
{ {
@@ -547,7 +550,7 @@ std::optional<ReadResult<u32>> HostTryReadInstruction(const u32 address,
} }
case RequestedAddressSpace::Virtual: case RequestedAddressSpace::Virtual:
{ {
if (!MSR.DR) if (!PowerPC::ppcState.msr.DR)
return std::nullopt; return std::nullopt;
const u32 value = ReadFromHardware<XCheckTLBFlag::OpcodeNoException, u32>(memory, address); const u32 value = ReadFromHardware<XCheckTLBFlag::OpcodeNoException, u32>(memory, address);
return ReadResult<u32>(true, value); return ReadResult<u32>(true, value);
@@ -575,7 +578,7 @@ static void Memcheck(u32 address, u64 var, bool write, size_t size)
mc->num_hits++; mc->num_hits++;
const bool pause = mc->Action(&debug_interface, var, address, write, size, PC); const bool pause = mc->Action(&debug_interface, var, address, write, size, PowerPC::ppcState.pc);
if (!pause) if (!pause)
return; return;
@@ -658,7 +661,7 @@ static std::optional<ReadResult<T>> HostTryReadUX(const u32 address, RequestedAd
case RequestedAddressSpace::Effective: case RequestedAddressSpace::Effective:
{ {
T value = ReadFromHardware<XCheckTLBFlag::NoException, T>(memory, address); T value = ReadFromHardware<XCheckTLBFlag::NoException, T>(memory, address);
return ReadResult<T>(!!MSR.DR, std::move(value)); return ReadResult<T>(!!PowerPC::ppcState.msr.DR, std::move(value));
} }
case RequestedAddressSpace::Physical: case RequestedAddressSpace::Physical:
{ {
@@ -667,7 +670,7 @@ static std::optional<ReadResult<T>> HostTryReadUX(const u32 address, RequestedAd
} }
case RequestedAddressSpace::Virtual: case RequestedAddressSpace::Virtual:
{ {
if (!MSR.DR) if (!PowerPC::ppcState.msr.DR)
return std::nullopt; return std::nullopt;
T value = ReadFromHardware<XCheckTLBFlag::NoException, T>(memory, address); T value = ReadFromHardware<XCheckTLBFlag::NoException, T>(memory, address);
return ReadResult<T>(true, std::move(value)); return ReadResult<T>(true, std::move(value));
@@ -877,12 +880,12 @@ static std::optional<WriteResult> HostTryWriteUX(const u32 var, const u32 addres
{ {
case RequestedAddressSpace::Effective: case RequestedAddressSpace::Effective:
WriteToHardware<XCheckTLBFlag::NoException>(system, memory, address, var, size); WriteToHardware<XCheckTLBFlag::NoException>(system, memory, address, var, size);
return WriteResult(!!MSR.DR); return WriteResult(!!PowerPC::ppcState.msr.DR);
case RequestedAddressSpace::Physical: case RequestedAddressSpace::Physical:
WriteToHardware<XCheckTLBFlag::NoException, true>(system, memory, address, var, size); WriteToHardware<XCheckTLBFlag::NoException, true>(system, memory, address, var, size);
return WriteResult(false); return WriteResult(false);
case RequestedAddressSpace::Virtual: case RequestedAddressSpace::Virtual:
if (!MSR.DR) if (!PowerPC::ppcState.msr.DR)
return std::nullopt; return std::nullopt;
WriteToHardware<XCheckTLBFlag::NoException>(system, memory, address, var, size); WriteToHardware<XCheckTLBFlag::NoException>(system, memory, address, var, size);
return WriteResult(true); return WriteResult(true);
@@ -977,7 +980,7 @@ bool IsOptimizableRAMAddress(const u32 address)
if (PowerPC::memchecks.HasAny()) if (PowerPC::memchecks.HasAny())
return false; return false;
if (!MSR.DR) if (!PowerPC::ppcState.msr.DR)
return false; return false;
// TODO: This API needs to take an access size // TODO: This API needs to take an access size
@@ -1029,11 +1032,11 @@ bool HostIsRAMAddress(u32 address, RequestedAddressSpace space)
switch (space) switch (space)
{ {
case RequestedAddressSpace::Effective: case RequestedAddressSpace::Effective:
return IsRAMAddress<XCheckTLBFlag::NoException>(memory, address, MSR.DR); return IsRAMAddress<XCheckTLBFlag::NoException>(memory, address, PowerPC::ppcState.msr.DR);
case RequestedAddressSpace::Physical: case RequestedAddressSpace::Physical:
return IsRAMAddress<XCheckTLBFlag::NoException>(memory, address, false); return IsRAMAddress<XCheckTLBFlag::NoException>(memory, address, false);
case RequestedAddressSpace::Virtual: case RequestedAddressSpace::Virtual:
if (!MSR.DR) if (!PowerPC::ppcState.msr.DR)
return false; return false;
return IsRAMAddress<XCheckTLBFlag::NoException>(memory, address, true); return IsRAMAddress<XCheckTLBFlag::NoException>(memory, address, true);
} }
@@ -1054,11 +1057,12 @@ bool HostIsInstructionRAMAddress(u32 address, RequestedAddressSpace space)
switch (space) switch (space)
{ {
case RequestedAddressSpace::Effective: case RequestedAddressSpace::Effective:
return IsRAMAddress<XCheckTLBFlag::OpcodeNoException>(memory, address, MSR.IR); return IsRAMAddress<XCheckTLBFlag::OpcodeNoException>(memory, address,
PowerPC::ppcState.msr.IR);
case RequestedAddressSpace::Physical: case RequestedAddressSpace::Physical:
return IsRAMAddress<XCheckTLBFlag::OpcodeNoException>(memory, address, false); return IsRAMAddress<XCheckTLBFlag::OpcodeNoException>(memory, address, false);
case RequestedAddressSpace::Virtual: case RequestedAddressSpace::Virtual:
if (!MSR.IR) if (!PowerPC::ppcState.msr.IR)
return false; return false;
return IsRAMAddress<XCheckTLBFlag::OpcodeNoException>(memory, address, true); return IsRAMAddress<XCheckTLBFlag::OpcodeNoException>(memory, address, true);
} }
@@ -1148,7 +1152,7 @@ void DMA_MemoryToLC(const u32 cache_address, const u32 mem_address, const u32 nu
void ClearDCacheLine(u32 address) void ClearDCacheLine(u32 address)
{ {
DEBUG_ASSERT((address & 0x1F) == 0); DEBUG_ASSERT((address & 0x1F) == 0);
if (MSR.DR) if (PowerPC::ppcState.msr.DR)
{ {
auto translated_address = TranslateAddress<XCheckTLBFlag::Write>(address); auto translated_address = TranslateAddress<XCheckTLBFlag::Write>(address);
if (translated_address.result == TranslateAddressResultEnum::DIRECT_STORE_SEGMENT) if (translated_address.result == TranslateAddressResultEnum::DIRECT_STORE_SEGMENT)
@@ -1180,7 +1184,7 @@ void StoreDCacheLine(u32 address)
{ {
address &= ~0x1F; address &= ~0x1F;
if (MSR.DR) if (PowerPC::ppcState.msr.DR)
{ {
auto translated_address = TranslateAddress<XCheckTLBFlag::Write>(address); auto translated_address = TranslateAddress<XCheckTLBFlag::Write>(address);
if (translated_address.result == TranslateAddressResultEnum::DIRECT_STORE_SEGMENT) if (translated_address.result == TranslateAddressResultEnum::DIRECT_STORE_SEGMENT)
@@ -1204,7 +1208,7 @@ void InvalidateDCacheLine(u32 address)
{ {
address &= ~0x1F; address &= ~0x1F;
if (MSR.DR) if (PowerPC::ppcState.msr.DR)
{ {
auto translated_address = TranslateAddress<XCheckTLBFlag::Write>(address); auto translated_address = TranslateAddress<XCheckTLBFlag::Write>(address);
if (translated_address.result == TranslateAddressResultEnum::DIRECT_STORE_SEGMENT) if (translated_address.result == TranslateAddressResultEnum::DIRECT_STORE_SEGMENT)
@@ -1226,7 +1230,7 @@ void FlushDCacheLine(u32 address)
{ {
address &= ~0x1F; address &= ~0x1F;
if (MSR.DR) if (PowerPC::ppcState.msr.DR)
{ {
auto translated_address = TranslateAddress<XCheckTLBFlag::Write>(address); auto translated_address = TranslateAddress<XCheckTLBFlag::Write>(address);
if (translated_address.result == TranslateAddressResultEnum::DIRECT_STORE_SEGMENT) if (translated_address.result == TranslateAddressResultEnum::DIRECT_STORE_SEGMENT)
@@ -1250,7 +1254,7 @@ void TouchDCacheLine(u32 address, bool store)
{ {
address &= ~0x1F; address &= ~0x1F;
if (MSR.DR) if (PowerPC::ppcState.msr.DR)
{ {
auto translated_address = TranslateAddress<XCheckTLBFlag::Write>(address); auto translated_address = TranslateAddress<XCheckTLBFlag::Write>(address);
if (translated_address.result == TranslateAddressResultEnum::DIRECT_STORE_SEGMENT) if (translated_address.result == TranslateAddressResultEnum::DIRECT_STORE_SEGMENT)
@@ -1275,7 +1279,7 @@ u32 IsOptimizableMMIOAccess(u32 address, u32 access_size)
if (PowerPC::memchecks.HasAny()) if (PowerPC::memchecks.HasAny())
return 0; return 0;
if (!MSR.DR) if (!PowerPC::ppcState.msr.DR)
return 0; return 0;
// Translate address // Translate address
@@ -1298,7 +1302,7 @@ bool IsOptimizableGatherPipeWrite(u32 address)
if (PowerPC::memchecks.HasAny()) if (PowerPC::memchecks.HasAny())
return false; return false;
if (!MSR.DR) if (!PowerPC::ppcState.msr.DR)
return false; return false;
// Translate address, only check BAT mapping. // Translate address, only check BAT mapping.
@@ -1314,7 +1318,7 @@ bool IsOptimizableGatherPipeWrite(u32 address)
TranslateResult JitCache_TranslateAddress(u32 address) TranslateResult JitCache_TranslateAddress(u32 address)
{ {
if (!MSR.IR) if (!PowerPC::ppcState.msr.IR)
return TranslateResult{address}; return TranslateResult{address};
// TODO: We shouldn't use FLAG_OPCODE if the caller is the debugger. // TODO: We shouldn't use FLAG_OPCODE if the caller is the debugger.
@@ -1362,7 +1366,7 @@ static void GenerateDSIException(u32 effective_address, bool write)
if (!Core::System::GetInstance().IsMMUMode()) if (!Core::System::GetInstance().IsMMUMode())
{ {
PanicAlertFmt("Invalid {} {:#010x}, PC = {:#010x}", write ? "write to" : "read from", PanicAlertFmt("Invalid {} {:#010x}, PC = {:#010x}", write ? "write to" : "read from",
effective_address, PC); effective_address, PowerPC::ppcState.pc);
if (Core::System::GetInstance().IsPauseOnPanicMode()) if (Core::System::GetInstance().IsPauseOnPanicMode())
{ {
CPU::Break(); CPU::Break();
@@ -1387,10 +1391,10 @@ static void GenerateDSIException(u32 effective_address, bool write)
static void GenerateISIException(u32 effective_address) static void GenerateISIException(u32 effective_address)
{ {
// Address of instruction could not be translated // Address of instruction could not be translated
NPC = effective_address; PowerPC::ppcState.npc = effective_address;
PowerPC::ppcState.Exceptions |= EXCEPTION_ISI; PowerPC::ppcState.Exceptions |= EXCEPTION_ISI;
WARN_LOG_FMT(POWERPC, "ISI exception at {:#010x}", PC); WARN_LOG_FMT(POWERPC, "ISI exception at {:#010x}", PowerPC::ppcState.pc);
} }
void SDRUpdated() void SDRUpdated()
@@ -1733,7 +1737,7 @@ void DBATUpdated()
dbat_table = {}; dbat_table = {};
UpdateBATs(dbat_table, SPR_DBAT0U); UpdateBATs(dbat_table, SPR_DBAT0U);
bool extended_bats = SConfig::GetInstance().bWii && HID4.SBE; bool extended_bats = SConfig::GetInstance().bWii && HID4(PowerPC::ppcState).SBE;
if (extended_bats) if (extended_bats)
UpdateBATs(dbat_table, SPR_DBAT4U); UpdateBATs(dbat_table, SPR_DBAT4U);
if (memory.GetFakeVMEM()) if (memory.GetFakeVMEM())
@@ -1758,7 +1762,7 @@ void IBATUpdated()
ibat_table = {}; ibat_table = {};
UpdateBATs(ibat_table, SPR_IBAT0U); UpdateBATs(ibat_table, SPR_IBAT0U);
bool extended_bats = SConfig::GetInstance().bWii && HID4.SBE; bool extended_bats = SConfig::GetInstance().bWii && HID4(PowerPC::ppcState).SBE;
if (extended_bats) if (extended_bats)
UpdateBATs(ibat_table, SPR_IBAT4U); UpdateBATs(ibat_table, SPR_IBAT4U);
if (memory.GetFakeVMEM()) if (memory.GetFakeVMEM())

View File

@@ -394,17 +394,17 @@ u32 InstructionCache::ReadInstruction(u32 addr)
auto& system = Core::System::GetInstance(); auto& system = Core::System::GetInstance();
auto& memory = system.GetMemory(); auto& memory = system.GetMemory();
if (!HID0.ICE || m_disable_icache) // instruction cache is disabled if (!HID0(PowerPC::ppcState).ICE || m_disable_icache) // instruction cache is disabled
return memory.Read_U32(addr); return memory.Read_U32(addr);
u32 value; u32 value;
Read(addr, &value, sizeof(value), HID0.ILOCK); Read(addr, &value, sizeof(value), HID0(PowerPC::ppcState).ILOCK);
return Common::swap32(value); return Common::swap32(value);
} }
void InstructionCache::Invalidate(u32 addr) void InstructionCache::Invalidate(u32 addr)
{ {
if (!HID0.ICE || m_disable_icache) if (!HID0(PowerPC::ppcState).ICE || m_disable_icache)
return; return;
// Invalidates the whole set // Invalidates the whole set

View File

@@ -51,7 +51,8 @@ GekkoOPInfo* GetOpInfo(UGeckoInstruction inst)
case 63: case 63:
return m_infoTable63[inst.SUBOP10]; return m_infoTable63[inst.SUBOP10];
default: default:
ASSERT_MSG(POWERPC, 0, "GetOpInfo - invalid subtable op {:08x} @ {:08x}", inst.hex, PC); ASSERT_MSG(POWERPC, 0, "GetOpInfo - invalid subtable op {:08x} @ {:08x}", inst.hex,
PowerPC::ppcState.pc);
return nullptr; return nullptr;
} }
} }
@@ -59,7 +60,8 @@ GekkoOPInfo* GetOpInfo(UGeckoInstruction inst)
{ {
if (info->type == OpType::Invalid) if (info->type == OpType::Invalid)
{ {
ASSERT_MSG(POWERPC, 0, "GetOpInfo - invalid op {:08x} @ {:08x}", inst.hex, PC); ASSERT_MSG(POWERPC, 0, "GetOpInfo - invalid op {:08x} @ {:08x}", inst.hex,
PowerPC::ppcState.pc);
return nullptr; return nullptr;
} }
return m_infoTable[inst.OPCD]; return m_infoTable[inst.OPCD];
@@ -85,7 +87,7 @@ Interpreter::Instruction GetInterpreterOp(UGeckoInstruction inst)
return Interpreter::m_op_table63[inst.SUBOP10]; return Interpreter::m_op_table63[inst.SUBOP10];
default: default:
ASSERT_MSG(POWERPC, 0, "GetInterpreterOp - invalid subtable op {:08x} @ {:08x}", inst.hex, ASSERT_MSG(POWERPC, 0, "GetInterpreterOp - invalid subtable op {:08x} @ {:08x}", inst.hex,
PC); PowerPC::ppcState.pc);
return nullptr; return nullptr;
} }
} }
@@ -93,7 +95,8 @@ Interpreter::Instruction GetInterpreterOp(UGeckoInstruction inst)
{ {
if (info->type == OpType::Invalid) if (info->type == OpType::Invalid)
{ {
ASSERT_MSG(POWERPC, 0, "GetInterpreterOp - invalid op {:08x} @ {:08x}", inst.hex, PC); ASSERT_MSG(POWERPC, 0, "GetInterpreterOp - invalid op {:08x} @ {:08x}", inst.hex,
PowerPC::ppcState.pc);
return nullptr; return nullptr;
} }
return Interpreter::m_op_table[inst.OPCD]; return Interpreter::m_op_table[inst.OPCD];

View File

@@ -45,7 +45,7 @@ static CoreMode s_mode = CoreMode::Interpreter;
BreakPoints breakpoints; BreakPoints breakpoints;
MemChecks memchecks; MemChecks memchecks;
PPCDebugInterface debug_interface; PPCDebugInterface debug_interface(Core::System::GetInstance());
static CoreTiming::EventType* s_invalidate_cache_thread_safe; static CoreTiming::EventType* s_invalidate_cache_thread_safe;
@@ -106,9 +106,9 @@ void DoState(PointerWrap& p)
// and because the values it's changing have been added to CoreTiming::DoState, so it might // and because the values it's changing have been added to CoreTiming::DoState, so it might
// conflict to mess with them here. // conflict to mess with them here.
// rSPR(SPR_DEC) = SystemTimers::GetFakeDecrementer(); // PowerPC::ppcState.spr[SPR_DEC] = SystemTimers::GetFakeDecrementer();
// *((u64 *)&TL) = SystemTimers::GetFakeTimeBase(); //works since we are little endian and TL // *((u64 *)&TL(PowerPC::ppcState)) = SystemTimers::GetFakeTimeBase(); //works since we are little
// comes first :) // endian and TL comes first :)
p.DoArray(ppcState.gpr); p.DoArray(ppcState.gpr);
p.Do(ppcState.pc); p.Do(ppcState.pc);
@@ -200,19 +200,19 @@ static void ResetRegisters()
{ {
v = 0x8000000000000001; v = 0x8000000000000001;
} }
SetXER({}); ppcState.SetXER({});
RoundingModeUpdated(); RoundingModeUpdated();
DBATUpdated(); DBATUpdated();
IBATUpdated(); IBATUpdated();
TL = 0; TL(PowerPC::ppcState) = 0;
TU = 0; TU(PowerPC::ppcState) = 0;
SystemTimers::TimeBaseSet(); SystemTimers::TimeBaseSet();
// MSR should be 0x40, but we don't emulate BS1, so it would never be turned off :} // MSR should be 0x40, but we don't emulate BS1, so it would never be turned off :}
ppcState.msr.Hex = 0; ppcState.msr.Hex = 0;
rDEC = 0xFFFFFFFF; ppcState.spr[SPR_DEC] = 0xFFFFFFFF;
SystemTimers::DecrementerSet(); SystemTimers::DecrementerSet();
} }
@@ -394,72 +394,75 @@ void RunLoop()
u64 ReadFullTimeBaseValue() u64 ReadFullTimeBaseValue()
{ {
u64 value; u64 value;
std::memcpy(&value, &TL, sizeof(value)); std::memcpy(&value, &TL(PowerPC::ppcState), sizeof(value));
return value; return value;
} }
void WriteFullTimeBaseValue(u64 value) void WriteFullTimeBaseValue(u64 value)
{ {
std::memcpy(&TL, &value, sizeof(value)); std::memcpy(&TL(PowerPC::ppcState), &value, sizeof(value));
} }
void UpdatePerformanceMonitor(u32 cycles, u32 num_load_stores, u32 num_fp_inst) void UpdatePerformanceMonitor(u32 cycles, u32 num_load_stores, u32 num_fp_inst,
PowerPCState& ppc_state)
{ {
switch (MMCR0.PMC1SELECT) switch (MMCR0(ppc_state).PMC1SELECT)
{ {
case 0: // No change case 0: // No change
break; break;
case 1: // Processor cycles case 1: // Processor cycles
PowerPC::ppcState.spr[SPR_PMC1] += cycles; ppc_state.spr[SPR_PMC1] += cycles;
break; break;
default: default:
break; break;
} }
switch (MMCR0.PMC2SELECT) switch (MMCR0(ppc_state).PMC2SELECT)
{ {
case 0: // No change case 0: // No change
break; break;
case 1: // Processor cycles case 1: // Processor cycles
PowerPC::ppcState.spr[SPR_PMC2] += cycles; ppc_state.spr[SPR_PMC2] += cycles;
break; break;
case 11: // Number of loads and stores completed case 11: // Number of loads and stores completed
PowerPC::ppcState.spr[SPR_PMC2] += num_load_stores; ppc_state.spr[SPR_PMC2] += num_load_stores;
break; break;
default: default:
break; break;
} }
switch (MMCR1.PMC3SELECT) switch (MMCR1(ppc_state).PMC3SELECT)
{ {
case 0: // No change case 0: // No change
break; break;
case 1: // Processor cycles case 1: // Processor cycles
PowerPC::ppcState.spr[SPR_PMC3] += cycles; ppc_state.spr[SPR_PMC3] += cycles;
break; break;
case 11: // Number of FPU instructions completed case 11: // Number of FPU instructions completed
PowerPC::ppcState.spr[SPR_PMC3] += num_fp_inst; ppc_state.spr[SPR_PMC3] += num_fp_inst;
break; break;
default: default:
break; break;
} }
switch (MMCR1.PMC4SELECT) switch (MMCR1(ppc_state).PMC4SELECT)
{ {
case 0: // No change case 0: // No change
break; break;
case 1: // Processor cycles case 1: // Processor cycles
PowerPC::ppcState.spr[SPR_PMC4] += cycles; ppc_state.spr[SPR_PMC4] += cycles;
break; break;
default: default:
break; break;
} }
if ((MMCR0.PMC1INTCONTROL && (PowerPC::ppcState.spr[SPR_PMC1] & 0x80000000) != 0) || if ((MMCR0(ppc_state).PMC1INTCONTROL && (ppc_state.spr[SPR_PMC1] & 0x80000000) != 0) ||
(MMCR0.PMCINTCONTROL && (PowerPC::ppcState.spr[SPR_PMC2] & 0x80000000) != 0) || (MMCR0(ppc_state).PMCINTCONTROL && (ppc_state.spr[SPR_PMC2] & 0x80000000) != 0) ||
(MMCR0.PMCINTCONTROL && (PowerPC::ppcState.spr[SPR_PMC3] & 0x80000000) != 0) || (MMCR0(ppc_state).PMCINTCONTROL && (ppc_state.spr[SPR_PMC3] & 0x80000000) != 0) ||
(MMCR0.PMCINTCONTROL && (PowerPC::ppcState.spr[SPR_PMC4] & 0x80000000) != 0)) (MMCR0(ppc_state).PMCINTCONTROL && (ppc_state.spr[SPR_PMC4] & 0x80000000) != 0))
PowerPC::ppcState.Exceptions |= EXCEPTION_PERFORMANCE_MONITOR; {
ppc_state.Exceptions |= EXCEPTION_PERFORMANCE_MONITOR;
}
} }
void CheckExceptions() void CheckExceptions()
@@ -489,47 +492,47 @@ void CheckExceptions()
if (exceptions & EXCEPTION_ISI) if (exceptions & EXCEPTION_ISI)
{ {
SRR0 = NPC; SRR0(PowerPC::ppcState) = PowerPC::ppcState.npc;
// Page fault occurred // Page fault occurred
SRR1 = (MSR.Hex & 0x87C0FFFF) | (1 << 30); SRR1(PowerPC::ppcState) = (PowerPC::ppcState.msr.Hex & 0x87C0FFFF) | (1 << 30);
MSR.LE = MSR.ILE; PowerPC::ppcState.msr.LE = PowerPC::ppcState.msr.ILE;
MSR.Hex &= ~0x04EF36; PowerPC::ppcState.msr.Hex &= ~0x04EF36;
PC = NPC = 0x00000400; PowerPC::ppcState.pc = PowerPC::ppcState.npc = 0x00000400;
DEBUG_LOG_FMT(POWERPC, "EXCEPTION_ISI"); DEBUG_LOG_FMT(POWERPC, "EXCEPTION_ISI");
ppcState.Exceptions &= ~EXCEPTION_ISI; ppcState.Exceptions &= ~EXCEPTION_ISI;
} }
else if (exceptions & EXCEPTION_PROGRAM) else if (exceptions & EXCEPTION_PROGRAM)
{ {
SRR0 = PC; SRR0(PowerPC::ppcState) = PowerPC::ppcState.pc;
// SRR1 was partially set by GenerateProgramException, so bitwise or is used here // SRR1 was partially set by GenerateProgramException, so bitwise or is used here
SRR1 |= MSR.Hex & 0x87C0FFFF; SRR1(PowerPC::ppcState) |= PowerPC::ppcState.msr.Hex & 0x87C0FFFF;
MSR.LE = MSR.ILE; PowerPC::ppcState.msr.LE = PowerPC::ppcState.msr.ILE;
MSR.Hex &= ~0x04EF36; PowerPC::ppcState.msr.Hex &= ~0x04EF36;
PC = NPC = 0x00000700; PowerPC::ppcState.pc = PowerPC::ppcState.npc = 0x00000700;
DEBUG_LOG_FMT(POWERPC, "EXCEPTION_PROGRAM"); DEBUG_LOG_FMT(POWERPC, "EXCEPTION_PROGRAM");
ppcState.Exceptions &= ~EXCEPTION_PROGRAM; ppcState.Exceptions &= ~EXCEPTION_PROGRAM;
} }
else if (exceptions & EXCEPTION_SYSCALL) else if (exceptions & EXCEPTION_SYSCALL)
{ {
SRR0 = NPC; SRR0(PowerPC::ppcState) = PowerPC::ppcState.npc;
SRR1 = MSR.Hex & 0x87C0FFFF; SRR1(PowerPC::ppcState) = PowerPC::ppcState.msr.Hex & 0x87C0FFFF;
MSR.LE = MSR.ILE; PowerPC::ppcState.msr.LE = PowerPC::ppcState.msr.ILE;
MSR.Hex &= ~0x04EF36; PowerPC::ppcState.msr.Hex &= ~0x04EF36;
PC = NPC = 0x00000C00; PowerPC::ppcState.pc = PowerPC::ppcState.npc = 0x00000C00;
DEBUG_LOG_FMT(POWERPC, "EXCEPTION_SYSCALL (PC={:08x})", PC); DEBUG_LOG_FMT(POWERPC, "EXCEPTION_SYSCALL (PC={:08x})", PowerPC::ppcState.pc);
ppcState.Exceptions &= ~EXCEPTION_SYSCALL; ppcState.Exceptions &= ~EXCEPTION_SYSCALL;
} }
else if (exceptions & EXCEPTION_FPU_UNAVAILABLE) else if (exceptions & EXCEPTION_FPU_UNAVAILABLE)
{ {
// This happens a lot - GameCube OS uses deferred FPU context switching // This happens a lot - GameCube OS uses deferred FPU context switching
SRR0 = PC; // re-execute the instruction SRR0(PowerPC::ppcState) = PowerPC::ppcState.pc; // re-execute the instruction
SRR1 = MSR.Hex & 0x87C0FFFF; SRR1(PowerPC::ppcState) = PowerPC::ppcState.msr.Hex & 0x87C0FFFF;
MSR.LE = MSR.ILE; PowerPC::ppcState.msr.LE = PowerPC::ppcState.msr.ILE;
MSR.Hex &= ~0x04EF36; PowerPC::ppcState.msr.Hex &= ~0x04EF36;
PC = NPC = 0x00000800; PowerPC::ppcState.pc = PowerPC::ppcState.npc = 0x00000800;
DEBUG_LOG_FMT(POWERPC, "EXCEPTION_FPU_UNAVAILABLE"); DEBUG_LOG_FMT(POWERPC, "EXCEPTION_FPU_UNAVAILABLE");
ppcState.Exceptions &= ~EXCEPTION_FPU_UNAVAILABLE; ppcState.Exceptions &= ~EXCEPTION_FPU_UNAVAILABLE;
@@ -540,11 +543,11 @@ void CheckExceptions()
} }
else if (exceptions & EXCEPTION_DSI) else if (exceptions & EXCEPTION_DSI)
{ {
SRR0 = PC; SRR0(PowerPC::ppcState) = PowerPC::ppcState.pc;
SRR1 = MSR.Hex & 0x87C0FFFF; SRR1(PowerPC::ppcState) = PowerPC::ppcState.msr.Hex & 0x87C0FFFF;
MSR.LE = MSR.ILE; PowerPC::ppcState.msr.LE = PowerPC::ppcState.msr.ILE;
MSR.Hex &= ~0x04EF36; PowerPC::ppcState.msr.Hex &= ~0x04EF36;
PC = NPC = 0x00000300; PowerPC::ppcState.pc = PowerPC::ppcState.npc = 0x00000300;
// DSISR and DAR regs are changed in GenerateDSIException() // DSISR and DAR regs are changed in GenerateDSIException()
DEBUG_LOG_FMT(POWERPC, "EXCEPTION_DSI"); DEBUG_LOG_FMT(POWERPC, "EXCEPTION_DSI");
@@ -552,11 +555,11 @@ void CheckExceptions()
} }
else if (exceptions & EXCEPTION_ALIGNMENT) else if (exceptions & EXCEPTION_ALIGNMENT)
{ {
SRR0 = PC; SRR0(PowerPC::ppcState) = PowerPC::ppcState.pc;
SRR1 = MSR.Hex & 0x87C0FFFF; SRR1(PowerPC::ppcState) = PowerPC::ppcState.msr.Hex & 0x87C0FFFF;
MSR.LE = MSR.ILE; PowerPC::ppcState.msr.LE = PowerPC::ppcState.msr.ILE;
MSR.Hex &= ~0x04EF36; PowerPC::ppcState.msr.Hex &= ~0x04EF36;
PC = NPC = 0x00000600; PowerPC::ppcState.pc = PowerPC::ppcState.npc = 0x00000600;
// TODO crazy amount of DSISR options to check out // TODO crazy amount of DSISR options to check out
@@ -577,40 +580,41 @@ void CheckExternalExceptions()
// EXTERNAL INTERRUPT // EXTERNAL INTERRUPT
// Handling is delayed until MSR.EE=1. // Handling is delayed until MSR.EE=1.
if (exceptions && MSR.EE) if (exceptions && PowerPC::ppcState.msr.EE)
{ {
if (exceptions & EXCEPTION_EXTERNAL_INT) if (exceptions & EXCEPTION_EXTERNAL_INT)
{ {
// Pokemon gets this "too early", it hasn't a handler yet // Pokemon gets this "too early", it hasn't a handler yet
SRR0 = NPC; SRR0(PowerPC::ppcState) = PowerPC::ppcState.npc;
SRR1 = MSR.Hex & 0x87C0FFFF; SRR1(PowerPC::ppcState) = PowerPC::ppcState.msr.Hex & 0x87C0FFFF;
MSR.LE = MSR.ILE; PowerPC::ppcState.msr.LE = PowerPC::ppcState.msr.ILE;
MSR.Hex &= ~0x04EF36; PowerPC::ppcState.msr.Hex &= ~0x04EF36;
PC = NPC = 0x00000500; PowerPC::ppcState.pc = PowerPC::ppcState.npc = 0x00000500;
DEBUG_LOG_FMT(POWERPC, "EXCEPTION_EXTERNAL_INT"); DEBUG_LOG_FMT(POWERPC, "EXCEPTION_EXTERNAL_INT");
ppcState.Exceptions &= ~EXCEPTION_EXTERNAL_INT; ppcState.Exceptions &= ~EXCEPTION_EXTERNAL_INT;
DEBUG_ASSERT_MSG(POWERPC, (SRR1 & 0x02) != 0, "EXTERNAL_INT unrecoverable???"); DEBUG_ASSERT_MSG(POWERPC, (SRR1(PowerPC::ppcState) & 0x02) != 0,
"EXTERNAL_INT unrecoverable???");
} }
else if (exceptions & EXCEPTION_PERFORMANCE_MONITOR) else if (exceptions & EXCEPTION_PERFORMANCE_MONITOR)
{ {
SRR0 = NPC; SRR0(PowerPC::ppcState) = PowerPC::ppcState.npc;
SRR1 = MSR.Hex & 0x87C0FFFF; SRR1(PowerPC::ppcState) = PowerPC::ppcState.msr.Hex & 0x87C0FFFF;
MSR.LE = MSR.ILE; PowerPC::ppcState.msr.LE = PowerPC::ppcState.msr.ILE;
MSR.Hex &= ~0x04EF36; PowerPC::ppcState.msr.Hex &= ~0x04EF36;
PC = NPC = 0x00000F00; PowerPC::ppcState.pc = PowerPC::ppcState.npc = 0x00000F00;
DEBUG_LOG_FMT(POWERPC, "EXCEPTION_PERFORMANCE_MONITOR"); DEBUG_LOG_FMT(POWERPC, "EXCEPTION_PERFORMANCE_MONITOR");
ppcState.Exceptions &= ~EXCEPTION_PERFORMANCE_MONITOR; ppcState.Exceptions &= ~EXCEPTION_PERFORMANCE_MONITOR;
} }
else if (exceptions & EXCEPTION_DECREMENTER) else if (exceptions & EXCEPTION_DECREMENTER)
{ {
SRR0 = NPC; SRR0(PowerPC::ppcState) = PowerPC::ppcState.npc;
SRR1 = MSR.Hex & 0x87C0FFFF; SRR1(PowerPC::ppcState) = PowerPC::ppcState.msr.Hex & 0x87C0FFFF;
MSR.LE = MSR.ILE; PowerPC::ppcState.msr.LE = PowerPC::ppcState.msr.ILE;
MSR.Hex &= ~0x04EF36; PowerPC::ppcState.msr.Hex &= ~0x04EF36;
PC = NPC = 0x00000900; PowerPC::ppcState.pc = PowerPC::ppcState.npc = 0x00000900;
DEBUG_LOG_FMT(POWERPC, "EXCEPTION_DECREMENTER"); DEBUG_LOG_FMT(POWERPC, "EXCEPTION_DECREMENTER");
ppcState.Exceptions &= ~EXCEPTION_DECREMENTER; ppcState.Exceptions &= ~EXCEPTION_DECREMENTER;
@@ -626,7 +630,7 @@ void CheckExternalExceptions()
void CheckBreakPoints() void CheckBreakPoints()
{ {
const TBreakPoint* bp = PowerPC::breakpoints.GetBreakpoint(PC); const TBreakPoint* bp = PowerPC::breakpoints.GetBreakpoint(PowerPC::ppcState.pc);
if (!bp || !bp->is_enabled || !EvaluateCondition(bp->condition)) if (!bp || !bp->is_enabled || !EvaluateCondition(bp->condition))
return; return;
@@ -642,11 +646,14 @@ void CheckBreakPoints()
NOTICE_LOG_FMT(MEMMAP, NOTICE_LOG_FMT(MEMMAP,
"BP {:08x} {}({:08x} {:08x} {:08x} {:08x} {:08x} {:08x} {:08x} {:08x} {:08x} " "BP {:08x} {}({:08x} {:08x} {:08x} {:08x} {:08x} {:08x} {:08x} {:08x} {:08x} "
"{:08x}) LR={:08x}", "{:08x}) LR={:08x}",
PC, g_symbolDB.GetDescription(PC), GPR(3), GPR(4), GPR(5), GPR(6), GPR(7), PowerPC::ppcState.pc, g_symbolDB.GetDescription(PowerPC::ppcState.pc),
GPR(8), GPR(9), GPR(10), GPR(11), GPR(12), LR); PowerPC::ppcState.gpr[3], PowerPC::ppcState.gpr[4], PowerPC::ppcState.gpr[5],
PowerPC::ppcState.gpr[6], PowerPC::ppcState.gpr[7], PowerPC::ppcState.gpr[8],
PowerPC::ppcState.gpr[9], PowerPC::ppcState.gpr[10], PowerPC::ppcState.gpr[11],
PowerPC::ppcState.gpr[12], LR(PowerPC::ppcState));
} }
if (PowerPC::breakpoints.IsTempBreakPoint(PC)) if (PowerPC::breakpoints.IsTempBreakPoint(PowerPC::ppcState.pc))
PowerPC::breakpoints.Remove(PC); PowerPC::breakpoints.Remove(PowerPC::ppcState.pc);
} }
void PowerPCState::SetSR(u32 index, u32 value) void PowerPCState::SetSR(u32 index, u32 value)
@@ -657,14 +664,14 @@ void PowerPCState::SetSR(u32 index, u32 value)
// FPSCR update functions // FPSCR update functions
void UpdateFPRFDouble(double dvalue) void PowerPCState::UpdateFPRFDouble(double dvalue)
{ {
FPSCR.FPRF = Common::ClassifyDouble(dvalue); fpscr.FPRF = Common::ClassifyDouble(dvalue);
} }
void UpdateFPRFSingle(float fvalue) void PowerPCState::UpdateFPRFSingle(float fvalue)
{ {
FPSCR.FPRF = Common::ClassifyFloat(fvalue); fpscr.FPRF = Common::ClassifyFloat(fvalue);
} }
void RoundingModeUpdated() void RoundingModeUpdated()
@@ -672,7 +679,7 @@ void RoundingModeUpdated()
// The rounding mode is separate for each thread, so this must run on the CPU thread // The rounding mode is separate for each thread, so this must run on the CPU thread
ASSERT(Core::IsCPUThread()); ASSERT(Core::IsCPUThread());
FPURoundMode::SetSIMDMode(FPSCR.RN, FPSCR.NI); FPURoundMode::SetSIMDMode(PowerPC::ppcState.fpscr.RN, PowerPC::ppcState.fpscr.NI);
} }
} // namespace PowerPC } // namespace PowerPC

View File

@@ -185,6 +185,41 @@ struct PowerPCState
} }
void SetSR(u32 index, u32 value); void SetSR(u32 index, u32 value);
void SetCarry(u32 ca) { xer_ca = ca; }
u32 GetCarry() const { return xer_ca; }
UReg_XER GetXER() const
{
u32 xer = 0;
xer |= xer_stringctrl;
xer |= xer_ca << XER_CA_SHIFT;
xer |= xer_so_ov << XER_OV_SHIFT;
return UReg_XER{xer};
}
void SetXER(UReg_XER new_xer)
{
xer_stringctrl = new_xer.BYTE_COUNT + (new_xer.BYTE_CMP << 8);
xer_ca = new_xer.CA;
xer_so_ov = (new_xer.SO << 1) + new_xer.OV;
}
u32 GetXER_SO() const { return xer_so_ov >> 1; }
void SetXER_SO(bool value) { xer_so_ov |= static_cast<u32>(value) << 1; }
u32 GetXER_OV() const { return xer_so_ov & 1; }
void SetXER_OV(bool value)
{
xer_so_ov = (xer_so_ov & 0xFE) | static_cast<u32>(value);
SetXER_SO(value);
}
void UpdateFPRFDouble(double dvalue);
void UpdateFPRFSingle(float fvalue);
}; };
#if _M_X86_64 #if _M_X86_64
@@ -232,91 +267,28 @@ void RunLoop();
u64 ReadFullTimeBaseValue(); u64 ReadFullTimeBaseValue();
void WriteFullTimeBaseValue(u64 value); void WriteFullTimeBaseValue(u64 value);
void UpdatePerformanceMonitor(u32 cycles, u32 num_load_stores, u32 num_fp_inst); void UpdatePerformanceMonitor(u32 cycles, u32 num_load_stores, u32 num_fp_inst,
PowerPCState& ppc_state);
// Easy register access macros. // Easy register access macros.
#define HID0 ((UReg_HID0&)PowerPC::ppcState.spr[SPR_HID0]) #define HID0(ppc_state) ((UReg_HID0&)(ppc_state).spr[SPR_HID0])
#define HID2 ((UReg_HID2&)PowerPC::ppcState.spr[SPR_HID2]) #define HID2(ppc_state) ((UReg_HID2&)(ppc_state).spr[SPR_HID2])
#define HID4 ((UReg_HID4&)PowerPC::ppcState.spr[SPR_HID4]) #define HID4(ppc_state) ((UReg_HID4&)(ppc_state).spr[SPR_HID4])
#define DMAU (*(UReg_DMAU*)&PowerPC::ppcState.spr[SPR_DMAU]) #define DMAU(ppc_state) (*(UReg_DMAU*)&(ppc_state).spr[SPR_DMAU])
#define DMAL (*(UReg_DMAL*)&PowerPC::ppcState.spr[SPR_DMAL]) #define DMAL(ppc_state) (*(UReg_DMAL*)&(ppc_state).spr[SPR_DMAL])
#define MMCR0 ((UReg_MMCR0&)PowerPC::ppcState.spr[SPR_MMCR0]) #define MMCR0(ppc_state) ((UReg_MMCR0&)(ppc_state).spr[SPR_MMCR0])
#define MMCR1 ((UReg_MMCR1&)PowerPC::ppcState.spr[SPR_MMCR1]) #define MMCR1(ppc_state) ((UReg_MMCR1&)(ppc_state).spr[SPR_MMCR1])
#define THRM1 ((UReg_THRM12&)PowerPC::ppcState.spr[SPR_THRM1]) #define THRM1(ppc_state) ((UReg_THRM12&)(ppc_state).spr[SPR_THRM1])
#define THRM2 ((UReg_THRM12&)PowerPC::ppcState.spr[SPR_THRM2]) #define THRM2(ppc_state) ((UReg_THRM12&)(ppc_state).spr[SPR_THRM2])
#define THRM3 ((UReg_THRM3&)PowerPC::ppcState.spr[SPR_THRM3]) #define THRM3(ppc_state) ((UReg_THRM3&)(ppc_state).spr[SPR_THRM3])
#define PC PowerPC::ppcState.pc
#define NPC PowerPC::ppcState.npc
#define FPSCR PowerPC::ppcState.fpscr
#define MSR PowerPC::ppcState.msr
#define GPR(n) PowerPC::ppcState.gpr[n]
#define rGPR PowerPC::ppcState.gpr #define LR(ppc_state) (ppc_state).spr[SPR_LR]
#define rSPR(i) PowerPC::ppcState.spr[i] #define CTR(ppc_state) (ppc_state).spr[SPR_CTR]
#define LR PowerPC::ppcState.spr[SPR_LR] #define SRR0(ppc_state) (ppc_state).spr[SPR_SRR0]
#define CTR PowerPC::ppcState.spr[SPR_CTR] #define SRR1(ppc_state) (ppc_state).spr[SPR_SRR1]
#define rDEC PowerPC::ppcState.spr[SPR_DEC] #define GQR(ppc_state, x) (ppc_state).spr[SPR_GQR0 + (x)]
#define SRR0 PowerPC::ppcState.spr[SPR_SRR0] #define TL(ppc_state) (ppc_state).spr[SPR_TL]
#define SRR1 PowerPC::ppcState.spr[SPR_SRR1] #define TU(ppc_state) (ppc_state).spr[SPR_TU]
#define SPRG0 PowerPC::ppcState.spr[SPR_SPRG0]
#define SPRG1 PowerPC::ppcState.spr[SPR_SPRG1]
#define SPRG2 PowerPC::ppcState.spr[SPR_SPRG2]
#define SPRG3 PowerPC::ppcState.spr[SPR_SPRG3]
#define GQR(x) PowerPC::ppcState.spr[SPR_GQR0 + (x)]
#define TL PowerPC::ppcState.spr[SPR_TL]
#define TU PowerPC::ppcState.spr[SPR_TU]
#define rPS(i) (PowerPC::ppcState.ps[(i)])
inline void SetCarry(u32 ca)
{
PowerPC::ppcState.xer_ca = ca;
}
inline u32 GetCarry()
{
return PowerPC::ppcState.xer_ca;
}
inline UReg_XER GetXER()
{
u32 xer = 0;
xer |= PowerPC::ppcState.xer_stringctrl;
xer |= PowerPC::ppcState.xer_ca << XER_CA_SHIFT;
xer |= PowerPC::ppcState.xer_so_ov << XER_OV_SHIFT;
return UReg_XER{xer};
}
inline void SetXER(UReg_XER new_xer)
{
PowerPC::ppcState.xer_stringctrl = new_xer.BYTE_COUNT + (new_xer.BYTE_CMP << 8);
PowerPC::ppcState.xer_ca = new_xer.CA;
PowerPC::ppcState.xer_so_ov = (new_xer.SO << 1) + new_xer.OV;
}
inline u32 GetXER_SO()
{
return PowerPC::ppcState.xer_so_ov >> 1;
}
inline void SetXER_SO(bool value)
{
PowerPC::ppcState.xer_so_ov |= static_cast<u32>(value) << 1;
}
inline u32 GetXER_OV()
{
return PowerPC::ppcState.xer_so_ov & 1;
}
inline void SetXER_OV(bool value)
{
PowerPC::ppcState.xer_so_ov = (PowerPC::ppcState.xer_so_ov & 0xFE) | static_cast<u32>(value);
SetXER_SO(value);
}
void UpdateFPRFDouble(double dvalue);
void UpdateFPRFSingle(float fvalue);
void RoundingModeUpdated(); void RoundingModeUpdated();

View File

@@ -20,6 +20,7 @@
#include "Core/HW/SI/SI.h" #include "Core/HW/SI/SI.h"
#include "Core/HW/Sram.h" #include "Core/HW/Sram.h"
#include "Core/HW/VideoInterface.h" #include "Core/HW/VideoInterface.h"
#include "Core/PowerPC/PowerPC.h"
#include "IOS/USB/Emulated/Skylander.h" #include "IOS/USB/Emulated/Skylander.h"
#include "VideoCommon/CommandProcessor.h" #include "VideoCommon/CommandProcessor.h"
#include "VideoCommon/Fifo.h" #include "VideoCommon/Fifo.h"
@@ -32,7 +33,10 @@ namespace Core
{ {
struct System::Impl struct System::Impl
{ {
explicit Impl(System& system) : m_gp_fifo(system) {} explicit Impl(System& system)
: m_core_timing(system), m_gp_fifo(system), m_ppc_state(PowerPC::ppcState)
{
}
std::unique_ptr<SoundStream> m_sound_stream; std::unique_ptr<SoundStream> m_sound_stream;
bool m_sound_stream_running = false; bool m_sound_stream_running = false;
@@ -53,6 +57,7 @@ struct System::Impl
MemoryInterface::MemoryInterfaceState m_memory_interface_state; MemoryInterface::MemoryInterfaceState m_memory_interface_state;
PixelEngine::PixelEngineManager m_pixel_engine; PixelEngine::PixelEngineManager m_pixel_engine;
PixelShaderManager m_pixel_shader_manager; PixelShaderManager m_pixel_shader_manager;
PowerPC::PowerPCState& m_ppc_state;
ProcessorInterface::ProcessorInterfaceManager m_processor_interface; ProcessorInterface::ProcessorInterfaceManager m_processor_interface;
SerialInterface::SerialInterfaceState m_serial_interface_state; SerialInterface::SerialInterfaceState m_serial_interface_state;
Sram m_sram; Sram m_sram;
@@ -178,6 +183,11 @@ PixelShaderManager& System::GetPixelShaderManager() const
return m_impl->m_pixel_shader_manager; return m_impl->m_pixel_shader_manager;
} }
PowerPC::PowerPCState& System::GetPPCState() const
{
return m_impl->m_ppc_state;
}
ProcessorInterface::ProcessorInterfaceManager& System::GetProcessorInterface() const ProcessorInterface::ProcessorInterfaceManager& System::GetProcessorInterface() const
{ {
return m_impl->m_processor_interface; return m_impl->m_processor_interface;

View File

@@ -63,6 +63,10 @@ namespace PixelEngine
{ {
class PixelEngineManager; class PixelEngineManager;
}; };
namespace PowerPC
{
struct PowerPCState;
}
namespace ProcessorInterface namespace ProcessorInterface
{ {
class ProcessorInterfaceManager; class ProcessorInterfaceManager;
@@ -125,6 +129,7 @@ public:
MemoryInterface::MemoryInterfaceState& GetMemoryInterfaceState() const; MemoryInterface::MemoryInterfaceState& GetMemoryInterfaceState() const;
PixelEngine::PixelEngineManager& GetPixelEngine() const; PixelEngine::PixelEngineManager& GetPixelEngine() const;
PixelShaderManager& GetPixelShaderManager() const; PixelShaderManager& GetPixelShaderManager() const;
PowerPC::PowerPCState& GetPPCState() const;
ProcessorInterface::ProcessorInterfaceManager& GetProcessorInterface() const; ProcessorInterface::ProcessorInterfaceManager& GetProcessorInterface() const;
SerialInterface::SerialInterfaceState& GetSerialInterfaceState() const; SerialInterface::SerialInterfaceState& GetSerialInterfaceState() const;
Sram& GetSRAM() const; Sram& GetSRAM() const;

View File

@@ -497,10 +497,11 @@ static void ApplyMemoryPatch(u32 offset, const std::vector<u8>& value,
if (!original.empty() && !MemoryMatchesAt(offset, original)) if (!original.empty() && !MemoryMatchesAt(offset, original))
return; return;
auto& system = Core::System::GetInstance();
const u32 size = static_cast<u32>(value.size()); const u32 size = static_cast<u32>(value.size());
for (u32 i = 0; i < size; ++i) for (u32 i = 0; i < size; ++i)
PowerPC::HostTryWriteU8(value[i], offset + i); PowerPC::HostTryWriteU8(value[i], offset + i);
const u32 overlapping_hook_count = HLE::UnpatchRange(offset, offset + size); const u32 overlapping_hook_count = HLE::UnpatchRange(system, offset, offset + size);
if (overlapping_hook_count != 0) if (overlapping_hook_count != 0)
{ {
WARN_LOG_FMT(OSHLE, "Riivolution memory patch overlaps {} HLE hook(s) at {:08x} (size: {})", WARN_LOG_FMT(OSHLE, "Riivolution memory patch overlaps {} HLE hook(s) at {:08x} (size: {})",
@@ -551,6 +552,7 @@ static void ApplyOcarinaMemoryPatch(const Patch& patch, const Memory& memory_pat
if (value.empty()) if (value.empty())
return; return;
auto& system = Core::System::GetInstance();
for (u32 i = 0; i < length; i += 4) for (u32 i = 0; i < length; i += 4)
{ {
// first find the pattern // first find the pattern
@@ -568,7 +570,8 @@ static void ApplyOcarinaMemoryPatch(const Patch& patch, const Memory& memory_pat
const u32 target = memory_patch.m_offset | 0x80000000; const u32 target = memory_patch.m_offset | 0x80000000;
const u32 jmp = ((target - blr_address) & 0x03fffffc) | 0x48000000; const u32 jmp = ((target - blr_address) & 0x03fffffc) | 0x48000000;
PowerPC::HostTryWriteU32(jmp, blr_address); PowerPC::HostTryWriteU32(jmp, blr_address);
const u32 overlapping_hook_count = HLE::UnpatchRange(blr_address, blr_address + 4); const u32 overlapping_hook_count =
HLE::UnpatchRange(system, blr_address, blr_address + 4);
if (overlapping_hook_count != 0) if (overlapping_hook_count != 0)
{ {
WARN_LOG_FMT(OSHLE, "Riivolution ocarina patch overlaps HLE hook at {}", blr_address); WARN_LOG_FMT(OSHLE, "Riivolution ocarina patch overlaps HLE hook at {}", blr_address);

View File

@@ -167,11 +167,11 @@ CodeViewWidget::CodeViewWidget()
&CodeViewWidget::FontBasedSizing); &CodeViewWidget::FontBasedSizing);
connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, [this] { connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, [this] {
m_address = PC; m_address = PowerPC::ppcState.pc;
Update(); Update();
}); });
connect(Host::GetInstance(), &Host::UpdateDisasmDialog, this, [this] { connect(Host::GetInstance(), &Host::UpdateDisasmDialog, this, [this] {
m_address = PC; m_address = PowerPC::ppcState.pc;
Update(); Update();
}); });
@@ -567,9 +567,9 @@ void CodeViewWidget::OnContextMenu()
menu->addAction(tr("Restore instruction"), this, &CodeViewWidget::OnRestoreInstruction); menu->addAction(tr("Restore instruction"), this, &CodeViewWidget::OnRestoreInstruction);
QString target; QString target;
if (addr == PC && running && Core::GetState() == Core::State::Paused) if (addr == PowerPC::ppcState.pc && running && Core::GetState() == Core::State::Paused)
{ {
const std::string line = PowerPC::debug_interface.Disassemble(PC); const std::string line = PowerPC::debug_interface.Disassemble(PowerPC::ppcState.pc);
const auto target_it = std::find(line.begin(), line.end(), '\t'); const auto target_it = std::find(line.begin(), line.end(), '\t');
const auto target_end = std::find(target_it, line.end(), ','); const auto target_end = std::find(target_it, line.end(), ',');

View File

@@ -24,6 +24,7 @@
#include "Core/PowerPC/MMU.h" #include "Core/PowerPC/MMU.h"
#include "Core/PowerPC/PPCSymbolDB.h" #include "Core/PowerPC/PPCSymbolDB.h"
#include "Core/PowerPC/PowerPC.h" #include "Core/PowerPC/PowerPC.h"
#include "Core/System.h"
#include "DolphinQt/Host.h" #include "DolphinQt/Host.h"
#include "DolphinQt/Settings.h" #include "DolphinQt/Settings.h"
@@ -328,7 +329,7 @@ void CodeWidget::UpdateCallstack()
std::vector<Dolphin_Debugger::CallstackEntry> stack; std::vector<Dolphin_Debugger::CallstackEntry> stack;
bool success = Dolphin_Debugger::GetCallstack(stack); bool success = Dolphin_Debugger::GetCallstack(Core::System::GetInstance(), stack);
if (!success) if (!success)
{ {
@@ -451,11 +452,11 @@ void CodeWidget::StepOver()
if (!CPU::IsStepping()) if (!CPU::IsStepping())
return; return;
UGeckoInstruction inst = PowerPC::HostRead_Instruction(PC); UGeckoInstruction inst = PowerPC::HostRead_Instruction(PowerPC::ppcState.pc);
if (inst.LK) if (inst.LK)
{ {
PowerPC::breakpoints.ClearAllTemporary(); PowerPC::breakpoints.ClearAllTemporary();
PowerPC::breakpoints.Add(PC + 4, true); PowerPC::breakpoints.Add(PowerPC::ppcState.pc + 4, true);
CPU::EnableStepping(false); CPU::EnableStepping(false);
Core::DisplayMessage(tr("Step over in progress...").toStdString(), 2000); Core::DisplayMessage(tr("Step over in progress...").toStdString(), 2000);
} }
@@ -471,7 +472,8 @@ static bool WillInstructionReturn(UGeckoInstruction inst)
// Is a rfi instruction // Is a rfi instruction
if (inst.hex == 0x4C000064u) if (inst.hex == 0x4C000064u)
return true; return true;
bool counter = (inst.BO_2 >> 2 & 1) != 0 || (CTR != 0) != ((inst.BO_2 >> 1 & 1) != 0); bool counter =
(inst.BO_2 >> 2 & 1) != 0 || (CTR(PowerPC::ppcState) != 0) != ((inst.BO_2 >> 1 & 1) != 0);
bool condition = bool condition =
inst.BO_2 >> 4 != 0 || PowerPC::ppcState.cr.GetBit(inst.BI_2) == (inst.BO_2 >> 3 & 1); inst.BO_2 >> 4 != 0 || PowerPC::ppcState.cr.GetBit(inst.BI_2) == (inst.BO_2 >> 3 & 1);
bool isBclr = inst.OPCD_7 == 0b010011 && (inst.hex >> 1 & 0b10000) != 0; bool isBclr = inst.OPCD_7 == 0b010011 && (inst.hex >> 1 & 0b10000) != 0;
@@ -495,7 +497,7 @@ void CodeWidget::StepOut()
// Loop until either the current instruction is a return instruction with no Link flag // Loop until either the current instruction is a return instruction with no Link flag
// or a breakpoint is detected so it can step at the breakpoint. If the PC is currently // or a breakpoint is detected so it can step at the breakpoint. If the PC is currently
// on a breakpoint, skip it. // on a breakpoint, skip it.
UGeckoInstruction inst = PowerPC::HostRead_Instruction(PC); UGeckoInstruction inst = PowerPC::HostRead_Instruction(PowerPC::ppcState.pc);
do do
{ {
if (WillInstructionReturn(inst)) if (WillInstructionReturn(inst))
@@ -507,27 +509,28 @@ void CodeWidget::StepOut()
if (inst.LK) if (inst.LK)
{ {
// Step over branches // Step over branches
u32 next_pc = PC + 4; u32 next_pc = PowerPC::ppcState.pc + 4;
do do
{ {
PowerPC::SingleStep(); PowerPC::SingleStep();
} while (PC != next_pc && clock::now() < timeout && } while (PowerPC::ppcState.pc != next_pc && clock::now() < timeout &&
!PowerPC::breakpoints.IsAddressBreakPoint(PC)); !PowerPC::breakpoints.IsAddressBreakPoint(PowerPC::ppcState.pc));
} }
else else
{ {
PowerPC::SingleStep(); PowerPC::SingleStep();
} }
inst = PowerPC::HostRead_Instruction(PC); inst = PowerPC::HostRead_Instruction(PowerPC::ppcState.pc);
} while (clock::now() < timeout && !PowerPC::breakpoints.IsAddressBreakPoint(PC)); } while (clock::now() < timeout &&
!PowerPC::breakpoints.IsAddressBreakPoint(PowerPC::ppcState.pc));
PowerPC::SetMode(old_mode); PowerPC::SetMode(old_mode);
CPU::PauseAndLock(false, false); CPU::PauseAndLock(false, false);
emit Host::GetInstance()->UpdateDisasmDialog(); emit Host::GetInstance()->UpdateDisasmDialog();
if (PowerPC::breakpoints.IsAddressBreakPoint(PC)) if (PowerPC::breakpoints.IsAddressBreakPoint(PowerPC::ppcState.pc))
Core::DisplayMessage(tr("Breakpoint encountered! Step out aborted.").toStdString(), 2000); Core::DisplayMessage(tr("Breakpoint encountered! Step out aborted.").toStdString(), 2000);
else if (clock::now() >= timeout) else if (clock::now() >= timeout)
Core::DisplayMessage(tr("Step out timed out!").toStdString(), 2000); Core::DisplayMessage(tr("Step out timed out!").toStdString(), 2000);
@@ -537,19 +540,19 @@ void CodeWidget::StepOut()
void CodeWidget::Skip() void CodeWidget::Skip()
{ {
PC += 4; PowerPC::ppcState.pc += 4;
ShowPC(); ShowPC();
} }
void CodeWidget::ShowPC() void CodeWidget::ShowPC()
{ {
m_code_view->SetAddress(PC, CodeViewWidget::SetAddressUpdate::WithUpdate); m_code_view->SetAddress(PowerPC::ppcState.pc, CodeViewWidget::SetAddressUpdate::WithUpdate);
Update(); Update();
} }
void CodeWidget::SetPC() void CodeWidget::SetPC()
{ {
PC = m_code_view->GetAddress(); PowerPC::ppcState.pc = m_code_view->GetAddress();
Update(); Update();
} }

View File

@@ -314,17 +314,18 @@ void RegisterWidget::PopulateTable()
{ {
// General purpose registers (int) // General purpose registers (int)
AddRegister( AddRegister(
i, 0, RegisterType::gpr, "r" + std::to_string(i), [i] { return GPR(i); }, i, 0, RegisterType::gpr, "r" + std::to_string(i), [i] { return PowerPC::ppcState.gpr[i]; },
[i](u64 value) { GPR(i) = value; }); [i](u64 value) { PowerPC::ppcState.gpr[i] = value; });
// Floating point registers (double) // Floating point registers (double)
AddRegister( AddRegister(
i, 2, RegisterType::fpr, "f" + std::to_string(i), [i] { return rPS(i).PS0AsU64(); }, i, 2, RegisterType::fpr, "f" + std::to_string(i),
[i](u64 value) { rPS(i).SetPS0(value); }); [i] { return PowerPC::ppcState.ps[i].PS0AsU64(); },
[i](u64 value) { PowerPC::ppcState.ps[i].SetPS0(value); });
AddRegister( AddRegister(
i, 4, RegisterType::fpr, "", [i] { return rPS(i).PS1AsU64(); }, i, 4, RegisterType::fpr, "", [i] { return PowerPC::ppcState.ps[i].PS1AsU64(); },
[i](u64 value) { rPS(i).SetPS1(value); }); [i](u64 value) { PowerPC::ppcState.ps[i].SetPS1(value); });
} }
// The IBAT and DBAT registers have a large gap between // The IBAT and DBAT registers have a large gap between
@@ -421,8 +422,8 @@ void RegisterWidget::PopulateTable()
// XER // XER
AddRegister( AddRegister(
21, 5, RegisterType::xer, "XER", [] { return PowerPC::GetXER().Hex; }, 21, 5, RegisterType::xer, "XER", [] { return PowerPC::ppcState.GetXER().Hex; },
[](u64 value) { PowerPC::SetXER(UReg_XER(value)); }); [](u64 value) { PowerPC::ppcState.SetXER(UReg_XER(value)); });
// FPSCR // FPSCR
AddRegister( AddRegister(

View File

@@ -1438,7 +1438,7 @@ void MenuBar::LoadSymbolMap()
tr("Loaded symbols from '%1'").arg(existing_map_file_path)); tr("Loaded symbols from '%1'").arg(existing_map_file_path));
} }
HLE::PatchFunctions(); HLE::PatchFunctions(system);
emit NotifySymbolsUpdated(); emit NotifySymbolsUpdated();
} }
@@ -1462,7 +1462,8 @@ void MenuBar::LoadOtherSymbolMap()
if (!TryLoadMapFile(file)) if (!TryLoadMapFile(file))
return; return;
HLE::PatchFunctions(); auto& system = Core::System::GetInstance();
HLE::PatchFunctions(system);
emit NotifySymbolsUpdated(); emit NotifySymbolsUpdated();
} }
@@ -1478,7 +1479,8 @@ void MenuBar::LoadBadSymbolMap()
if (!TryLoadMapFile(file, true)) if (!TryLoadMapFile(file, true))
return; return;
HLE::PatchFunctions(); auto& system = Core::System::GetInstance();
HLE::PatchFunctions(system);
emit NotifySymbolsUpdated(); emit NotifySymbolsUpdated();
} }
@@ -1597,7 +1599,8 @@ void MenuBar::ApplySignatureFile()
db.Load(load_path); db.Load(load_path);
db.Apply(&g_symbolDB); db.Apply(&g_symbolDB);
db.List(); db.List();
HLE::PatchFunctions(); auto& system = Core::System::GetInstance();
HLE::PatchFunctions(system);
emit NotifySymbolsUpdated(); emit NotifySymbolsUpdated();
} }
@@ -1636,7 +1639,8 @@ void MenuBar::CombineSignatureFiles()
void MenuBar::PatchHLEFunctions() void MenuBar::PatchHLEFunctions()
{ {
HLE::PatchFunctions(); auto& system = Core::System::GetInstance();
HLE::PatchFunctions(system);
} }
void MenuBar::ClearCache() void MenuBar::ClearCache()

View File

@@ -6,9 +6,6 @@
#include <sstream> #include <sstream>
#if defined(HAVE_LLVM) #if defined(HAVE_LLVM)
// PowerPC.h defines PC.
// This conflicts with a function that has an argument named PC
#undef PC
#include <fmt/format.h> #include <fmt/format.h>
#include <llvm-c/Disassembler.h> #include <llvm-c/Disassembler.h>
#include <llvm-c/Target.h> #include <llvm-c/Target.h>

View File

@@ -684,7 +684,8 @@ void CommandProcessorManager::HandleUnknownOpcode(u8 cmd_byte, const u8* buffer,
fifo.bFF_Breakpoint.load(std::memory_order_relaxed) ? "true" : "false", fifo.bFF_Breakpoint.load(std::memory_order_relaxed) ? "true" : "false",
fifo.bFF_GPLinkEnable.load(std::memory_order_relaxed) ? "true" : "false", fifo.bFF_GPLinkEnable.load(std::memory_order_relaxed) ? "true" : "false",
fifo.bFF_HiWatermarkInt.load(std::memory_order_relaxed) ? "true" : "false", fifo.bFF_HiWatermarkInt.load(std::memory_order_relaxed) ? "true" : "false",
fifo.bFF_LoWatermarkInt.load(std::memory_order_relaxed) ? "true" : "false", PC, LR); fifo.bFF_LoWatermarkInt.load(std::memory_order_relaxed) ? "true" : "false",
PowerPC::ppcState.pc, LR(PowerPC::ppcState));
if (!m_is_fifo_error_seen && !suppress_panic_alert) if (!m_is_fifo_error_seen && !suppress_panic_alert)
{ {

View File

@@ -71,15 +71,15 @@ TEST(JitArm64, FPRF)
for (const u64 double_input : double_test_values) for (const u64 double_input : double_test_values)
{ {
const u32 expected_double = const u32 expected_double = RunUpdateFPRF(
RunUpdateFPRF([&] { PowerPC::UpdateFPRFDouble(Common::BitCast<double>(double_input)); }); [&] { PowerPC::ppcState.UpdateFPRFDouble(Common::BitCast<double>(double_input)); });
const u32 actual_double = RunUpdateFPRF([&] { test.fprf_double(double_input); }); const u32 actual_double = RunUpdateFPRF([&] { test.fprf_double(double_input); });
EXPECT_EQ(expected_double, actual_double); EXPECT_EQ(expected_double, actual_double);
const u32 single_input = ConvertToSingle(double_input); const u32 single_input = ConvertToSingle(double_input);
const u32 expected_single = const u32 expected_single = RunUpdateFPRF(
RunUpdateFPRF([&] { PowerPC::UpdateFPRFSingle(Common::BitCast<float>(single_input)); }); [&] { PowerPC::ppcState.UpdateFPRFSingle(Common::BitCast<float>(single_input)); });
const u32 actual_single = RunUpdateFPRF([&] { test.fprf_single(single_input); }); const u32 actual_single = RunUpdateFPRF([&] { test.fprf_single(single_input); });
EXPECT_EQ(expected_single, actual_single); EXPECT_EQ(expected_single, actual_single);
} }