Merge pull request #11429 from AdmiralCurtiss/globals-ppc
Reduce usage of ppcState global.
This commit is contained in:
commit
41272dc5f1
|
@ -11,6 +11,7 @@
|
|||
#include "Core/Debugger/PPCDebugInterface.h"
|
||||
#include "Core/HW/CPU.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
#include "Core/System.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
@ -56,11 +57,13 @@ void CodeTrace::SetRegTracked(const std::string& reg)
|
|||
|
||||
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
|
||||
// decision has to be made, otherwise used afterwards on a log file.
|
||||
InstructionAttributes tmp_attributes;
|
||||
tmp_attributes.instruction = instruction.instruction;
|
||||
tmp_attributes.address = PC;
|
||||
tmp_attributes.address = system.GetPPCState().pc;
|
||||
std::string instr = instruction.instruction;
|
||||
std::smatch match;
|
||||
|
||||
|
@ -106,11 +109,14 @@ InstructionAttributes CodeTrace::GetInstructionAttributes(const TraceOutput& ins
|
|||
|
||||
TraceOutput CodeTrace::SaveCurrentInstruction() const
|
||||
{
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& ppc_state = system.GetPPCState();
|
||||
|
||||
// Quickly save instruction and memory target for fast logging.
|
||||
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.address = PC;
|
||||
output.address = ppc_state.pc;
|
||||
|
||||
if (IsInstructionLoadStore(output.instruction))
|
||||
output.memory_target = PowerPC::debug_interface.GetMemoryAddressFromInstruction(instr);
|
||||
|
|
|
@ -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(0x01300000, data.data() + 0x820, 0x1AFE00);
|
||||
|
||||
PowerPC::ppcState.gpr[3] = 0xfff0001f;
|
||||
PowerPC::ppcState.gpr[4] = 0x00002030;
|
||||
PowerPC::ppcState.gpr[5] = 0x0000009c;
|
||||
auto& ppc_state = system.GetPPCState();
|
||||
ppc_state.gpr[3] = 0xfff0001f;
|
||||
ppc_state.gpr[4] = 0x00002030;
|
||||
ppc_state.gpr[5] = 0x0000009c;
|
||||
|
||||
MSR.FP = 1;
|
||||
MSR.DR = 1;
|
||||
MSR.IR = 1;
|
||||
ppc_state.msr.FP = 1;
|
||||
ppc_state.msr.DR = 1;
|
||||
ppc_state.msr.IR = 1;
|
||||
|
||||
PowerPC::ppcState.spr[SPR_HID0] = 0x0011c464;
|
||||
PowerPC::ppcState.spr[SPR_IBAT3U] = 0xfff0001f;
|
||||
PowerPC::ppcState.spr[SPR_IBAT3L] = 0xfff00001;
|
||||
PowerPC::ppcState.spr[SPR_DBAT3U] = 0xfff0001f;
|
||||
PowerPC::ppcState.spr[SPR_DBAT3L] = 0xfff00001;
|
||||
SetupBAT(/*is_wii*/ false);
|
||||
ppc_state.spr[SPR_HID0] = 0x0011c464;
|
||||
ppc_state.spr[SPR_IBAT3U] = 0xfff0001f;
|
||||
ppc_state.spr[SPR_IBAT3L] = 0xfff00001;
|
||||
ppc_state.spr[SPR_DBAT3U] = 0xfff0001f;
|
||||
ppc_state.spr[SPR_DBAT3L] = 0xfff00001;
|
||||
SetupBAT(system, /*is_wii*/ false);
|
||||
|
||||
PC = 0x81200150;
|
||||
ppc_state.pc = 0x81200150;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -543,16 +544,18 @@ bool CBoot::BootUp(Core::System& system, std::unique_ptr<BootParameters> boot)
|
|||
|
||||
SetDefaultDisc();
|
||||
|
||||
SetupMSR();
|
||||
SetupHID(config.bWii);
|
||||
SetupBAT(config.bWii);
|
||||
auto& ppc_state = system.GetPPCState();
|
||||
|
||||
SetupMSR(ppc_state);
|
||||
SetupHID(ppc_state, config.bWii);
|
||||
SetupBAT(system, config.bWii);
|
||||
CopyDefaultExceptionHandlers(system);
|
||||
|
||||
if (config.bWii)
|
||||
{
|
||||
// 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.
|
||||
PowerPC::ppcState.gpr[1] = 0x8004d4bc;
|
||||
ppc_state.gpr[1] = 0x8004d4bc;
|
||||
|
||||
// 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.
|
||||
|
@ -572,12 +575,12 @@ bool CBoot::BootUp(Core::System& system, std::unique_ptr<BootParameters> boot)
|
|||
|
||||
SConfig::OnNewTitleLoad();
|
||||
|
||||
PC = executable.reader->GetEntryPoint();
|
||||
ppc_state.pc = executable.reader->GetEntryPoint();
|
||||
|
||||
if (executable.reader->LoadSymbols())
|
||||
{
|
||||
UpdateDebugger_MapLoaded();
|
||||
HLE::PatchFunctions();
|
||||
HLE::PatchFunctions(system);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -34,6 +34,11 @@ namespace IOS::HLE::FS
|
|||
class FileSystem;
|
||||
}
|
||||
|
||||
namespace PowerPC
|
||||
{
|
||||
struct PowerPCState;
|
||||
}
|
||||
|
||||
struct RegionSetting
|
||||
{
|
||||
std::string area;
|
||||
|
@ -167,17 +172,17 @@ private:
|
|||
static bool DVDRead(const DiscIO::VolumeDisc& disc, u64 dvd_offset, u32 output_address,
|
||||
u32 length, const DiscIO::Partition& partition);
|
||||
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 bool Boot_WiiWAD(Core::System& system, const DiscIO::VolumeWAD& wad);
|
||||
static bool BootNANDTitle(Core::System& system, u64 title_id);
|
||||
|
||||
static void SetupMSR();
|
||||
static void SetupHID(bool is_wii);
|
||||
static void SetupBAT(bool is_wii);
|
||||
static bool RunApploader(bool is_wii, const DiscIO::VolumeDisc& volume,
|
||||
static void SetupMSR(PowerPC::PowerPCState& ppc_state);
|
||||
static void SetupHID(PowerPC::PowerPCState& ppc_state, bool is_wii);
|
||||
static void SetupBAT(Core::System& system, bool is_wii);
|
||||
static bool RunApploader(Core::System& system, bool is_wii, const DiscIO::VolumeDisc& volume,
|
||||
const std::vector<DiscIO::Riivolution::Patch>& riivolution_patches);
|
||||
static bool EmulatedBS2_GC(Core::System& system, const DiscIO::VolumeDisc& volume,
|
||||
const std::vector<DiscIO::Riivolution::Patch>& riivolution_patches);
|
||||
|
|
|
@ -55,80 +55,83 @@ void PresetTimeBaseTicks()
|
|||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
void CBoot::RunFunction(u32 address)
|
||||
void CBoot::RunFunction(Core::System& system, u32 address)
|
||||
{
|
||||
PC = address;
|
||||
LR = 0x00;
|
||||
auto& ppc_state = system.GetPPCState();
|
||||
|
||||
while (PC != 0x00)
|
||||
ppc_state.pc = address;
|
||||
LR(ppc_state) = 0x00;
|
||||
|
||||
while (ppc_state.pc != 0x00)
|
||||
PowerPC::SingleStep();
|
||||
}
|
||||
|
||||
void CBoot::SetupMSR()
|
||||
void CBoot::SetupMSR(PowerPC::PowerPCState& ppc_state)
|
||||
{
|
||||
// 0x0002032
|
||||
MSR.RI = 1;
|
||||
MSR.DR = 1;
|
||||
MSR.IR = 1;
|
||||
MSR.FP = 1;
|
||||
ppc_state.msr.RI = 1;
|
||||
ppc_state.msr.DR = 1;
|
||||
ppc_state.msr.IR = 1;
|
||||
ppc_state.msr.FP = 1;
|
||||
}
|
||||
|
||||
void CBoot::SetupHID(bool is_wii)
|
||||
void CBoot::SetupHID(PowerPC::PowerPCState& ppc_state, bool is_wii)
|
||||
{
|
||||
// HID0 is 0x0011c464 on GC, 0x0011c664 on Wii
|
||||
HID0.BHT = 1;
|
||||
HID0.BTIC = 1;
|
||||
HID0.DCFA = 1;
|
||||
HID0(ppc_state).BHT = 1;
|
||||
HID0(ppc_state).BTIC = 1;
|
||||
HID0(ppc_state).DCFA = 1;
|
||||
if (is_wii)
|
||||
HID0.SPD = 1;
|
||||
HID0.DCFI = 1;
|
||||
HID0.DCE = 1;
|
||||
HID0(ppc_state).SPD = 1;
|
||||
HID0(ppc_state).DCFI = 1;
|
||||
HID0(ppc_state).DCE = 1;
|
||||
// Note that Datel titles will fail to boot if the instruction cache is not enabled; see
|
||||
// https://bugs.dolphin-emu.org/issues/8223
|
||||
HID0.ICE = 1;
|
||||
HID0.NHR = 1;
|
||||
HID0.DPM = 1;
|
||||
HID0(ppc_state).ICE = 1;
|
||||
HID0(ppc_state).NHR = 1;
|
||||
HID0(ppc_state).DPM = 1;
|
||||
|
||||
// HID1 is initialized in PowerPC.cpp to 0x80000000
|
||||
// HID2 is 0xe0000000
|
||||
HID2.PSE = 1;
|
||||
HID2.WPE = 1;
|
||||
HID2.LSQE = 1;
|
||||
HID2(ppc_state).PSE = 1;
|
||||
HID2(ppc_state).WPE = 1;
|
||||
HID2(ppc_state).LSQE = 1;
|
||||
|
||||
// HID4 is 0 on GC and 0x83900000 on Wii
|
||||
if (is_wii)
|
||||
{
|
||||
HID4.L2CFI = 1;
|
||||
HID4.LPE = 1;
|
||||
HID4.ST0 = 1;
|
||||
HID4.SBE = 1;
|
||||
HID4.reserved_3 = 1;
|
||||
HID4(ppc_state).L2CFI = 1;
|
||||
HID4(ppc_state).LPE = 1;
|
||||
HID4(ppc_state).ST0 = 1;
|
||||
HID4(ppc_state).SBE = 1;
|
||||
HID4(ppc_state).reserved_3 = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void CBoot::SetupBAT(bool is_wii)
|
||||
void CBoot::SetupBAT(Core::System& system, bool is_wii)
|
||||
{
|
||||
PowerPC::ppcState.spr[SPR_IBAT0U] = 0x80001fff;
|
||||
PowerPC::ppcState.spr[SPR_IBAT0L] = 0x00000002;
|
||||
PowerPC::ppcState.spr[SPR_DBAT0U] = 0x80001fff;
|
||||
PowerPC::ppcState.spr[SPR_DBAT0L] = 0x00000002;
|
||||
PowerPC::ppcState.spr[SPR_DBAT1U] = 0xc0001fff;
|
||||
PowerPC::ppcState.spr[SPR_DBAT1L] = 0x0000002a;
|
||||
auto& ppc_state = system.GetPPCState();
|
||||
ppc_state.spr[SPR_IBAT0U] = 0x80001fff;
|
||||
ppc_state.spr[SPR_IBAT0L] = 0x00000002;
|
||||
ppc_state.spr[SPR_DBAT0U] = 0x80001fff;
|
||||
ppc_state.spr[SPR_DBAT0L] = 0x00000002;
|
||||
ppc_state.spr[SPR_DBAT1U] = 0xc0001fff;
|
||||
ppc_state.spr[SPR_DBAT1L] = 0x0000002a;
|
||||
if (is_wii)
|
||||
{
|
||||
PowerPC::ppcState.spr[SPR_IBAT4U] = 0x90001fff;
|
||||
PowerPC::ppcState.spr[SPR_IBAT4L] = 0x10000002;
|
||||
PowerPC::ppcState.spr[SPR_DBAT4U] = 0x90001fff;
|
||||
PowerPC::ppcState.spr[SPR_DBAT4L] = 0x10000002;
|
||||
PowerPC::ppcState.spr[SPR_DBAT5U] = 0xd0001fff;
|
||||
PowerPC::ppcState.spr[SPR_DBAT5L] = 0x1000002a;
|
||||
HID4.SBE = 1;
|
||||
ppc_state.spr[SPR_IBAT4U] = 0x90001fff;
|
||||
ppc_state.spr[SPR_IBAT4L] = 0x10000002;
|
||||
ppc_state.spr[SPR_DBAT4U] = 0x90001fff;
|
||||
ppc_state.spr[SPR_DBAT4L] = 0x10000002;
|
||||
ppc_state.spr[SPR_DBAT5U] = 0xd0001fff;
|
||||
ppc_state.spr[SPR_DBAT5L] = 0x1000002a;
|
||||
HID4(ppc_state).SBE = 1;
|
||||
}
|
||||
PowerPC::DBATUpdated();
|
||||
PowerPC::IBATUpdated();
|
||||
}
|
||||
|
||||
bool CBoot::RunApploader(bool is_wii, const DiscIO::VolumeDisc& volume,
|
||||
bool CBoot::RunApploader(Core::System& system, bool is_wii, const DiscIO::VolumeDisc& volume,
|
||||
const std::vector<DiscIO::Riivolution::Patch>& riivolution_patches)
|
||||
{
|
||||
const DiscIO::Partition partition = volume.GetGamePartition();
|
||||
|
@ -148,40 +151,42 @@ bool CBoot::RunApploader(bool is_wii, const DiscIO::VolumeDisc& volume,
|
|||
|
||||
// TODO - Make Apploader(or just RunFunction()) debuggable!!!
|
||||
|
||||
auto& ppc_state = system.GetPPCState();
|
||||
|
||||
// Call iAppLoaderEntry.
|
||||
DEBUG_LOG_FMT(BOOT, "Call iAppLoaderEntry");
|
||||
const u32 iAppLoaderFuncAddr = is_wii ? 0x80004000 : 0x80003100;
|
||||
PowerPC::ppcState.gpr[3] = iAppLoaderFuncAddr + 0;
|
||||
PowerPC::ppcState.gpr[4] = iAppLoaderFuncAddr + 4;
|
||||
PowerPC::ppcState.gpr[5] = iAppLoaderFuncAddr + 8;
|
||||
RunFunction(*entry);
|
||||
ppc_state.gpr[3] = iAppLoaderFuncAddr + 0;
|
||||
ppc_state.gpr[4] = iAppLoaderFuncAddr + 4;
|
||||
ppc_state.gpr[5] = iAppLoaderFuncAddr + 8;
|
||||
RunFunction(system, *entry);
|
||||
const u32 iAppLoaderInit = PowerPC::Read_U32(iAppLoaderFuncAddr + 0);
|
||||
const u32 iAppLoaderMain = PowerPC::Read_U32(iAppLoaderFuncAddr + 4);
|
||||
const u32 iAppLoaderClose = PowerPC::Read_U32(iAppLoaderFuncAddr + 8);
|
||||
|
||||
// iAppLoaderInit
|
||||
DEBUG_LOG_FMT(BOOT, "Call iAppLoaderInit");
|
||||
PowerPC::HostWrite_U32(0x4E800020, 0x81300000); // Write BLR
|
||||
HLE::Patch(0x81300000, "AppLoaderReport"); // HLE OSReport for Apploader
|
||||
PowerPC::ppcState.gpr[3] = 0x81300000;
|
||||
RunFunction(iAppLoaderInit);
|
||||
PowerPC::HostWrite_U32(0x4E800020, 0x81300000); // Write BLR
|
||||
HLE::Patch(system, 0x81300000, "AppLoaderReport"); // HLE OSReport for Apploader
|
||||
ppc_state.gpr[3] = 0x81300000;
|
||||
RunFunction(system, iAppLoaderInit);
|
||||
|
||||
// iAppLoaderMain - Here we load the apploader, the DOL (the exe) and the FST (filesystem).
|
||||
// To give you an idea about where the stuff is located on the disc take a look at yagcd
|
||||
// ch 13.
|
||||
DEBUG_LOG_FMT(BOOT, "Call iAppLoaderMain");
|
||||
|
||||
PowerPC::ppcState.gpr[3] = 0x81300004;
|
||||
PowerPC::ppcState.gpr[4] = 0x81300008;
|
||||
PowerPC::ppcState.gpr[5] = 0x8130000c;
|
||||
ppc_state.gpr[3] = 0x81300004;
|
||||
ppc_state.gpr[4] = 0x81300008;
|
||||
ppc_state.gpr[5] = 0x8130000c;
|
||||
|
||||
RunFunction(iAppLoaderMain);
|
||||
RunFunction(system, iAppLoaderMain);
|
||||
|
||||
// iAppLoaderMain returns 1 if the pointers in R3/R4/R5 were filled with values for DVD copy
|
||||
// Typical behaviour is doing it once for each section defined in the DOL header. Some unlicensed
|
||||
// titles don't have a properly constructed DOL and maintain a table of these values in apploader.
|
||||
// iAppLoaderMain returns 0 when there are no more sections to copy.
|
||||
while (PowerPC::ppcState.gpr[3] != 0x00)
|
||||
while (ppc_state.gpr[3] != 0x00)
|
||||
{
|
||||
const u32 ram_address = PowerPC::Read_U32(0x81300004);
|
||||
const u32 length = PowerPC::Read_U32(0x81300008);
|
||||
|
@ -193,20 +198,20 @@ bool CBoot::RunApploader(bool is_wii, const DiscIO::VolumeDisc& volume,
|
|||
|
||||
DiscIO::Riivolution::ApplyApploaderMemoryPatches(riivolution_patches, ram_address, length);
|
||||
|
||||
PowerPC::ppcState.gpr[3] = 0x81300004;
|
||||
PowerPC::ppcState.gpr[4] = 0x81300008;
|
||||
PowerPC::ppcState.gpr[5] = 0x8130000c;
|
||||
ppc_state.gpr[3] = 0x81300004;
|
||||
ppc_state.gpr[4] = 0x81300008;
|
||||
ppc_state.gpr[5] = 0x8130000c;
|
||||
|
||||
RunFunction(iAppLoaderMain);
|
||||
RunFunction(system, iAppLoaderMain);
|
||||
}
|
||||
|
||||
// iAppLoaderClose
|
||||
DEBUG_LOG_FMT(BOOT, "call iAppLoaderClose");
|
||||
RunFunction(iAppLoaderClose);
|
||||
HLE::UnPatch("AppLoaderReport");
|
||||
RunFunction(system, iAppLoaderClose);
|
||||
HLE::UnPatch(system, "AppLoaderReport");
|
||||
|
||||
// return
|
||||
PC = PowerPC::ppcState.gpr[3];
|
||||
ppc_state.pc = ppc_state.gpr[3];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -255,9 +260,11 @@ bool CBoot::EmulatedBS2_GC(Core::System& system, const DiscIO::VolumeDisc& volum
|
|||
{
|
||||
INFO_LOG_FMT(BOOT, "Faking GC BS2...");
|
||||
|
||||
SetupMSR();
|
||||
SetupHID(/*is_wii*/ false);
|
||||
SetupBAT(/*is_wii*/ false);
|
||||
auto& ppc_state = system.GetPPCState();
|
||||
|
||||
SetupMSR(ppc_state);
|
||||
SetupHID(ppc_state, /*is_wii*/ false);
|
||||
SetupBAT(system, /*is_wii*/ false);
|
||||
|
||||
SetupGCMemory(system);
|
||||
|
||||
|
@ -296,13 +303,13 @@ bool CBoot::EmulatedBS2_GC(Core::System& system, const DiscIO::VolumeDisc& volum
|
|||
// Setup pointers like real BS2 does
|
||||
|
||||
// StackPointer, used to be set to 0x816ffff0
|
||||
PowerPC::ppcState.gpr[1] = ntsc ? 0x81566550 : 0x815edca8;
|
||||
ppc_state.gpr[1] = ntsc ? 0x81566550 : 0x815edca8;
|
||||
// Global pointer to Small Data Area 2 Base (haven't seen anything use it...meh)
|
||||
PowerPC::ppcState.gpr[2] = ntsc ? 0x81465cc0 : 0x814b5b20;
|
||||
ppc_state.gpr[2] = ntsc ? 0x81465cc0 : 0x814b5b20;
|
||||
// Global pointer to Small Data Area Base (Luigi's Mansion's apploader uses it)
|
||||
PowerPC::ppcState.gpr[13] = ntsc ? 0x81465320 : 0x814b4fc0;
|
||||
ppc_state.gpr[13] = ntsc ? 0x81465320 : 0x814b4fc0;
|
||||
|
||||
return RunApploader(/*is_wii*/ false, volume, riivolution_patches);
|
||||
return RunApploader(system, /*is_wii*/ false, volume, riivolution_patches);
|
||||
}
|
||||
|
||||
static DiscIO::Region CodeRegion(char c)
|
||||
|
@ -559,17 +566,19 @@ bool CBoot::EmulatedBS2_Wii(Core::System& system, const DiscIO::VolumeDisc& volu
|
|||
// after this check during booting.
|
||||
DVDRead(volume, 0, 0x3180, 4, partition);
|
||||
|
||||
SetupMSR();
|
||||
SetupHID(/*is_wii*/ true);
|
||||
SetupBAT(/*is_wii*/ true);
|
||||
auto& ppc_state = system.GetPPCState();
|
||||
|
||||
SetupMSR(ppc_state);
|
||||
SetupHID(ppc_state, /*is_wii*/ true);
|
||||
SetupBAT(system, /*is_wii*/ true);
|
||||
|
||||
memory.Write_U32(0x4c000064, 0x00000300); // Write default DSI Handler: rfi
|
||||
memory.Write_U32(0x4c000064, 0x00000800); // Write default FPU Handler: rfi
|
||||
memory.Write_U32(0x4c000064, 0x00000C00); // Write default Syscall Handler: rfi
|
||||
|
||||
PowerPC::ppcState.gpr[1] = 0x816ffff0; // StackPointer
|
||||
ppc_state.gpr[1] = 0x816ffff0; // StackPointer
|
||||
|
||||
if (!RunApploader(/*is_wii*/ true, volume, riivolution_patches))
|
||||
if (!RunApploader(system, /*is_wii*/ true, volume, riivolution_patches))
|
||||
return false;
|
||||
|
||||
// The Apploader probably just overwrote values needed for RAM Override. Run this again!
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "Core/HW/Memmap.h"
|
||||
#include "Core/PowerPC/MMU.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
#include "Core/System.h"
|
||||
|
||||
Cheats::DataType Cheats::GetDataType(const Cheats::SearchValue& value)
|
||||
{
|
||||
|
@ -204,7 +205,9 @@ Cheats::NewSearch(const std::vector<Cheats::MemoryRange>& memory_ranges,
|
|||
return;
|
||||
}
|
||||
|
||||
if (address_space == PowerPC::RequestedAddressSpace::Virtual && !MSR.DR)
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& ppc_state = system.GetPPCState();
|
||||
if (address_space == PowerPC::RequestedAddressSpace::Virtual && !ppc_state.msr.DR)
|
||||
{
|
||||
error_code = Cheats::SearchErrorCode::VirtualAddressesCurrentlyNotAccessible;
|
||||
return;
|
||||
|
@ -263,7 +266,9 @@ Cheats::NextSearch(const std::vector<Cheats::SearchResult<T>>& previous_results,
|
|||
return;
|
||||
}
|
||||
|
||||
if (address_space == PowerPC::RequestedAddressSpace::Virtual && !MSR.DR)
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& ppc_state = system.GetPPCState();
|
||||
if (address_space == PowerPC::RequestedAddressSpace::Virtual && !ppc_state.msr.DR)
|
||||
{
|
||||
error_code = Cheats::SearchErrorCode::VirtualAddressesCurrentlyNotAccessible;
|
||||
return;
|
||||
|
|
|
@ -51,6 +51,7 @@
|
|||
#include "Core/PatchEngine.h"
|
||||
#include "Core/PowerPC/PPCSymbolDB.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
#include "Core/System.h"
|
||||
#include "Core/TitleDatabase.h"
|
||||
#include "VideoCommon/HiresTextures.h"
|
||||
|
||||
|
@ -202,7 +203,8 @@ void SConfig::OnNewTitleLoad()
|
|||
Host_NotifyMapLoaded();
|
||||
}
|
||||
CBoot::LoadMapFromFilename();
|
||||
HLE::Reload();
|
||||
auto& system = Core::System::GetInstance();
|
||||
HLE::Reload(system);
|
||||
PatchEngine::Reload();
|
||||
HiresTexture::Update();
|
||||
}
|
||||
|
|
|
@ -44,6 +44,10 @@ static void EmptyTimedCallback(Core::System& system, u64 userdata, s64 cyclesLat
|
|||
{
|
||||
}
|
||||
|
||||
CoreTimingManager::CoreTimingManager(Core::System& system) : m_system(system)
|
||||
{
|
||||
}
|
||||
|
||||
// Changing the CPU speed in Dolphin isn't actually done by changing the physical clock rate,
|
||||
// but by changing the amount of work done in a particular amount of time. This tends to be more
|
||||
// compatible because it stops the games from actually knowing directly that the clock rate has
|
||||
|
@ -90,7 +94,7 @@ void CoreTimingManager::Init()
|
|||
|
||||
m_last_oc_factor = m_config_oc_factor;
|
||||
m_globals.last_OC_factor_inverted = m_config_oc_inv_factor;
|
||||
PowerPC::ppcState.downcount = CyclesToDowncount(MAX_SLICE_LENGTH);
|
||||
m_system.GetPPCState().downcount = CyclesToDowncount(MAX_SLICE_LENGTH);
|
||||
m_globals.slice_length = MAX_SLICE_LENGTH;
|
||||
m_globals.global_timer = 0;
|
||||
m_idled_cycles = 0;
|
||||
|
@ -195,7 +199,7 @@ u64 CoreTimingManager::GetTicks() const
|
|||
u64 ticks = static_cast<u64>(m_globals.global_timer);
|
||||
if (!m_is_global_timer_sane)
|
||||
{
|
||||
int downcount = DowncountToCycles(PowerPC::ppcState.downcount);
|
||||
int downcount = DowncountToCycles(m_system.GetPPCState().downcount);
|
||||
ticks += m_globals.slice_length - downcount;
|
||||
}
|
||||
return ticks;
|
||||
|
@ -277,13 +281,13 @@ void CoreTimingManager::RemoveAllEvents(EventType* event_type)
|
|||
void CoreTimingManager::ForceExceptionCheck(s64 cycles)
|
||||
{
|
||||
cycles = std::max<s64>(0, cycles);
|
||||
if (DowncountToCycles(PowerPC::ppcState.downcount) > cycles)
|
||||
auto& ppc_state = m_system.GetPPCState();
|
||||
if (DowncountToCycles(ppc_state.downcount) > cycles)
|
||||
{
|
||||
// downcount is always (much) smaller than MAX_INT so we can safely cast cycles to an int here.
|
||||
// Account for cycles already executed by adjusting the m_globals.slice_length
|
||||
m_globals.slice_length -=
|
||||
DowncountToCycles(PowerPC::ppcState.downcount) - static_cast<int>(cycles);
|
||||
PowerPC::ppcState.downcount = CyclesToDowncount(static_cast<int>(cycles));
|
||||
m_globals.slice_length -= DowncountToCycles(ppc_state.downcount) - static_cast<int>(cycles);
|
||||
ppc_state.downcount = CyclesToDowncount(static_cast<int>(cycles));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -299,11 +303,12 @@ void CoreTimingManager::MoveEvents()
|
|||
|
||||
void CoreTimingManager::Advance()
|
||||
{
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& system = m_system;
|
||||
auto& ppc_state = m_system.GetPPCState();
|
||||
|
||||
MoveEvents();
|
||||
|
||||
int cyclesExecuted = m_globals.slice_length - DowncountToCycles(PowerPC::ppcState.downcount);
|
||||
int cyclesExecuted = m_globals.slice_length - DowncountToCycles(ppc_state.downcount);
|
||||
m_globals.global_timer += cyclesExecuted;
|
||||
m_last_oc_factor = m_config_oc_factor;
|
||||
m_globals.last_OC_factor_inverted = m_config_oc_inv_factor;
|
||||
|
@ -330,7 +335,7 @@ void CoreTimingManager::Advance()
|
|||
std::min<s64>(m_event_queue.front().time - m_globals.global_timer, MAX_SLICE_LENGTH));
|
||||
}
|
||||
|
||||
PowerPC::ppcState.downcount = CyclesToDowncount(m_globals.slice_length);
|
||||
ppc_state.downcount = CyclesToDowncount(m_globals.slice_length);
|
||||
|
||||
// Check for any external exceptions.
|
||||
// It's important to do this after processing events otherwise any exceptions will be delayed
|
||||
|
@ -438,18 +443,20 @@ void CoreTimingManager::AdjustEventQueueTimes(u32 new_ppc_clock, u32 old_ppc_clo
|
|||
|
||||
void CoreTimingManager::Idle()
|
||||
{
|
||||
auto& system = m_system;
|
||||
auto& ppc_state = m_system.GetPPCState();
|
||||
|
||||
if (m_config_sync_on_skip_idle)
|
||||
{
|
||||
// When the FIFO is processing data we must not advance because in this way
|
||||
// the VI will be desynchronized. So, We are waiting until the FIFO finish and
|
||||
// while we process only the events required by the FIFO.
|
||||
auto& system = Core::System::GetInstance();
|
||||
system.GetFifo().FlushGpu(system);
|
||||
}
|
||||
|
||||
PowerPC::UpdatePerformanceMonitor(PowerPC::ppcState.downcount, 0, 0);
|
||||
m_idled_cycles += DowncountToCycles(PowerPC::ppcState.downcount);
|
||||
PowerPC::ppcState.downcount = 0;
|
||||
PowerPC::UpdatePerformanceMonitor(ppc_state.downcount, 0, 0, ppc_state);
|
||||
m_idled_cycles += DowncountToCycles(ppc_state.downcount);
|
||||
ppc_state.downcount = 0;
|
||||
}
|
||||
|
||||
std::string CoreTimingManager::GetScheduledEventsSummary() const
|
||||
|
|
|
@ -75,6 +75,8 @@ void GlobalIdle();
|
|||
class CoreTimingManager
|
||||
{
|
||||
public:
|
||||
explicit CoreTimingManager(Core::System& system);
|
||||
|
||||
// CoreTiming begins at the boundary of timing slice -1. An initial call to Advance() is
|
||||
// required to end slice -1 and start slice 0 before the first cycle of code is executed.
|
||||
void Init();
|
||||
|
@ -151,6 +153,8 @@ public:
|
|||
private:
|
||||
Globals m_globals;
|
||||
|
||||
Core::System& m_system;
|
||||
|
||||
// unordered_map stores each element separately as a linked list node so pointers to elements
|
||||
// remain stable regardless of rehashes/resizing.
|
||||
std::unordered_map<std::string, EventType> m_event_types;
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "Core/PowerPC/MMU.h"
|
||||
#include "Core/PowerPC/PPCSymbolDB.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
#include "Core/System.h"
|
||||
|
||||
namespace Dolphin_Debugger
|
||||
{
|
||||
|
@ -43,11 +44,13 @@ static bool IsStackBottom(u32 addr)
|
|||
return !addr || !PowerPC::HostIsRAMAddress(addr);
|
||||
}
|
||||
|
||||
static void WalkTheStack(const std::function<void(u32)>& stack_step)
|
||||
static void WalkTheStack(Core::System& system, const std::function<void(u32)>& stack_step)
|
||||
{
|
||||
if (!IsStackBottom(PowerPC::ppcState.gpr[1]))
|
||||
auto& ppc_state = system.GetPPCState();
|
||||
|
||||
if (!IsStackBottom(ppc_state.gpr[1]))
|
||||
{
|
||||
u32 addr = PowerPC::HostRead_U32(PowerPC::ppcState.gpr[1]); // SP
|
||||
u32 addr = PowerPC::HostRead_U32(ppc_state.gpr[1]); // SP
|
||||
|
||||
// Walk the stack chain
|
||||
for (int count = 0; !IsStackBottom(addr + 4) && (count++ < 20); ++count)
|
||||
|
@ -66,12 +69,14 @@ static void WalkTheStack(const std::function<void(u32)>& stack_step)
|
|||
// Returns callstack "formatted for debugging" - meaning that it
|
||||
// includes LR as the last item, and all items are the last step,
|
||||
// instead of "pointing ahead"
|
||||
bool GetCallstack(std::vector<CallstackEntry>& output)
|
||||
bool GetCallstack(Core::System& system, std::vector<CallstackEntry>& output)
|
||||
{
|
||||
if (!Core::IsRunning() || !PowerPC::HostIsRAMAddress(PowerPC::ppcState.gpr[1]))
|
||||
auto& ppc_state = system.GetPPCState();
|
||||
|
||||
if (!Core::IsRunning() || !PowerPC::HostIsRAMAddress(ppc_state.gpr[1]))
|
||||
return false;
|
||||
|
||||
if (LR == 0)
|
||||
if (LR(ppc_state) == 0)
|
||||
{
|
||||
CallstackEntry entry;
|
||||
entry.Name = "(error: LR=0)";
|
||||
|
@ -81,11 +86,12 @@ bool GetCallstack(std::vector<CallstackEntry>& output)
|
|||
}
|
||||
|
||||
CallstackEntry entry;
|
||||
entry.Name = fmt::format(" * {} [ LR = {:08x} ]\n", g_symbolDB.GetDescription(LR), LR - 4);
|
||||
entry.vAddress = LR - 4;
|
||||
entry.Name = fmt::format(" * {} [ LR = {:08x} ]\n", g_symbolDB.GetDescription(LR(ppc_state)),
|
||||
LR(ppc_state) - 4);
|
||||
entry.vAddress = LR(ppc_state) - 4;
|
||||
output.push_back(entry);
|
||||
|
||||
WalkTheStack([&entry, &output](u32 func_addr) {
|
||||
WalkTheStack(system, [&entry, &output](u32 func_addr) {
|
||||
std::string func_desc = g_symbolDB.GetDescription(func_addr);
|
||||
if (func_desc.empty() || func_desc == "Invalid")
|
||||
func_desc = "(unknown)";
|
||||
|
@ -97,21 +103,24 @@ bool GetCallstack(std::vector<CallstackEntry>& output)
|
|||
return true;
|
||||
}
|
||||
|
||||
void PrintCallstack(Common::Log::LogType type, Common::Log::LogLevel level)
|
||||
void PrintCallstack(Core::System& system, Common::Log::LogType type, Common::Log::LogLevel level)
|
||||
{
|
||||
GENERIC_LOG_FMT(type, level, "== STACK TRACE - SP = {:08x} ==", PowerPC::ppcState.gpr[1]);
|
||||
auto& ppc_state = system.GetPPCState();
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
if (g_symbolDB.GetDescription(PC) != g_symbolDB.GetDescription(LR))
|
||||
if (g_symbolDB.GetDescription(ppc_state.pc) != g_symbolDB.GetDescription(LR(ppc_state)))
|
||||
{
|
||||
GENERIC_LOG_FMT(type, level, " * {} [ LR = {:08x} ]", g_symbolDB.GetDescription(LR), LR);
|
||||
GENERIC_LOG_FMT(type, level, " * {} [ LR = {:08x} ]", g_symbolDB.GetDescription(LR(ppc_state)),
|
||||
LR(ppc_state));
|
||||
}
|
||||
|
||||
WalkTheStack([type, level](u32 func_addr) {
|
||||
WalkTheStack(system, [type, level](u32 func_addr) {
|
||||
std::string func_desc = g_symbolDB.GetDescription(func_addr);
|
||||
if (func_desc.empty() || func_desc == "Invalid")
|
||||
func_desc = "(unknown)";
|
||||
|
|
|
@ -10,6 +10,11 @@
|
|||
#include "Common/CommonTypes.h"
|
||||
#include "Common/Logging/Log.h"
|
||||
|
||||
namespace Core
|
||||
{
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Dolphin_Debugger
|
||||
{
|
||||
struct CallstackEntry
|
||||
|
@ -18,8 +23,8 @@ struct CallstackEntry
|
|||
u32 vAddress = 0;
|
||||
};
|
||||
|
||||
bool GetCallstack(std::vector<CallstackEntry>& output);
|
||||
void PrintCallstack(Common::Log::LogType type, Common::Log::LogLevel level);
|
||||
bool GetCallstack(Core::System& system, std::vector<CallstackEntry>& output);
|
||||
void PrintCallstack(Core::System& system, Common::Log::LogType type, Common::Log::LogLevel level);
|
||||
void PrintDataBuffer(Common::Log::LogType type, const u8* data, size_t size,
|
||||
std::string_view title);
|
||||
void AddAutoBreakpoints();
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "Core/PowerPC/MMU.h"
|
||||
#include "Core/PowerPC/PPCSymbolDB.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
#include "Core/System.h"
|
||||
|
||||
void ApplyMemoryPatch(Common::Debug::MemoryPatch& patch, bool store_existing_value)
|
||||
{
|
||||
|
@ -81,7 +82,10 @@ void PPCPatches::UnPatch(std::size_t index)
|
|||
PatchEngine::RemoveMemoryPatch(index);
|
||||
}
|
||||
|
||||
PPCDebugInterface::PPCDebugInterface() = default;
|
||||
PPCDebugInterface::PPCDebugInterface(Core::System& system) : m_system(system)
|
||||
{
|
||||
}
|
||||
|
||||
PPCDebugInterface::~PPCDebugInterface() = default;
|
||||
|
||||
std::size_t PPCDebugInterface::SetWatch(u32 address, std::string name)
|
||||
|
@ -449,7 +453,7 @@ PPCDebugInterface::GetMemoryAddressFromInstruction(const std::string& instructio
|
|||
if (is_reg == offset_match[0])
|
||||
{
|
||||
const int register_index = std::stoi(offset_match.substr(1), nullptr, 10);
|
||||
offset = (register_index == 0 ? 0 : GPR(register_index));
|
||||
offset = (register_index == 0 ? 0 : m_system.GetPPCState().gpr[register_index]);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -468,7 +472,7 @@ PPCDebugInterface::GetMemoryAddressFromInstruction(const std::string& instructio
|
|||
else
|
||||
i = std::stoi(register_match, nullptr, 10);
|
||||
|
||||
const u32 base_address = GPR(i);
|
||||
const u32 base_address = m_system.GetPPCState().gpr[i];
|
||||
|
||||
if (!match.str(1).empty())
|
||||
return base_address - offset;
|
||||
|
@ -478,12 +482,12 @@ PPCDebugInterface::GetMemoryAddressFromInstruction(const std::string& instructio
|
|||
|
||||
u32 PPCDebugInterface::GetPC() const
|
||||
{
|
||||
return PowerPC::ppcState.pc;
|
||||
return m_system.GetPPCState().pc;
|
||||
}
|
||||
|
||||
void PPCDebugInterface::SetPC(u32 address)
|
||||
{
|
||||
PowerPC::ppcState.pc = address;
|
||||
m_system.GetPPCState().pc = address;
|
||||
}
|
||||
|
||||
void PPCDebugInterface::RunToBreakpoint()
|
||||
|
|
|
@ -12,6 +12,11 @@
|
|||
#include "Common/DebugInterface.h"
|
||||
#include "Core/NetworkCaptureLogger.h"
|
||||
|
||||
namespace Core
|
||||
{
|
||||
class System;
|
||||
}
|
||||
|
||||
void ApplyMemoryPatch(Common::Debug::MemoryPatch& patch, bool store_existing_value = true);
|
||||
|
||||
class PPCPatches final : public Common::Debug::MemoryPatches
|
||||
|
@ -29,7 +34,7 @@ private:
|
|||
class PPCDebugInterface final : public Common::DebugInterface
|
||||
{
|
||||
public:
|
||||
PPCDebugInterface();
|
||||
explicit PPCDebugInterface(Core::System& system);
|
||||
~PPCDebugInterface() override;
|
||||
|
||||
// Watches
|
||||
|
@ -102,4 +107,5 @@ private:
|
|||
Common::Debug::Watches m_watches;
|
||||
PPCPatches m_patches;
|
||||
std::shared_ptr<Core::NetworkCaptureLogger> m_network_logger;
|
||||
Core::System& m_system;
|
||||
};
|
||||
|
|
|
@ -514,6 +514,7 @@ void FifoPlayer::WriteFifo(const u8* data, u32 start, u32 end)
|
|||
auto& system = Core::System::GetInstance();
|
||||
auto& core_timing = system.GetCoreTiming();
|
||||
auto& gpfifo = system.GetGPFifo();
|
||||
auto& ppc_state = system.GetPPCState();
|
||||
|
||||
// Write up to 256 bytes at a time
|
||||
while (written < end)
|
||||
|
@ -528,8 +529,8 @@ void FifoPlayer::WriteFifo(const u8* data, u32 start, u32 end)
|
|||
|
||||
u32 burstEnd = std::min(written + 255, lastBurstEnd);
|
||||
|
||||
std::copy(data + written, data + burstEnd, PowerPC::ppcState.gather_pipe_ptr);
|
||||
PowerPC::ppcState.gather_pipe_ptr += burstEnd - written;
|
||||
std::copy(data + written, data + burstEnd, ppc_state.gather_pipe_ptr);
|
||||
ppc_state.gather_pipe_ptr += burstEnd - written;
|
||||
written = burstEnd;
|
||||
|
||||
gpfifo.Write8(data[written++]);
|
||||
|
@ -539,7 +540,7 @@ void FifoPlayer::WriteFifo(const u8* data, u32 start, u32 end)
|
|||
u32 cyclesUsed = elapsedCycles - m_ElapsedCycles;
|
||||
m_ElapsedCycles = elapsedCycles;
|
||||
|
||||
PowerPC::ppcState.downcount -= cyclesUsed;
|
||||
ppc_state.downcount -= cyclesUsed;
|
||||
core_timing.Advance();
|
||||
}
|
||||
}
|
||||
|
@ -629,16 +630,19 @@ void FifoPlayer::ClearEfb()
|
|||
|
||||
void FifoPlayer::LoadMemory()
|
||||
{
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& ppc_state = system.GetPPCState();
|
||||
|
||||
UReg_MSR newMSR;
|
||||
newMSR.DR = 1;
|
||||
newMSR.IR = 1;
|
||||
MSR.Hex = newMSR.Hex;
|
||||
PowerPC::ppcState.spr[SPR_IBAT0U] = 0x80001fff;
|
||||
PowerPC::ppcState.spr[SPR_IBAT0L] = 0x00000002;
|
||||
PowerPC::ppcState.spr[SPR_DBAT0U] = 0x80001fff;
|
||||
PowerPC::ppcState.spr[SPR_DBAT0L] = 0x00000002;
|
||||
PowerPC::ppcState.spr[SPR_DBAT1U] = 0xc0001fff;
|
||||
PowerPC::ppcState.spr[SPR_DBAT1L] = 0x0000002a;
|
||||
ppc_state.msr.Hex = newMSR.Hex;
|
||||
ppc_state.spr[SPR_IBAT0U] = 0x80001fff;
|
||||
ppc_state.spr[SPR_IBAT0L] = 0x00000002;
|
||||
ppc_state.spr[SPR_DBAT0U] = 0x80001fff;
|
||||
ppc_state.spr[SPR_DBAT0L] = 0x00000002;
|
||||
ppc_state.spr[SPR_DBAT1U] = 0xc0001fff;
|
||||
ppc_state.spr[SPR_DBAT1L] = 0x0000002a;
|
||||
PowerPC::DBATUpdated();
|
||||
PowerPC::IBATUpdated();
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "Core/ConfigManager.h"
|
||||
#include "Core/PowerPC/MMU.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
#include "Core/System.h"
|
||||
|
||||
namespace Gecko
|
||||
{
|
||||
|
@ -204,10 +205,13 @@ static Installation InstallCodeHandlerLocked()
|
|||
// Turn on codes
|
||||
PowerPC::HostWrite_U8(1, INSTALLER_BASE_ADDRESS + 7);
|
||||
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& ppc_state = system.GetPPCState();
|
||||
|
||||
// Invalidate the icache and any asm codes
|
||||
for (unsigned int j = 0; j < (INSTALLER_END_ADDRESS - INSTALLER_BASE_ADDRESS); j += 32)
|
||||
{
|
||||
PowerPC::ppcState.iCache.Invalidate(INSTALLER_BASE_ADDRESS + j);
|
||||
ppc_state.iCache.Invalidate(INSTALLER_BASE_ADDRESS + j);
|
||||
}
|
||||
return Installation::Installed;
|
||||
}
|
||||
|
@ -253,36 +257,40 @@ void RunCodeHandler()
|
|||
}
|
||||
}
|
||||
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& ppc_state = system.GetPPCState();
|
||||
|
||||
// We always do this to avoid problems with the stack since we're branching in random locations.
|
||||
// Even with function call return hooks (PC == LR), hand coded assembler won't necessarily
|
||||
// follow the ABI. [Volatile FPR, GPR, CR may not be volatile]
|
||||
// The codehandler will STMW all of the GPR registers, but we need to fix the Stack's Red
|
||||
// Zone, the LR, PC (return address) and the volatile floating point registers.
|
||||
// Build a function call stack frame.
|
||||
u32 SFP = GPR(1); // Stack Frame Pointer
|
||||
GPR(1) -= 256; // Stack's Red Zone
|
||||
GPR(1) -= 16 + 2 * 14 * sizeof(u64); // Our stack frame (HLE_Misc::GeckoReturnTrampoline)
|
||||
GPR(1) -= 8; // Fake stack frame for codehandler
|
||||
GPR(1) &= 0xFFFFFFF0; // Align stack to 16bytes
|
||||
u32 SP = GPR(1); // Stack Pointer
|
||||
u32 SFP = ppc_state.gpr[1]; // Stack Frame Pointer
|
||||
ppc_state.gpr[1] -= 256; // Stack's Red Zone
|
||||
ppc_state.gpr[1] -= 16 + 2 * 14 * sizeof(u64); // Our stack frame
|
||||
// (HLE_Misc::GeckoReturnTrampoline)
|
||||
ppc_state.gpr[1] -= 8; // Fake stack frame for codehandler
|
||||
ppc_state.gpr[1] &= 0xFFFFFFF0; // Align stack to 16bytes
|
||||
u32 SP = ppc_state.gpr[1]; // Stack Pointer
|
||||
PowerPC::HostWrite_U32(SP + 8, SP);
|
||||
// SP + 4 is reserved for the codehandler to save LR to the stack.
|
||||
PowerPC::HostWrite_U32(SFP, SP + 8); // Real stack frame
|
||||
PowerPC::HostWrite_U32(PC, SP + 12);
|
||||
PowerPC::HostWrite_U32(LR, SP + 16);
|
||||
PowerPC::HostWrite_U32(PowerPC::ppcState.cr.Get(), SP + 20);
|
||||
PowerPC::HostWrite_U32(ppc_state.pc, SP + 12);
|
||||
PowerPC::HostWrite_U32(LR(ppc_state), SP + 16);
|
||||
PowerPC::HostWrite_U32(ppc_state.cr.Get(), SP + 20);
|
||||
// Registers FPR0->13 are volatile
|
||||
for (int i = 0; i < 14; ++i)
|
||||
{
|
||||
PowerPC::HostWrite_U64(rPS(i).PS0AsU64(), SP + 24 + 2 * i * sizeof(u64));
|
||||
PowerPC::HostWrite_U64(rPS(i).PS1AsU64(), SP + 24 + (2 * i + 1) * sizeof(u64));
|
||||
PowerPC::HostWrite_U64(ppc_state.ps[i].PS0AsU64(), SP + 24 + 2 * i * sizeof(u64));
|
||||
PowerPC::HostWrite_U64(ppc_state.ps[i].PS1AsU64(), SP + 24 + (2 * i + 1) * sizeof(u64));
|
||||
}
|
||||
DEBUG_LOG_FMT(ACTIONREPLAY,
|
||||
"GeckoCodes: Initiating phantom branch-and-link. "
|
||||
"PC = {:#010x}, SP = {:#010x}, SFP = {:#010x}",
|
||||
PC, SP, SFP);
|
||||
LR = HLE_TRAMPOLINE_ADDRESS;
|
||||
PC = NPC = ENTRY_POINT;
|
||||
ppc_state.pc, SP, SFP);
|
||||
LR(ppc_state) = HLE_TRAMPOLINE_ADDRESS;
|
||||
ppc_state.pc = ppc_state.npc = ENTRY_POINT;
|
||||
}
|
||||
|
||||
} // namespace Gecko
|
||||
|
|
|
@ -63,20 +63,21 @@ constexpr std::array<Hook, 23> os_patches{{
|
|||
}};
|
||||
// clang-format on
|
||||
|
||||
void Patch(u32 addr, std::string_view func_name)
|
||||
void Patch(Core::System& system, u32 addr, std::string_view func_name)
|
||||
{
|
||||
auto& ppc_state = system.GetPPCState();
|
||||
for (u32 i = 1; i < os_patches.size(); ++i)
|
||||
{
|
||||
if (os_patches[i].name == func_name)
|
||||
{
|
||||
s_hooked_addresses[addr] = i;
|
||||
PowerPC::ppcState.iCache.Invalidate(addr);
|
||||
ppc_state.iCache.Invalidate(addr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PatchFixedFunctions()
|
||||
void PatchFixedFunctions(Core::System& system)
|
||||
{
|
||||
// MIOS puts patch data in low MEM1 (0x1800-0x3000) for its own use.
|
||||
// Overwriting data in this range can cause the IPL to crash when launching games
|
||||
|
@ -90,28 +91,29 @@ void PatchFixedFunctions()
|
|||
// handler
|
||||
if (!Config::Get(Config::MAIN_ENABLE_CHEATS))
|
||||
{
|
||||
Patch(0x80001800, "HBReload");
|
||||
auto& system = Core::System::GetInstance();
|
||||
Patch(system, 0x80001800, "HBReload");
|
||||
auto& memory = system.GetMemory();
|
||||
memory.CopyToEmu(0x00001804, "STUBHAXX", 8);
|
||||
}
|
||||
|
||||
// Not part of the binary itself, but either we or Gecko OS might insert
|
||||
// this, and it doesn't clear the icache properly.
|
||||
Patch(Gecko::ENTRY_POINT, "GeckoCodehandler");
|
||||
Patch(system, Gecko::ENTRY_POINT, "GeckoCodehandler");
|
||||
// This has to always be installed even if cheats are not enabled because of the possiblity of
|
||||
// loading a savestate where PC is inside the code handler while cheats are disabled.
|
||||
Patch(Gecko::HLE_TRAMPOLINE_ADDRESS, "GeckoHandlerReturnTrampoline");
|
||||
Patch(system, Gecko::HLE_TRAMPOLINE_ADDRESS, "GeckoHandlerReturnTrampoline");
|
||||
}
|
||||
|
||||
void PatchFunctions()
|
||||
void PatchFunctions(Core::System& system)
|
||||
{
|
||||
auto& ppc_state = system.GetPPCState();
|
||||
|
||||
// Remove all hooks that aren't fixed address hooks
|
||||
for (auto i = s_hooked_addresses.begin(); i != s_hooked_addresses.end();)
|
||||
{
|
||||
if (os_patches[i->second].flags != HookFlag::Fixed)
|
||||
{
|
||||
PowerPC::ppcState.iCache.Invalidate(i->first);
|
||||
ppc_state.iCache.Invalidate(i->first);
|
||||
i = s_hooked_addresses.erase(i);
|
||||
}
|
||||
else
|
||||
|
@ -131,7 +133,7 @@ void PatchFunctions()
|
|||
for (u32 addr = symbol->address; addr < symbol->address + symbol->size; addr += 4)
|
||||
{
|
||||
s_hooked_addresses[addr] = i;
|
||||
PowerPC::ppcState.iCache.Invalidate(addr);
|
||||
ppc_state.iCache.Invalidate(addr);
|
||||
}
|
||||
INFO_LOG_FMT(OSHLE, "Patching {} {:08x}", os_patches[i].name, symbol->address);
|
||||
}
|
||||
|
@ -143,11 +145,11 @@ void Clear()
|
|||
s_hooked_addresses.clear();
|
||||
}
|
||||
|
||||
void Reload()
|
||||
void Reload(Core::System& system)
|
||||
{
|
||||
Clear();
|
||||
PatchFixedFunctions();
|
||||
PatchFunctions();
|
||||
PatchFixedFunctions(system);
|
||||
PatchFunctions(system);
|
||||
}
|
||||
|
||||
void Execute(u32 current_pc, u32 hook_index)
|
||||
|
@ -196,13 +198,15 @@ bool IsEnabled(HookFlag flag)
|
|||
PowerPC::GetMode() == PowerPC::CoreMode::Interpreter;
|
||||
}
|
||||
|
||||
u32 UnPatch(std::string_view patch_name)
|
||||
u32 UnPatch(Core::System& system, std::string_view patch_name)
|
||||
{
|
||||
const auto patch = std::find_if(std::begin(os_patches), std::end(os_patches),
|
||||
[&](const Hook& p) { return patch_name == p.name; });
|
||||
if (patch == std::end(os_patches))
|
||||
return 0;
|
||||
|
||||
auto& ppc_state = system.GetPPCState();
|
||||
|
||||
if (patch->flags == HookFlag::Fixed)
|
||||
{
|
||||
const u32 patch_idx = static_cast<u32>(std::distance(os_patches.begin(), patch));
|
||||
|
@ -213,7 +217,7 @@ u32 UnPatch(std::string_view patch_name)
|
|||
if (i->second == patch_idx)
|
||||
{
|
||||
addr = i->first;
|
||||
PowerPC::ppcState.iCache.Invalidate(i->first);
|
||||
ppc_state.iCache.Invalidate(i->first);
|
||||
i = s_hooked_addresses.erase(i);
|
||||
}
|
||||
else
|
||||
|
@ -231,7 +235,7 @@ u32 UnPatch(std::string_view patch_name)
|
|||
for (u32 addr = symbol->address; addr < symbol->address + symbol->size; addr += 4)
|
||||
{
|
||||
s_hooked_addresses.erase(addr);
|
||||
PowerPC::ppcState.iCache.Invalidate(addr);
|
||||
ppc_state.iCache.Invalidate(addr);
|
||||
}
|
||||
return symbol->address;
|
||||
}
|
||||
|
@ -239,8 +243,10 @@ u32 UnPatch(std::string_view patch_name)
|
|||
return 0;
|
||||
}
|
||||
|
||||
u32 UnpatchRange(u32 start_addr, u32 end_addr)
|
||||
u32 UnpatchRange(Core::System& system, u32 start_addr, u32 end_addr)
|
||||
{
|
||||
auto& ppc_state = system.GetPPCState();
|
||||
|
||||
u32 count = 0;
|
||||
|
||||
auto i = s_hooked_addresses.lower_bound(start_addr);
|
||||
|
@ -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,
|
||||
os_patches[i->second].name, i->first);
|
||||
PowerPC::ppcState.iCache.Invalidate(i->first);
|
||||
ppc_state.iCache.Invalidate(i->first);
|
||||
i = s_hooked_addresses.erase(i);
|
||||
count += 1;
|
||||
}
|
||||
|
|
|
@ -7,6 +7,11 @@
|
|||
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
namespace Core
|
||||
{
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace HLE
|
||||
{
|
||||
using HookFunction = void (*)();
|
||||
|
@ -33,14 +38,14 @@ struct Hook
|
|||
HookFlag flags;
|
||||
};
|
||||
|
||||
void PatchFixedFunctions();
|
||||
void PatchFunctions();
|
||||
void PatchFixedFunctions(Core::System& system);
|
||||
void PatchFunctions(Core::System& system);
|
||||
void Clear();
|
||||
void Reload();
|
||||
void Reload(Core::System& system);
|
||||
|
||||
void Patch(u32 pc, std::string_view func_name);
|
||||
u32 UnPatch(std::string_view patch_name);
|
||||
u32 UnpatchRange(u32 start_addr, u32 end_addr);
|
||||
void Patch(Core::System& system, u32 pc, std::string_view func_name);
|
||||
u32 UnPatch(Core::System& system, std::string_view patch_name);
|
||||
u32 UnpatchRange(Core::System& system, u32 start_addr, u32 end_addr);
|
||||
void Execute(u32 current_pc, u32 hook_index);
|
||||
|
||||
// Returns the HLE hook index of the address
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "Core/Host.h"
|
||||
#include "Core/PowerPC/MMU.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
#include "Core/System.h"
|
||||
|
||||
namespace HLE_Misc
|
||||
{
|
||||
|
@ -17,7 +18,9 @@ namespace HLE_Misc
|
|||
// According to the PPC ABI, the return value is always in r3.
|
||||
void UnimplementedFunction()
|
||||
{
|
||||
NPC = LR;
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& ppc_state = system.GetPPCState();
|
||||
ppc_state.npc = LR(ppc_state);
|
||||
}
|
||||
|
||||
void HBReload()
|
||||
|
@ -29,6 +32,9 @@ void HBReload()
|
|||
|
||||
void GeckoCodeHandlerICacheFlush()
|
||||
{
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& ppc_state = system.GetPPCState();
|
||||
|
||||
// Work around the codehandler not properly invalidating the icache, but
|
||||
// only the first few frames.
|
||||
// (Project M uses a conditional to only apply patches after something has
|
||||
|
@ -46,7 +52,7 @@ void GeckoCodeHandlerICacheFlush()
|
|||
}
|
||||
PowerPC::HostWrite_U32(gch_gameid + 1, Gecko::INSTALLER_BASE_ADDRESS);
|
||||
|
||||
PowerPC::ppcState.iCache.Reset();
|
||||
ppc_state.iCache.Reset();
|
||||
}
|
||||
|
||||
// Because Dolphin messes around with the CPU state instead of patching the game binary, we
|
||||
|
@ -55,16 +61,19 @@ void GeckoCodeHandlerICacheFlush()
|
|||
// and PC before the magic, invisible BL instruction happened.
|
||||
void GeckoReturnTrampoline()
|
||||
{
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& ppc_state = system.GetPPCState();
|
||||
|
||||
// Stack frame is built in GeckoCode.cpp, Gecko::RunCodeHandler.
|
||||
u32 SP = GPR(1);
|
||||
GPR(1) = PowerPC::HostRead_U32(SP + 8);
|
||||
NPC = PowerPC::HostRead_U32(SP + 12);
|
||||
LR = PowerPC::HostRead_U32(SP + 16);
|
||||
PowerPC::ppcState.cr.Set(PowerPC::HostRead_U32(SP + 20));
|
||||
u32 SP = ppc_state.gpr[1];
|
||||
ppc_state.gpr[1] = PowerPC::HostRead_U32(SP + 8);
|
||||
ppc_state.npc = PowerPC::HostRead_U32(SP + 12);
|
||||
LR(ppc_state) = PowerPC::HostRead_U32(SP + 16);
|
||||
ppc_state.cr.Set(PowerPC::HostRead_U32(SP + 20));
|
||||
for (int i = 0; i < 14; ++i)
|
||||
{
|
||||
rPS(i).SetBoth(PowerPC::HostRead_U64(SP + 24 + 2 * i * sizeof(u64)),
|
||||
PowerPC::HostRead_U64(SP + 24 + (2 * i + 1) * sizeof(u64)));
|
||||
ppc_state.ps[i].SetBoth(PowerPC::HostRead_U64(SP + 24 + 2 * i * sizeof(u64)),
|
||||
PowerPC::HostRead_U64(SP + 24 + (2 * i + 1) * sizeof(u64)));
|
||||
}
|
||||
}
|
||||
} // namespace HLE_Misc
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "Core/HLE/HLE_VarArgs.h"
|
||||
#include "Core/PowerPC/MMU.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
#include "Core/System.h"
|
||||
|
||||
namespace HLE_OS
|
||||
{
|
||||
|
@ -22,7 +23,7 @@ enum class ParameterType : bool
|
|||
VariableArgumentList = true
|
||||
};
|
||||
|
||||
std::string GetStringVA(u32 str_reg = 3,
|
||||
std::string GetStringVA(Core::System& system, u32 str_reg = 3,
|
||||
ParameterType parameter_type = ParameterType::ParameterList);
|
||||
void HLE_GeneralDebugPrint(ParameterType parameter_type);
|
||||
void HLE_LogDPrint(ParameterType parameter_type);
|
||||
|
@ -30,56 +31,64 @@ void HLE_LogFPrint(ParameterType parameter_type);
|
|||
|
||||
void HLE_OSPanic()
|
||||
{
|
||||
std::string error = GetStringVA();
|
||||
std::string msg = GetStringVA(5);
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& ppc_state = system.GetPPCState();
|
||||
|
||||
std::string error = GetStringVA(system);
|
||||
std::string msg = GetStringVA(system, 5);
|
||||
|
||||
StringPopBackIf(&error, '\n');
|
||||
StringPopBackIf(&msg, '\n');
|
||||
|
||||
PanicAlertFmt("OSPanic: {}: {}", error, msg);
|
||||
ERROR_LOG_FMT(OSREPORT_HLE, "{:08x}->{:08x}| OSPanic: {}: {}", LR, PC, error, msg);
|
||||
ERROR_LOG_FMT(OSREPORT_HLE, "{:08x}->{:08x}| OSPanic: {}: {}", LR(ppc_state), ppc_state.pc, error,
|
||||
msg);
|
||||
|
||||
NPC = LR;
|
||||
ppc_state.npc = LR(ppc_state);
|
||||
}
|
||||
|
||||
// Generalized function for printing formatted string.
|
||||
void HLE_GeneralDebugPrint(ParameterType parameter_type)
|
||||
{
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& ppc_state = system.GetPPCState();
|
||||
|
||||
std::string report_message;
|
||||
|
||||
// Is gpr3 pointing to a pointer (including nullptr) rather than an ASCII string
|
||||
if (PowerPC::HostIsRAMAddress(GPR(3)) &&
|
||||
(PowerPC::HostIsRAMAddress(PowerPC::HostRead_U32(GPR(3))) ||
|
||||
PowerPC::HostRead_U32(GPR(3)) == 0))
|
||||
if (PowerPC::HostIsRAMAddress(ppc_state.gpr[3]) &&
|
||||
(PowerPC::HostIsRAMAddress(PowerPC::HostRead_U32(ppc_state.gpr[3])) ||
|
||||
PowerPC::HostRead_U32(ppc_state.gpr[3]) == 0))
|
||||
{
|
||||
if (PowerPC::HostIsRAMAddress(GPR(4)))
|
||||
if (PowerPC::HostIsRAMAddress(ppc_state.gpr[4]))
|
||||
{
|
||||
// ___blank(void* this, const char* fmt, ...);
|
||||
report_message = GetStringVA(4, parameter_type);
|
||||
report_message = GetStringVA(system, 4, parameter_type);
|
||||
}
|
||||
else
|
||||
{
|
||||
// ___blank(void* this, int log_type, const char* fmt, ...);
|
||||
report_message = GetStringVA(5, parameter_type);
|
||||
report_message = GetStringVA(system, 5, parameter_type);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (PowerPC::HostIsRAMAddress(GPR(3)))
|
||||
if (PowerPC::HostIsRAMAddress(ppc_state.gpr[3]))
|
||||
{
|
||||
// ___blank(const char* fmt, ...);
|
||||
report_message = GetStringVA(3, parameter_type);
|
||||
report_message = GetStringVA(system, 3, parameter_type);
|
||||
}
|
||||
else
|
||||
{
|
||||
// ___blank(int log_type, const char* fmt, ...);
|
||||
report_message = GetStringVA(4, parameter_type);
|
||||
report_message = GetStringVA(system, 4, parameter_type);
|
||||
}
|
||||
}
|
||||
|
||||
StringPopBackIf(&report_message, '\n');
|
||||
|
||||
NOTICE_LOG_FMT(OSREPORT_HLE, "{:08x}->{:08x}| {}", LR, PC, SHIFTJISToUTF8(report_message));
|
||||
NOTICE_LOG_FMT(OSREPORT_HLE, "{:08x}->{:08x}| {}", LR(ppc_state), ppc_state.pc,
|
||||
SHIFTJISToUTF8(report_message));
|
||||
}
|
||||
|
||||
// Generalized function for printing formatted string using parameter list.
|
||||
|
@ -97,10 +106,13 @@ void HLE_GeneralDebugVPrint()
|
|||
// __write_console(int fd, const void* buffer, const u32* size)
|
||||
void HLE_write_console()
|
||||
{
|
||||
std::string report_message = GetStringVA(4);
|
||||
if (PowerPC::HostIsRAMAddress(GPR(5)))
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& ppc_state = system.GetPPCState();
|
||||
|
||||
std::string report_message = GetStringVA(system, 4);
|
||||
if (PowerPC::HostIsRAMAddress(ppc_state.gpr[5]))
|
||||
{
|
||||
const u32 size = PowerPC::Read_U32(GPR(5));
|
||||
const u32 size = PowerPC::Read_U32(ppc_state.gpr[5]);
|
||||
if (size > report_message.size())
|
||||
WARN_LOG_FMT(OSREPORT_HLE, "__write_console uses an invalid size of {:#010x}", size);
|
||||
else if (size == 0)
|
||||
|
@ -115,18 +127,23 @@ void HLE_write_console()
|
|||
|
||||
StringPopBackIf(&report_message, '\n');
|
||||
|
||||
NOTICE_LOG_FMT(OSREPORT_HLE, "{:08x}->{:08x}| {}", LR, PC, SHIFTJISToUTF8(report_message));
|
||||
NOTICE_LOG_FMT(OSREPORT_HLE, "{:08x}->{:08x}| {}", LR(ppc_state), ppc_state.pc,
|
||||
SHIFTJISToUTF8(report_message));
|
||||
}
|
||||
|
||||
// Log (v)dprintf message if fd is 1 (stdout) or 2 (stderr)
|
||||
void HLE_LogDPrint(ParameterType parameter_type)
|
||||
{
|
||||
if (GPR(3) != 1 && GPR(3) != 2)
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& ppc_state = system.GetPPCState();
|
||||
|
||||
if (ppc_state.gpr[3] != 1 && ppc_state.gpr[3] != 2)
|
||||
return;
|
||||
|
||||
std::string report_message = GetStringVA(4, parameter_type);
|
||||
std::string report_message = GetStringVA(system, 4, parameter_type);
|
||||
StringPopBackIf(&report_message, '\n');
|
||||
NOTICE_LOG_FMT(OSREPORT_HLE, "{:08x}->{:08x}| {}", LR, PC, SHIFTJISToUTF8(report_message));
|
||||
NOTICE_LOG_FMT(OSREPORT_HLE, "{:08x}->{:08x}| {}", LR(ppc_state), ppc_state.pc,
|
||||
SHIFTJISToUTF8(report_message));
|
||||
}
|
||||
|
||||
// Log dprintf message
|
||||
|
@ -146,25 +163,30 @@ void HLE_LogVDPrint()
|
|||
// Log (v)fprintf message if FILE is stdout or stderr
|
||||
void HLE_LogFPrint(ParameterType parameter_type)
|
||||
{
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& ppc_state = system.GetPPCState();
|
||||
|
||||
// The structure FILE is implementation defined.
|
||||
// Both libogc and Dolphin SDK seem to store the fd at the same address.
|
||||
int fd = -1;
|
||||
if (PowerPC::HostIsRAMAddress(GPR(3)) && PowerPC::HostIsRAMAddress(GPR(3) + 0xF))
|
||||
if (PowerPC::HostIsRAMAddress(ppc_state.gpr[3]) &&
|
||||
PowerPC::HostIsRAMAddress(ppc_state.gpr[3] + 0xF))
|
||||
{
|
||||
// The fd is stored as a short at FILE+0xE.
|
||||
fd = static_cast<short>(PowerPC::HostRead_U16(GPR(3) + 0xE));
|
||||
fd = static_cast<short>(PowerPC::HostRead_U16(ppc_state.gpr[3] + 0xE));
|
||||
}
|
||||
if (fd != 1 && fd != 2)
|
||||
{
|
||||
// On RVL SDK it seems stored at FILE+0x2.
|
||||
fd = static_cast<short>(PowerPC::HostRead_U16(GPR(3) + 0x2));
|
||||
fd = static_cast<short>(PowerPC::HostRead_U16(ppc_state.gpr[3] + 0x2));
|
||||
}
|
||||
if (fd != 1 && fd != 2)
|
||||
return;
|
||||
|
||||
std::string report_message = GetStringVA(4, parameter_type);
|
||||
std::string report_message = GetStringVA(system, 4, parameter_type);
|
||||
StringPopBackIf(&report_message, '\n');
|
||||
NOTICE_LOG_FMT(OSREPORT_HLE, "{:08x}->{:08x}| {}", LR, PC, SHIFTJISToUTF8(report_message));
|
||||
NOTICE_LOG_FMT(OSREPORT_HLE, "{:08x}->{:08x}| {}", LR(ppc_state), ppc_state.pc,
|
||||
SHIFTJISToUTF8(report_message));
|
||||
}
|
||||
|
||||
// Log fprintf message
|
||||
|
@ -181,14 +203,17 @@ void HLE_LogVFPrint()
|
|||
HLE_LogFPrint(ParameterType::VariableArgumentList);
|
||||
}
|
||||
|
||||
std::string GetStringVA(u32 str_reg, ParameterType parameter_type)
|
||||
std::string GetStringVA(Core::System& system, u32 str_reg, ParameterType parameter_type)
|
||||
{
|
||||
auto& ppc_state = system.GetPPCState();
|
||||
|
||||
std::string ArgumentBuffer;
|
||||
std::string result;
|
||||
std::string string = PowerPC::HostGetString(GPR(str_reg));
|
||||
auto ap = parameter_type == ParameterType::VariableArgumentList ?
|
||||
std::make_unique<HLE::SystemVABI::VAListStruct>(GPR(str_reg + 1)) :
|
||||
std::make_unique<HLE::SystemVABI::VAList>(GPR(1) + 0x8, str_reg + 1);
|
||||
std::string string = PowerPC::HostGetString(ppc_state.gpr[str_reg]);
|
||||
auto ap =
|
||||
parameter_type == ParameterType::VariableArgumentList ?
|
||||
std::make_unique<HLE::SystemVABI::VAListStruct>(system, ppc_state.gpr[str_reg + 1]) :
|
||||
std::make_unique<HLE::SystemVABI::VAList>(system, ppc_state.gpr[1] + 0x8, str_reg + 1);
|
||||
|
||||
for (size_t i = 0; i < string.size(); i++)
|
||||
{
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "Core/HLE/HLE_VarArgs.h"
|
||||
#include "Core/System.h"
|
||||
|
||||
#include "Common/Logging/Log.h"
|
||||
|
||||
|
@ -9,18 +10,19 @@ HLE::SystemVABI::VAList::~VAList() = default;
|
|||
|
||||
u32 HLE::SystemVABI::VAList::GetGPR(u32 gpr) const
|
||||
{
|
||||
return GPR(gpr);
|
||||
return m_system.GetPPCState().gpr[gpr];
|
||||
}
|
||||
|
||||
double HLE::SystemVABI::VAList::GetFPR(u32 fpr) const
|
||||
{
|
||||
return rPS(fpr).PS0AsDouble();
|
||||
return m_system.GetPPCState().ps[fpr].PS0AsDouble();
|
||||
}
|
||||
|
||||
HLE::SystemVABI::VAListStruct::VAListStruct(u32 address)
|
||||
: VAList(0), m_va_list{PowerPC::HostRead_U8(address), PowerPC::HostRead_U8(address + 1),
|
||||
PowerPC::HostRead_U32(address + 4), PowerPC::HostRead_U32(address + 8)},
|
||||
m_address(address), m_has_fpr_area(PowerPC::ppcState.cr.GetBit(6) == 1)
|
||||
HLE::SystemVABI::VAListStruct::VAListStruct(Core::System& system, u32 address)
|
||||
: VAList(system, 0), m_va_list{PowerPC::HostRead_U8(address), PowerPC::HostRead_U8(address + 1),
|
||||
PowerPC::HostRead_U32(address + 4),
|
||||
PowerPC::HostRead_U32(address + 8)},
|
||||
m_address(address), m_has_fpr_area(system.GetPPCState().cr.GetBit(6) == 1)
|
||||
{
|
||||
m_stack = m_va_list.overflow_arg_area;
|
||||
m_gpr += m_va_list.gpr;
|
||||
|
|
|
@ -11,6 +11,11 @@
|
|||
|
||||
#include <type_traits>
|
||||
|
||||
namespace Core
|
||||
{
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace HLE::SystemVABI
|
||||
{
|
||||
// SFINAE
|
||||
|
@ -32,8 +37,10 @@ constexpr bool IS_ARG_REAL = std::is_floating_point<T>();
|
|||
class VAList
|
||||
{
|
||||
public:
|
||||
explicit VAList(u32 stack, u32 gpr = 3, u32 fpr = 1, u32 gpr_max = 10, u32 fpr_max = 8)
|
||||
: m_gpr(gpr), m_fpr(fpr), m_gpr_max(gpr_max), m_fpr_max(fpr_max), m_stack(stack)
|
||||
explicit VAList(Core::System& system, u32 stack, u32 gpr = 3, u32 fpr = 1, u32 gpr_max = 10,
|
||||
u32 fpr_max = 8)
|
||||
: m_system(system), m_gpr(gpr), m_fpr(fpr), m_gpr_max(gpr_max), m_fpr_max(fpr_max),
|
||||
m_stack(stack)
|
||||
{
|
||||
}
|
||||
virtual ~VAList();
|
||||
|
@ -127,6 +134,7 @@ public:
|
|||
}
|
||||
|
||||
protected:
|
||||
Core::System& m_system;
|
||||
u32 m_gpr = 3;
|
||||
u32 m_fpr = 1;
|
||||
const u32 m_gpr_max = 10;
|
||||
|
@ -147,7 +155,7 @@ private:
|
|||
class VAListStruct : public VAList
|
||||
{
|
||||
public:
|
||||
explicit VAListStruct(u32 address);
|
||||
explicit VAListStruct(Core::System& system, u32 address);
|
||||
~VAListStruct() = default;
|
||||
|
||||
private:
|
||||
|
|
|
@ -173,16 +173,18 @@ void IncreaseSampleCount(const u32 amount)
|
|||
if (!IsPlaying())
|
||||
return;
|
||||
|
||||
auto& state = Core::System::GetInstance().GetAudioInterfaceState().GetData();
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& state = system.GetAudioInterfaceState().GetData();
|
||||
|
||||
const u32 old_sample_counter = state.sample_counter + 1;
|
||||
state.sample_counter += amount;
|
||||
|
||||
if ((state.interrupt_timing - old_sample_counter) <= (state.sample_counter - old_sample_counter))
|
||||
{
|
||||
DEBUG_LOG_FMT(
|
||||
AUDIO_INTERFACE, "GenerateAudioInterrupt {:08x}:{:08x} at PC {:08x} control.AIINTVLD={}",
|
||||
state.sample_counter, state.interrupt_timing, PowerPC::ppcState.pc, state.control.AIINTVLD);
|
||||
DEBUG_LOG_FMT(AUDIO_INTERFACE,
|
||||
"GenerateAudioInterrupt {:08x}:{:08x} at PC {:08x} control.AIINTVLD={}",
|
||||
state.sample_counter, state.interrupt_timing, system.GetPPCState().pc,
|
||||
state.control.AIINTVLD);
|
||||
GenerateAudioInterrupt();
|
||||
}
|
||||
}
|
||||
|
@ -382,7 +384,7 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
|
|||
auto& core_timing = system.GetCoreTiming();
|
||||
auto& state = system.GetAudioInterfaceState().GetData();
|
||||
DEBUG_LOG_FMT(AUDIO_INTERFACE, "AI_INTERRUPT_TIMING={:08x} at PC: {:08x}", val,
|
||||
PowerPC::ppcState.pc);
|
||||
system.GetPPCState().pc);
|
||||
state.interrupt_timing = val;
|
||||
core_timing.RemoveEvent(state.event_type_ai);
|
||||
core_timing.ScheduleEvent(GetAIPeriod(), state.event_type_ai);
|
||||
|
|
|
@ -88,6 +88,8 @@ static void ExecutePendingJobs(std::unique_lock<std::mutex>& state_lock)
|
|||
|
||||
void Run()
|
||||
{
|
||||
auto& system = Core::System::GetInstance();
|
||||
|
||||
// Updating the host CPU's rounding mode must be done on the CPU thread.
|
||||
// We can't rely on PowerPC::Init doing it, since it's called from EmuThread.
|
||||
PowerPC::RoundingModeUpdated();
|
||||
|
@ -111,7 +113,8 @@ void Run()
|
|||
// If watchpoints are enabled, any instruction could be a breakpoint.
|
||||
if (PowerPC::GetMode() != PowerPC::CoreMode::Interpreter)
|
||||
{
|
||||
if (PowerPC::breakpoints.IsAddressBreakPoint(PC) || PowerPC::memchecks.HasAny())
|
||||
if (PowerPC::breakpoints.IsAddressBreakPoint(system.GetPPCState().pc) ||
|
||||
PowerPC::memchecks.HasAny())
|
||||
{
|
||||
s_state = State::Stepping;
|
||||
PowerPC::CoreMode old_mode = PowerPC::GetMode();
|
||||
|
|
|
@ -69,7 +69,7 @@ const State* GetStatePtr();
|
|||
|
||||
// Locks the CPU Thread (waiting for it to become idle).
|
||||
// While this lock is held, the CPU Thread will not perform any action so it is safe to access
|
||||
// PowerPC::ppcState, CoreTiming, etc. without racing the CPU Thread.
|
||||
// PowerPC, CoreTiming, etc. without racing the CPU Thread.
|
||||
// Cannot be used recursively. Must be paired as PauseAndLock(true)/PauseAndLock(false).
|
||||
// Return value for do_lock == true is whether the state was State::Running or not.
|
||||
// Return value for do_lock == false is whether the state was changed *to* State::Running or not.
|
||||
|
|
|
@ -572,7 +572,8 @@ static void Do_ARAM_DMA()
|
|||
{
|
||||
// ARAM -> MRAM
|
||||
DEBUG_LOG_FMT(DSPINTERFACE, "DMA {:08x} bytes from ARAM {:08x} to MRAM {:08x} PC: {:08x}",
|
||||
state.aram_dma.Cnt.count, state.aram_dma.ARAddr, state.aram_dma.MMAddr, PC);
|
||||
state.aram_dma.Cnt.count, state.aram_dma.ARAddr, state.aram_dma.MMAddr,
|
||||
system.GetPPCState().pc);
|
||||
|
||||
// Outgoing data from ARAM is mirrored every 64MB (verified on real HW)
|
||||
state.aram_dma.ARAddr &= 0x3ffffff;
|
||||
|
@ -620,7 +621,8 @@ static void Do_ARAM_DMA()
|
|||
{
|
||||
// MRAM -> ARAM
|
||||
DEBUG_LOG_FMT(DSPINTERFACE, "DMA {:08x} bytes from MRAM {:08x} to ARAM {:08x} PC: {:08x}",
|
||||
state.aram_dma.Cnt.count, state.aram_dma.MMAddr, state.aram_dma.ARAddr, PC);
|
||||
state.aram_dma.Cnt.count, state.aram_dma.MMAddr, state.aram_dma.ARAddr,
|
||||
system.GetPPCState().pc);
|
||||
|
||||
// Incoming data into ARAM is mirrored every 64MB (verified on real HW)
|
||||
state.aram_dma.ARAddr &= 0x3ffffff;
|
||||
|
|
|
@ -35,12 +35,12 @@ GPFifoManager::GPFifoManager(Core::System& system) : m_system(system)
|
|||
|
||||
size_t GPFifoManager::GetGatherPipeCount()
|
||||
{
|
||||
return PowerPC::ppcState.gather_pipe_ptr - m_gather_pipe;
|
||||
return m_system.GetPPCState().gather_pipe_ptr - m_gather_pipe;
|
||||
}
|
||||
|
||||
void GPFifoManager::SetGatherPipeCount(size_t size)
|
||||
{
|
||||
PowerPC::ppcState.gather_pipe_ptr = m_gather_pipe + size;
|
||||
m_system.GetPPCState().gather_pipe_ptr = m_gather_pipe + size;
|
||||
}
|
||||
|
||||
void GPFifoManager::DoState(PointerWrap& p)
|
||||
|
@ -54,7 +54,7 @@ void GPFifoManager::DoState(PointerWrap& p)
|
|||
void GPFifoManager::Init()
|
||||
{
|
||||
ResetGatherPipe();
|
||||
PowerPC::ppcState.gather_pipe_base_ptr = m_gather_pipe;
|
||||
m_system.GetPPCState().gather_pipe_base_ptr = m_gather_pipe;
|
||||
memset(m_gather_pipe, 0, sizeof(m_gather_pipe));
|
||||
}
|
||||
|
||||
|
@ -162,29 +162,33 @@ void GPFifoManager::Write64(const u64 value)
|
|||
|
||||
void GPFifoManager::FastWrite8(const u8 value)
|
||||
{
|
||||
*PowerPC::ppcState.gather_pipe_ptr = value;
|
||||
PowerPC::ppcState.gather_pipe_ptr += sizeof(u8);
|
||||
auto& ppc_state = m_system.GetPPCState();
|
||||
*ppc_state.gather_pipe_ptr = value;
|
||||
ppc_state.gather_pipe_ptr += sizeof(u8);
|
||||
}
|
||||
|
||||
void GPFifoManager::FastWrite16(u16 value)
|
||||
{
|
||||
value = Common::swap16(value);
|
||||
std::memcpy(PowerPC::ppcState.gather_pipe_ptr, &value, sizeof(u16));
|
||||
PowerPC::ppcState.gather_pipe_ptr += sizeof(u16);
|
||||
auto& ppc_state = m_system.GetPPCState();
|
||||
std::memcpy(ppc_state.gather_pipe_ptr, &value, sizeof(u16));
|
||||
ppc_state.gather_pipe_ptr += sizeof(u16);
|
||||
}
|
||||
|
||||
void GPFifoManager::FastWrite32(u32 value)
|
||||
{
|
||||
value = Common::swap32(value);
|
||||
std::memcpy(PowerPC::ppcState.gather_pipe_ptr, &value, sizeof(u32));
|
||||
PowerPC::ppcState.gather_pipe_ptr += sizeof(u32);
|
||||
auto& ppc_state = m_system.GetPPCState();
|
||||
std::memcpy(ppc_state.gather_pipe_ptr, &value, sizeof(u32));
|
||||
ppc_state.gather_pipe_ptr += sizeof(u32);
|
||||
}
|
||||
|
||||
void GPFifoManager::FastWrite64(u64 value)
|
||||
{
|
||||
value = Common::swap64(value);
|
||||
std::memcpy(PowerPC::ppcState.gather_pipe_ptr, &value, sizeof(u64));
|
||||
PowerPC::ppcState.gather_pipe_ptr += sizeof(u64);
|
||||
auto& ppc_state = m_system.GetPPCState();
|
||||
std::memcpy(ppc_state.gather_pipe_ptr, &value, sizeof(u64));
|
||||
ppc_state.gather_pipe_ptr += sizeof(u64);
|
||||
}
|
||||
|
||||
void UpdateGatherPipe(GPFifoManager& gpfifo)
|
||||
|
|
|
@ -482,7 +482,9 @@ u8* MemoryManager::GetPointer(u32 address) const
|
|||
return m_exram + (address & GetExRamMask());
|
||||
}
|
||||
|
||||
PanicAlertFmt("Unknown Pointer {:#010x} PC {:#010x} LR {:#010x}", address, PC, LR);
|
||||
auto& ppc_state = Core::System::GetInstance().GetPPCState();
|
||||
PanicAlertFmt("Unknown Pointer {:#010x} PC {:#010x} LR {:#010x}", address, ppc_state.pc,
|
||||
LR(ppc_state));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
|
@ -65,14 +65,14 @@ void ProcessorInterfaceManager::RegisterMMIO(MMIO::Mapping* mmio, u32 base)
|
|||
MMIO::ComplexWrite<u32>([](Core::System& system, u32, u32 val) {
|
||||
auto& processor_interface = system.GetProcessorInterface();
|
||||
processor_interface.m_interrupt_cause &= ~val;
|
||||
processor_interface.UpdateException();
|
||||
processor_interface.UpdateException(system);
|
||||
}));
|
||||
|
||||
mmio->Register(base | PI_INTERRUPT_MASK, MMIO::DirectRead<u32>(&m_interrupt_mask),
|
||||
MMIO::ComplexWrite<u32>([](Core::System& system, u32, u32 val) {
|
||||
auto& processor_interface = system.GetProcessorInterface();
|
||||
processor_interface.m_interrupt_mask = val;
|
||||
processor_interface.UpdateException();
|
||||
processor_interface.UpdateException(system);
|
||||
}));
|
||||
|
||||
mmio->Register(base | PI_FIFO_BASE, MMIO::DirectRead<u32>(&m_fifo_cpu_base),
|
||||
|
@ -137,12 +137,13 @@ void ProcessorInterfaceManager::RegisterMMIO(MMIO::Mapping* mmio, u32 base)
|
|||
}
|
||||
}
|
||||
|
||||
void ProcessorInterfaceManager::UpdateException()
|
||||
void ProcessorInterfaceManager::UpdateException(Core::System& system)
|
||||
{
|
||||
auto& ppc_state = system.GetPPCState();
|
||||
if ((m_interrupt_cause & m_interrupt_mask) != 0)
|
||||
PowerPC::ppcState.Exceptions |= EXCEPTION_EXTERNAL_INT;
|
||||
ppc_state.Exceptions |= EXCEPTION_EXTERNAL_INT;
|
||||
else
|
||||
PowerPC::ppcState.Exceptions &= ~EXCEPTION_EXTERNAL_INT;
|
||||
ppc_state.Exceptions &= ~EXCEPTION_EXTERNAL_INT;
|
||||
}
|
||||
|
||||
static const char* Debug_GetInterruptName(u32 cause_mask)
|
||||
|
@ -208,7 +209,7 @@ void ProcessorInterfaceManager::SetInterrupt(u32 cause_mask, bool set)
|
|||
m_interrupt_cause &= ~cause_mask; // is there any reason to have this possibility?
|
||||
// F|RES: i think the hw devices reset the interrupt in the PI to 0
|
||||
// if the interrupt cause is eliminated. that isn't done by software (afaik)
|
||||
UpdateException();
|
||||
UpdateException(Core::System::GetInstance());
|
||||
}
|
||||
|
||||
void ProcessorInterfaceManager::SetResetButton(bool set)
|
||||
|
|
|
@ -87,7 +87,7 @@ public:
|
|||
|
||||
private:
|
||||
// Let the PPC know that an external exception is set/cleared
|
||||
void UpdateException();
|
||||
void UpdateException(Core::System& system);
|
||||
|
||||
void SetResetButton(bool set);
|
||||
|
||||
|
|
|
@ -153,8 +153,9 @@ void VICallback(Core::System& system, u64 userdata, s64 cyclesLate)
|
|||
|
||||
void DecrementerCallback(Core::System& system, u64 userdata, s64 cyclesLate)
|
||||
{
|
||||
PowerPC::ppcState.spr[SPR_DEC] = 0xFFFFFFFF;
|
||||
PowerPC::ppcState.Exceptions |= EXCEPTION_DECREMENTER;
|
||||
auto& ppc_state = system.GetPPCState();
|
||||
ppc_state.spr[SPR_DEC] = 0xFFFFFFFF;
|
||||
ppc_state.Exceptions |= EXCEPTION_DECREMENTER;
|
||||
}
|
||||
|
||||
void PatchEngineCallback(Core::System& system, u64 userdata, s64 cycles_late)
|
||||
|
@ -192,8 +193,9 @@ void DecrementerSet()
|
|||
{
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& core_timing = system.GetCoreTiming();
|
||||
auto& ppc_state = system.GetPPCState();
|
||||
|
||||
u32 decValue = PowerPC::ppcState.spr[SPR_DEC];
|
||||
u32 decValue = ppc_state.spr[SPR_DEC];
|
||||
|
||||
core_timing.RemoveEvent(et_Dec);
|
||||
if ((decValue & 0x80000000) == 0)
|
||||
|
|
|
@ -200,7 +200,7 @@ static void ResetAndPausePPC()
|
|||
auto& memory = system.GetMemory();
|
||||
memory.Write_U32(0x48000000, 0x00000000); // b 0x0
|
||||
PowerPC::Reset();
|
||||
PC = 0;
|
||||
system.GetPPCState().pc = 0;
|
||||
}
|
||||
|
||||
static void ReleasePPC()
|
||||
|
@ -212,7 +212,7 @@ static void ReleasePPC()
|
|||
// NAND titles start with address translation off at 0x3400 (via the PPC bootstub)
|
||||
// The state of other CPU registers (like the BAT registers) doesn't matter much
|
||||
// because the realmode code at 0x3400 initializes everything itself anyway.
|
||||
PC = 0x3400;
|
||||
system.GetPPCState().pc = 0x3400;
|
||||
}
|
||||
|
||||
static void ReleasePPCAncast()
|
||||
|
@ -223,7 +223,7 @@ static void ReleasePPCAncast()
|
|||
// On a real console the Espresso verifies and decrypts the Ancast image,
|
||||
// then jumps to the decrypted ancast body.
|
||||
// The Ancast loader already did this, so just jump to the decrypted body.
|
||||
PC = ESPRESSO_ANCAST_LOCATION_VIRT + sizeof(EspressoAncastHeader);
|
||||
system.GetPPCState().pc = ESPRESSO_ANCAST_LOCATION_VIRT + sizeof(EspressoAncastHeader);
|
||||
}
|
||||
|
||||
void RAMOverrideForIOSMemoryValues(MemorySetupType setup_type)
|
||||
|
|
|
@ -72,14 +72,15 @@ bool Load()
|
|||
if (g_symbolDB.LoadMap(File::GetUserPath(D_MAPS_IDX) + "mios-ipl.map"))
|
||||
{
|
||||
::HLE::Clear();
|
||||
::HLE::PatchFunctions();
|
||||
::HLE::PatchFunctions(system);
|
||||
Host_NotifyMapLoaded();
|
||||
}
|
||||
|
||||
auto& ppc_state = system.GetPPCState();
|
||||
const PowerPC::CoreMode core_mode = PowerPC::GetMode();
|
||||
PowerPC::SetMode(PowerPC::CoreMode::Interpreter);
|
||||
MSR.Hex = 0;
|
||||
PC = 0x3400;
|
||||
ppc_state.msr.Hex = 0;
|
||||
ppc_state.pc = 0x3400;
|
||||
NOTICE_LOG_FMT(IOS, "Loaded MIOS and bootstrapped PPC.");
|
||||
|
||||
// IOS writes 0 to 0x30f8 before bootstrapping the PPC. Once started, the IPL eventually writes
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "Core/GeckoCodeConfig.h"
|
||||
#include "Core/PowerPC/MMU.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
#include "Core/System.h"
|
||||
|
||||
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.
|
||||
static bool IsStackSane()
|
||||
{
|
||||
DEBUG_ASSERT(MSR.DR && MSR.IR);
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& ppc_state = system.GetPPCState();
|
||||
|
||||
DEBUG_ASSERT(ppc_state.msr.DR && ppc_state.msr.IR);
|
||||
|
||||
// Check the stack pointer
|
||||
u32 SP = GPR(1);
|
||||
u32 SP = ppc_state.gpr[1];
|
||||
if (!PowerPC::HostIsRAMAddress(SP))
|
||||
return false;
|
||||
|
||||
|
@ -311,16 +315,19 @@ void RemoveMemoryPatch(std::size_t index)
|
|||
|
||||
bool ApplyFramePatches()
|
||||
{
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& ppc_state = system.GetPPCState();
|
||||
|
||||
// Because we're using the VI Interrupt to time this instead of patching the game with a
|
||||
// callback hook we can end up catching the game in an exception vector.
|
||||
// We deal with this by returning false so that SystemTimers will reschedule us in a few cycles
|
||||
// where we can try again after the CPU hopefully returns back to the normal instruction flow.
|
||||
if (!MSR.DR || !MSR.IR || !IsStackSane())
|
||||
if (!ppc_state.msr.DR || !ppc_state.msr.IR || !IsStackSane())
|
||||
{
|
||||
DEBUG_LOG_FMT(ACTIONREPLAY,
|
||||
"Need to retry later. CPU configuration is currently incorrect. PC = {:#010x}, "
|
||||
"MSR = {:#010x}",
|
||||
PC, MSR.Hex);
|
||||
ppc_state.pc, ppc_state.msr.Hex);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -81,7 +81,7 @@ void CachedInterpreter::ExecuteOneBlock()
|
|||
const u8* normal_entry = m_block_cache.Dispatch();
|
||||
if (!normal_entry)
|
||||
{
|
||||
Jit(PC);
|
||||
Jit(PowerPC::ppcState.pc);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -136,35 +136,35 @@ void CachedInterpreter::SingleStep()
|
|||
|
||||
static void EndBlock(UGeckoInstruction data)
|
||||
{
|
||||
PC = NPC;
|
||||
PowerPC::ppcState.pc = PowerPC::ppcState.npc;
|
||||
PowerPC::ppcState.downcount -= data.hex;
|
||||
PowerPC::UpdatePerformanceMonitor(data.hex, 0, 0);
|
||||
PowerPC::UpdatePerformanceMonitor(data.hex, 0, 0, PowerPC::ppcState);
|
||||
}
|
||||
|
||||
static void UpdateNumLoadStoreInstructions(UGeckoInstruction data)
|
||||
{
|
||||
PowerPC::UpdatePerformanceMonitor(0, data.hex, 0);
|
||||
PowerPC::UpdatePerformanceMonitor(0, data.hex, 0, PowerPC::ppcState);
|
||||
}
|
||||
|
||||
static void UpdateNumFloatingPointInstructions(UGeckoInstruction data)
|
||||
{
|
||||
PowerPC::UpdatePerformanceMonitor(0, 0, data.hex);
|
||||
PowerPC::UpdatePerformanceMonitor(0, 0, data.hex, PowerPC::ppcState);
|
||||
}
|
||||
|
||||
static void WritePC(UGeckoInstruction data)
|
||||
{
|
||||
PC = data.hex;
|
||||
NPC = data.hex + 4;
|
||||
PowerPC::ppcState.pc = data.hex;
|
||||
PowerPC::ppcState.npc = data.hex + 4;
|
||||
}
|
||||
|
||||
static void WriteBrokenBlockNPC(UGeckoInstruction data)
|
||||
{
|
||||
NPC = data.hex;
|
||||
PowerPC::ppcState.npc = data.hex;
|
||||
}
|
||||
|
||||
static bool CheckFPU(u32 data)
|
||||
{
|
||||
if (!MSR.FP)
|
||||
if (!PowerPC::ppcState.msr.FP)
|
||||
{
|
||||
PowerPC::ppcState.Exceptions |= EXCEPTION_FPU_UNAVAILABLE;
|
||||
PowerPC::CheckExceptions();
|
||||
|
@ -239,20 +239,21 @@ void CachedInterpreter::Jit(u32 address)
|
|||
ClearCache();
|
||||
}
|
||||
|
||||
const u32 nextPC = analyzer.Analyze(PC, &code_block, &m_code_buffer, m_code_buffer.size());
|
||||
const u32 nextPC =
|
||||
analyzer.Analyze(PowerPC::ppcState.pc, &code_block, &m_code_buffer, m_code_buffer.size());
|
||||
if (code_block.m_memory_exception)
|
||||
{
|
||||
// Address of instruction could not be translated
|
||||
NPC = nextPC;
|
||||
PowerPC::ppcState.npc = nextPC;
|
||||
PowerPC::ppcState.Exceptions |= EXCEPTION_ISI;
|
||||
PowerPC::CheckExceptions();
|
||||
WARN_LOG_FMT(POWERPC, "ISI exception at {:#010x}", nextPC);
|
||||
return;
|
||||
}
|
||||
|
||||
JitBlock* b = m_block_cache.AllocateBlock(PC);
|
||||
JitBlock* b = m_block_cache.AllocateBlock(PowerPC::ppcState.pc);
|
||||
|
||||
js.blockStart = PC;
|
||||
js.blockStart = PowerPC::ppcState.pc;
|
||||
js.firstFPInstructionFound = false;
|
||||
js.fifoBytesSinceCheck = 0;
|
||||
js.downcountAmount = 0;
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "Core/Debugger/Debugger_SymbolMap.h"
|
||||
#include "Core/PowerPC/MMU.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
#include "Core/System.h"
|
||||
|
||||
template <typename T>
|
||||
static T HostRead(u32 address);
|
||||
|
@ -109,7 +110,7 @@ static double CallstackFunc(expr_func* f, vec_expr_t* args, void* c)
|
|||
return 0;
|
||||
|
||||
std::vector<Dolphin_Debugger::CallstackEntry> stack;
|
||||
bool success = Dolphin_Debugger::GetCallstack(stack);
|
||||
bool success = Dolphin_Debugger::GetCallstack(Core::System::GetInstance(), stack);
|
||||
if (!success)
|
||||
return 0;
|
||||
|
||||
|
@ -246,25 +247,25 @@ void Expression::SynchronizeBindings(SynchronizeDirection dir) const
|
|||
break;
|
||||
case VarBindingType::GPR:
|
||||
if (dir == SynchronizeDirection::From)
|
||||
v->value = static_cast<double>(GPR(bind->index));
|
||||
v->value = static_cast<double>(PowerPC::ppcState.gpr[bind->index]);
|
||||
else
|
||||
GPR(bind->index) = static_cast<u32>(static_cast<s64>(v->value));
|
||||
PowerPC::ppcState.gpr[bind->index] = static_cast<u32>(static_cast<s64>(v->value));
|
||||
break;
|
||||
case VarBindingType::FPR:
|
||||
if (dir == SynchronizeDirection::From)
|
||||
v->value = rPS(bind->index).PS0AsDouble();
|
||||
v->value = PowerPC::ppcState.ps[bind->index].PS0AsDouble();
|
||||
else
|
||||
rPS(bind->index).SetPS0(v->value);
|
||||
PowerPC::ppcState.ps[bind->index].SetPS0(v->value);
|
||||
break;
|
||||
case VarBindingType::SPR:
|
||||
if (dir == SynchronizeDirection::From)
|
||||
v->value = static_cast<double>(rSPR(bind->index));
|
||||
v->value = static_cast<double>(PowerPC::ppcState.spr[bind->index]);
|
||||
else
|
||||
rSPR(bind->index) = static_cast<u32>(static_cast<s64>(v->value));
|
||||
PowerPC::ppcState.spr[bind->index] = static_cast<u32>(static_cast<s64>(v->value));
|
||||
break;
|
||||
case VarBindingType::PCtr:
|
||||
if (dir == SynchronizeDirection::From)
|
||||
v->value = static_cast<double>(PC);
|
||||
v->value = static_cast<double>(PowerPC::ppcState.pc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -397,6 +397,9 @@ static u64 re64hex(u8* p)
|
|||
|
||||
static void ReadRegister()
|
||||
{
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& ppc_state = system.GetPPCState();
|
||||
|
||||
static u8 reply[64];
|
||||
u32 id;
|
||||
|
||||
|
@ -410,161 +413,161 @@ static void ReadRegister()
|
|||
|
||||
if (id < 32)
|
||||
{
|
||||
wbe32hex(reply, GPR(id));
|
||||
wbe32hex(reply, ppc_state.gpr[id]);
|
||||
}
|
||||
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)
|
||||
{
|
||||
wbe32hex(reply, PowerPC::ppcState.sr[id - 71]);
|
||||
wbe32hex(reply, ppc_state.sr[id - 71]);
|
||||
}
|
||||
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
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case 64:
|
||||
wbe32hex(reply, PC);
|
||||
wbe32hex(reply, ppc_state.pc);
|
||||
break;
|
||||
case 65:
|
||||
wbe32hex(reply, MSR.Hex);
|
||||
wbe32hex(reply, ppc_state.msr.Hex);
|
||||
break;
|
||||
case 66:
|
||||
wbe32hex(reply, PowerPC::ppcState.cr.Get());
|
||||
wbe32hex(reply, ppc_state.cr.Get());
|
||||
break;
|
||||
case 67:
|
||||
wbe32hex(reply, LR);
|
||||
wbe32hex(reply, LR(ppc_state));
|
||||
break;
|
||||
case 68:
|
||||
wbe32hex(reply, CTR);
|
||||
wbe32hex(reply, CTR(ppc_state));
|
||||
break;
|
||||
case 69:
|
||||
wbe32hex(reply, PowerPC::ppcState.spr[SPR_XER]);
|
||||
wbe32hex(reply, ppc_state.spr[SPR_XER]);
|
||||
break;
|
||||
case 70:
|
||||
wbe32hex(reply, FPSCR.Hex);
|
||||
wbe32hex(reply, ppc_state.fpscr.Hex);
|
||||
break;
|
||||
case 87:
|
||||
wbe32hex(reply, PowerPC::ppcState.spr[SPR_PVR]);
|
||||
wbe32hex(reply, ppc_state.spr[SPR_PVR]);
|
||||
break;
|
||||
case 104:
|
||||
wbe32hex(reply, PowerPC::ppcState.spr[SPR_SDR]);
|
||||
wbe32hex(reply, ppc_state.spr[SPR_SDR]);
|
||||
break;
|
||||
case 105:
|
||||
wbe64hex(reply, PowerPC::ppcState.spr[SPR_ASR]);
|
||||
wbe64hex(reply, ppc_state.spr[SPR_ASR]);
|
||||
break;
|
||||
case 106:
|
||||
wbe32hex(reply, PowerPC::ppcState.spr[SPR_DAR]);
|
||||
wbe32hex(reply, ppc_state.spr[SPR_DAR]);
|
||||
break;
|
||||
case 107:
|
||||
wbe32hex(reply, PowerPC::ppcState.spr[SPR_DSISR]);
|
||||
wbe32hex(reply, ppc_state.spr[SPR_DSISR]);
|
||||
break;
|
||||
case 108:
|
||||
wbe32hex(reply, PowerPC::ppcState.spr[SPR_SPRG0]);
|
||||
wbe32hex(reply, ppc_state.spr[SPR_SPRG0]);
|
||||
break;
|
||||
case 109:
|
||||
wbe32hex(reply, PowerPC::ppcState.spr[SPR_SPRG1]);
|
||||
wbe32hex(reply, ppc_state.spr[SPR_SPRG1]);
|
||||
break;
|
||||
case 110:
|
||||
wbe32hex(reply, PowerPC::ppcState.spr[SPR_SPRG2]);
|
||||
wbe32hex(reply, ppc_state.spr[SPR_SPRG2]);
|
||||
break;
|
||||
case 111:
|
||||
wbe32hex(reply, PowerPC::ppcState.spr[SPR_SPRG3]);
|
||||
wbe32hex(reply, ppc_state.spr[SPR_SPRG3]);
|
||||
break;
|
||||
case 112:
|
||||
wbe32hex(reply, PowerPC::ppcState.spr[SPR_SRR0]);
|
||||
wbe32hex(reply, ppc_state.spr[SPR_SRR0]);
|
||||
break;
|
||||
case 113:
|
||||
wbe32hex(reply, PowerPC::ppcState.spr[SPR_SRR1]);
|
||||
wbe32hex(reply, ppc_state.spr[SPR_SRR1]);
|
||||
break;
|
||||
case 114:
|
||||
wbe32hex(reply, PowerPC::ppcState.spr[SPR_TL]);
|
||||
wbe32hex(reply, ppc_state.spr[SPR_TL]);
|
||||
break;
|
||||
case 115:
|
||||
wbe32hex(reply, PowerPC::ppcState.spr[SPR_TU]);
|
||||
wbe32hex(reply, ppc_state.spr[SPR_TU]);
|
||||
break;
|
||||
case 116:
|
||||
wbe32hex(reply, PowerPC::ppcState.spr[SPR_DEC]);
|
||||
wbe32hex(reply, ppc_state.spr[SPR_DEC]);
|
||||
break;
|
||||
case 117:
|
||||
wbe32hex(reply, PowerPC::ppcState.spr[SPR_DABR]);
|
||||
wbe32hex(reply, ppc_state.spr[SPR_DABR]);
|
||||
break;
|
||||
case 118:
|
||||
wbe32hex(reply, PowerPC::ppcState.spr[SPR_EAR]);
|
||||
wbe32hex(reply, ppc_state.spr[SPR_EAR]);
|
||||
break;
|
||||
case 119:
|
||||
wbe32hex(reply, PowerPC::ppcState.spr[SPR_HID0]);
|
||||
wbe32hex(reply, ppc_state.spr[SPR_HID0]);
|
||||
break;
|
||||
case 120:
|
||||
wbe32hex(reply, PowerPC::ppcState.spr[SPR_HID1]);
|
||||
wbe32hex(reply, ppc_state.spr[SPR_HID1]);
|
||||
break;
|
||||
case 121:
|
||||
wbe32hex(reply, PowerPC::ppcState.spr[SPR_IABR]);
|
||||
wbe32hex(reply, ppc_state.spr[SPR_IABR]);
|
||||
break;
|
||||
case 122:
|
||||
wbe32hex(reply, PowerPC::ppcState.spr[SPR_DABR]);
|
||||
wbe32hex(reply, ppc_state.spr[SPR_DABR]);
|
||||
break;
|
||||
case 124:
|
||||
wbe32hex(reply, PowerPC::ppcState.spr[SPR_UMMCR0]);
|
||||
wbe32hex(reply, ppc_state.spr[SPR_UMMCR0]);
|
||||
break;
|
||||
case 125:
|
||||
wbe32hex(reply, PowerPC::ppcState.spr[SPR_UPMC1]);
|
||||
wbe32hex(reply, ppc_state.spr[SPR_UPMC1]);
|
||||
break;
|
||||
case 126:
|
||||
wbe32hex(reply, PowerPC::ppcState.spr[SPR_UPMC2]);
|
||||
wbe32hex(reply, ppc_state.spr[SPR_UPMC2]);
|
||||
break;
|
||||
case 127:
|
||||
wbe32hex(reply, PowerPC::ppcState.spr[SPR_USIA]);
|
||||
wbe32hex(reply, ppc_state.spr[SPR_USIA]);
|
||||
break;
|
||||
case 128:
|
||||
wbe32hex(reply, PowerPC::ppcState.spr[SPR_UMMCR1]);
|
||||
wbe32hex(reply, ppc_state.spr[SPR_UMMCR1]);
|
||||
break;
|
||||
case 129:
|
||||
wbe32hex(reply, PowerPC::ppcState.spr[SPR_UPMC3]);
|
||||
wbe32hex(reply, ppc_state.spr[SPR_UPMC3]);
|
||||
break;
|
||||
case 130:
|
||||
wbe32hex(reply, PowerPC::ppcState.spr[SPR_UPMC4]);
|
||||
wbe32hex(reply, ppc_state.spr[SPR_UPMC4]);
|
||||
break;
|
||||
case 131:
|
||||
wbe32hex(reply, PowerPC::ppcState.spr[SPR_MMCR0]);
|
||||
wbe32hex(reply, ppc_state.spr[SPR_MMCR0]);
|
||||
break;
|
||||
case 132:
|
||||
wbe32hex(reply, PowerPC::ppcState.spr[SPR_PMC1]);
|
||||
wbe32hex(reply, ppc_state.spr[SPR_PMC1]);
|
||||
break;
|
||||
case 133:
|
||||
wbe32hex(reply, PowerPC::ppcState.spr[SPR_PMC2]);
|
||||
wbe32hex(reply, ppc_state.spr[SPR_PMC2]);
|
||||
break;
|
||||
case 134:
|
||||
wbe32hex(reply, PowerPC::ppcState.spr[SPR_SIA]);
|
||||
wbe32hex(reply, ppc_state.spr[SPR_SIA]);
|
||||
break;
|
||||
case 135:
|
||||
wbe32hex(reply, PowerPC::ppcState.spr[SPR_MMCR1]);
|
||||
wbe32hex(reply, ppc_state.spr[SPR_MMCR1]);
|
||||
break;
|
||||
case 136:
|
||||
wbe32hex(reply, PowerPC::ppcState.spr[SPR_PMC3]);
|
||||
wbe32hex(reply, ppc_state.spr[SPR_PMC3]);
|
||||
break;
|
||||
case 137:
|
||||
wbe32hex(reply, PowerPC::ppcState.spr[SPR_PMC4]);
|
||||
wbe32hex(reply, ppc_state.spr[SPR_PMC4]);
|
||||
break;
|
||||
case 138:
|
||||
wbe32hex(reply, PowerPC::ppcState.spr[SPR_L2CR]);
|
||||
wbe32hex(reply, ppc_state.spr[SPR_L2CR]);
|
||||
break;
|
||||
case 139:
|
||||
wbe32hex(reply, PowerPC::ppcState.spr[SPR_ICTC]);
|
||||
wbe32hex(reply, ppc_state.spr[SPR_ICTC]);
|
||||
break;
|
||||
case 140:
|
||||
wbe32hex(reply, PowerPC::ppcState.spr[SPR_THRM1]);
|
||||
wbe32hex(reply, ppc_state.spr[SPR_THRM1]);
|
||||
break;
|
||||
case 141:
|
||||
wbe32hex(reply, PowerPC::ppcState.spr[SPR_THRM2]);
|
||||
wbe32hex(reply, ppc_state.spr[SPR_THRM2]);
|
||||
break;
|
||||
case 142:
|
||||
wbe32hex(reply, PowerPC::ppcState.spr[SPR_THRM3]);
|
||||
wbe32hex(reply, ppc_state.spr[SPR_THRM3]);
|
||||
break;
|
||||
default:
|
||||
return SendReply("E01");
|
||||
|
@ -577,6 +580,9 @@ static void ReadRegister()
|
|||
|
||||
static void ReadRegisters()
|
||||
{
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& ppc_state = system.GetPPCState();
|
||||
|
||||
static u8 bfr[GDB_BFR_MAX - 4];
|
||||
u8* bufptr = bfr;
|
||||
u32 i;
|
||||
|
@ -585,7 +591,7 @@ static void ReadRegisters()
|
|||
|
||||
for (i = 0; i < 32; i++)
|
||||
{
|
||||
wbe32hex(bufptr + i * 8, GPR(i));
|
||||
wbe32hex(bufptr + i * 8, ppc_state.gpr[i]);
|
||||
}
|
||||
bufptr += 32 * 8;
|
||||
|
||||
|
@ -594,12 +600,15 @@ static void ReadRegisters()
|
|||
|
||||
static void WriteRegisters()
|
||||
{
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& ppc_state = system.GetPPCState();
|
||||
|
||||
u32 i;
|
||||
u8* bufptr = s_cmd_bfr;
|
||||
|
||||
for (i = 0; i < 32; i++)
|
||||
{
|
||||
GPR(i) = re32hex(bufptr + i * 8);
|
||||
ppc_state.gpr[i] = re32hex(bufptr + i * 8);
|
||||
}
|
||||
bufptr += 32 * 8;
|
||||
|
||||
|
@ -608,6 +617,9 @@ static void WriteRegisters()
|
|||
|
||||
static void WriteRegister()
|
||||
{
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& ppc_state = system.GetPPCState();
|
||||
|
||||
u32 id;
|
||||
|
||||
u8* bufptr = s_cmd_bfr + 3;
|
||||
|
@ -622,161 +634,161 @@ static void WriteRegister()
|
|||
|
||||
if (id < 32)
|
||||
{
|
||||
GPR(id) = re32hex(bufptr);
|
||||
ppc_state.gpr[id] = re32hex(bufptr);
|
||||
}
|
||||
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)
|
||||
{
|
||||
PowerPC::ppcState.sr[id - 71] = re32hex(bufptr);
|
||||
ppc_state.sr[id - 71] = re32hex(bufptr);
|
||||
}
|
||||
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
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case 64:
|
||||
PC = re32hex(bufptr);
|
||||
ppc_state.pc = re32hex(bufptr);
|
||||
break;
|
||||
case 65:
|
||||
MSR.Hex = re32hex(bufptr);
|
||||
ppc_state.msr.Hex = re32hex(bufptr);
|
||||
break;
|
||||
case 66:
|
||||
PowerPC::ppcState.cr.Set(re32hex(bufptr));
|
||||
ppc_state.cr.Set(re32hex(bufptr));
|
||||
break;
|
||||
case 67:
|
||||
LR = re32hex(bufptr);
|
||||
LR(ppc_state) = re32hex(bufptr);
|
||||
break;
|
||||
case 68:
|
||||
CTR = re32hex(bufptr);
|
||||
CTR(ppc_state) = re32hex(bufptr);
|
||||
break;
|
||||
case 69:
|
||||
PowerPC::ppcState.spr[SPR_XER] = re32hex(bufptr);
|
||||
ppc_state.spr[SPR_XER] = re32hex(bufptr);
|
||||
break;
|
||||
case 70:
|
||||
FPSCR.Hex = re32hex(bufptr);
|
||||
ppc_state.fpscr.Hex = re32hex(bufptr);
|
||||
break;
|
||||
case 87:
|
||||
PowerPC::ppcState.spr[SPR_PVR] = re32hex(bufptr);
|
||||
ppc_state.spr[SPR_PVR] = re32hex(bufptr);
|
||||
break;
|
||||
case 104:
|
||||
PowerPC::ppcState.spr[SPR_SDR] = re32hex(bufptr);
|
||||
ppc_state.spr[SPR_SDR] = re32hex(bufptr);
|
||||
break;
|
||||
case 105:
|
||||
PowerPC::ppcState.spr[SPR_ASR] = re64hex(bufptr);
|
||||
ppc_state.spr[SPR_ASR] = re64hex(bufptr);
|
||||
break;
|
||||
case 106:
|
||||
PowerPC::ppcState.spr[SPR_DAR] = re32hex(bufptr);
|
||||
ppc_state.spr[SPR_DAR] = re32hex(bufptr);
|
||||
break;
|
||||
case 107:
|
||||
PowerPC::ppcState.spr[SPR_DSISR] = re32hex(bufptr);
|
||||
ppc_state.spr[SPR_DSISR] = re32hex(bufptr);
|
||||
break;
|
||||
case 108:
|
||||
PowerPC::ppcState.spr[SPR_SPRG0] = re32hex(bufptr);
|
||||
ppc_state.spr[SPR_SPRG0] = re32hex(bufptr);
|
||||
break;
|
||||
case 109:
|
||||
PowerPC::ppcState.spr[SPR_SPRG1] = re32hex(bufptr);
|
||||
ppc_state.spr[SPR_SPRG1] = re32hex(bufptr);
|
||||
break;
|
||||
case 110:
|
||||
PowerPC::ppcState.spr[SPR_SPRG2] = re32hex(bufptr);
|
||||
ppc_state.spr[SPR_SPRG2] = re32hex(bufptr);
|
||||
break;
|
||||
case 111:
|
||||
PowerPC::ppcState.spr[SPR_SPRG3] = re32hex(bufptr);
|
||||
ppc_state.spr[SPR_SPRG3] = re32hex(bufptr);
|
||||
break;
|
||||
case 112:
|
||||
PowerPC::ppcState.spr[SPR_SRR0] = re32hex(bufptr);
|
||||
ppc_state.spr[SPR_SRR0] = re32hex(bufptr);
|
||||
break;
|
||||
case 113:
|
||||
PowerPC::ppcState.spr[SPR_SRR1] = re32hex(bufptr);
|
||||
ppc_state.spr[SPR_SRR1] = re32hex(bufptr);
|
||||
break;
|
||||
case 114:
|
||||
PowerPC::ppcState.spr[SPR_TL] = re32hex(bufptr);
|
||||
ppc_state.spr[SPR_TL] = re32hex(bufptr);
|
||||
break;
|
||||
case 115:
|
||||
PowerPC::ppcState.spr[SPR_TU] = re32hex(bufptr);
|
||||
ppc_state.spr[SPR_TU] = re32hex(bufptr);
|
||||
break;
|
||||
case 116:
|
||||
PowerPC::ppcState.spr[SPR_DEC] = re32hex(bufptr);
|
||||
ppc_state.spr[SPR_DEC] = re32hex(bufptr);
|
||||
break;
|
||||
case 117:
|
||||
PowerPC::ppcState.spr[SPR_DABR] = re32hex(bufptr);
|
||||
ppc_state.spr[SPR_DABR] = re32hex(bufptr);
|
||||
break;
|
||||
case 118:
|
||||
PowerPC::ppcState.spr[SPR_EAR] = re32hex(bufptr);
|
||||
ppc_state.spr[SPR_EAR] = re32hex(bufptr);
|
||||
break;
|
||||
case 119:
|
||||
PowerPC::ppcState.spr[SPR_HID0] = re32hex(bufptr);
|
||||
ppc_state.spr[SPR_HID0] = re32hex(bufptr);
|
||||
break;
|
||||
case 120:
|
||||
PowerPC::ppcState.spr[SPR_HID1] = re32hex(bufptr);
|
||||
ppc_state.spr[SPR_HID1] = re32hex(bufptr);
|
||||
break;
|
||||
case 121:
|
||||
PowerPC::ppcState.spr[SPR_IABR] = re32hex(bufptr);
|
||||
ppc_state.spr[SPR_IABR] = re32hex(bufptr);
|
||||
break;
|
||||
case 122:
|
||||
PowerPC::ppcState.spr[SPR_DABR] = re32hex(bufptr);
|
||||
ppc_state.spr[SPR_DABR] = re32hex(bufptr);
|
||||
break;
|
||||
case 124:
|
||||
PowerPC::ppcState.spr[SPR_UMMCR0] = re32hex(bufptr);
|
||||
ppc_state.spr[SPR_UMMCR0] = re32hex(bufptr);
|
||||
break;
|
||||
case 125:
|
||||
PowerPC::ppcState.spr[SPR_UPMC1] = re32hex(bufptr);
|
||||
ppc_state.spr[SPR_UPMC1] = re32hex(bufptr);
|
||||
break;
|
||||
case 126:
|
||||
PowerPC::ppcState.spr[SPR_UPMC2] = re32hex(bufptr);
|
||||
ppc_state.spr[SPR_UPMC2] = re32hex(bufptr);
|
||||
break;
|
||||
case 127:
|
||||
PowerPC::ppcState.spr[SPR_USIA] = re32hex(bufptr);
|
||||
ppc_state.spr[SPR_USIA] = re32hex(bufptr);
|
||||
break;
|
||||
case 128:
|
||||
PowerPC::ppcState.spr[SPR_UMMCR1] = re32hex(bufptr);
|
||||
ppc_state.spr[SPR_UMMCR1] = re32hex(bufptr);
|
||||
break;
|
||||
case 129:
|
||||
PowerPC::ppcState.spr[SPR_UPMC3] = re32hex(bufptr);
|
||||
ppc_state.spr[SPR_UPMC3] = re32hex(bufptr);
|
||||
break;
|
||||
case 130:
|
||||
PowerPC::ppcState.spr[SPR_UPMC4] = re32hex(bufptr);
|
||||
ppc_state.spr[SPR_UPMC4] = re32hex(bufptr);
|
||||
break;
|
||||
case 131:
|
||||
PowerPC::ppcState.spr[SPR_MMCR0] = re32hex(bufptr);
|
||||
ppc_state.spr[SPR_MMCR0] = re32hex(bufptr);
|
||||
break;
|
||||
case 132:
|
||||
PowerPC::ppcState.spr[SPR_PMC1] = re32hex(bufptr);
|
||||
ppc_state.spr[SPR_PMC1] = re32hex(bufptr);
|
||||
break;
|
||||
case 133:
|
||||
PowerPC::ppcState.spr[SPR_PMC2] = re32hex(bufptr);
|
||||
ppc_state.spr[SPR_PMC2] = re32hex(bufptr);
|
||||
break;
|
||||
case 134:
|
||||
PowerPC::ppcState.spr[SPR_SIA] = re32hex(bufptr);
|
||||
ppc_state.spr[SPR_SIA] = re32hex(bufptr);
|
||||
break;
|
||||
case 135:
|
||||
PowerPC::ppcState.spr[SPR_MMCR1] = re32hex(bufptr);
|
||||
ppc_state.spr[SPR_MMCR1] = re32hex(bufptr);
|
||||
break;
|
||||
case 136:
|
||||
PowerPC::ppcState.spr[SPR_PMC3] = re32hex(bufptr);
|
||||
ppc_state.spr[SPR_PMC3] = re32hex(bufptr);
|
||||
break;
|
||||
case 137:
|
||||
PowerPC::ppcState.spr[SPR_PMC4] = re32hex(bufptr);
|
||||
ppc_state.spr[SPR_PMC4] = re32hex(bufptr);
|
||||
break;
|
||||
case 138:
|
||||
PowerPC::ppcState.spr[SPR_L2CR] = re32hex(bufptr);
|
||||
ppc_state.spr[SPR_L2CR] = re32hex(bufptr);
|
||||
break;
|
||||
case 139:
|
||||
PowerPC::ppcState.spr[SPR_ICTC] = re32hex(bufptr);
|
||||
ppc_state.spr[SPR_ICTC] = re32hex(bufptr);
|
||||
break;
|
||||
case 140:
|
||||
PowerPC::ppcState.spr[SPR_THRM1] = re32hex(bufptr);
|
||||
ppc_state.spr[SPR_THRM1] = re32hex(bufptr);
|
||||
break;
|
||||
case 141:
|
||||
PowerPC::ppcState.spr[SPR_THRM2] = re32hex(bufptr);
|
||||
ppc_state.spr[SPR_THRM2] = re32hex(bufptr);
|
||||
break;
|
||||
case 142:
|
||||
PowerPC::ppcState.spr[SPR_THRM3] = re32hex(bufptr);
|
||||
ppc_state.spr[SPR_THRM3] = re32hex(bufptr);
|
||||
break;
|
||||
default:
|
||||
return SendReply("E01");
|
||||
|
@ -981,10 +993,14 @@ void ProcessCommands(bool loop_until_continue)
|
|||
ReadMemory();
|
||||
break;
|
||||
case 'M':
|
||||
{
|
||||
WriteMemory();
|
||||
PowerPC::ppcState.iCache.Reset();
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& ppc_state = system.GetPPCState();
|
||||
ppc_state.iCache.Reset();
|
||||
Host_UpdateDisasmDialog();
|
||||
break;
|
||||
}
|
||||
case 's':
|
||||
Step();
|
||||
return;
|
||||
|
@ -1121,9 +1137,12 @@ bool JustConnected()
|
|||
|
||||
void SendSignal(Signal signal)
|
||||
{
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& ppc_state = system.GetPPCState();
|
||||
|
||||
char bfr[128] = {};
|
||||
fmt::format_to(bfr, "T{:02x}{:02x}:{:08x};{:02x}:{:08x};", static_cast<u8>(signal), 64, PC, 1,
|
||||
GPR(1));
|
||||
fmt::format_to(bfr, "T{:02x}{:02x}:{:08x};{:02x}:{:08x};", static_cast<u8>(signal), 64,
|
||||
ppc_state.pc, 1, ppc_state.gpr[1]);
|
||||
SendReply(bfr);
|
||||
}
|
||||
} // namespace GDBStub
|
||||
|
|
|
@ -64,16 +64,17 @@ bool IsPairedSingleInstruction(UGeckoInstruction inst)
|
|||
// but HID2.LSQE is not set.
|
||||
bool IsInvalidPairedSingleExecution(UGeckoInstruction inst)
|
||||
{
|
||||
if (!HID2.PSE && IsPairedSingleInstruction(inst))
|
||||
if (!HID2(PowerPC::ppcState).PSE && IsPairedSingleInstruction(inst))
|
||||
return true;
|
||||
|
||||
return HID2.PSE && !HID2.LSQE && IsPairedSingleQuantizedNonIndexedInstruction(inst);
|
||||
return HID2(PowerPC::ppcState).PSE && !HID2(PowerPC::ppcState).LSQE &&
|
||||
IsPairedSingleQuantizedNonIndexedInstruction(inst);
|
||||
}
|
||||
|
||||
void UpdatePC()
|
||||
{
|
||||
last_pc = PC;
|
||||
PC = NPC;
|
||||
last_pc = PowerPC::ppcState.pc;
|
||||
PowerPC::ppcState.pc = PowerPC::ppcState.npc;
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
|
@ -125,12 +126,14 @@ static void Trace(const UGeckoInstruction& inst)
|
|||
fregs += fmt::format("f{:02d}: {:08x} {:08x} ", i, ps.PS0AsU64(), ps.PS1AsU64());
|
||||
}
|
||||
|
||||
const std::string ppc_inst = Common::GekkoDisassembler::Disassemble(inst.hex, PC);
|
||||
const std::string ppc_inst =
|
||||
Common::GekkoDisassembler::Disassemble(inst.hex, PowerPC::ppcState.pc);
|
||||
DEBUG_LOG_FMT(POWERPC,
|
||||
"INTER PC: {:08x} SRR0: {:08x} SRR1: {:08x} CRval: {:016x} "
|
||||
"FPSCR: {:08x} MSR: {:08x} LR: {:08x} {} {:08x} {}",
|
||||
PC, SRR0, SRR1, PowerPC::ppcState.cr.fields[0], FPSCR.Hex, MSR.Hex,
|
||||
PowerPC::ppcState.spr[8], regs, inst.hex, ppc_inst);
|
||||
PowerPC::ppcState.pc, SRR0(PowerPC::ppcState), SRR1(PowerPC::ppcState),
|
||||
PowerPC::ppcState.cr.fields[0], PowerPC::ppcState.fpscr.Hex,
|
||||
PowerPC::ppcState.msr.Hex, PowerPC::ppcState.spr[8], regs, inst.hex, ppc_inst);
|
||||
}
|
||||
|
||||
bool Interpreter::HandleFunctionHooking(u32 address)
|
||||
|
@ -143,20 +146,25 @@ bool Interpreter::HandleFunctionHooking(u32 address)
|
|||
|
||||
int Interpreter::SingleStepInner()
|
||||
{
|
||||
if (HandleFunctionHooking(PC))
|
||||
if (HandleFunctionHooking(PowerPC::ppcState.pc))
|
||||
{
|
||||
UpdatePC();
|
||||
return PPCTables::GetOpInfo(m_prev_inst)->numCycles;
|
||||
}
|
||||
|
||||
NPC = PC + sizeof(UGeckoInstruction);
|
||||
m_prev_inst.hex = PowerPC::Read_Opcode(PC);
|
||||
PowerPC::ppcState.npc = PowerPC::ppcState.pc + sizeof(UGeckoInstruction);
|
||||
m_prev_inst.hex = PowerPC::Read_Opcode(PowerPC::ppcState.pc);
|
||||
|
||||
// Uncomment to trace the interpreter
|
||||
// if ((PC & 0x00FFFFFF) >= 0x000AB54C && (PC & 0x00FFFFFF) <= 0x000AB624)
|
||||
// if ((PowerPC::ppcState.pc & 0x00FFFFFF) >= 0x000AB54C &&
|
||||
// (PowerPC::ppcState.pc & 0x00FFFFFF) <= 0x000AB624)
|
||||
// {
|
||||
// s_start_trace = true;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// s_start_trace = false;
|
||||
// }
|
||||
|
||||
if (s_start_trace)
|
||||
{
|
||||
|
@ -170,7 +178,7 @@ int Interpreter::SingleStepInner()
|
|||
GenerateProgramException(ProgramExceptionCause::IllegalInstruction);
|
||||
CheckExceptions();
|
||||
}
|
||||
else if (MSR.FP)
|
||||
else if (PowerPC::ppcState.msr.FP)
|
||||
{
|
||||
m_op_table[m_prev_inst.OPCD](m_prev_inst);
|
||||
if ((PowerPC::ppcState.Exceptions & EXCEPTION_DSI) != 0)
|
||||
|
@ -206,7 +214,7 @@ int Interpreter::SingleStepInner()
|
|||
|
||||
const GekkoOPInfo* opinfo = PPCTables::GetOpInfo(m_prev_inst);
|
||||
PowerPC::UpdatePerformanceMonitor(opinfo->numCycles, (opinfo->flags & FL_LOADSTORE) != 0,
|
||||
(opinfo->flags & FL_USE_FPU) != 0);
|
||||
(opinfo->flags & FL_USE_FPU) != 0, PowerPC::ppcState);
|
||||
return opinfo->numCycles;
|
||||
}
|
||||
|
||||
|
@ -227,7 +235,7 @@ void Interpreter::SingleStep()
|
|||
if (PowerPC::ppcState.Exceptions != 0)
|
||||
{
|
||||
PowerPC::CheckExceptions();
|
||||
PC = NPC;
|
||||
PowerPC::ppcState.pc = PowerPC::ppcState.npc;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -255,7 +263,7 @@ void Interpreter::Run()
|
|||
if (Config::Get(Config::MAIN_ENABLE_DEBUGGING))
|
||||
{
|
||||
#ifdef SHOW_HISTORY
|
||||
s_pc_block_vec.push_back(PC);
|
||||
s_pc_block_vec.push_back(PowerPC::ppcState.pc);
|
||||
if (s_pc_block_vec.size() > s_show_blocks)
|
||||
s_pc_block_vec.erase(s_pc_block_vec.begin());
|
||||
#endif
|
||||
|
@ -269,13 +277,13 @@ void Interpreter::Run()
|
|||
while (!m_end_block)
|
||||
{
|
||||
#ifdef SHOW_HISTORY
|
||||
s_pc_vec.push_back(PC);
|
||||
s_pc_vec.push_back(PowerPC::ppcState.pc);
|
||||
if (s_pc_vec.size() > s_show_steps)
|
||||
s_pc_vec.erase(s_pc_vec.begin());
|
||||
#endif
|
||||
|
||||
// 2: check for breakpoint
|
||||
if (PowerPC::breakpoints.IsAddressBreakPoint(PC))
|
||||
if (PowerPC::breakpoints.IsAddressBreakPoint(PowerPC::ppcState.pc))
|
||||
{
|
||||
#ifdef SHOW_HISTORY
|
||||
NOTICE_LOG_FMT(POWERPC, "----------------------------");
|
||||
|
@ -296,12 +304,12 @@ void Interpreter::Run()
|
|||
NOTICE_LOG_FMT(POWERPC, "PC: {:#010x}", s_pc_vec[j]);
|
||||
}
|
||||
#endif
|
||||
INFO_LOG_FMT(POWERPC, "Hit Breakpoint - {:08x}", PC);
|
||||
INFO_LOG_FMT(POWERPC, "Hit Breakpoint - {:08x}", PowerPC::ppcState.pc);
|
||||
CPU::Break();
|
||||
if (GDBStub::IsActive())
|
||||
GDBStub::TakeControl();
|
||||
if (PowerPC::breakpoints.IsTempBreakPoint(PC))
|
||||
PowerPC::breakpoints.Remove(PC);
|
||||
if (PowerPC::breakpoints.IsTempBreakPoint(PowerPC::ppcState.pc))
|
||||
PowerPC::breakpoints.Remove(PowerPC::ppcState.pc);
|
||||
|
||||
Host_UpdateDisasmDialog();
|
||||
return;
|
||||
|
@ -334,19 +342,21 @@ void Interpreter::unknown_instruction(UGeckoInstruction inst)
|
|||
const u32 opcode = PowerPC::HostRead_U32(last_pc);
|
||||
const std::string disasm = Common::GekkoDisassembler::Disassemble(opcode, last_pc);
|
||||
NOTICE_LOG_FMT(POWERPC, "Last PC = {:08x} : {}", last_pc, disasm);
|
||||
Dolphin_Debugger::PrintCallstack(Common::Log::LogType::POWERPC, Common::Log::LogLevel::LNOTICE);
|
||||
Dolphin_Debugger::PrintCallstack(Core::System::GetInstance(), Common::Log::LogType::POWERPC,
|
||||
Common::Log::LogLevel::LNOTICE);
|
||||
NOTICE_LOG_FMT(
|
||||
POWERPC,
|
||||
"\nIntCPU: Unknown instruction {:08x} at PC = {:08x} last_PC = {:08x} LR = {:08x}\n",
|
||||
inst.hex, PC, last_pc, LR);
|
||||
inst.hex, PowerPC::ppcState.pc, last_pc, LR(PowerPC::ppcState));
|
||||
for (int i = 0; i < 32; i += 4)
|
||||
{
|
||||
NOTICE_LOG_FMT(POWERPC, "r{}: {:#010x} r{}: {:#010x} r{}: {:#010x} r{}: {:#010x}", i, rGPR[i],
|
||||
i + 1, rGPR[i + 1], i + 2, rGPR[i + 2], i + 3, rGPR[i + 3]);
|
||||
NOTICE_LOG_FMT(POWERPC, "r{}: {:#010x} r{}: {:#010x} r{}: {:#010x} r{}: {:#010x}", i,
|
||||
PowerPC::ppcState.gpr[i], i + 1, PowerPC::ppcState.gpr[i + 1], i + 2,
|
||||
PowerPC::ppcState.gpr[i + 2], i + 3, PowerPC::ppcState.gpr[i + 3]);
|
||||
}
|
||||
ASSERT_MSG(POWERPC, 0,
|
||||
"\nIntCPU: Unknown instruction {:08x} at PC = {:08x} last_PC = {:08x} LR = {:08x}\n",
|
||||
inst.hex, PC, last_pc, LR);
|
||||
inst.hex, PowerPC::ppcState.pc, last_pc, LR(PowerPC::ppcState));
|
||||
if (Core::System::GetInstance().IsPauseOnPanicMode())
|
||||
CPU::Break();
|
||||
}
|
||||
|
|
|
@ -13,14 +13,14 @@
|
|||
void Interpreter::bx(UGeckoInstruction inst)
|
||||
{
|
||||
if (inst.LK)
|
||||
LR = PC + 4;
|
||||
LR(PowerPC::ppcState) = PowerPC::ppcState.pc + 4;
|
||||
|
||||
const auto address = u32(SignExt26(inst.LI << 2));
|
||||
|
||||
if (inst.AA)
|
||||
NPC = address;
|
||||
PowerPC::ppcState.npc = address;
|
||||
else
|
||||
NPC = PC + address;
|
||||
PowerPC::ppcState.npc = PowerPC::ppcState.pc + address;
|
||||
|
||||
m_end_block = true;
|
||||
}
|
||||
|
@ -29,12 +29,12 @@ void Interpreter::bx(UGeckoInstruction inst)
|
|||
void Interpreter::bcx(UGeckoInstruction inst)
|
||||
{
|
||||
if ((inst.BO & BO_DONT_DECREMENT_FLAG) == 0)
|
||||
CTR--;
|
||||
CTR(PowerPC::ppcState)--;
|
||||
|
||||
const bool true_false = ((inst.BO >> 3) & 1) != 0;
|
||||
const bool only_counter_check = ((inst.BO >> 4) & 1) != 0;
|
||||
const bool only_condition_check = ((inst.BO >> 2) & 1) != 0;
|
||||
const u32 ctr_check = ((CTR != 0) ^ (inst.BO >> 1)) & 1;
|
||||
const u32 ctr_check = ((CTR(PowerPC::ppcState) != 0) ^ (inst.BO >> 1)) & 1;
|
||||
const bool counter = only_condition_check || ctr_check != 0;
|
||||
const bool condition =
|
||||
only_counter_check || (PowerPC::ppcState.cr.GetBit(inst.BI) == u32(true_false));
|
||||
|
@ -42,14 +42,14 @@ void Interpreter::bcx(UGeckoInstruction inst)
|
|||
if (counter && condition)
|
||||
{
|
||||
if (inst.LK)
|
||||
LR = PC + 4;
|
||||
LR(PowerPC::ppcState) = PowerPC::ppcState.pc + 4;
|
||||
|
||||
const auto address = u32(SignExt16(s16(inst.BD << 2)));
|
||||
|
||||
if (inst.AA)
|
||||
NPC = address;
|
||||
PowerPC::ppcState.npc = address;
|
||||
else
|
||||
NPC = PC + address;
|
||||
PowerPC::ppcState.npc = PowerPC::ppcState.pc + address;
|
||||
}
|
||||
|
||||
m_end_block = true;
|
||||
|
@ -65,9 +65,9 @@ void Interpreter::bcctrx(UGeckoInstruction inst)
|
|||
|
||||
if (condition != 0)
|
||||
{
|
||||
NPC = CTR & (~3);
|
||||
PowerPC::ppcState.npc = CTR(PowerPC::ppcState) & (~3);
|
||||
if (inst.LK_3)
|
||||
LR = PC + 4;
|
||||
LR(PowerPC::ppcState) = PowerPC::ppcState.pc + 4;
|
||||
}
|
||||
|
||||
m_end_block = true;
|
||||
|
@ -76,17 +76,17 @@ void Interpreter::bcctrx(UGeckoInstruction inst)
|
|||
void Interpreter::bclrx(UGeckoInstruction inst)
|
||||
{
|
||||
if ((inst.BO_2 & BO_DONT_DECREMENT_FLAG) == 0)
|
||||
CTR--;
|
||||
CTR(PowerPC::ppcState)--;
|
||||
|
||||
const u32 counter = ((inst.BO_2 >> 2) | ((CTR != 0) ^ (inst.BO_2 >> 1))) & 1;
|
||||
const u32 counter = ((inst.BO_2 >> 2) | ((CTR(PowerPC::ppcState) != 0) ^ (inst.BO_2 >> 1))) & 1;
|
||||
const u32 condition =
|
||||
((inst.BO_2 >> 4) | (PowerPC::ppcState.cr.GetBit(inst.BI_2) == ((inst.BO_2 >> 3) & 1))) & 1;
|
||||
|
||||
if ((counter & condition) != 0)
|
||||
{
|
||||
NPC = LR & (~3);
|
||||
PowerPC::ppcState.npc = LR(PowerPC::ppcState) & (~3);
|
||||
if (inst.LK_3)
|
||||
LR = PC + 4;
|
||||
LR(PowerPC::ppcState) = PowerPC::ppcState.pc + 4;
|
||||
}
|
||||
|
||||
m_end_block = true;
|
||||
|
@ -95,12 +95,12 @@ void Interpreter::bclrx(UGeckoInstruction inst)
|
|||
void Interpreter::HLEFunction(UGeckoInstruction inst)
|
||||
{
|
||||
m_end_block = true;
|
||||
HLE::Execute(PC, inst.hex);
|
||||
HLE::Execute(PowerPC::ppcState.pc, inst.hex);
|
||||
}
|
||||
|
||||
void Interpreter::rfi(UGeckoInstruction inst)
|
||||
{
|
||||
if (MSR.PR)
|
||||
if (PowerPC::ppcState.msr.PR)
|
||||
{
|
||||
GenerateProgramException(ProgramExceptionCause::PrivilegedInstruction);
|
||||
return;
|
||||
|
@ -109,16 +109,17 @@ void Interpreter::rfi(UGeckoInstruction inst)
|
|||
// Restore saved bits from SRR1 to MSR.
|
||||
// Gecko/Broadway can save more bits than explicitly defined in ppc spec
|
||||
const u32 mask = 0x87C0FFFF;
|
||||
MSR.Hex = (MSR.Hex & ~mask) | (SRR1 & mask);
|
||||
PowerPC::ppcState.msr.Hex =
|
||||
(PowerPC::ppcState.msr.Hex & ~mask) | (SRR1(PowerPC::ppcState) & mask);
|
||||
// MSR[13] is set to 0.
|
||||
MSR.Hex &= 0xFFFBFFFF;
|
||||
PowerPC::ppcState.msr.Hex &= 0xFFFBFFFF;
|
||||
// Here we should check if there are pending exceptions, and if their corresponding enable bits
|
||||
// are set
|
||||
// if above is true, we'd do:
|
||||
// PowerPC::CheckExceptions();
|
||||
// else
|
||||
// set NPC to saved offset and resume
|
||||
NPC = SRR0;
|
||||
PowerPC::ppcState.npc = SRR0(PowerPC::ppcState);
|
||||
m_end_block = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ enum class FPCC
|
|||
|
||||
inline void CheckFPExceptions(UReg_FPSCR fpscr)
|
||||
{
|
||||
if (fpscr.FEX && (MSR.FE0 || MSR.FE1))
|
||||
if (fpscr.FEX && (PowerPC::ppcState.msr.FE0 || PowerPC::ppcState.msr.FE1))
|
||||
GenerateProgramException(ProgramExceptionCause::FloatingPoint);
|
||||
}
|
||||
|
||||
|
|
|
@ -37,31 +37,31 @@ void SetFI(UReg_FPSCR* fpscr, u32 FI)
|
|||
// The Programming Environments Manual for 32 and 64-bit Microprocessors
|
||||
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;
|
||||
bool exception_occurred = false;
|
||||
|
||||
if (std::isnan(b))
|
||||
{
|
||||
if (Common::IsSNAN(b))
|
||||
SetFPException(&FPSCR, FPSCR_VXSNAN);
|
||||
SetFPException(&PowerPC::ppcState.fpscr, FPSCR_VXSNAN);
|
||||
|
||||
value = 0x80000000;
|
||||
SetFPException(&FPSCR, FPSCR_VXCVI);
|
||||
SetFPException(&PowerPC::ppcState.fpscr, FPSCR_VXCVI);
|
||||
exception_occurred = true;
|
||||
}
|
||||
else if (b > static_cast<double>(0x7fffffff))
|
||||
{
|
||||
// Positive large operand or +inf
|
||||
value = 0x7fffffff;
|
||||
SetFPException(&FPSCR, FPSCR_VXCVI);
|
||||
SetFPException(&PowerPC::ppcState.fpscr, FPSCR_VXCVI);
|
||||
exception_occurred = true;
|
||||
}
|
||||
else if (b < -static_cast<double>(0x80000000))
|
||||
{
|
||||
// Negative large operand or -inf
|
||||
value = 0x80000000;
|
||||
SetFPException(&FPSCR, FPSCR_VXCVI);
|
||||
SetFPException(&PowerPC::ppcState.fpscr, FPSCR_VXCVI);
|
||||
exception_occurred = true;
|
||||
}
|
||||
else
|
||||
|
@ -103,22 +103,22 @@ void ConvertToInteger(UGeckoInstruction inst, RoundingMode rounding_mode)
|
|||
const double di = i;
|
||||
if (di == b)
|
||||
{
|
||||
FPSCR.ClearFIFR();
|
||||
PowerPC::ppcState.fpscr.ClearFIFR();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Also sets FPSCR[XX]
|
||||
SetFI(&FPSCR, 1);
|
||||
FPSCR.FR = fabs(di) > fabs(b);
|
||||
SetFI(&PowerPC::ppcState.fpscr, 1);
|
||||
PowerPC::ppcState.fpscr.FR = fabs(di) > fabs(b);
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
// FPRF is not affected
|
||||
|
@ -126,7 +126,7 @@ void ConvertToInteger(UGeckoInstruction inst, RoundingMode rounding_mode)
|
|||
if (value == 0 && std::signbit(b))
|
||||
result |= 0x100000000ull;
|
||||
|
||||
rPS(inst.FD).SetPS0(result);
|
||||
PowerPC::ppcState.ps[inst.FD].SetPS0(result);
|
||||
}
|
||||
|
||||
if (inst.Rc)
|
||||
|
@ -143,15 +143,15 @@ void Interpreter::Helper_FloatCompareOrdered(UGeckoInstruction inst, double fa,
|
|||
compare_result = FPCC::FU;
|
||||
if (Common::IsSNAN(fa) || Common::IsSNAN(fb))
|
||||
{
|
||||
SetFPException(&FPSCR, FPSCR_VXSNAN);
|
||||
if (FPSCR.VE == 0)
|
||||
SetFPException(&PowerPC::ppcState.fpscr, FPSCR_VXSNAN);
|
||||
if (PowerPC::ppcState.fpscr.VE == 0)
|
||||
{
|
||||
SetFPException(&FPSCR, FPSCR_VXVC);
|
||||
SetFPException(&PowerPC::ppcState.fpscr, FPSCR_VXVC);
|
||||
}
|
||||
}
|
||||
else // QNaN
|
||||
{
|
||||
SetFPException(&FPSCR, FPSCR_VXVC);
|
||||
SetFPException(&PowerPC::ppcState.fpscr, FPSCR_VXVC);
|
||||
}
|
||||
}
|
||||
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);
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
@ -185,7 +185,7 @@ void Interpreter::Helper_FloatCompareUnordered(UGeckoInstruction inst, double fa
|
|||
|
||||
if (Common::IsSNAN(fa) || Common::IsSNAN(fb))
|
||||
{
|
||||
SetFPException(&FPSCR, FPSCR_VXSNAN);
|
||||
SetFPException(&PowerPC::ppcState.fpscr, FPSCR_VXSNAN);
|
||||
}
|
||||
}
|
||||
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);
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
void Interpreter::fcmpo(UGeckoInstruction inst)
|
||||
{
|
||||
const auto& a = rPS(inst.FA);
|
||||
const auto& b = rPS(inst.FB);
|
||||
const auto& a = PowerPC::ppcState.ps[inst.FA];
|
||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
||||
|
||||
Helper_FloatCompareOrdered(inst, a.PS0AsDouble(), b.PS0AsDouble());
|
||||
}
|
||||
|
||||
void Interpreter::fcmpu(UGeckoInstruction inst)
|
||||
{
|
||||
const auto& a = rPS(inst.FA);
|
||||
const auto& b = rPS(inst.FB);
|
||||
const auto& a = PowerPC::ppcState.ps[inst.FA];
|
||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
||||
|
||||
Helper_FloatCompareUnordered(inst, a.PS0AsDouble(), b.PS0AsDouble());
|
||||
}
|
||||
|
||||
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)
|
||||
|
@ -237,7 +237,7 @@ void Interpreter::fctiwzx(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
|
||||
if (inst.Rc)
|
||||
|
@ -246,7 +246,7 @@ void Interpreter::fmrx(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
|
||||
if (inst.Rc)
|
||||
|
@ -255,7 +255,8 @@ void Interpreter::fabsx(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
|
||||
if (inst.Rc)
|
||||
|
@ -264,7 +265,8 @@ void Interpreter::fnabsx(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
|
||||
if (inst.Rc)
|
||||
|
@ -273,11 +275,12 @@ void Interpreter::fnegx(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::fselx(UGeckoInstruction inst)
|
||||
{
|
||||
const auto& a = rPS(inst.FA);
|
||||
const auto& b = rPS(inst.FB);
|
||||
const auto& c = rPS(inst.FC);
|
||||
const auto& a = PowerPC::ppcState.ps[inst.FA];
|
||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
||||
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
|
||||
if (inst.Rc)
|
||||
|
@ -289,30 +292,30 @@ void Interpreter::fselx(UGeckoInstruction inst)
|
|||
// PS1 is said to be undefined
|
||||
void Interpreter::frspx(UGeckoInstruction inst) // round to single
|
||||
{
|
||||
const double b = rPS(inst.FB).PS0AsDouble();
|
||||
const float rounded = ForceSingle(FPSCR, b);
|
||||
const double b = PowerPC::ppcState.ps[inst.FB].PS0AsDouble();
|
||||
const float rounded = ForceSingle(PowerPC::ppcState.fpscr, b);
|
||||
|
||||
if (std::isnan(b))
|
||||
{
|
||||
const bool is_snan = Common::IsSNAN(b);
|
||||
|
||||
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::UpdateFPRFSingle(rounded);
|
||||
PowerPC::ppcState.ps[inst.FD].Fill(rounded);
|
||||
PowerPC::ppcState.UpdateFPRFSingle(rounded);
|
||||
}
|
||||
|
||||
FPSCR.ClearFIFR();
|
||||
PowerPC::ppcState.fpscr.ClearFIFR();
|
||||
}
|
||||
else
|
||||
{
|
||||
SetFI(&FPSCR, b != rounded);
|
||||
FPSCR.FR = fabs(rounded) > fabs(b);
|
||||
PowerPC::UpdateFPRFSingle(rounded);
|
||||
rPS(inst.FD).Fill(rounded);
|
||||
SetFI(&PowerPC::ppcState.fpscr, b != rounded);
|
||||
PowerPC::ppcState.fpscr.FR = fabs(rounded) > fabs(b);
|
||||
PowerPC::ppcState.UpdateFPRFSingle(rounded);
|
||||
PowerPC::ppcState.ps[inst.FD].Fill(rounded);
|
||||
}
|
||||
|
||||
if (inst.Rc)
|
||||
|
@ -321,19 +324,19 @@ void Interpreter::frspx(UGeckoInstruction inst) // round to single
|
|||
|
||||
void Interpreter::fmulx(UGeckoInstruction inst)
|
||||
{
|
||||
const auto& a = rPS(inst.FA);
|
||||
const auto& c = rPS(inst.FC);
|
||||
const auto& a = PowerPC::ppcState.ps[inst.FA];
|
||||
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);
|
||||
FPSCR.FI = 0; // are these flags important?
|
||||
FPSCR.FR = 0;
|
||||
PowerPC::UpdateFPRFDouble(result);
|
||||
PowerPC::ppcState.ps[inst.FD].SetPS0(result);
|
||||
PowerPC::ppcState.fpscr.FI = 0; // are these flags important?
|
||||
PowerPC::ppcState.fpscr.FR = 0;
|
||||
PowerPC::ppcState.UpdateFPRFDouble(result);
|
||||
}
|
||||
|
||||
if (inst.Rc)
|
||||
|
@ -341,20 +344,20 @@ void Interpreter::fmulx(UGeckoInstruction inst)
|
|||
}
|
||||
void Interpreter::fmulsx(UGeckoInstruction inst)
|
||||
{
|
||||
const auto& a = rPS(inst.FA);
|
||||
const auto& c = rPS(inst.FC);
|
||||
const auto& a = PowerPC::ppcState.ps[inst.FA];
|
||||
const auto& c = PowerPC::ppcState.ps[inst.FC];
|
||||
|
||||
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);
|
||||
FPSCR.FI = 0;
|
||||
FPSCR.FR = 0;
|
||||
PowerPC::UpdateFPRFSingle(result);
|
||||
PowerPC::ppcState.ps[inst.FD].Fill(result);
|
||||
PowerPC::ppcState.fpscr.FI = 0;
|
||||
PowerPC::ppcState.fpscr.FR = 0;
|
||||
PowerPC::ppcState.UpdateFPRFSingle(result);
|
||||
}
|
||||
|
||||
if (inst.Rc)
|
||||
|
@ -363,16 +366,17 @@ void Interpreter::fmulsx(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::fmaddx(UGeckoInstruction inst)
|
||||
{
|
||||
const auto& a = rPS(inst.FA);
|
||||
const auto& b = rPS(inst.FB);
|
||||
const auto& c = rPS(inst.FC);
|
||||
const FPResult product = NI_madd(&FPSCR, a.PS0AsDouble(), c.PS0AsDouble(), b.PS0AsDouble());
|
||||
const auto& a = PowerPC::ppcState.ps[inst.FA];
|
||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
||||
const auto& c = PowerPC::ppcState.ps[inst.FC];
|
||||
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);
|
||||
rPS(inst.FD).SetPS0(result);
|
||||
PowerPC::UpdateFPRFDouble(result);
|
||||
const double result = ForceDouble(PowerPC::ppcState.fpscr, product.value);
|
||||
PowerPC::ppcState.ps[inst.FD].SetPS0(result);
|
||||
PowerPC::ppcState.UpdateFPRFDouble(result);
|
||||
}
|
||||
|
||||
if (inst.Rc)
|
||||
|
@ -381,21 +385,22 @@ void Interpreter::fmaddx(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::fmaddsx(UGeckoInstruction inst)
|
||||
{
|
||||
const auto& a = rPS(inst.FA);
|
||||
const auto& b = rPS(inst.FB);
|
||||
const auto& c = rPS(inst.FC);
|
||||
const auto& a = PowerPC::ppcState.ps[inst.FA];
|
||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
||||
const auto& c = PowerPC::ppcState.ps[inst.FC];
|
||||
|
||||
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);
|
||||
FPSCR.FI = d_value.value != result;
|
||||
FPSCR.FR = 0;
|
||||
PowerPC::UpdateFPRFSingle(result);
|
||||
PowerPC::ppcState.ps[inst.FD].Fill(result);
|
||||
PowerPC::ppcState.fpscr.FI = d_value.value != result;
|
||||
PowerPC::ppcState.fpscr.FR = 0;
|
||||
PowerPC::ppcState.UpdateFPRFSingle(result);
|
||||
}
|
||||
|
||||
if (inst.Rc)
|
||||
|
@ -404,16 +409,16 @@ void Interpreter::fmaddsx(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::faddx(UGeckoInstruction inst)
|
||||
{
|
||||
const auto& a = rPS(inst.FA);
|
||||
const auto& b = rPS(inst.FB);
|
||||
const auto& a = PowerPC::ppcState.ps[inst.FA];
|
||||
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);
|
||||
rPS(inst.FD).SetPS0(result);
|
||||
PowerPC::UpdateFPRFDouble(result);
|
||||
const double result = ForceDouble(PowerPC::ppcState.fpscr, sum.value);
|
||||
PowerPC::ppcState.ps[inst.FD].SetPS0(result);
|
||||
PowerPC::ppcState.UpdateFPRFDouble(result);
|
||||
}
|
||||
|
||||
if (inst.Rc)
|
||||
|
@ -421,16 +426,16 @@ void Interpreter::faddx(UGeckoInstruction inst)
|
|||
}
|
||||
void Interpreter::faddsx(UGeckoInstruction inst)
|
||||
{
|
||||
const auto& a = rPS(inst.FA);
|
||||
const auto& b = rPS(inst.FB);
|
||||
const auto& a = PowerPC::ppcState.ps[inst.FA];
|
||||
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);
|
||||
rPS(inst.FD).Fill(result);
|
||||
PowerPC::UpdateFPRFSingle(result);
|
||||
const float result = ForceSingle(PowerPC::ppcState.fpscr, sum.value);
|
||||
PowerPC::ppcState.ps[inst.FD].Fill(result);
|
||||
PowerPC::ppcState.UpdateFPRFSingle(result);
|
||||
}
|
||||
|
||||
if (inst.Rc)
|
||||
|
@ -439,18 +444,18 @@ void Interpreter::faddsx(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::fdivx(UGeckoInstruction inst)
|
||||
{
|
||||
const auto& a = rPS(inst.FA);
|
||||
const auto& b = rPS(inst.FB);
|
||||
const auto& a = PowerPC::ppcState.ps[inst.FA];
|
||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
||||
|
||||
const FPResult quotient = NI_div(&FPSCR, a.PS0AsDouble(), b.PS0AsDouble());
|
||||
const bool not_divide_by_zero = FPSCR.ZE == 0 || quotient.exception != FPSCR_ZX;
|
||||
const bool not_invalid = FPSCR.VE == 0 || quotient.HasNoInvalidExceptions();
|
||||
const FPResult quotient = NI_div(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), b.PS0AsDouble());
|
||||
const bool not_divide_by_zero = PowerPC::ppcState.fpscr.ZE == 0 || quotient.exception != FPSCR_ZX;
|
||||
const bool not_invalid = PowerPC::ppcState.fpscr.VE == 0 || quotient.HasNoInvalidExceptions();
|
||||
|
||||
if (not_divide_by_zero && not_invalid)
|
||||
{
|
||||
const double result = ForceDouble(FPSCR, quotient.value);
|
||||
rPS(inst.FD).SetPS0(result);
|
||||
PowerPC::UpdateFPRFDouble(result);
|
||||
const double result = ForceDouble(PowerPC::ppcState.fpscr, quotient.value);
|
||||
PowerPC::ppcState.ps[inst.FD].SetPS0(result);
|
||||
PowerPC::ppcState.UpdateFPRFDouble(result);
|
||||
}
|
||||
|
||||
// FR,FI,OX,UX???
|
||||
|
@ -459,18 +464,18 @@ void Interpreter::fdivx(UGeckoInstruction inst)
|
|||
}
|
||||
void Interpreter::fdivsx(UGeckoInstruction inst)
|
||||
{
|
||||
const auto& a = rPS(inst.FA);
|
||||
const auto& b = rPS(inst.FB);
|
||||
const auto& a = PowerPC::ppcState.ps[inst.FA];
|
||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
||||
|
||||
const FPResult quotient = NI_div(&FPSCR, a.PS0AsDouble(), b.PS0AsDouble());
|
||||
const bool not_divide_by_zero = FPSCR.ZE == 0 || quotient.exception != FPSCR_ZX;
|
||||
const bool not_invalid = FPSCR.VE == 0 || quotient.HasNoInvalidExceptions();
|
||||
const FPResult quotient = NI_div(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), b.PS0AsDouble());
|
||||
const bool not_divide_by_zero = PowerPC::ppcState.fpscr.ZE == 0 || quotient.exception != FPSCR_ZX;
|
||||
const bool not_invalid = PowerPC::ppcState.fpscr.VE == 0 || quotient.HasNoInvalidExceptions();
|
||||
|
||||
if (not_divide_by_zero && not_invalid)
|
||||
{
|
||||
const float result = ForceSingle(FPSCR, quotient.value);
|
||||
rPS(inst.FD).Fill(result);
|
||||
PowerPC::UpdateFPRFSingle(result);
|
||||
const float result = ForceSingle(PowerPC::ppcState.fpscr, quotient.value);
|
||||
PowerPC::ppcState.ps[inst.FD].Fill(result);
|
||||
PowerPC::ppcState.UpdateFPRFSingle(result);
|
||||
}
|
||||
|
||||
if (inst.Rc)
|
||||
|
@ -480,34 +485,34 @@ void Interpreter::fdivsx(UGeckoInstruction inst)
|
|||
// Single precision only.
|
||||
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 double result = Common::ApproximateReciprocal(value);
|
||||
rPS(inst.FD).Fill(result);
|
||||
PowerPC::UpdateFPRFSingle(float(result));
|
||||
PowerPC::ppcState.ps[inst.FD].Fill(result);
|
||||
PowerPC::ppcState.UpdateFPRFSingle(float(result));
|
||||
};
|
||||
|
||||
if (b == 0.0)
|
||||
{
|
||||
SetFPException(&FPSCR, FPSCR_ZX);
|
||||
FPSCR.ClearFIFR();
|
||||
SetFPException(&PowerPC::ppcState.fpscr, FPSCR_ZX);
|
||||
PowerPC::ppcState.fpscr.ClearFIFR();
|
||||
|
||||
if (FPSCR.ZE == 0)
|
||||
if (PowerPC::ppcState.fpscr.ZE == 0)
|
||||
compute_result(b);
|
||||
}
|
||||
else if (Common::IsSNAN(b))
|
||||
{
|
||||
SetFPException(&FPSCR, FPSCR_VXSNAN);
|
||||
FPSCR.ClearFIFR();
|
||||
SetFPException(&PowerPC::ppcState.fpscr, FPSCR_VXSNAN);
|
||||
PowerPC::ppcState.fpscr.ClearFIFR();
|
||||
|
||||
if (FPSCR.VE == 0)
|
||||
if (PowerPC::ppcState.fpscr.VE == 0)
|
||||
compute_result(b);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (std::isnan(b) || std::isinf(b))
|
||||
FPSCR.ClearFIFR();
|
||||
PowerPC::ppcState.fpscr.ClearFIFR();
|
||||
|
||||
compute_result(b);
|
||||
}
|
||||
|
@ -518,42 +523,42 @@ void Interpreter::fresx(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 double result = Common::ApproximateReciprocalSquareRoot(value);
|
||||
rPS(inst.FD).SetPS0(result);
|
||||
PowerPC::UpdateFPRFDouble(result);
|
||||
PowerPC::ppcState.ps[inst.FD].SetPS0(result);
|
||||
PowerPC::ppcState.UpdateFPRFDouble(result);
|
||||
};
|
||||
|
||||
if (b < 0.0)
|
||||
{
|
||||
SetFPException(&FPSCR, FPSCR_VXSQRT);
|
||||
FPSCR.ClearFIFR();
|
||||
SetFPException(&PowerPC::ppcState.fpscr, FPSCR_VXSQRT);
|
||||
PowerPC::ppcState.fpscr.ClearFIFR();
|
||||
|
||||
if (FPSCR.VE == 0)
|
||||
if (PowerPC::ppcState.fpscr.VE == 0)
|
||||
compute_result(b);
|
||||
}
|
||||
else if (b == 0.0)
|
||||
{
|
||||
SetFPException(&FPSCR, FPSCR_ZX);
|
||||
FPSCR.ClearFIFR();
|
||||
SetFPException(&PowerPC::ppcState.fpscr, FPSCR_ZX);
|
||||
PowerPC::ppcState.fpscr.ClearFIFR();
|
||||
|
||||
if (FPSCR.ZE == 0)
|
||||
if (PowerPC::ppcState.fpscr.ZE == 0)
|
||||
compute_result(b);
|
||||
}
|
||||
else if (Common::IsSNAN(b))
|
||||
{
|
||||
SetFPException(&FPSCR, FPSCR_VXSNAN);
|
||||
FPSCR.ClearFIFR();
|
||||
SetFPException(&PowerPC::ppcState.fpscr, FPSCR_VXSNAN);
|
||||
PowerPC::ppcState.fpscr.ClearFIFR();
|
||||
|
||||
if (FPSCR.VE == 0)
|
||||
if (PowerPC::ppcState.fpscr.VE == 0)
|
||||
compute_result(b);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (std::isnan(b) || std::isinf(b))
|
||||
FPSCR.ClearFIFR();
|
||||
PowerPC::ppcState.fpscr.ClearFIFR();
|
||||
|
||||
compute_result(b);
|
||||
}
|
||||
|
@ -564,17 +569,18 @@ void Interpreter::frsqrtex(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::fmsubx(UGeckoInstruction inst)
|
||||
{
|
||||
const auto& a = rPS(inst.FA);
|
||||
const auto& b = rPS(inst.FB);
|
||||
const auto& c = rPS(inst.FC);
|
||||
const auto& a = PowerPC::ppcState.ps[inst.FA];
|
||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
||||
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);
|
||||
rPS(inst.FD).SetPS0(result);
|
||||
PowerPC::UpdateFPRFDouble(result);
|
||||
const double result = ForceDouble(PowerPC::ppcState.fpscr, product.value);
|
||||
PowerPC::ppcState.ps[inst.FD].SetPS0(result);
|
||||
PowerPC::ppcState.UpdateFPRFDouble(result);
|
||||
}
|
||||
|
||||
if (inst.Rc)
|
||||
|
@ -583,18 +589,19 @@ void Interpreter::fmsubx(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::fmsubsx(UGeckoInstruction inst)
|
||||
{
|
||||
const auto& a = rPS(inst.FA);
|
||||
const auto& b = rPS(inst.FB);
|
||||
const auto& c = rPS(inst.FC);
|
||||
const auto& a = PowerPC::ppcState.ps[inst.FA];
|
||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
||||
const auto& c = PowerPC::ppcState.ps[inst.FC];
|
||||
|
||||
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);
|
||||
rPS(inst.FD).Fill(result);
|
||||
PowerPC::UpdateFPRFSingle(result);
|
||||
const float result = ForceSingle(PowerPC::ppcState.fpscr, product.value);
|
||||
PowerPC::ppcState.ps[inst.FD].Fill(result);
|
||||
PowerPC::ppcState.UpdateFPRFSingle(result);
|
||||
}
|
||||
|
||||
if (inst.Rc)
|
||||
|
@ -603,19 +610,20 @@ void Interpreter::fmsubsx(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::fnmaddx(UGeckoInstruction inst)
|
||||
{
|
||||
const auto& a = rPS(inst.FA);
|
||||
const auto& b = rPS(inst.FB);
|
||||
const auto& c = rPS(inst.FC);
|
||||
const auto& a = PowerPC::ppcState.ps[inst.FA];
|
||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
||||
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;
|
||||
|
||||
rPS(inst.FD).SetPS0(result);
|
||||
PowerPC::UpdateFPRFDouble(result);
|
||||
PowerPC::ppcState.ps[inst.FD].SetPS0(result);
|
||||
PowerPC::ppcState.UpdateFPRFDouble(result);
|
||||
}
|
||||
|
||||
if (inst.Rc)
|
||||
|
@ -624,20 +632,21 @@ void Interpreter::fnmaddx(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::fnmaddsx(UGeckoInstruction inst)
|
||||
{
|
||||
const auto& a = rPS(inst.FA);
|
||||
const auto& b = rPS(inst.FB);
|
||||
const auto& c = rPS(inst.FC);
|
||||
const auto& a = PowerPC::ppcState.ps[inst.FA];
|
||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
||||
const auto& c = PowerPC::ppcState.ps[inst.FC];
|
||||
|
||||
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;
|
||||
|
||||
rPS(inst.FD).Fill(result);
|
||||
PowerPC::UpdateFPRFSingle(result);
|
||||
PowerPC::ppcState.ps[inst.FD].Fill(result);
|
||||
PowerPC::ppcState.UpdateFPRFSingle(result);
|
||||
}
|
||||
|
||||
if (inst.Rc)
|
||||
|
@ -646,19 +655,20 @@ void Interpreter::fnmaddsx(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::fnmsubx(UGeckoInstruction inst)
|
||||
{
|
||||
const auto& a = rPS(inst.FA);
|
||||
const auto& b = rPS(inst.FB);
|
||||
const auto& c = rPS(inst.FC);
|
||||
const auto& a = PowerPC::ppcState.ps[inst.FA];
|
||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
||||
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;
|
||||
|
||||
rPS(inst.FD).SetPS0(result);
|
||||
PowerPC::UpdateFPRFDouble(result);
|
||||
PowerPC::ppcState.ps[inst.FD].SetPS0(result);
|
||||
PowerPC::ppcState.UpdateFPRFDouble(result);
|
||||
}
|
||||
|
||||
if (inst.Rc)
|
||||
|
@ -667,20 +677,21 @@ void Interpreter::fnmsubx(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::fnmsubsx(UGeckoInstruction inst)
|
||||
{
|
||||
const auto& a = rPS(inst.FA);
|
||||
const auto& b = rPS(inst.FB);
|
||||
const auto& c = rPS(inst.FC);
|
||||
const auto& a = PowerPC::ppcState.ps[inst.FA];
|
||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
||||
const auto& c = PowerPC::ppcState.ps[inst.FC];
|
||||
|
||||
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;
|
||||
|
||||
rPS(inst.FD).Fill(result);
|
||||
PowerPC::UpdateFPRFSingle(result);
|
||||
PowerPC::ppcState.ps[inst.FD].Fill(result);
|
||||
PowerPC::ppcState.UpdateFPRFSingle(result);
|
||||
}
|
||||
|
||||
if (inst.Rc)
|
||||
|
@ -689,16 +700,16 @@ void Interpreter::fnmsubsx(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::fsubx(UGeckoInstruction inst)
|
||||
{
|
||||
const auto& a = rPS(inst.FA);
|
||||
const auto& b = rPS(inst.FB);
|
||||
const auto& a = PowerPC::ppcState.ps[inst.FA];
|
||||
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);
|
||||
rPS(inst.FD).SetPS0(result);
|
||||
PowerPC::UpdateFPRFDouble(result);
|
||||
const double result = ForceDouble(PowerPC::ppcState.fpscr, difference.value);
|
||||
PowerPC::ppcState.ps[inst.FD].SetPS0(result);
|
||||
PowerPC::ppcState.UpdateFPRFDouble(result);
|
||||
}
|
||||
|
||||
if (inst.Rc)
|
||||
|
@ -707,16 +718,16 @@ void Interpreter::fsubx(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::fsubsx(UGeckoInstruction inst)
|
||||
{
|
||||
const auto& a = rPS(inst.FA);
|
||||
const auto& b = rPS(inst.FB);
|
||||
const auto& a = PowerPC::ppcState.ps[inst.FA];
|
||||
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);
|
||||
rPS(inst.FD).Fill(result);
|
||||
PowerPC::UpdateFPRFSingle(result);
|
||||
const float result = ForceSingle(PowerPC::ppcState.fpscr, difference.value);
|
||||
PowerPC::ppcState.ps[inst.FD].Fill(result);
|
||||
PowerPC::ppcState.UpdateFPRFSingle(result);
|
||||
}
|
||||
|
||||
if (inst.Rc)
|
||||
|
|
|
@ -16,7 +16,7 @@ void Interpreter::Helper_UpdateCR0(u32 value)
|
|||
const s64 sign_extended = s64{s32(value)};
|
||||
u64 cr_val = u64(sign_extended);
|
||||
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;
|
||||
}
|
||||
|
@ -29,44 +29,44 @@ u32 Interpreter::Helper_Carry(u32 value1, u32 value2)
|
|||
void Interpreter::addi(UGeckoInstruction inst)
|
||||
{
|
||||
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
|
||||
rGPR[inst.RD] = u32(inst.SIMM_16);
|
||||
PowerPC::ppcState.gpr[inst.RD] = u32(inst.SIMM_16);
|
||||
}
|
||||
|
||||
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});
|
||||
|
||||
rGPR[inst.RD] = a + imm;
|
||||
PowerPC::SetCarry(Helper_Carry(a, imm));
|
||||
PowerPC::ppcState.gpr[inst.RD] = a + imm;
|
||||
PowerPC::ppcState.SetCarry(Helper_Carry(a, imm));
|
||||
}
|
||||
|
||||
void Interpreter::addic_rc(UGeckoInstruction inst)
|
||||
{
|
||||
addic(inst);
|
||||
Helper_UpdateCR0(rGPR[inst.RD]);
|
||||
Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RD]);
|
||||
}
|
||||
|
||||
void Interpreter::addis(UGeckoInstruction inst)
|
||||
{
|
||||
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
|
||||
rGPR[inst.RD] = u32(inst.SIMM_16 << 16);
|
||||
PowerPC::ppcState.gpr[inst.RD] = u32(inst.SIMM_16 << 16);
|
||||
}
|
||||
|
||||
void Interpreter::andi_rc(UGeckoInstruction inst)
|
||||
{
|
||||
rGPR[inst.RA] = rGPR[inst.RS] & inst.UIMM;
|
||||
Helper_UpdateCR0(rGPR[inst.RA]);
|
||||
PowerPC::ppcState.gpr[inst.RA] = PowerPC::ppcState.gpr[inst.RS] & inst.UIMM;
|
||||
Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
|
||||
}
|
||||
|
||||
void Interpreter::andis_rc(UGeckoInstruction inst)
|
||||
{
|
||||
rGPR[inst.RA] = rGPR[inst.RS] & (u32{inst.UIMM} << 16);
|
||||
Helper_UpdateCR0(rGPR[inst.RA]);
|
||||
PowerPC::ppcState.gpr[inst.RA] = PowerPC::ppcState.gpr[inst.RS] & (u32{inst.UIMM} << 16);
|
||||
Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
@ -81,7 +81,7 @@ void Interpreter::Helper_IntCompare(UGeckoInstruction inst, T a, T b)
|
|||
else
|
||||
cr_field = PowerPC::CR_EQ;
|
||||
|
||||
if (PowerPC::GetXER_SO())
|
||||
if (PowerPC::ppcState.GetXER_SO())
|
||||
cr_field |= PowerPC::CR_SO;
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
Helper_IntCompare(inst, a, b);
|
||||
}
|
||||
|
||||
void Interpreter::cmpli(UGeckoInstruction inst)
|
||||
{
|
||||
const u32 a = rGPR[inst.RA];
|
||||
const u32 a = PowerPC::ppcState.gpr[inst.RA];
|
||||
const u32 b = inst.UIMM;
|
||||
Helper_IntCompare(inst, a, b);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
const s32 immediate = inst.SIMM_16;
|
||||
rGPR[inst.RD] = u32(immediate - s32(rGPR[inst.RA]));
|
||||
PowerPC::SetCarry((rGPR[inst.RA] == 0) || (Helper_Carry(0 - rGPR[inst.RA], u32(immediate))));
|
||||
PowerPC::ppcState.gpr[inst.RD] = u32(immediate - s32(PowerPC::ppcState.gpr[inst.RA]));
|
||||
PowerPC::ppcState.SetCarry((PowerPC::ppcState.gpr[inst.RA] == 0) ||
|
||||
(Helper_Carry(0 - PowerPC::ppcState.gpr[inst.RA], u32(immediate))));
|
||||
}
|
||||
|
||||
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 u32 TO = inst.TO;
|
||||
|
||||
|
@ -142,199 +143,207 @@ void Interpreter::twi(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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
Helper_UpdateCR0(rGPR[inst.RA]);
|
||||
Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
|
||||
}
|
||||
|
||||
void Interpreter::rlwinmx(UGeckoInstruction inst)
|
||||
{
|
||||
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)
|
||||
Helper_UpdateCR0(rGPR[inst.RA]);
|
||||
Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
|
||||
}
|
||||
|
||||
void Interpreter::rlwnmx(UGeckoInstruction inst)
|
||||
{
|
||||
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)
|
||||
Helper_UpdateCR0(rGPR[inst.RA]);
|
||||
Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
|
||||
}
|
||||
|
||||
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)
|
||||
Helper_UpdateCR0(rGPR[inst.RA]);
|
||||
Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
|
||||
}
|
||||
|
||||
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)
|
||||
Helper_UpdateCR0(rGPR[inst.RA]);
|
||||
Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
|
||||
}
|
||||
|
||||
void Interpreter::cmp(UGeckoInstruction inst)
|
||||
{
|
||||
const s32 a = static_cast<s32>(rGPR[inst.RA]);
|
||||
const s32 b = static_cast<s32>(rGPR[inst.RB]);
|
||||
const s32 a = static_cast<s32>(PowerPC::ppcState.gpr[inst.RA]);
|
||||
const s32 b = static_cast<s32>(PowerPC::ppcState.gpr[inst.RB]);
|
||||
Helper_IntCompare(inst, a, b);
|
||||
}
|
||||
|
||||
void Interpreter::cmpl(UGeckoInstruction inst)
|
||||
{
|
||||
const u32 a = rGPR[inst.RA];
|
||||
const u32 b = rGPR[inst.RB];
|
||||
const u32 a = PowerPC::ppcState.gpr[inst.RA];
|
||||
const u32 b = PowerPC::ppcState.gpr[inst.RB];
|
||||
Helper_IntCompare(inst, a, b);
|
||||
}
|
||||
|
||||
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)
|
||||
Helper_UpdateCR0(rGPR[inst.RA]);
|
||||
Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
|
||||
}
|
||||
|
||||
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)
|
||||
Helper_UpdateCR0(rGPR[inst.RA]);
|
||||
Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
|
||||
}
|
||||
|
||||
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)
|
||||
Helper_UpdateCR0(rGPR[inst.RA]);
|
||||
Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
|
||||
}
|
||||
|
||||
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)
|
||||
Helper_UpdateCR0(rGPR[inst.RA]);
|
||||
Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
|
||||
}
|
||||
|
||||
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)
|
||||
Helper_UpdateCR0(rGPR[inst.RA]);
|
||||
Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
|
||||
}
|
||||
|
||||
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)
|
||||
Helper_UpdateCR0(rGPR[inst.RA]);
|
||||
Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
|
||||
}
|
||||
|
||||
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)
|
||||
Helper_UpdateCR0(rGPR[inst.RA]);
|
||||
Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
|
||||
}
|
||||
|
||||
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)
|
||||
Helper_UpdateCR0(rGPR[inst.RA]);
|
||||
Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
|
||||
}
|
||||
|
||||
void Interpreter::slwx(UGeckoInstruction inst)
|
||||
{
|
||||
const u32 amount = rGPR[inst.RB];
|
||||
rGPR[inst.RA] = (amount & 0x20) != 0 ? 0 : rGPR[inst.RS] << (amount & 0x1f);
|
||||
const u32 amount = PowerPC::ppcState.gpr[inst.RB];
|
||||
PowerPC::ppcState.gpr[inst.RA] =
|
||||
(amount & 0x20) != 0 ? 0 : PowerPC::ppcState.gpr[inst.RS] << (amount & 0x1f);
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR0(rGPR[inst.RA]);
|
||||
Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
|
||||
}
|
||||
|
||||
void Interpreter::srawx(UGeckoInstruction inst)
|
||||
{
|
||||
const u32 rb = rGPR[inst.RB];
|
||||
const u32 rb = PowerPC::ppcState.gpr[inst.RB];
|
||||
|
||||
if ((rb & 0x20) != 0)
|
||||
{
|
||||
if ((rGPR[inst.RS] & 0x80000000) != 0)
|
||||
if ((PowerPC::ppcState.gpr[inst.RS] & 0x80000000) != 0)
|
||||
{
|
||||
rGPR[inst.RA] = 0xFFFFFFFF;
|
||||
PowerPC::SetCarry(1);
|
||||
PowerPC::ppcState.gpr[inst.RA] = 0xFFFFFFFF;
|
||||
PowerPC::ppcState.SetCarry(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
rGPR[inst.RA] = 0x00000000;
|
||||
PowerPC::SetCarry(0);
|
||||
PowerPC::ppcState.gpr[inst.RA] = 0x00000000;
|
||||
PowerPC::ppcState.SetCarry(0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const u32 amount = rb & 0x1f;
|
||||
const s32 rrs = s32(rGPR[inst.RS]);
|
||||
rGPR[inst.RA] = u32(rrs >> amount);
|
||||
const s32 rrs = s32(PowerPC::ppcState.gpr[inst.RS]);
|
||||
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)
|
||||
Helper_UpdateCR0(rGPR[inst.RA]);
|
||||
Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
|
||||
}
|
||||
|
||||
void Interpreter::srawix(UGeckoInstruction inst)
|
||||
{
|
||||
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::SetCarry(rrs < 0 && amount > 0 && (u32(rrs) << (32 - amount)) != 0);
|
||||
PowerPC::ppcState.gpr[inst.RA] = u32(rrs >> amount);
|
||||
PowerPC::ppcState.SetCarry(rrs < 0 && amount > 0 && (u32(rrs) << (32 - amount)) != 0);
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR0(rGPR[inst.RA]);
|
||||
Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
|
||||
}
|
||||
|
||||
void Interpreter::srwx(UGeckoInstruction inst)
|
||||
{
|
||||
const u32 amount = rGPR[inst.RB];
|
||||
rGPR[inst.RA] = (amount & 0x20) != 0 ? 0 : (rGPR[inst.RS] >> (amount & 0x1f));
|
||||
const u32 amount = PowerPC::ppcState.gpr[inst.RB];
|
||||
PowerPC::ppcState.gpr[inst.RA] =
|
||||
(amount & 0x20) != 0 ? 0 : (PowerPC::ppcState.gpr[inst.RS] >> (amount & 0x1f));
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR0(rGPR[inst.RA]);
|
||||
Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
|
||||
}
|
||||
|
||||
void Interpreter::tw(UGeckoInstruction inst)
|
||||
{
|
||||
const s32 a = s32(rGPR[inst.RA]);
|
||||
const s32 b = s32(rGPR[inst.RB]);
|
||||
const s32 a = s32(PowerPC::ppcState.gpr[inst.RA]);
|
||||
const s32 b = s32(PowerPC::ppcState.gpr[inst.RB]);
|
||||
const u32 TO = inst.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)
|
||||
{
|
||||
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)
|
||||
Helper_UpdateCR0(rGPR[inst.RA]);
|
||||
Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
const u32 a = rGPR[inst.RA];
|
||||
const u32 b = rGPR[inst.RB];
|
||||
const u32 a = PowerPC::ppcState.gpr[inst.RA];
|
||||
const u32 b = PowerPC::ppcState.gpr[inst.RB];
|
||||
const u32 result = a + b;
|
||||
|
||||
rGPR[inst.RD] = result;
|
||||
PowerPC::ppcState.gpr[inst.RD] = result;
|
||||
|
||||
if (inst.OE)
|
||||
PowerPC::SetXER_OV(HasAddOverflowed(a, b, result));
|
||||
PowerPC::ppcState.SetXER_OV(HasAddOverflowed(a, b, result));
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR0(result);
|
||||
|
@ -380,15 +389,15 @@ void Interpreter::addx(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::addcx(UGeckoInstruction inst)
|
||||
{
|
||||
const u32 a = rGPR[inst.RA];
|
||||
const u32 b = rGPR[inst.RB];
|
||||
const u32 a = PowerPC::ppcState.gpr[inst.RA];
|
||||
const u32 b = PowerPC::ppcState.gpr[inst.RB];
|
||||
const u32 result = a + b;
|
||||
|
||||
rGPR[inst.RD] = result;
|
||||
PowerPC::SetCarry(Helper_Carry(a, b));
|
||||
PowerPC::ppcState.gpr[inst.RD] = result;
|
||||
PowerPC::ppcState.SetCarry(Helper_Carry(a, b));
|
||||
|
||||
if (inst.OE)
|
||||
PowerPC::SetXER_OV(HasAddOverflowed(a, b, result));
|
||||
PowerPC::ppcState.SetXER_OV(HasAddOverflowed(a, b, result));
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR0(result);
|
||||
|
@ -396,16 +405,16 @@ void Interpreter::addcx(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::addex(UGeckoInstruction inst)
|
||||
{
|
||||
const u32 carry = PowerPC::GetCarry();
|
||||
const u32 a = rGPR[inst.RA];
|
||||
const u32 b = rGPR[inst.RB];
|
||||
const u32 carry = PowerPC::ppcState.GetCarry();
|
||||
const u32 a = PowerPC::ppcState.gpr[inst.RA];
|
||||
const u32 b = PowerPC::ppcState.gpr[inst.RB];
|
||||
const u32 result = a + b + carry;
|
||||
|
||||
rGPR[inst.RD] = result;
|
||||
PowerPC::SetCarry(Helper_Carry(a, b) || (carry != 0 && Helper_Carry(a + b, carry)));
|
||||
PowerPC::ppcState.gpr[inst.RD] = result;
|
||||
PowerPC::ppcState.SetCarry(Helper_Carry(a, b) || (carry != 0 && Helper_Carry(a + b, carry)));
|
||||
|
||||
if (inst.OE)
|
||||
PowerPC::SetXER_OV(HasAddOverflowed(a, b, result));
|
||||
PowerPC::ppcState.SetXER_OV(HasAddOverflowed(a, b, result));
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR0(result);
|
||||
|
@ -413,16 +422,16 @@ void Interpreter::addex(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::addmex(UGeckoInstruction inst)
|
||||
{
|
||||
const u32 carry = PowerPC::GetCarry();
|
||||
const u32 a = rGPR[inst.RA];
|
||||
const u32 carry = PowerPC::ppcState.GetCarry();
|
||||
const u32 a = PowerPC::ppcState.gpr[inst.RA];
|
||||
const u32 b = 0xFFFFFFFF;
|
||||
const u32 result = a + b + carry;
|
||||
|
||||
rGPR[inst.RD] = result;
|
||||
PowerPC::SetCarry(Helper_Carry(a, carry - 1));
|
||||
PowerPC::ppcState.gpr[inst.RD] = result;
|
||||
PowerPC::ppcState.SetCarry(Helper_Carry(a, carry - 1));
|
||||
|
||||
if (inst.OE)
|
||||
PowerPC::SetXER_OV(HasAddOverflowed(a, b, result));
|
||||
PowerPC::ppcState.SetXER_OV(HasAddOverflowed(a, b, result));
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR0(result);
|
||||
|
@ -430,15 +439,15 @@ void Interpreter::addmex(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::addzex(UGeckoInstruction inst)
|
||||
{
|
||||
const u32 carry = PowerPC::GetCarry();
|
||||
const u32 a = rGPR[inst.RA];
|
||||
const u32 carry = PowerPC::ppcState.GetCarry();
|
||||
const u32 a = PowerPC::ppcState.gpr[inst.RA];
|
||||
const u32 result = a + carry;
|
||||
|
||||
rGPR[inst.RD] = result;
|
||||
PowerPC::SetCarry(Helper_Carry(a, carry));
|
||||
PowerPC::ppcState.gpr[inst.RD] = result;
|
||||
PowerPC::ppcState.SetCarry(Helper_Carry(a, carry));
|
||||
|
||||
if (inst.OE)
|
||||
PowerPC::SetXER_OV(HasAddOverflowed(a, 0, result));
|
||||
PowerPC::ppcState.SetXER_OV(HasAddOverflowed(a, 0, result));
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR0(result);
|
||||
|
@ -446,58 +455,58 @@ void Interpreter::addzex(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::divwx(UGeckoInstruction inst)
|
||||
{
|
||||
const auto a = s32(rGPR[inst.RA]);
|
||||
const auto b = s32(rGPR[inst.RB]);
|
||||
const auto a = s32(PowerPC::ppcState.gpr[inst.RA]);
|
||||
const auto b = s32(PowerPC::ppcState.gpr[inst.RB]);
|
||||
const bool overflow = b == 0 || (static_cast<u32>(a) == 0x80000000 && b == -1);
|
||||
|
||||
if (overflow)
|
||||
{
|
||||
if (a < 0)
|
||||
rGPR[inst.RD] = UINT32_MAX;
|
||||
PowerPC::ppcState.gpr[inst.RD] = UINT32_MAX;
|
||||
else
|
||||
rGPR[inst.RD] = 0;
|
||||
PowerPC::ppcState.gpr[inst.RD] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
rGPR[inst.RD] = static_cast<u32>(a / b);
|
||||
PowerPC::ppcState.gpr[inst.RD] = static_cast<u32>(a / b);
|
||||
}
|
||||
|
||||
if (inst.OE)
|
||||
PowerPC::SetXER_OV(overflow);
|
||||
PowerPC::ppcState.SetXER_OV(overflow);
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR0(rGPR[inst.RD]);
|
||||
Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RD]);
|
||||
}
|
||||
|
||||
void Interpreter::divwux(UGeckoInstruction inst)
|
||||
{
|
||||
const u32 a = rGPR[inst.RA];
|
||||
const u32 b = rGPR[inst.RB];
|
||||
const u32 a = PowerPC::ppcState.gpr[inst.RA];
|
||||
const u32 b = PowerPC::ppcState.gpr[inst.RB];
|
||||
const bool overflow = b == 0;
|
||||
|
||||
if (overflow)
|
||||
{
|
||||
rGPR[inst.RD] = 0;
|
||||
PowerPC::ppcState.gpr[inst.RD] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
rGPR[inst.RD] = a / b;
|
||||
PowerPC::ppcState.gpr[inst.RD] = a / b;
|
||||
}
|
||||
|
||||
if (inst.OE)
|
||||
PowerPC::SetXER_OV(overflow);
|
||||
PowerPC::ppcState.SetXER_OV(overflow);
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR0(rGPR[inst.RD]);
|
||||
Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RD]);
|
||||
}
|
||||
|
||||
void Interpreter::mulhwx(UGeckoInstruction inst)
|
||||
{
|
||||
const s64 a = static_cast<s32>(rGPR[inst.RA]);
|
||||
const s64 b = static_cast<s32>(rGPR[inst.RB]);
|
||||
const s64 a = static_cast<s32>(PowerPC::ppcState.gpr[inst.RA]);
|
||||
const s64 b = static_cast<s32>(PowerPC::ppcState.gpr[inst.RB]);
|
||||
const u32 d = static_cast<u32>((a * b) >> 32);
|
||||
|
||||
rGPR[inst.RD] = d;
|
||||
PowerPC::ppcState.gpr[inst.RD] = d;
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR0(d);
|
||||
|
@ -505,11 +514,11 @@ void Interpreter::mulhwx(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::mulhwux(UGeckoInstruction inst)
|
||||
{
|
||||
const u64 a = rGPR[inst.RA];
|
||||
const u64 b = rGPR[inst.RB];
|
||||
const u64 a = PowerPC::ppcState.gpr[inst.RA];
|
||||
const u64 b = PowerPC::ppcState.gpr[inst.RB];
|
||||
const u32 d = static_cast<u32>((a * b) >> 32);
|
||||
|
||||
rGPR[inst.RD] = d;
|
||||
PowerPC::ppcState.gpr[inst.RD] = d;
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR0(d);
|
||||
|
@ -517,42 +526,42 @@ void Interpreter::mulhwux(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::mullwx(UGeckoInstruction inst)
|
||||
{
|
||||
const s64 a = static_cast<s32>(rGPR[inst.RA]);
|
||||
const s64 b = static_cast<s32>(rGPR[inst.RB]);
|
||||
const s64 a = static_cast<s32>(PowerPC::ppcState.gpr[inst.RA]);
|
||||
const s64 b = static_cast<s32>(PowerPC::ppcState.gpr[inst.RB]);
|
||||
const s64 result = a * b;
|
||||
|
||||
rGPR[inst.RD] = static_cast<u32>(result);
|
||||
PowerPC::ppcState.gpr[inst.RD] = static_cast<u32>(result);
|
||||
|
||||
if (inst.OE)
|
||||
PowerPC::SetXER_OV(result < -0x80000000LL || result > 0x7FFFFFFFLL);
|
||||
PowerPC::ppcState.SetXER_OV(result < -0x80000000LL || result > 0x7FFFFFFFLL);
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR0(rGPR[inst.RD]);
|
||||
Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RD]);
|
||||
}
|
||||
|
||||
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)
|
||||
PowerPC::SetXER_OV(a == 0x80000000);
|
||||
PowerPC::ppcState.SetXER_OV(a == 0x80000000);
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR0(rGPR[inst.RD]);
|
||||
Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RD]);
|
||||
}
|
||||
|
||||
void Interpreter::subfx(UGeckoInstruction inst)
|
||||
{
|
||||
const u32 a = ~rGPR[inst.RA];
|
||||
const u32 b = rGPR[inst.RB];
|
||||
const u32 a = ~PowerPC::ppcState.gpr[inst.RA];
|
||||
const u32 b = PowerPC::ppcState.gpr[inst.RB];
|
||||
const u32 result = a + b + 1;
|
||||
|
||||
rGPR[inst.RD] = result;
|
||||
PowerPC::ppcState.gpr[inst.RD] = result;
|
||||
|
||||
if (inst.OE)
|
||||
PowerPC::SetXER_OV(HasAddOverflowed(a, b, result));
|
||||
PowerPC::ppcState.SetXER_OV(HasAddOverflowed(a, b, result));
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR0(result);
|
||||
|
@ -560,15 +569,15 @@ void Interpreter::subfx(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::subfcx(UGeckoInstruction inst)
|
||||
{
|
||||
const u32 a = ~rGPR[inst.RA];
|
||||
const u32 b = rGPR[inst.RB];
|
||||
const u32 a = ~PowerPC::ppcState.gpr[inst.RA];
|
||||
const u32 b = PowerPC::ppcState.gpr[inst.RB];
|
||||
const u32 result = a + b + 1;
|
||||
|
||||
rGPR[inst.RD] = result;
|
||||
PowerPC::SetCarry(a == 0xFFFFFFFF || Helper_Carry(b, a + 1));
|
||||
PowerPC::ppcState.gpr[inst.RD] = result;
|
||||
PowerPC::ppcState.SetCarry(a == 0xFFFFFFFF || Helper_Carry(b, a + 1));
|
||||
|
||||
if (inst.OE)
|
||||
PowerPC::SetXER_OV(HasAddOverflowed(a, b, result));
|
||||
PowerPC::ppcState.SetXER_OV(HasAddOverflowed(a, b, result));
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR0(result);
|
||||
|
@ -576,16 +585,16 @@ void Interpreter::subfcx(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::subfex(UGeckoInstruction inst)
|
||||
{
|
||||
const u32 a = ~rGPR[inst.RA];
|
||||
const u32 b = rGPR[inst.RB];
|
||||
const u32 carry = PowerPC::GetCarry();
|
||||
const u32 a = ~PowerPC::ppcState.gpr[inst.RA];
|
||||
const u32 b = PowerPC::ppcState.gpr[inst.RB];
|
||||
const u32 carry = PowerPC::ppcState.GetCarry();
|
||||
const u32 result = a + b + carry;
|
||||
|
||||
rGPR[inst.RD] = result;
|
||||
PowerPC::SetCarry(Helper_Carry(a, b) || Helper_Carry(a + b, carry));
|
||||
PowerPC::ppcState.gpr[inst.RD] = result;
|
||||
PowerPC::ppcState.SetCarry(Helper_Carry(a, b) || Helper_Carry(a + b, carry));
|
||||
|
||||
if (inst.OE)
|
||||
PowerPC::SetXER_OV(HasAddOverflowed(a, b, result));
|
||||
PowerPC::ppcState.SetXER_OV(HasAddOverflowed(a, b, result));
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR0(result);
|
||||
|
@ -594,16 +603,16 @@ void Interpreter::subfex(UGeckoInstruction inst)
|
|||
// sub from minus one
|
||||
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 carry = PowerPC::GetCarry();
|
||||
const u32 carry = PowerPC::ppcState.GetCarry();
|
||||
const u32 result = a + b + carry;
|
||||
|
||||
rGPR[inst.RD] = result;
|
||||
PowerPC::SetCarry(Helper_Carry(a, carry - 1));
|
||||
PowerPC::ppcState.gpr[inst.RD] = result;
|
||||
PowerPC::ppcState.SetCarry(Helper_Carry(a, carry - 1));
|
||||
|
||||
if (inst.OE)
|
||||
PowerPC::SetXER_OV(HasAddOverflowed(a, b, result));
|
||||
PowerPC::ppcState.SetXER_OV(HasAddOverflowed(a, b, result));
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR0(result);
|
||||
|
@ -612,15 +621,15 @@ void Interpreter::subfmex(UGeckoInstruction inst)
|
|||
// sub from zero
|
||||
void Interpreter::subfzex(UGeckoInstruction inst)
|
||||
{
|
||||
const u32 a = ~rGPR[inst.RA];
|
||||
const u32 carry = PowerPC::GetCarry();
|
||||
const u32 a = ~PowerPC::ppcState.gpr[inst.RA];
|
||||
const u32 carry = PowerPC::ppcState.GetCarry();
|
||||
const u32 result = a + carry;
|
||||
|
||||
rGPR[inst.RD] = result;
|
||||
PowerPC::SetCarry(Helper_Carry(a, carry));
|
||||
PowerPC::ppcState.gpr[inst.RD] = result;
|
||||
PowerPC::ppcState.SetCarry(Helper_Carry(a, carry));
|
||||
|
||||
if (inst.OE)
|
||||
PowerPC::SetXER_OV(HasAddOverflowed(a, 0, result));
|
||||
PowerPC::ppcState.SetXER_OV(HasAddOverflowed(a, 0, result));
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR0(result);
|
||||
|
|
|
@ -42,7 +42,7 @@ void Interpreter::lbz(UGeckoInstruction inst)
|
|||
const u32 temp = PowerPC::Read_U8(Helper_Get_EA(PowerPC::ppcState, inst));
|
||||
|
||||
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
|
||||
rGPR[inst.RD] = temp;
|
||||
PowerPC::ppcState.gpr[inst.RD] = temp;
|
||||
}
|
||||
|
||||
void Interpreter::lbzu(UGeckoInstruction inst)
|
||||
|
@ -52,8 +52,8 @@ void Interpreter::lbzu(UGeckoInstruction inst)
|
|||
|
||||
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
|
||||
{
|
||||
rGPR[inst.RD] = temp;
|
||||
rGPR[inst.RA] = address;
|
||||
PowerPC::ppcState.gpr[inst.RD] = temp;
|
||||
PowerPC::ppcState.gpr[inst.RA] = address;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -70,7 +70,7 @@ void Interpreter::lfd(UGeckoInstruction inst)
|
|||
const u64 temp = PowerPC::Read_U64(address);
|
||||
|
||||
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
|
||||
rPS(inst.FD).SetPS0(temp);
|
||||
PowerPC::ppcState.ps[inst.FD].SetPS0(temp);
|
||||
}
|
||||
|
||||
void Interpreter::lfdu(UGeckoInstruction inst)
|
||||
|
@ -87,8 +87,8 @@ void Interpreter::lfdu(UGeckoInstruction inst)
|
|||
|
||||
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
|
||||
{
|
||||
rPS(inst.FD).SetPS0(temp);
|
||||
rGPR[inst.RA] = address;
|
||||
PowerPC::ppcState.ps[inst.FD].SetPS0(temp);
|
||||
PowerPC::ppcState.gpr[inst.RA] = address;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -106,8 +106,8 @@ void Interpreter::lfdux(UGeckoInstruction inst)
|
|||
|
||||
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
|
||||
{
|
||||
rPS(inst.FD).SetPS0(temp);
|
||||
rGPR[inst.RA] = address;
|
||||
PowerPC::ppcState.ps[inst.FD].SetPS0(temp);
|
||||
PowerPC::ppcState.gpr[inst.RA] = address;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -124,7 +124,7 @@ void Interpreter::lfdx(UGeckoInstruction inst)
|
|||
const u64 temp = PowerPC::Read_U64(address);
|
||||
|
||||
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
|
||||
rPS(inst.FD).SetPS0(temp);
|
||||
PowerPC::ppcState.ps[inst.FD].SetPS0(temp);
|
||||
}
|
||||
|
||||
void Interpreter::lfs(UGeckoInstruction inst)
|
||||
|
@ -142,7 +142,7 @@ void Interpreter::lfs(UGeckoInstruction inst)
|
|||
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
|
||||
{
|
||||
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))
|
||||
{
|
||||
const u64 value = ConvertToDouble(temp);
|
||||
rPS(inst.FD).Fill(value);
|
||||
rGPR[inst.RA] = address;
|
||||
PowerPC::ppcState.ps[inst.FD].Fill(value);
|
||||
PowerPC::ppcState.gpr[inst.RA] = address;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -181,8 +181,8 @@ void Interpreter::lfsux(UGeckoInstruction inst)
|
|||
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
|
||||
{
|
||||
const u64 value = ConvertToDouble(temp);
|
||||
rPS(inst.FD).Fill(value);
|
||||
rGPR[inst.RA] = address;
|
||||
PowerPC::ppcState.ps[inst.FD].Fill(value);
|
||||
PowerPC::ppcState.gpr[inst.RA] = address;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -201,7 +201,7 @@ void Interpreter::lfsx(UGeckoInstruction inst)
|
|||
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
|
||||
{
|
||||
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))
|
||||
{
|
||||
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))
|
||||
{
|
||||
rGPR[inst.RD] = temp;
|
||||
rGPR[inst.RA] = address;
|
||||
PowerPC::ppcState.gpr[inst.RD] = temp;
|
||||
PowerPC::ppcState.gpr[inst.RA] = address;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -233,7 +233,7 @@ void Interpreter::lhz(UGeckoInstruction inst)
|
|||
|
||||
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))
|
||||
{
|
||||
rGPR[inst.RD] = temp;
|
||||
rGPR[inst.RA] = address;
|
||||
PowerPC::ppcState.gpr[inst.RD] = temp;
|
||||
PowerPC::ppcState.gpr[inst.RA] = address;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -254,7 +254,7 @@ void Interpreter::lmw(UGeckoInstruction 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);
|
||||
return;
|
||||
|
@ -272,7 +272,7 @@ void Interpreter::lmw(UGeckoInstruction inst)
|
|||
}
|
||||
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);
|
||||
|
||||
if ((address & 0b11) != 0 || MSR.LE)
|
||||
if ((address & 0b11) != 0 || PowerPC::ppcState.msr.LE)
|
||||
{
|
||||
GenerateAlignmentException(address);
|
||||
return;
|
||||
|
@ -290,7 +290,7 @@ void Interpreter::stmw(UGeckoInstruction inst)
|
|||
|
||||
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)
|
||||
{
|
||||
PanicAlertFmt("DSI exception in stmw");
|
||||
|
@ -307,7 +307,7 @@ void Interpreter::lwz(UGeckoInstruction inst)
|
|||
|
||||
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))
|
||||
{
|
||||
rGPR[inst.RD] = temp;
|
||||
rGPR[inst.RA] = address;
|
||||
PowerPC::ppcState.gpr[inst.RD] = temp;
|
||||
PowerPC::ppcState.gpr[inst.RA] = address;
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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))
|
||||
{
|
||||
rGPR[inst.RA] = address;
|
||||
PowerPC::ppcState.gpr[inst.RA] = address;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -349,7 +349,7 @@ void Interpreter::stfd(UGeckoInstruction inst)
|
|||
return;
|
||||
}
|
||||
|
||||
PowerPC::Write_U64(rPS(inst.FS).PS0AsU64(), address);
|
||||
PowerPC::Write_U64(PowerPC::ppcState.ps[inst.FS].PS0AsU64(), address);
|
||||
}
|
||||
|
||||
void Interpreter::stfdu(UGeckoInstruction inst)
|
||||
|
@ -362,10 +362,10 @@ void Interpreter::stfdu(UGeckoInstruction inst)
|
|||
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))
|
||||
{
|
||||
rGPR[inst.RA] = address;
|
||||
PowerPC::ppcState.gpr[inst.RA] = address;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -379,7 +379,7 @@ void Interpreter::stfs(UGeckoInstruction inst)
|
|||
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)
|
||||
|
@ -392,42 +392,42 @@ void Interpreter::stfsu(UGeckoInstruction inst)
|
|||
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))
|
||||
{
|
||||
rGPR[inst.RA] = address;
|
||||
PowerPC::ppcState.gpr[inst.RA] = address;
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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))
|
||||
{
|
||||
rGPR[inst.RA] = address;
|
||||
PowerPC::ppcState.gpr[inst.RA] = address;
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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))
|
||||
{
|
||||
rGPR[inst.RA] = address;
|
||||
PowerPC::ppcState.gpr[inst.RA] = address;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -453,7 +453,7 @@ void Interpreter::dcbf(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::dcbi(UGeckoInstruction inst)
|
||||
{
|
||||
if (MSR.PR)
|
||||
if (PowerPC::ppcState.msr.PR)
|
||||
{
|
||||
GenerateProgramException(ProgramExceptionCause::PrivilegedInstruction);
|
||||
return;
|
||||
|
@ -503,7 +503,7 @@ void Interpreter::dcbz(UGeckoInstruction inst)
|
|||
{
|
||||
const u32 dcbz_addr = Helper_Get_EA_X(PowerPC::ppcState, inst);
|
||||
|
||||
if (!HID0.DCE)
|
||||
if (!HID0(PowerPC::ppcState).DCE)
|
||||
{
|
||||
GenerateAlignmentException(dcbz_addr);
|
||||
return;
|
||||
|
@ -525,7 +525,7 @@ void Interpreter::dcbz(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::dcbz_l(UGeckoInstruction inst)
|
||||
{
|
||||
if (!HID2.LCE)
|
||||
if (!HID2(PowerPC::ppcState).LCE)
|
||||
{
|
||||
GenerateProgramException(ProgramExceptionCause::IllegalInstruction);
|
||||
return;
|
||||
|
@ -533,7 +533,7 @@ void Interpreter::dcbz_l(UGeckoInstruction inst)
|
|||
|
||||
const u32 address = Helper_Get_EA_X(PowerPC::ppcState, inst);
|
||||
|
||||
if (!HID0.DCE)
|
||||
if (!HID0(PowerPC::ppcState).DCE)
|
||||
{
|
||||
GenerateAlignmentException(address);
|
||||
return;
|
||||
|
@ -560,7 +560,7 @@ void Interpreter::eciwx(UGeckoInstruction inst)
|
|||
return;
|
||||
}
|
||||
|
||||
rGPR[inst.RD] = PowerPC::Read_U32(EA);
|
||||
PowerPC::ppcState.gpr[inst.RD] = PowerPC::Read_U32(EA);
|
||||
}
|
||||
|
||||
void Interpreter::ecowx(UGeckoInstruction inst)
|
||||
|
@ -579,7 +579,7 @@ void Interpreter::ecowx(UGeckoInstruction inst)
|
|||
return;
|
||||
}
|
||||
|
||||
PowerPC::Write_U32(rGPR[inst.RS], EA);
|
||||
PowerPC::Write_U32(PowerPC::ppcState.gpr[inst.RS], EA);
|
||||
}
|
||||
|
||||
void Interpreter::eieio(UGeckoInstruction inst)
|
||||
|
@ -604,8 +604,8 @@ void Interpreter::lbzux(UGeckoInstruction inst)
|
|||
|
||||
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
|
||||
{
|
||||
rGPR[inst.RD] = temp;
|
||||
rGPR[inst.RA] = address;
|
||||
PowerPC::ppcState.gpr[inst.RD] = temp;
|
||||
PowerPC::ppcState.gpr[inst.RA] = address;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -615,7 +615,7 @@ void Interpreter::lbzx(UGeckoInstruction inst)
|
|||
|
||||
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))
|
||||
{
|
||||
rGPR[inst.RD] = u32(temp);
|
||||
rGPR[inst.RA] = address;
|
||||
PowerPC::ppcState.gpr[inst.RD] = u32(temp);
|
||||
PowerPC::ppcState.gpr[inst.RA] = address;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -637,7 +637,7 @@ void Interpreter::lhax(UGeckoInstruction inst)
|
|||
|
||||
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))
|
||||
{
|
||||
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))
|
||||
{
|
||||
rGPR[inst.RD] = temp;
|
||||
rGPR[inst.RA] = address;
|
||||
PowerPC::ppcState.gpr[inst.RD] = temp;
|
||||
PowerPC::ppcState.gpr[inst.RA] = address;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -669,7 +669,7 @@ void Interpreter::lhzx(UGeckoInstruction inst)
|
|||
|
||||
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);
|
||||
|
||||
if (MSR.LE)
|
||||
if (PowerPC::ppcState.msr.LE)
|
||||
{
|
||||
GenerateAlignmentException(EA);
|
||||
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++)
|
||||
{
|
||||
const u32 reg = (inst.RD + (n >> 2)) & 0x1f;
|
||||
const u32 offset = (n & 3) << 3;
|
||||
|
||||
if ((n & 0b11) == 0)
|
||||
rGPR[reg] = 0;
|
||||
PowerPC::ppcState.gpr[reg] = 0;
|
||||
|
||||
const u32 temp_value = PowerPC::Read_U8(EA) << (24 - offset);
|
||||
// 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");
|
||||
return;
|
||||
}
|
||||
rGPR[reg] |= temp_value;
|
||||
PowerPC::ppcState.gpr[reg] |= temp_value;
|
||||
|
||||
EA++;
|
||||
}
|
||||
|
@ -712,7 +712,7 @@ void Interpreter::lwbrx(UGeckoInstruction inst)
|
|||
|
||||
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))
|
||||
{
|
||||
rGPR[inst.RD] = temp;
|
||||
rGPR[inst.RA] = address;
|
||||
PowerPC::ppcState.gpr[inst.RD] = temp;
|
||||
PowerPC::ppcState.gpr[inst.RA] = address;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -735,7 +735,7 @@ void Interpreter::lwzx(UGeckoInstruction inst)
|
|||
|
||||
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);
|
||||
|
||||
PowerPC::Write_U8(rGPR[inst.RS], address);
|
||||
PowerPC::Write_U8(PowerPC::ppcState.gpr[inst.RS], address);
|
||||
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
|
||||
{
|
||||
rGPR[inst.RA] = address;
|
||||
PowerPC::ppcState.gpr[inst.RA] = address;
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
|
@ -765,10 +765,10 @@ void Interpreter::stfdux(UGeckoInstruction inst)
|
|||
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))
|
||||
{
|
||||
rGPR[inst.RA] = address;
|
||||
PowerPC::ppcState.gpr[inst.RA] = address;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -782,7 +782,7 @@ void Interpreter::stfdx(UGeckoInstruction inst)
|
|||
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
|
||||
|
@ -796,7 +796,7 @@ void Interpreter::stfiwx(UGeckoInstruction inst)
|
|||
return;
|
||||
}
|
||||
|
||||
PowerPC::Write_U32(rPS(inst.FS).PS0AsU32(), address);
|
||||
PowerPC::Write_U32(PowerPC::ppcState.ps[inst.FS].PS0AsU32(), address);
|
||||
}
|
||||
|
||||
void Interpreter::stfsux(UGeckoInstruction inst)
|
||||
|
@ -809,10 +809,10 @@ void Interpreter::stfsux(UGeckoInstruction inst)
|
|||
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))
|
||||
{
|
||||
rGPR[inst.RA] = address;
|
||||
PowerPC::ppcState.gpr[inst.RA] = address;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -826,28 +826,28 @@ void Interpreter::stfsx(UGeckoInstruction inst)
|
|||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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))
|
||||
{
|
||||
rGPR[inst.RA] = address;
|
||||
PowerPC::ppcState.gpr[inst.RA] = address;
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -856,9 +856,9 @@ void Interpreter::lswi(UGeckoInstruction inst)
|
|||
{
|
||||
u32 EA = 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);
|
||||
return;
|
||||
|
@ -876,7 +876,7 @@ void Interpreter::lswi(UGeckoInstruction inst)
|
|||
{
|
||||
r++;
|
||||
r &= 31;
|
||||
rGPR[r] = 0;
|
||||
PowerPC::ppcState.gpr[r] = 0;
|
||||
}
|
||||
|
||||
const u32 temp_value = PowerPC::Read_U8(EA) << (24 - i);
|
||||
|
@ -886,7 +886,7 @@ void Interpreter::lswi(UGeckoInstruction inst)
|
|||
return;
|
||||
}
|
||||
|
||||
rGPR[r] |= temp_value;
|
||||
PowerPC::ppcState.gpr[r] |= temp_value;
|
||||
|
||||
i += 8;
|
||||
if (i == 32)
|
||||
|
@ -903,9 +903,9 @@ void Interpreter::stswi(UGeckoInstruction inst)
|
|||
{
|
||||
u32 EA = 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);
|
||||
return;
|
||||
|
@ -924,7 +924,7 @@ void Interpreter::stswi(UGeckoInstruction inst)
|
|||
r++;
|
||||
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)
|
||||
{
|
||||
return;
|
||||
|
@ -943,7 +943,7 @@ void Interpreter::stswx(UGeckoInstruction inst)
|
|||
{
|
||||
u32 EA = Helper_Get_EA_X(PowerPC::ppcState, inst);
|
||||
|
||||
if (MSR.LE)
|
||||
if (PowerPC::ppcState.msr.LE)
|
||||
{
|
||||
GenerateAlignmentException(EA);
|
||||
return;
|
||||
|
@ -955,7 +955,7 @@ void Interpreter::stswx(UGeckoInstruction inst)
|
|||
|
||||
while (n > 0)
|
||||
{
|
||||
PowerPC::Write_U8((rGPR[r] >> (24 - i)) & 0xFF, EA);
|
||||
PowerPC::Write_U8((PowerPC::ppcState.gpr[r] >> (24 - i)) & 0xFF, EA);
|
||||
|
||||
EA++;
|
||||
n--;
|
||||
|
@ -972,7 +972,7 @@ void Interpreter::stwbrx(UGeckoInstruction 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
|
||||
|
@ -992,7 +992,7 @@ void Interpreter::lwarx(UGeckoInstruction inst)
|
|||
|
||||
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
|
||||
{
|
||||
rGPR[inst.RD] = temp;
|
||||
PowerPC::ppcState.gpr[inst.RD] = temp;
|
||||
PowerPC::ppcState.reserve = true;
|
||||
PowerPC::ppcState.reserve_address = address;
|
||||
}
|
||||
|
@ -1013,27 +1013,27 @@ void Interpreter::stwcxd(UGeckoInstruction inst)
|
|||
{
|
||||
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))
|
||||
{
|
||||
PowerPC::ppcState.reserve = false;
|
||||
PowerPC::ppcState.cr.SetField(0, 2 | PowerPC::GetXER_SO());
|
||||
PowerPC::ppcState.cr.SetField(0, 2 | PowerPC::ppcState.GetXER_SO());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PowerPC::ppcState.cr.SetField(0, PowerPC::GetXER_SO());
|
||||
PowerPC::ppcState.cr.SetField(0, PowerPC::ppcState.GetXER_SO());
|
||||
}
|
||||
|
||||
void Interpreter::stwux(UGeckoInstruction 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))
|
||||
{
|
||||
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);
|
||||
|
||||
PowerPC::Write_U32(rGPR[inst.RS], address);
|
||||
PowerPC::Write_U32(PowerPC::ppcState.gpr[inst.RS], address);
|
||||
}
|
||||
|
||||
void Interpreter::sync(UGeckoInstruction inst)
|
||||
|
@ -1051,21 +1051,21 @@ void Interpreter::sync(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::tlbie(UGeckoInstruction inst)
|
||||
{
|
||||
if (MSR.PR)
|
||||
if (PowerPC::ppcState.msr.PR)
|
||||
{
|
||||
GenerateProgramException(ProgramExceptionCause::PrivilegedInstruction);
|
||||
return;
|
||||
}
|
||||
|
||||
// Invalidate TLB entry
|
||||
const u32 address = rGPR[inst.RB];
|
||||
const u32 address = PowerPC::ppcState.gpr[inst.RB];
|
||||
|
||||
PowerPC::InvalidateTLBEntry(address);
|
||||
}
|
||||
|
||||
void Interpreter::tlbsync(UGeckoInstruction inst)
|
||||
{
|
||||
if (MSR.PR)
|
||||
if (PowerPC::ppcState.msr.PR)
|
||||
{
|
||||
GenerateProgramException(ProgramExceptionCause::PrivilegedInstruction);
|
||||
}
|
||||
|
|
|
@ -310,25 +310,25 @@ static void Helper_Dequantize(PowerPC::PowerPCState* ppcs, u32 addr, u32 instI,
|
|||
|
||||
void Interpreter::psq_l(UGeckoInstruction inst)
|
||||
{
|
||||
if (HID2.LSQE == 0)
|
||||
if (HID2(PowerPC::ppcState).LSQE == 0)
|
||||
{
|
||||
GenerateProgramException(ProgramExceptionCause::IllegalInstruction);
|
||||
return;
|
||||
}
|
||||
|
||||
const u32 EA = inst.RA ? (rGPR[inst.RA] + u32(inst.SIMM_12)) : u32(inst.SIMM_12);
|
||||
const u32 EA = inst.RA ? (PowerPC::ppcState.gpr[inst.RA] + u32(inst.SIMM_12)) : u32(inst.SIMM_12);
|
||||
Helper_Dequantize(&PowerPC::ppcState, EA, inst.I, inst.RD, inst.W);
|
||||
}
|
||||
|
||||
void Interpreter::psq_lu(UGeckoInstruction inst)
|
||||
{
|
||||
if (HID2.LSQE == 0)
|
||||
if (HID2(PowerPC::ppcState).LSQE == 0)
|
||||
{
|
||||
GenerateProgramException(ProgramExceptionCause::IllegalInstruction);
|
||||
return;
|
||||
}
|
||||
|
||||
const u32 EA = rGPR[inst.RA] + u32(inst.SIMM_12);
|
||||
const u32 EA = PowerPC::ppcState.gpr[inst.RA] + u32(inst.SIMM_12);
|
||||
Helper_Dequantize(&PowerPC::ppcState, EA, inst.I, inst.RD, inst.W);
|
||||
|
||||
if ((PowerPC::ppcState.Exceptions & EXCEPTION_DSI) != 0)
|
||||
|
@ -336,30 +336,30 @@ void Interpreter::psq_lu(UGeckoInstruction inst)
|
|||
return;
|
||||
}
|
||||
|
||||
rGPR[inst.RA] = EA;
|
||||
PowerPC::ppcState.gpr[inst.RA] = EA;
|
||||
}
|
||||
|
||||
void Interpreter::psq_st(UGeckoInstruction inst)
|
||||
{
|
||||
if (HID2.LSQE == 0)
|
||||
if (HID2(PowerPC::ppcState).LSQE == 0)
|
||||
{
|
||||
GenerateProgramException(ProgramExceptionCause::IllegalInstruction);
|
||||
return;
|
||||
}
|
||||
|
||||
const u32 EA = inst.RA ? (rGPR[inst.RA] + u32(inst.SIMM_12)) : u32(inst.SIMM_12);
|
||||
const u32 EA = inst.RA ? (PowerPC::ppcState.gpr[inst.RA] + u32(inst.SIMM_12)) : u32(inst.SIMM_12);
|
||||
Helper_Quantize(&PowerPC::ppcState, EA, inst.I, inst.RS, inst.W);
|
||||
}
|
||||
|
||||
void Interpreter::psq_stu(UGeckoInstruction inst)
|
||||
{
|
||||
if (HID2.LSQE == 0)
|
||||
if (HID2(PowerPC::ppcState).LSQE == 0)
|
||||
{
|
||||
GenerateProgramException(ProgramExceptionCause::IllegalInstruction);
|
||||
return;
|
||||
}
|
||||
|
||||
const u32 EA = rGPR[inst.RA] + u32(inst.SIMM_12);
|
||||
const u32 EA = PowerPC::ppcState.gpr[inst.RA] + u32(inst.SIMM_12);
|
||||
Helper_Quantize(&PowerPC::ppcState, EA, inst.I, inst.RS, inst.W);
|
||||
|
||||
if ((PowerPC::ppcState.Exceptions & EXCEPTION_DSI) != 0)
|
||||
|
@ -367,24 +367,26 @@ void Interpreter::psq_stu(UGeckoInstruction inst)
|
|||
return;
|
||||
}
|
||||
|
||||
rGPR[inst.RA] = EA;
|
||||
PowerPC::ppcState.gpr[inst.RA] = EA;
|
||||
}
|
||||
|
||||
void Interpreter::psq_lx(UGeckoInstruction inst)
|
||||
{
|
||||
const u32 EA = inst.RA ? (rGPR[inst.RA] + rGPR[inst.RB]) : rGPR[inst.RB];
|
||||
const u32 EA = inst.RA ? (PowerPC::ppcState.gpr[inst.RA] + PowerPC::ppcState.gpr[inst.RB]) :
|
||||
PowerPC::ppcState.gpr[inst.RB];
|
||||
Helper_Dequantize(&PowerPC::ppcState, EA, inst.Ix, inst.RD, inst.Wx);
|
||||
}
|
||||
|
||||
void Interpreter::psq_stx(UGeckoInstruction inst)
|
||||
{
|
||||
const u32 EA = inst.RA ? (rGPR[inst.RA] + rGPR[inst.RB]) : rGPR[inst.RB];
|
||||
const u32 EA = inst.RA ? (PowerPC::ppcState.gpr[inst.RA] + PowerPC::ppcState.gpr[inst.RB]) :
|
||||
PowerPC::ppcState.gpr[inst.RB];
|
||||
Helper_Quantize(&PowerPC::ppcState, EA, inst.Ix, inst.RS, inst.Wx);
|
||||
}
|
||||
|
||||
void Interpreter::psq_lux(UGeckoInstruction inst)
|
||||
{
|
||||
const u32 EA = rGPR[inst.RA] + rGPR[inst.RB];
|
||||
const u32 EA = PowerPC::ppcState.gpr[inst.RA] + PowerPC::ppcState.gpr[inst.RB];
|
||||
Helper_Dequantize(&PowerPC::ppcState, EA, inst.Ix, inst.RD, inst.Wx);
|
||||
|
||||
if ((PowerPC::ppcState.Exceptions & EXCEPTION_DSI) != 0)
|
||||
|
@ -392,12 +394,12 @@ void Interpreter::psq_lux(UGeckoInstruction inst)
|
|||
return;
|
||||
}
|
||||
|
||||
rGPR[inst.RA] = EA;
|
||||
PowerPC::ppcState.gpr[inst.RA] = EA;
|
||||
}
|
||||
|
||||
void Interpreter::psq_stux(UGeckoInstruction inst)
|
||||
{
|
||||
const u32 EA = rGPR[inst.RA] + rGPR[inst.RB];
|
||||
const u32 EA = PowerPC::ppcState.gpr[inst.RA] + PowerPC::ppcState.gpr[inst.RB];
|
||||
Helper_Quantize(&PowerPC::ppcState, EA, inst.Ix, inst.RS, inst.Wx);
|
||||
|
||||
if ((PowerPC::ppcState.Exceptions & EXCEPTION_DSI) != 0)
|
||||
|
@ -405,5 +407,5 @@ void Interpreter::psq_stux(UGeckoInstruction inst)
|
|||
return;
|
||||
}
|
||||
|
||||
rGPR[inst.RA] = EA;
|
||||
PowerPC::ppcState.gpr[inst.RA] = EA;
|
||||
}
|
||||
|
|
|
@ -13,12 +13,13 @@
|
|||
// These "binary instructions" do not alter FPSCR.
|
||||
void Interpreter::ps_sel(UGeckoInstruction inst)
|
||||
{
|
||||
const auto& a = rPS(inst.FA);
|
||||
const auto& b = rPS(inst.FB);
|
||||
const auto& c = rPS(inst.FC);
|
||||
const auto& a = PowerPC::ppcState.ps[inst.FA];
|
||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
||||
const auto& c = PowerPC::ppcState.ps[inst.FC];
|
||||
|
||||
rPS(inst.FD).SetBoth(a.PS0AsDouble() >= -0.0 ? c.PS0AsDouble() : b.PS0AsDouble(),
|
||||
a.PS1AsDouble() >= -0.0 ? c.PS1AsDouble() : b.PS1AsDouble());
|
||||
PowerPC::ppcState.ps[inst.FD].SetBoth(a.PS0AsDouble() >= -0.0 ? c.PS0AsDouble() : b.PS0AsDouble(),
|
||||
a.PS1AsDouble() >= -0.0 ? c.PS1AsDouble() :
|
||||
b.PS1AsDouble());
|
||||
|
||||
if (inst.Rc)
|
||||
PowerPC::ppcState.UpdateCR1();
|
||||
|
@ -26,9 +27,10 @@ void Interpreter::ps_sel(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)
|
||||
PowerPC::ppcState.UpdateCR1();
|
||||
|
@ -36,7 +38,7 @@ void Interpreter::ps_neg(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)
|
||||
PowerPC::ppcState.UpdateCR1();
|
||||
|
@ -44,9 +46,10 @@ void Interpreter::ps_mr(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)
|
||||
PowerPC::ppcState.UpdateCR1();
|
||||
|
@ -54,9 +57,10 @@ void Interpreter::ps_nabs(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)
|
||||
PowerPC::ppcState.UpdateCR1();
|
||||
|
@ -65,10 +69,10 @@ void Interpreter::ps_abs(UGeckoInstruction inst)
|
|||
// These are just moves, double is OK.
|
||||
void Interpreter::ps_merge00(UGeckoInstruction inst)
|
||||
{
|
||||
const auto& a = rPS(inst.FA);
|
||||
const auto& b = rPS(inst.FB);
|
||||
const auto& a = PowerPC::ppcState.ps[inst.FA];
|
||||
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)
|
||||
PowerPC::ppcState.UpdateCR1();
|
||||
|
@ -76,10 +80,10 @@ void Interpreter::ps_merge00(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::ps_merge01(UGeckoInstruction inst)
|
||||
{
|
||||
const auto& a = rPS(inst.FA);
|
||||
const auto& b = rPS(inst.FB);
|
||||
const auto& a = PowerPC::ppcState.ps[inst.FA];
|
||||
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)
|
||||
PowerPC::ppcState.UpdateCR1();
|
||||
|
@ -87,10 +91,10 @@ void Interpreter::ps_merge01(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::ps_merge10(UGeckoInstruction inst)
|
||||
{
|
||||
const auto& a = rPS(inst.FA);
|
||||
const auto& b = rPS(inst.FB);
|
||||
const auto& a = PowerPC::ppcState.ps[inst.FA];
|
||||
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)
|
||||
PowerPC::ppcState.UpdateCR1();
|
||||
|
@ -98,10 +102,10 @@ void Interpreter::ps_merge10(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::ps_merge11(UGeckoInstruction inst)
|
||||
{
|
||||
const auto& a = rPS(inst.FA);
|
||||
const auto& b = rPS(inst.FB);
|
||||
const auto& a = PowerPC::ppcState.ps[inst.FA];
|
||||
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)
|
||||
PowerPC::ppcState.UpdateCR1();
|
||||
|
@ -110,14 +114,18 @@ void Interpreter::ps_merge11(UGeckoInstruction inst)
|
|||
// From here on, the real deal.
|
||||
void Interpreter::ps_div(UGeckoInstruction inst)
|
||||
{
|
||||
const auto& a = rPS(inst.FA);
|
||||
const auto& b = rPS(inst.FB);
|
||||
const auto& a = PowerPC::ppcState.ps[inst.FA];
|
||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
||||
|
||||
const float ps0 = ForceSingle(FPSCR, NI_div(&FPSCR, a.PS0AsDouble(), b.PS0AsDouble()).value);
|
||||
const float ps1 = ForceSingle(FPSCR, NI_div(&FPSCR, a.PS1AsDouble(), b.PS1AsDouble()).value);
|
||||
const float ps0 =
|
||||
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::UpdateFPRFSingle(ps0);
|
||||
PowerPC::ppcState.ps[inst.FD].SetBoth(ps0, ps1);
|
||||
PowerPC::ppcState.UpdateFPRFSingle(ps0);
|
||||
|
||||
if (inst.Rc)
|
||||
PowerPC::ppcState.UpdateCR1();
|
||||
|
@ -126,26 +134,26 @@ void Interpreter::ps_div(UGeckoInstruction inst)
|
|||
void Interpreter::ps_res(UGeckoInstruction inst)
|
||||
{
|
||||
// this code is based on the real hardware tests
|
||||
const double a = rPS(inst.FB).PS0AsDouble();
|
||||
const double b = rPS(inst.FB).PS1AsDouble();
|
||||
const double a = PowerPC::ppcState.ps[inst.FB].PS0AsDouble();
|
||||
const double b = PowerPC::ppcState.ps[inst.FB].PS1AsDouble();
|
||||
|
||||
if (a == 0.0 || b == 0.0)
|
||||
{
|
||||
SetFPException(&FPSCR, FPSCR_ZX);
|
||||
FPSCR.ClearFIFR();
|
||||
SetFPException(&PowerPC::ppcState.fpscr, FPSCR_ZX);
|
||||
PowerPC::ppcState.fpscr.ClearFIFR();
|
||||
}
|
||||
|
||||
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))
|
||||
SetFPException(&FPSCR, FPSCR_VXSNAN);
|
||||
SetFPException(&PowerPC::ppcState.fpscr, FPSCR_VXSNAN);
|
||||
|
||||
const double ps0 = Common::ApproximateReciprocal(a);
|
||||
const double ps1 = Common::ApproximateReciprocal(b);
|
||||
|
||||
rPS(inst.FD).SetBoth(ps0, ps1);
|
||||
PowerPC::UpdateFPRFSingle(float(ps0));
|
||||
PowerPC::ppcState.ps[inst.FD].SetBoth(ps0, ps1);
|
||||
PowerPC::ppcState.UpdateFPRFSingle(float(ps0));
|
||||
|
||||
if (inst.Rc)
|
||||
PowerPC::ppcState.UpdateCR1();
|
||||
|
@ -153,32 +161,34 @@ void Interpreter::ps_res(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::ps_rsqrte(UGeckoInstruction inst)
|
||||
{
|
||||
const double ps0 = rPS(inst.FB).PS0AsDouble();
|
||||
const double ps1 = rPS(inst.FB).PS1AsDouble();
|
||||
const double ps0 = PowerPC::ppcState.ps[inst.FB].PS0AsDouble();
|
||||
const double ps1 = PowerPC::ppcState.ps[inst.FB].PS1AsDouble();
|
||||
|
||||
if (ps0 == 0.0 || ps1 == 0.0)
|
||||
{
|
||||
SetFPException(&FPSCR, FPSCR_ZX);
|
||||
FPSCR.ClearFIFR();
|
||||
SetFPException(&PowerPC::ppcState.fpscr, FPSCR_ZX);
|
||||
PowerPC::ppcState.fpscr.ClearFIFR();
|
||||
}
|
||||
|
||||
if (ps0 < 0.0 || ps1 < 0.0)
|
||||
{
|
||||
SetFPException(&FPSCR, FPSCR_VXSQRT);
|
||||
FPSCR.ClearFIFR();
|
||||
SetFPException(&PowerPC::ppcState.fpscr, FPSCR_VXSQRT);
|
||||
PowerPC::ppcState.fpscr.ClearFIFR();
|
||||
}
|
||||
|
||||
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))
|
||||
SetFPException(&FPSCR, FPSCR_VXSNAN);
|
||||
SetFPException(&PowerPC::ppcState.fpscr, FPSCR_VXSNAN);
|
||||
|
||||
const float dst_ps0 = ForceSingle(FPSCR, Common::ApproximateReciprocalSquareRoot(ps0));
|
||||
const float dst_ps1 = ForceSingle(FPSCR, Common::ApproximateReciprocalSquareRoot(ps1));
|
||||
const float dst_ps0 =
|
||||
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::UpdateFPRFSingle(dst_ps0);
|
||||
PowerPC::ppcState.ps[inst.FD].SetBoth(dst_ps0, dst_ps1);
|
||||
PowerPC::ppcState.UpdateFPRFSingle(dst_ps0);
|
||||
|
||||
if (inst.Rc)
|
||||
PowerPC::ppcState.UpdateCR1();
|
||||
|
@ -186,14 +196,18 @@ void Interpreter::ps_rsqrte(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::ps_sub(UGeckoInstruction inst)
|
||||
{
|
||||
const auto& a = rPS(inst.FA);
|
||||
const auto& b = rPS(inst.FB);
|
||||
const auto& a = PowerPC::ppcState.ps[inst.FA];
|
||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
||||
|
||||
const float ps0 = ForceSingle(FPSCR, NI_sub(&FPSCR, a.PS0AsDouble(), b.PS0AsDouble()).value);
|
||||
const float ps1 = ForceSingle(FPSCR, NI_sub(&FPSCR, a.PS1AsDouble(), b.PS1AsDouble()).value);
|
||||
const float ps0 =
|
||||
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::UpdateFPRFSingle(ps0);
|
||||
PowerPC::ppcState.ps[inst.FD].SetBoth(ps0, ps1);
|
||||
PowerPC::ppcState.UpdateFPRFSingle(ps0);
|
||||
|
||||
if (inst.Rc)
|
||||
PowerPC::ppcState.UpdateCR1();
|
||||
|
@ -201,14 +215,18 @@ void Interpreter::ps_sub(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::ps_add(UGeckoInstruction inst)
|
||||
{
|
||||
const auto& a = rPS(inst.FA);
|
||||
const auto& b = rPS(inst.FB);
|
||||
const auto& a = PowerPC::ppcState.ps[inst.FA];
|
||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
||||
|
||||
const float ps0 = ForceSingle(FPSCR, NI_add(&FPSCR, a.PS0AsDouble(), b.PS0AsDouble()).value);
|
||||
const float ps1 = ForceSingle(FPSCR, NI_add(&FPSCR, a.PS1AsDouble(), b.PS1AsDouble()).value);
|
||||
const float ps0 =
|
||||
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::UpdateFPRFSingle(ps0);
|
||||
PowerPC::ppcState.ps[inst.FD].SetBoth(ps0, ps1);
|
||||
PowerPC::ppcState.UpdateFPRFSingle(ps0);
|
||||
|
||||
if (inst.Rc)
|
||||
PowerPC::ppcState.UpdateCR1();
|
||||
|
@ -216,17 +234,19 @@ void Interpreter::ps_add(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::ps_mul(UGeckoInstruction inst)
|
||||
{
|
||||
const auto& a = rPS(inst.FA);
|
||||
const auto& c = rPS(inst.FC);
|
||||
const auto& a = PowerPC::ppcState.ps[inst.FA];
|
||||
const auto& c = PowerPC::ppcState.ps[inst.FC];
|
||||
|
||||
const double c0 = Force25Bit(c.PS0AsDouble());
|
||||
const double c1 = Force25Bit(c.PS1AsDouble());
|
||||
|
||||
const float ps0 = ForceSingle(FPSCR, NI_mul(&FPSCR, a.PS0AsDouble(), c0).value);
|
||||
const float ps1 = ForceSingle(FPSCR, NI_mul(&FPSCR, a.PS1AsDouble(), c1).value);
|
||||
const float ps0 = ForceSingle(PowerPC::ppcState.fpscr,
|
||||
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::UpdateFPRFSingle(ps0);
|
||||
PowerPC::ppcState.ps[inst.FD].SetBoth(ps0, ps1);
|
||||
PowerPC::ppcState.UpdateFPRFSingle(ps0);
|
||||
|
||||
if (inst.Rc)
|
||||
PowerPC::ppcState.UpdateCR1();
|
||||
|
@ -234,18 +254,22 @@ void Interpreter::ps_mul(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::ps_msub(UGeckoInstruction inst)
|
||||
{
|
||||
const auto& a = rPS(inst.FA);
|
||||
const auto& b = rPS(inst.FB);
|
||||
const auto& c = rPS(inst.FC);
|
||||
const auto& a = PowerPC::ppcState.ps[inst.FA];
|
||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
||||
const auto& c = PowerPC::ppcState.ps[inst.FC];
|
||||
|
||||
const double c0 = Force25Bit(c.PS0AsDouble());
|
||||
const double c1 = Force25Bit(c.PS1AsDouble());
|
||||
|
||||
const float ps0 = ForceSingle(FPSCR, NI_msub(&FPSCR, a.PS0AsDouble(), c0, b.PS0AsDouble()).value);
|
||||
const float ps1 = ForceSingle(FPSCR, NI_msub(&FPSCR, a.PS1AsDouble(), c1, b.PS1AsDouble()).value);
|
||||
const float ps0 =
|
||||
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::UpdateFPRFSingle(ps0);
|
||||
PowerPC::ppcState.ps[inst.FD].SetBoth(ps0, ps1);
|
||||
PowerPC::ppcState.UpdateFPRFSingle(ps0);
|
||||
|
||||
if (inst.Rc)
|
||||
PowerPC::ppcState.UpdateCR1();
|
||||
|
@ -253,18 +277,22 @@ void Interpreter::ps_msub(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::ps_madd(UGeckoInstruction inst)
|
||||
{
|
||||
const auto& a = rPS(inst.FA);
|
||||
const auto& b = rPS(inst.FB);
|
||||
const auto& c = rPS(inst.FC);
|
||||
const auto& a = PowerPC::ppcState.ps[inst.FA];
|
||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
||||
const auto& c = PowerPC::ppcState.ps[inst.FC];
|
||||
|
||||
const double c0 = Force25Bit(c.PS0AsDouble());
|
||||
const double c1 = Force25Bit(c.PS1AsDouble());
|
||||
|
||||
const float ps0 = ForceSingle(FPSCR, NI_madd(&FPSCR, a.PS0AsDouble(), c0, b.PS0AsDouble()).value);
|
||||
const float ps1 = ForceSingle(FPSCR, NI_madd(&FPSCR, a.PS1AsDouble(), c1, b.PS1AsDouble()).value);
|
||||
const float ps0 =
|
||||
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::UpdateFPRFSingle(ps0);
|
||||
PowerPC::ppcState.ps[inst.FD].SetBoth(ps0, ps1);
|
||||
PowerPC::ppcState.UpdateFPRFSingle(ps0);
|
||||
|
||||
if (inst.Rc)
|
||||
PowerPC::ppcState.UpdateCR1();
|
||||
|
@ -272,23 +300,25 @@ void Interpreter::ps_madd(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::ps_nmsub(UGeckoInstruction inst)
|
||||
{
|
||||
const auto& a = rPS(inst.FA);
|
||||
const auto& b = rPS(inst.FB);
|
||||
const auto& c = rPS(inst.FC);
|
||||
const auto& a = PowerPC::ppcState.ps[inst.FA];
|
||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
||||
const auto& c = PowerPC::ppcState.ps[inst.FC];
|
||||
|
||||
const double c0 = Force25Bit(c.PS0AsDouble());
|
||||
const double c1 = Force25Bit(c.PS1AsDouble());
|
||||
|
||||
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 =
|
||||
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 ps1 = std::isnan(tmp1) ? tmp1 : -tmp1;
|
||||
|
||||
rPS(inst.FD).SetBoth(ps0, ps1);
|
||||
PowerPC::UpdateFPRFSingle(ps0);
|
||||
PowerPC::ppcState.ps[inst.FD].SetBoth(ps0, ps1);
|
||||
PowerPC::ppcState.UpdateFPRFSingle(ps0);
|
||||
|
||||
if (inst.Rc)
|
||||
PowerPC::ppcState.UpdateCR1();
|
||||
|
@ -296,23 +326,25 @@ void Interpreter::ps_nmsub(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::ps_nmadd(UGeckoInstruction inst)
|
||||
{
|
||||
const auto& a = rPS(inst.FA);
|
||||
const auto& b = rPS(inst.FB);
|
||||
const auto& c = rPS(inst.FC);
|
||||
const auto& a = PowerPC::ppcState.ps[inst.FA];
|
||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
||||
const auto& c = PowerPC::ppcState.ps[inst.FC];
|
||||
|
||||
const double c0 = Force25Bit(c.PS0AsDouble());
|
||||
const double c1 = Force25Bit(c.PS1AsDouble());
|
||||
|
||||
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 =
|
||||
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 ps1 = std::isnan(tmp1) ? tmp1 : -tmp1;
|
||||
|
||||
rPS(inst.FD).SetBoth(ps0, ps1);
|
||||
PowerPC::UpdateFPRFSingle(ps0);
|
||||
PowerPC::ppcState.ps[inst.FD].SetBoth(ps0, ps1);
|
||||
PowerPC::ppcState.UpdateFPRFSingle(ps0);
|
||||
|
||||
if (inst.Rc)
|
||||
PowerPC::ppcState.UpdateCR1();
|
||||
|
@ -320,15 +352,17 @@ void Interpreter::ps_nmadd(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::ps_sum0(UGeckoInstruction inst)
|
||||
{
|
||||
const auto& a = rPS(inst.FA);
|
||||
const auto& b = rPS(inst.FB);
|
||||
const auto& c = rPS(inst.FC);
|
||||
const auto& a = PowerPC::ppcState.ps[inst.FA];
|
||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
||||
const auto& c = PowerPC::ppcState.ps[inst.FC];
|
||||
|
||||
const float ps0 = ForceSingle(FPSCR, NI_add(&FPSCR, a.PS0AsDouble(), b.PS1AsDouble()).value);
|
||||
const float ps1 = ForceSingle(FPSCR, c.PS1AsDouble());
|
||||
const float ps0 =
|
||||
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::UpdateFPRFSingle(ps0);
|
||||
PowerPC::ppcState.ps[inst.FD].SetBoth(ps0, ps1);
|
||||
PowerPC::ppcState.UpdateFPRFSingle(ps0);
|
||||
|
||||
if (inst.Rc)
|
||||
PowerPC::ppcState.UpdateCR1();
|
||||
|
@ -336,15 +370,17 @@ void Interpreter::ps_sum0(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::ps_sum1(UGeckoInstruction inst)
|
||||
{
|
||||
const auto& a = rPS(inst.FA);
|
||||
const auto& b = rPS(inst.FB);
|
||||
const auto& c = rPS(inst.FC);
|
||||
const auto& a = PowerPC::ppcState.ps[inst.FA];
|
||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
||||
const auto& c = PowerPC::ppcState.ps[inst.FC];
|
||||
|
||||
const float ps0 = ForceSingle(FPSCR, c.PS0AsDouble());
|
||||
const float ps1 = ForceSingle(FPSCR, NI_add(&FPSCR, a.PS0AsDouble(), b.PS1AsDouble()).value);
|
||||
const float ps0 = ForceSingle(PowerPC::ppcState.fpscr, c.PS0AsDouble());
|
||||
const float ps1 =
|
||||
ForceSingle(PowerPC::ppcState.fpscr,
|
||||
NI_add(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), b.PS1AsDouble()).value);
|
||||
|
||||
rPS(inst.FD).SetBoth(ps0, ps1);
|
||||
PowerPC::UpdateFPRFSingle(ps1);
|
||||
PowerPC::ppcState.ps[inst.FD].SetBoth(ps0, ps1);
|
||||
PowerPC::ppcState.UpdateFPRFSingle(ps1);
|
||||
|
||||
if (inst.Rc)
|
||||
PowerPC::ppcState.UpdateCR1();
|
||||
|
@ -352,15 +388,17 @@ void Interpreter::ps_sum1(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::ps_muls0(UGeckoInstruction inst)
|
||||
{
|
||||
const auto& a = rPS(inst.FA);
|
||||
const auto& c = rPS(inst.FC);
|
||||
const auto& a = PowerPC::ppcState.ps[inst.FA];
|
||||
const auto& c = PowerPC::ppcState.ps[inst.FC];
|
||||
|
||||
const double c0 = Force25Bit(c.PS0AsDouble());
|
||||
const float ps0 = ForceSingle(FPSCR, NI_mul(&FPSCR, a.PS0AsDouble(), c0).value);
|
||||
const float ps1 = ForceSingle(FPSCR, NI_mul(&FPSCR, a.PS1AsDouble(), c0).value);
|
||||
const float ps0 = ForceSingle(PowerPC::ppcState.fpscr,
|
||||
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::UpdateFPRFSingle(ps0);
|
||||
PowerPC::ppcState.ps[inst.FD].SetBoth(ps0, ps1);
|
||||
PowerPC::ppcState.UpdateFPRFSingle(ps0);
|
||||
|
||||
if (inst.Rc)
|
||||
PowerPC::ppcState.UpdateCR1();
|
||||
|
@ -368,15 +406,17 @@ void Interpreter::ps_muls0(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::ps_muls1(UGeckoInstruction inst)
|
||||
{
|
||||
const auto& a = rPS(inst.FA);
|
||||
const auto& c = rPS(inst.FC);
|
||||
const auto& a = PowerPC::ppcState.ps[inst.FA];
|
||||
const auto& c = PowerPC::ppcState.ps[inst.FC];
|
||||
|
||||
const double c1 = Force25Bit(c.PS1AsDouble());
|
||||
const float ps0 = ForceSingle(FPSCR, NI_mul(&FPSCR, a.PS0AsDouble(), c1).value);
|
||||
const float ps1 = ForceSingle(FPSCR, NI_mul(&FPSCR, a.PS1AsDouble(), c1).value);
|
||||
const float ps0 = ForceSingle(PowerPC::ppcState.fpscr,
|
||||
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::UpdateFPRFSingle(ps0);
|
||||
PowerPC::ppcState.ps[inst.FD].SetBoth(ps0, ps1);
|
||||
PowerPC::ppcState.UpdateFPRFSingle(ps0);
|
||||
|
||||
if (inst.Rc)
|
||||
PowerPC::ppcState.UpdateCR1();
|
||||
|
@ -384,16 +424,20 @@ void Interpreter::ps_muls1(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::ps_madds0(UGeckoInstruction inst)
|
||||
{
|
||||
const auto& a = rPS(inst.FA);
|
||||
const auto& b = rPS(inst.FB);
|
||||
const auto& c = rPS(inst.FC);
|
||||
const auto& a = PowerPC::ppcState.ps[inst.FA];
|
||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
||||
const auto& c = PowerPC::ppcState.ps[inst.FC];
|
||||
|
||||
const double c0 = Force25Bit(c.PS0AsDouble());
|
||||
const float ps0 = ForceSingle(FPSCR, NI_madd(&FPSCR, a.PS0AsDouble(), c0, b.PS0AsDouble()).value);
|
||||
const float ps1 = ForceSingle(FPSCR, NI_madd(&FPSCR, a.PS1AsDouble(), c0, b.PS1AsDouble()).value);
|
||||
const float ps0 =
|
||||
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::UpdateFPRFSingle(ps0);
|
||||
PowerPC::ppcState.ps[inst.FD].SetBoth(ps0, ps1);
|
||||
PowerPC::ppcState.UpdateFPRFSingle(ps0);
|
||||
|
||||
if (inst.Rc)
|
||||
PowerPC::ppcState.UpdateCR1();
|
||||
|
@ -401,16 +445,20 @@ void Interpreter::ps_madds0(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::ps_madds1(UGeckoInstruction inst)
|
||||
{
|
||||
const auto& a = rPS(inst.FA);
|
||||
const auto& b = rPS(inst.FB);
|
||||
const auto& c = rPS(inst.FC);
|
||||
const auto& a = PowerPC::ppcState.ps[inst.FA];
|
||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
||||
const auto& c = PowerPC::ppcState.ps[inst.FC];
|
||||
|
||||
const double c1 = Force25Bit(c.PS1AsDouble());
|
||||
const float ps0 = ForceSingle(FPSCR, NI_madd(&FPSCR, a.PS0AsDouble(), c1, b.PS0AsDouble()).value);
|
||||
const float ps1 = ForceSingle(FPSCR, NI_madd(&FPSCR, a.PS1AsDouble(), c1, b.PS1AsDouble()).value);
|
||||
const float ps0 =
|
||||
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::UpdateFPRFSingle(ps0);
|
||||
PowerPC::ppcState.ps[inst.FD].SetBoth(ps0, ps1);
|
||||
PowerPC::ppcState.UpdateFPRFSingle(ps0);
|
||||
|
||||
if (inst.Rc)
|
||||
PowerPC::ppcState.UpdateCR1();
|
||||
|
@ -418,32 +466,32 @@ void Interpreter::ps_madds1(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::ps_cmpu0(UGeckoInstruction inst)
|
||||
{
|
||||
const auto& a = rPS(inst.FA);
|
||||
const auto& b = rPS(inst.FB);
|
||||
const auto& a = PowerPC::ppcState.ps[inst.FA];
|
||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
||||
|
||||
Helper_FloatCompareUnordered(inst, a.PS0AsDouble(), b.PS0AsDouble());
|
||||
}
|
||||
|
||||
void Interpreter::ps_cmpo0(UGeckoInstruction inst)
|
||||
{
|
||||
const auto& a = rPS(inst.FA);
|
||||
const auto& b = rPS(inst.FB);
|
||||
const auto& a = PowerPC::ppcState.ps[inst.FA];
|
||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
||||
|
||||
Helper_FloatCompareOrdered(inst, a.PS0AsDouble(), b.PS0AsDouble());
|
||||
}
|
||||
|
||||
void Interpreter::ps_cmpu1(UGeckoInstruction inst)
|
||||
{
|
||||
const auto& a = rPS(inst.FA);
|
||||
const auto& b = rPS(inst.FB);
|
||||
const auto& a = PowerPC::ppcState.ps[inst.FA];
|
||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
||||
|
||||
Helper_FloatCompareUnordered(inst, a.PS1AsDouble(), b.PS1AsDouble());
|
||||
}
|
||||
|
||||
void Interpreter::ps_cmpo1(UGeckoInstruction inst)
|
||||
{
|
||||
const auto& a = rPS(inst.FA);
|
||||
const auto& b = rPS(inst.FB);
|
||||
const auto& a = PowerPC::ppcState.ps[inst.FA];
|
||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
||||
|
||||
Helper_FloatCompareOrdered(inst, a.PS1AsDouble(), b.PS1AsDouble());
|
||||
}
|
||||
|
|
|
@ -36,8 +36,8 @@ void Interpreter::mtfsb0x(UGeckoInstruction inst)
|
|||
{
|
||||
u32 b = 0x80000000 >> inst.CRBD;
|
||||
|
||||
FPSCR.Hex &= ~b;
|
||||
FPSCRUpdated(&FPSCR);
|
||||
PowerPC::ppcState.fpscr.Hex &= ~b;
|
||||
FPSCRUpdated(&PowerPC::ppcState.fpscr);
|
||||
|
||||
if (inst.Rc)
|
||||
PowerPC::ppcState.UpdateCR1();
|
||||
|
@ -50,11 +50,11 @@ void Interpreter::mtfsb1x(UGeckoInstruction inst)
|
|||
const u32 b = 0x80000000 >> bit;
|
||||
|
||||
if ((b & FPSCR_ANY_X) != 0)
|
||||
SetFPException(&FPSCR, b);
|
||||
SetFPException(&PowerPC::ppcState.fpscr, b);
|
||||
else
|
||||
FPSCR |= b;
|
||||
PowerPC::ppcState.fpscr |= b;
|
||||
|
||||
FPSCRUpdated(&FPSCR);
|
||||
FPSCRUpdated(&PowerPC::ppcState.fpscr);
|
||||
|
||||
if (inst.Rc)
|
||||
PowerPC::ppcState.UpdateCR1();
|
||||
|
@ -67,9 +67,9 @@ void Interpreter::mtfsfix(UGeckoInstruction inst)
|
|||
const u32 mask = (pre_shifted_mask >> (4 * field));
|
||||
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)
|
||||
PowerPC::ppcState.UpdateCR1();
|
||||
|
@ -85,8 +85,9 @@ void Interpreter::mtfsfx(UGeckoInstruction inst)
|
|||
m |= (0xFU << (i * 4));
|
||||
}
|
||||
|
||||
FPSCR = (FPSCR.Hex & ~m) | (static_cast<u32>(rPS(inst.FB).PS0AsU64()) & m);
|
||||
FPSCRUpdated(&FPSCR);
|
||||
PowerPC::ppcState.fpscr = (PowerPC::ppcState.fpscr.Hex & ~m) |
|
||||
(static_cast<u32>(PowerPC::ppcState.ps[inst.FB].PS0AsU64()) & m);
|
||||
FPSCRUpdated(&PowerPC::ppcState.fpscr);
|
||||
|
||||
if (inst.Rc)
|
||||
PowerPC::ppcState.UpdateCR1();
|
||||
|
@ -94,14 +95,14 @@ void Interpreter::mtfsfx(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_so_ov = 0;
|
||||
}
|
||||
|
||||
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)
|
||||
|
@ -109,7 +110,7 @@ void Interpreter::mtcrf(UGeckoInstruction inst)
|
|||
const u32 crm = inst.CRM;
|
||||
if (crm == 0xFF)
|
||||
{
|
||||
PowerPC::ppcState.cr.Set(rGPR[inst.RS]);
|
||||
PowerPC::ppcState.cr.Set(PowerPC::ppcState.gpr[inst.RS]);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -121,56 +122,57 @@ void Interpreter::mtcrf(UGeckoInstruction inst)
|
|||
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)
|
||||
{
|
||||
if (MSR.PR)
|
||||
if (PowerPC::ppcState.msr.PR)
|
||||
{
|
||||
GenerateProgramException(ProgramExceptionCause::PrivilegedInstruction);
|
||||
return;
|
||||
}
|
||||
|
||||
rGPR[inst.RD] = MSR.Hex;
|
||||
PowerPC::ppcState.gpr[inst.RD] = PowerPC::ppcState.msr.Hex;
|
||||
}
|
||||
|
||||
void Interpreter::mfsr(UGeckoInstruction inst)
|
||||
{
|
||||
if (MSR.PR)
|
||||
if (PowerPC::ppcState.msr.PR)
|
||||
{
|
||||
GenerateProgramException(ProgramExceptionCause::PrivilegedInstruction);
|
||||
return;
|
||||
}
|
||||
|
||||
rGPR[inst.RD] = PowerPC::ppcState.sr[inst.SR];
|
||||
PowerPC::ppcState.gpr[inst.RD] = PowerPC::ppcState.sr[inst.SR];
|
||||
}
|
||||
|
||||
void Interpreter::mfsrin(UGeckoInstruction inst)
|
||||
{
|
||||
if (MSR.PR)
|
||||
if (PowerPC::ppcState.msr.PR)
|
||||
{
|
||||
GenerateProgramException(ProgramExceptionCause::PrivilegedInstruction);
|
||||
return;
|
||||
}
|
||||
|
||||
const u32 index = (rGPR[inst.RB] >> 28) & 0xF;
|
||||
rGPR[inst.RD] = PowerPC::ppcState.sr[index];
|
||||
const u32 index = (PowerPC::ppcState.gpr[inst.RB] >> 28) & 0xF;
|
||||
PowerPC::ppcState.gpr[inst.RD] = PowerPC::ppcState.sr[index];
|
||||
}
|
||||
|
||||
void Interpreter::mtmsr(UGeckoInstruction inst)
|
||||
{
|
||||
if (MSR.PR)
|
||||
if (PowerPC::ppcState.msr.PR)
|
||||
{
|
||||
GenerateProgramException(ProgramExceptionCause::PrivilegedInstruction);
|
||||
return;
|
||||
}
|
||||
|
||||
MSR.Hex = rGPR[inst.RS];
|
||||
PowerPC::ppcState.msr.Hex = PowerPC::ppcState.gpr[inst.RS];
|
||||
|
||||
// FE0/FE1 may have been set
|
||||
CheckFPExceptions(FPSCR);
|
||||
CheckFPExceptions(PowerPC::ppcState.fpscr);
|
||||
|
||||
PowerPC::CheckExceptions();
|
||||
m_end_block = true;
|
||||
|
@ -180,27 +182,27 @@ void Interpreter::mtmsr(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::mtsr(UGeckoInstruction inst)
|
||||
{
|
||||
if (MSR.PR)
|
||||
if (PowerPC::ppcState.msr.PR)
|
||||
{
|
||||
GenerateProgramException(ProgramExceptionCause::PrivilegedInstruction);
|
||||
return;
|
||||
}
|
||||
|
||||
const u32 index = inst.SR;
|
||||
const u32 value = rGPR[inst.RS];
|
||||
const u32 value = PowerPC::ppcState.gpr[inst.RS];
|
||||
PowerPC::ppcState.SetSR(index, value);
|
||||
}
|
||||
|
||||
void Interpreter::mtsrin(UGeckoInstruction inst)
|
||||
{
|
||||
if (MSR.PR)
|
||||
if (PowerPC::ppcState.msr.PR)
|
||||
{
|
||||
GenerateProgramException(ProgramExceptionCause::PrivilegedInstruction);
|
||||
return;
|
||||
}
|
||||
|
||||
const u32 index = (rGPR[inst.RB] >> 28) & 0xF;
|
||||
const u32 value = rGPR[inst.RS];
|
||||
const u32 index = (PowerPC::ppcState.gpr[inst.RB] >> 28) & 0xF;
|
||||
const u32 value = PowerPC::ppcState.gpr[inst.RS];
|
||||
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);
|
||||
|
||||
// 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 &&
|
||||
index != SPR_TU)
|
||||
if (PowerPC::ppcState.msr.PR && index != SPR_XER && index != SPR_LR && index != SPR_CTR &&
|
||||
index != SPR_TL && index != SPR_TU)
|
||||
{
|
||||
GenerateProgramException(ProgramExceptionCause::PrivilegedInstruction);
|
||||
return;
|
||||
|
@ -226,9 +228,9 @@ void Interpreter::mfspr(UGeckoInstruction inst)
|
|||
switch (index)
|
||||
{
|
||||
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;
|
||||
|
||||
|
@ -246,40 +248,40 @@ void Interpreter::mfspr(UGeckoInstruction inst)
|
|||
// 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).
|
||||
if (Core::System::GetInstance().GetGPFifo().IsBNE())
|
||||
rSPR(index) |= 1;
|
||||
PowerPC::ppcState.spr[index] |= 1;
|
||||
else
|
||||
rSPR(index) &= ~1;
|
||||
PowerPC::ppcState.spr[index] &= ~1;
|
||||
}
|
||||
break;
|
||||
|
||||
case SPR_XER:
|
||||
rSPR(index) = PowerPC::GetXER().Hex;
|
||||
PowerPC::ppcState.spr[index] = PowerPC::ppcState.GetXER().Hex;
|
||||
break;
|
||||
|
||||
case SPR_UPMC1:
|
||||
rSPR(index) = rSPR(SPR_PMC1);
|
||||
PowerPC::ppcState.spr[index] = PowerPC::ppcState.spr[SPR_PMC1];
|
||||
break;
|
||||
|
||||
case SPR_UPMC2:
|
||||
rSPR(index) = rSPR(SPR_PMC2);
|
||||
PowerPC::ppcState.spr[index] = PowerPC::ppcState.spr[SPR_PMC2];
|
||||
break;
|
||||
|
||||
case SPR_UPMC3:
|
||||
rSPR(index) = rSPR(SPR_PMC3);
|
||||
PowerPC::ppcState.spr[index] = PowerPC::ppcState.spr[SPR_PMC3];
|
||||
break;
|
||||
|
||||
case SPR_UPMC4:
|
||||
rSPR(index) = rSPR(SPR_PMC4);
|
||||
PowerPC::ppcState.spr[index] = PowerPC::ppcState.spr[SPR_PMC4];
|
||||
break;
|
||||
|
||||
case SPR_IABR:
|
||||
// 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
|
||||
// not apply to the DABR.
|
||||
rGPR[inst.RD] = rSPR(index) & ~1;
|
||||
PowerPC::ppcState.gpr[inst.RD] = PowerPC::ppcState.spr[index] & ~1;
|
||||
return;
|
||||
}
|
||||
rGPR[inst.RD] = rSPR(index);
|
||||
PowerPC::ppcState.gpr[inst.RD] = PowerPC::ppcState.spr[index];
|
||||
}
|
||||
|
||||
void Interpreter::mtspr(UGeckoInstruction inst)
|
||||
|
@ -287,14 +289,14 @@ void Interpreter::mtspr(UGeckoInstruction inst)
|
|||
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
|
||||
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);
|
||||
return;
|
||||
}
|
||||
|
||||
const u32 old_value = rSPR(index);
|
||||
rSPR(index) = rGPR[inst.RD];
|
||||
const u32 old_value = PowerPC::ppcState.spr[index];
|
||||
PowerPC::ppcState.spr[index] = PowerPC::ppcState.gpr[inst.RD];
|
||||
|
||||
// Our DMA emulation is highly inaccurate - instead of properly emulating the queue
|
||||
// and so on, we simply make all DMA:s complete instantaneously.
|
||||
|
@ -307,36 +309,38 @@ void Interpreter::mtspr(UGeckoInstruction inst)
|
|||
break;
|
||||
|
||||
case SPR_TL_W:
|
||||
TL = rGPR[inst.RD];
|
||||
TL(PowerPC::ppcState) = PowerPC::ppcState.gpr[inst.RD];
|
||||
SystemTimers::TimeBaseSet();
|
||||
break;
|
||||
|
||||
case SPR_TU_W:
|
||||
TU = rGPR[inst.RD];
|
||||
TU(PowerPC::ppcState) = PowerPC::ppcState.gpr[inst.RD];
|
||||
SystemTimers::TimeBaseSet();
|
||||
break;
|
||||
|
||||
case SPR_PVR:
|
||||
// PVR is a read-only register so maintain its value.
|
||||
rSPR(index) = old_value;
|
||||
PowerPC::ppcState.spr[index] = old_value;
|
||||
break;
|
||||
|
||||
case SPR_HID0: // HID0
|
||||
{
|
||||
UReg_HID0 old_hid0;
|
||||
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;
|
||||
INFO_LOG_FMT(POWERPC, "Flush Instruction Cache! ICE={}", HID0.ICE);
|
||||
HID0(PowerPC::ppcState).ICFI = 0;
|
||||
INFO_LOG_FMT(POWERPC, "Flush Instruction Cache! ICE={}", HID0(PowerPC::ppcState).ICE);
|
||||
// this is rather slow
|
||||
// most games do it only once during initialization
|
||||
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
|
||||
// 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.
|
||||
rSPR(index) &= 0xF8000000;
|
||||
PowerPC::ppcState.spr[index] &= 0xF8000000;
|
||||
break;
|
||||
|
||||
case SPR_HID2:
|
||||
|
@ -356,21 +360,23 @@ void Interpreter::mtspr(UGeckoInstruction inst)
|
|||
// TODO: emulate locked cache and DMA bits.
|
||||
// Only the lower half of the register (upper half from a little endian perspective)
|
||||
// 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;
|
||||
|
||||
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::DBATUpdated();
|
||||
}
|
||||
break;
|
||||
|
||||
case SPR_WPAR:
|
||||
ASSERT_MSG(POWERPC, rSPR(SPR_WPAR) == GPFifo::GATHER_PIPE_PHYSICAL_ADDRESS,
|
||||
"Gather pipe changed to unexpected address {:08x} @ PC {:08x}", rSPR(SPR_WPAR), PC);
|
||||
ASSERT_MSG(POWERPC, PowerPC::ppcState.spr[SPR_WPAR] == GPFifo::GATHER_PIPE_PHYSICAL_ADDRESS,
|
||||
"Gather pipe changed to unexpected address {:08x} @ PC {:08x}",
|
||||
PowerPC::ppcState.spr[SPR_WPAR], PowerPC::ppcState.pc);
|
||||
Core::System::GetInstance().GetGPFifo().ResetGatherPipe();
|
||||
break;
|
||||
|
||||
|
@ -388,20 +394,20 @@ void Interpreter::mtspr(UGeckoInstruction inst)
|
|||
case SPR_DMAL:
|
||||
// Locked cache<->Memory DMA
|
||||
// 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 cache_address = DMAL.LC_ADDR << 5;
|
||||
u32 length = ((DMAU.DMA_LEN_U << 2) | DMAL.DMA_LEN_L);
|
||||
const u32 mem_address = DMAU(PowerPC::ppcState).MEM_ADDR << 5;
|
||||
const u32 cache_address = DMAL(PowerPC::ppcState).LC_ADDR << 5;
|
||||
u32 length = ((DMAU(PowerPC::ppcState).DMA_LEN_U << 2) | DMAL(PowerPC::ppcState).DMA_LEN_L);
|
||||
|
||||
if (length == 0)
|
||||
length = 128;
|
||||
if (DMAL.DMA_LD)
|
||||
if (DMAL(PowerPC::ppcState).DMA_LD)
|
||||
PowerPC::DMA_MemoryToLC(cache_address, mem_address, length);
|
||||
else
|
||||
PowerPC::DMA_LCToMemory(mem_address, cache_address, length);
|
||||
}
|
||||
DMAL.DMA_T = 0;
|
||||
DMAL(PowerPC::ppcState).DMA_T = 0;
|
||||
break;
|
||||
|
||||
case SPR_L2CR:
|
||||
|
@ -409,7 +415,7 @@ void Interpreter::mtspr(UGeckoInstruction inst)
|
|||
|
||||
case SPR_DEC:
|
||||
// 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");
|
||||
PowerPC::ppcState.Exceptions |= EXCEPTION_DECREMENTER;
|
||||
|
@ -423,7 +429,7 @@ void Interpreter::mtspr(UGeckoInstruction inst)
|
|||
break;
|
||||
|
||||
case SPR_XER:
|
||||
PowerPC::SetXER(UReg_XER{rSPR(index)});
|
||||
PowerPC::ppcState.SetXER(UReg_XER{PowerPC::ppcState.spr[index]});
|
||||
break;
|
||||
|
||||
case SPR_DBAT0L:
|
||||
|
@ -442,9 +448,10 @@ void Interpreter::mtspr(UGeckoInstruction inst)
|
|||
case SPR_DBAT6U:
|
||||
case SPR_DBAT7L:
|
||||
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();
|
||||
}
|
||||
break;
|
||||
|
@ -465,9 +472,10 @@ void Interpreter::mtspr(UGeckoInstruction inst)
|
|||
case SPR_IBAT6U:
|
||||
case SPR_IBAT7L:
|
||||
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();
|
||||
}
|
||||
break;
|
||||
|
@ -484,7 +492,7 @@ void Interpreter::mtspr(UGeckoInstruction inst)
|
|||
constexpr u32 SIMULATED_TEMP = 42; // °C
|
||||
|
||||
auto UpdateThermalReg = [](UReg_THRM12* reg) {
|
||||
if (!THRM3.E || !reg->V)
|
||||
if (!THRM3(PowerPC::ppcState).E || !reg->V)
|
||||
{
|
||||
reg->TIV = 0;
|
||||
}
|
||||
|
@ -498,8 +506,8 @@ void Interpreter::mtspr(UGeckoInstruction inst)
|
|||
}
|
||||
};
|
||||
|
||||
UpdateThermalReg(&THRM1);
|
||||
UpdateThermalReg(&THRM2);
|
||||
UpdateThermalReg(&THRM1(PowerPC::ppcState));
|
||||
UpdateThermalReg(&THRM2(PowerPC::ppcState));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -585,18 +593,18 @@ void Interpreter::isync(UGeckoInstruction inst)
|
|||
void Interpreter::mcrfs(UGeckoInstruction inst)
|
||||
{
|
||||
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
|
||||
FPSCR.Hex &= ~((0xF << shift) & (FPSCR_FX | FPSCR_ANY_X));
|
||||
FPSCRUpdated(&FPSCR);
|
||||
PowerPC::ppcState.fpscr.Hex &= ~((0xF << shift) & (FPSCR_FX | FPSCR_ANY_X));
|
||||
FPSCRUpdated(&PowerPC::ppcState.fpscr);
|
||||
|
||||
PowerPC::ppcState.cr.SetField(inst.CRFD, fpflags);
|
||||
}
|
||||
|
||||
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)
|
||||
PowerPC::ppcState.UpdateCR1();
|
||||
|
|
|
@ -504,16 +504,17 @@ static void ImHere()
|
|||
if (!f)
|
||||
f.Open("log64.txt", "w");
|
||||
|
||||
f.WriteString(fmt::format("{0:08x}\n", PC));
|
||||
f.WriteString(fmt::format("{0:08x}\n", PowerPC::ppcState.pc));
|
||||
}
|
||||
if (been_here.find(PC) != been_here.end())
|
||||
if (been_here.find(PowerPC::ppcState.pc) != been_here.end())
|
||||
{
|
||||
been_here.find(PC)->second++;
|
||||
if ((been_here.find(PC)->second) & 1023)
|
||||
been_here.find(PowerPC::ppcState.pc)->second++;
|
||||
if ((been_here.find(PowerPC::ppcState.pc)->second) & 1023)
|
||||
return;
|
||||
}
|
||||
INFO_LOG_FMT(DYNA_REC, "I'm here - PC = {:08x} , LR = {:08x}", PC, LR);
|
||||
been_here[PC] = 1;
|
||||
INFO_LOG_FMT(DYNA_REC, "I'm here - PC = {:08x} , LR = {:08x}", PowerPC::ppcState.pc,
|
||||
LR(PowerPC::ppcState));
|
||||
been_here[PowerPC::ppcState.pc] = 1;
|
||||
}
|
||||
|
||||
bool Jit64::Cleanup()
|
||||
|
@ -534,11 +535,11 @@ bool Jit64::Cleanup()
|
|||
}
|
||||
|
||||
// SPEED HACK: MMCR0/MMCR1 should be checked at run-time, not at compile time.
|
||||
if (MMCR0.Hex || MMCR1.Hex)
|
||||
if (MMCR0(PowerPC::ppcState).Hex || MMCR1(PowerPC::ppcState).Hex)
|
||||
{
|
||||
ABI_PushRegistersAndAdjustStack({}, 0);
|
||||
ABI_CallFunctionCCC(PowerPC::UpdatePerformanceMonitor, js.downcountAmount, js.numLoadStoreInst,
|
||||
js.numFloatingPointInst);
|
||||
ABI_CallFunctionCCCP(PowerPC::UpdatePerformanceMonitor, js.downcountAmount, js.numLoadStoreInst,
|
||||
js.numFloatingPointInst, &PowerPC::ppcState);
|
||||
ABI_PopRegistersAndAdjustStack({}, 0);
|
||||
did_something = true;
|
||||
}
|
||||
|
@ -758,7 +759,9 @@ void Jit64::Trace()
|
|||
DEBUG_LOG_FMT(DYNA_REC,
|
||||
"JIT64 PC: {:08x} SRR0: {:08x} SRR1: {:08x} FPSCR: {:08x} "
|
||||
"MSR: {:08x} LR: {:08x} {} {}",
|
||||
PC, SRR0, SRR1, FPSCR.Hex, MSR.Hex, PowerPC::ppcState.spr[8], regs, fregs);
|
||||
PowerPC::ppcState.pc, SRR0(PowerPC::ppcState), SRR1(PowerPC::ppcState),
|
||||
PowerPC::ppcState.fpscr.Hex, PowerPC::ppcState.msr.Hex, PowerPC::ppcState.spr[8],
|
||||
regs, fregs);
|
||||
}
|
||||
|
||||
void Jit64::Jit(u32 em_address)
|
||||
|
@ -829,7 +832,7 @@ void Jit64::Jit(u32 em_address, bool clear_cache_and_retry_on_failure)
|
|||
if (code_block.m_memory_exception)
|
||||
{
|
||||
// Address of instruction could not be translated
|
||||
NPC = nextPC;
|
||||
PowerPC::ppcState.npc = nextPC;
|
||||
PowerPC::ppcState.Exceptions |= EXCEPTION_ISI;
|
||||
PowerPC::CheckExceptions();
|
||||
WARN_LOG_FMT(POWERPC, "ISI exception at {:#010x}", nextPC);
|
||||
|
@ -978,7 +981,7 @@ bool Jit64::DoJit(u32 em_address, JitBlock* b, u32 nextPC)
|
|||
// the start of the block in case our guess turns out wrong.
|
||||
for (int gqr : gqr_static)
|
||||
{
|
||||
u32 value = GQR(gqr);
|
||||
u32 value = GQR(PowerPC::ppcState, gqr);
|
||||
js.constantGqr[gqr] = value;
|
||||
CMP_or_TEST(32, PPCSTATE(spr[SPR_GQR0 + gqr]), Imm32(value));
|
||||
J_CC(CC_NZ, target);
|
||||
|
|
|
@ -320,7 +320,7 @@ void Jit64::dcbx(UGeckoInstruction inst)
|
|||
FixupBranch bat_lookup_failed;
|
||||
MOV(32, R(effective_address), R(addr));
|
||||
const u8* loop_start = GetCodePtr();
|
||||
if (MSR.IR)
|
||||
if (PowerPC::ppcState.msr.IR)
|
||||
{
|
||||
// Translate effective address to physical address.
|
||||
bat_lookup_failed = BATAddressLookup(addr, tmp, PowerPC::ibat_table.data());
|
||||
|
@ -349,7 +349,7 @@ void Jit64::dcbx(UGeckoInstruction inst)
|
|||
|
||||
SwitchToFarCode();
|
||||
SetJumpTarget(invalidate_needed);
|
||||
if (MSR.IR)
|
||||
if (PowerPC::ppcState.msr.IR)
|
||||
SetJumpTarget(bat_lookup_failed);
|
||||
|
||||
BitSet32 registersInUse = CallerSavedRegistersInUse();
|
||||
|
@ -422,7 +422,7 @@ void Jit64::dcbz(UGeckoInstruction inst)
|
|||
end_dcbz_hack = J_CC(CC_L);
|
||||
}
|
||||
|
||||
bool emit_fast_path = MSR.DR && m_jit.jo.fastmem_arena;
|
||||
bool emit_fast_path = PowerPC::ppcState.msr.DR && m_jit.jo.fastmem_arena;
|
||||
|
||||
if (emit_fast_path)
|
||||
{
|
||||
|
|
|
@ -23,7 +23,7 @@ void Jit64::psq_stXX(UGeckoInstruction inst)
|
|||
JITDISABLE(bJITLoadStorePairedOff);
|
||||
|
||||
// For performance, the AsmCommon routines assume address translation is on.
|
||||
FALLBACK_IF(!MSR.DR);
|
||||
FALLBACK_IF(!PowerPC::ppcState.msr.DR);
|
||||
|
||||
s32 offset = inst.SIMM_12;
|
||||
bool indexed = inst.OPCD == 4;
|
||||
|
@ -112,7 +112,7 @@ void Jit64::psq_lXX(UGeckoInstruction inst)
|
|||
JITDISABLE(bJITLoadStorePairedOff);
|
||||
|
||||
// For performance, the AsmCommon routines assume address translation is on.
|
||||
FALLBACK_IF(!MSR.DR);
|
||||
FALLBACK_IF(!PowerPC::ppcState.msr.DR);
|
||||
|
||||
s32 offset = inst.SIMM_12;
|
||||
bool indexed = inst.OPCD == 4;
|
||||
|
|
|
@ -367,7 +367,7 @@ void EmuCodeBlock::SafeLoadToReg(X64Reg reg_value, const Gen::OpArg& opAddress,
|
|||
}
|
||||
|
||||
FixupBranch exit;
|
||||
const bool dr_set = (flags & SAFE_LOADSTORE_DR_ON) || MSR.DR;
|
||||
const bool dr_set = (flags & SAFE_LOADSTORE_DR_ON) || PowerPC::ppcState.msr.DR;
|
||||
const bool fast_check_address = !slowmem && dr_set && m_jit.jo.fastmem_arena;
|
||||
if (fast_check_address)
|
||||
{
|
||||
|
@ -537,7 +537,7 @@ void EmuCodeBlock::SafeWriteRegToReg(OpArg reg_value, X64Reg reg_addr, int acces
|
|||
}
|
||||
|
||||
FixupBranch exit;
|
||||
const bool dr_set = (flags & SAFE_LOADSTORE_DR_ON) || MSR.DR;
|
||||
const bool dr_set = (flags & SAFE_LOADSTORE_DR_ON) || PowerPC::ppcState.msr.DR;
|
||||
const bool fast_check_address = !slowmem && dr_set && m_jit.jo.fastmem_arena;
|
||||
if (fast_check_address)
|
||||
{
|
||||
|
|
|
@ -288,12 +288,13 @@ void JitArm64::Cleanup()
|
|||
}
|
||||
|
||||
// SPEED HACK: MMCR0/MMCR1 should be checked at run-time, not at compile time.
|
||||
if (MMCR0.Hex || MMCR1.Hex)
|
||||
if (MMCR0(PowerPC::ppcState).Hex || MMCR1(PowerPC::ppcState).Hex)
|
||||
{
|
||||
MOVP2R(ARM64Reg::X8, &PowerPC::UpdatePerformanceMonitor);
|
||||
MOVI2R(ARM64Reg::X0, js.downcountAmount);
|
||||
MOVI2R(ARM64Reg::X1, js.numLoadStoreInst);
|
||||
MOVI2R(ARM64Reg::X2, js.numFloatingPointInst);
|
||||
MOVP2R(ARM64Reg::X3, &PowerPC::ppcState);
|
||||
BLR(ARM64Reg::X8);
|
||||
}
|
||||
}
|
||||
|
@ -705,7 +706,9 @@ void JitArm64::Trace()
|
|||
DEBUG_LOG_FMT(DYNA_REC,
|
||||
"JitArm64 PC: {:08x} SRR0: {:08x} SRR1: {:08x} FPSCR: {:08x} "
|
||||
"MSR: {:08x} LR: {:08x} {} {}",
|
||||
PC, SRR0, SRR1, FPSCR.Hex, MSR.Hex, PowerPC::ppcState.spr[8], regs, fregs);
|
||||
PowerPC::ppcState.pc, SRR0(PowerPC::ppcState), SRR1(PowerPC::ppcState),
|
||||
PowerPC::ppcState.fpscr.Hex, PowerPC::ppcState.msr.Hex, PowerPC::ppcState.spr[8],
|
||||
regs, fregs);
|
||||
}
|
||||
|
||||
void JitArm64::Jit(u32 em_address)
|
||||
|
@ -779,7 +782,7 @@ void JitArm64::Jit(u32 em_address, bool clear_cache_and_retry_on_failure)
|
|||
if (code_block.m_memory_exception)
|
||||
{
|
||||
// Address of instruction could not be translated
|
||||
NPC = nextPC;
|
||||
PowerPC::ppcState.npc = nextPC;
|
||||
PowerPC::ppcState.Exceptions |= EXCEPTION_ISI;
|
||||
PowerPC::CheckExceptions();
|
||||
WARN_LOG_FMT(POWERPC, "ISI exception at {:#010x}", nextPC);
|
||||
|
@ -895,7 +898,7 @@ bool JitArm64::DoJit(u32 em_address, JitBlock* b, u32 nextPC)
|
|||
js.pairedQuantizeAddresses.find(js.blockStart) == js.pairedQuantizeAddresses.end())
|
||||
{
|
||||
int gqr = *code_block.m_gqr_used.begin();
|
||||
if (!code_block.m_gqr_modified[gqr] && !GQR(gqr))
|
||||
if (!code_block.m_gqr_modified[gqr] && !GQR(PowerPC::ppcState, gqr))
|
||||
{
|
||||
LDR(IndexType::Unsigned, ARM64Reg::W0, PPC_REG, PPCSTATE_OFF_SPR(SPR_GQR0 + gqr));
|
||||
FixupBranch no_fail = CBZ(ARM64Reg::W0);
|
||||
|
|
|
@ -731,7 +731,7 @@ void JitArm64::dcbx(UGeckoInstruction inst)
|
|||
// Translate effective address to physical address.
|
||||
const u8* loop_start = GetCodePtr();
|
||||
FixupBranch bat_lookup_failed;
|
||||
if (MSR.IR)
|
||||
if (PowerPC::ppcState.msr.IR)
|
||||
{
|
||||
bat_lookup_failed =
|
||||
BATAddressLookup(physical_addr, effective_addr, WA, PowerPC::ibat_table.data());
|
||||
|
@ -760,7 +760,7 @@ void JitArm64::dcbx(UGeckoInstruction inst)
|
|||
|
||||
SwitchToFarCode();
|
||||
SetJumpTarget(invalidate_needed);
|
||||
if (MSR.IR)
|
||||
if (PowerPC::ppcState.msr.IR)
|
||||
SetJumpTarget(bat_lookup_failed);
|
||||
|
||||
BitSet32 gprs_to_push = gpr.GetCallerSavedUsed();
|
||||
|
|
|
@ -23,7 +23,7 @@ void JitArm64::psq_lXX(UGeckoInstruction inst)
|
|||
JITDISABLE(bJITLoadStorePairedOff);
|
||||
|
||||
// If we have a fastmem arena, the asm routines assume address translation is on.
|
||||
FALLBACK_IF(!js.assumeNoPairedQuantize && jo.fastmem_arena && !MSR.DR);
|
||||
FALLBACK_IF(!js.assumeNoPairedQuantize && jo.fastmem_arena && !PowerPC::ppcState.msr.DR);
|
||||
|
||||
// X30 is LR
|
||||
// X0 is the address
|
||||
|
@ -148,7 +148,7 @@ void JitArm64::psq_stXX(UGeckoInstruction inst)
|
|||
JITDISABLE(bJITLoadStorePairedOff);
|
||||
|
||||
// If we have a fastmem arena, the asm routines assume address translation is on.
|
||||
FALLBACK_IF(!js.assumeNoPairedQuantize && jo.fastmem_arena && !MSR.DR);
|
||||
FALLBACK_IF(!js.assumeNoPairedQuantize && jo.fastmem_arena && !PowerPC::ppcState.msr.DR);
|
||||
|
||||
// X30 is LR
|
||||
// X0 contains the scale
|
||||
|
|
|
@ -90,7 +90,8 @@ bool JitBase::CanMergeNextInstructions(int count) const
|
|||
void JitBase::UpdateMemoryAndExceptionOptions()
|
||||
{
|
||||
bool any_watchpoints = PowerPC::memchecks.HasAny();
|
||||
jo.fastmem = m_fastmem_enabled && jo.fastmem_arena && (MSR.DR || !any_watchpoints);
|
||||
jo.fastmem =
|
||||
m_fastmem_enabled && jo.fastmem_arena && (PowerPC::ppcState.msr.DR || !any_watchpoints);
|
||||
jo.memcheck = m_mmu_enabled || m_pause_on_panic_enabled || any_watchpoints;
|
||||
jo.fp_exceptions = m_enable_float_exceptions;
|
||||
jo.div_by_zero_exceptions = m_enable_div_by_zero_exceptions;
|
||||
|
|
|
@ -96,7 +96,7 @@ JitBlock* JitBaseBlockCache::AllocateBlock(u32 em_address)
|
|||
JitBlock& b = block_map.emplace(physical_address, JitBlock())->second;
|
||||
b.effectiveAddress = em_address;
|
||||
b.physicalAddress = physical_address;
|
||||
b.msrBits = MSR.Hex & JIT_CACHE_MSR_MASK;
|
||||
b.msrBits = PowerPC::ppcState.msr.Hex & JIT_CACHE_MSR_MASK;
|
||||
b.linkData.clear();
|
||||
b.fast_block_map_index = 0;
|
||||
return &b;
|
||||
|
@ -168,10 +168,14 @@ JitBlock* JitBaseBlockCache::GetBlockFromStartAddress(u32 addr, u32 msr)
|
|||
|
||||
const u8* JitBaseBlockCache::Dispatch()
|
||||
{
|
||||
JitBlock* block = fast_block_map[FastLookupIndexForAddress(PC)];
|
||||
JitBlock* block = fast_block_map[FastLookupIndexForAddress(PowerPC::ppcState.pc)];
|
||||
|
||||
if (!block || block->effectiveAddress != PC || block->msrBits != (MSR.Hex & JIT_CACHE_MSR_MASK))
|
||||
block = MoveBlockIntoFastCache(PC, MSR.Hex & JIT_CACHE_MSR_MASK);
|
||||
if (!block || block->effectiveAddress != PowerPC::ppcState.pc ||
|
||||
block->msrBits != (PowerPC::ppcState.msr.Hex & JIT_CACHE_MSR_MASK))
|
||||
{
|
||||
block = MoveBlockIntoFastCache(PowerPC::ppcState.pc,
|
||||
PowerPC::ppcState.msr.Hex & JIT_CACHE_MSR_MASK);
|
||||
}
|
||||
|
||||
if (!block)
|
||||
return nullptr;
|
||||
|
|
|
@ -153,12 +153,14 @@ std::variant<GetHostCodeError, GetHostCodeResult> GetHostCode(u32 address)
|
|||
return GetHostCodeError::NoJitActive;
|
||||
}
|
||||
|
||||
JitBlock* block = g_jit->GetBlockCache()->GetBlockFromStartAddress(address, MSR.Hex);
|
||||
JitBlock* block =
|
||||
g_jit->GetBlockCache()->GetBlockFromStartAddress(address, PowerPC::ppcState.msr.Hex);
|
||||
if (!block)
|
||||
{
|
||||
for (int i = 0; i < 500; i++)
|
||||
{
|
||||
block = g_jit->GetBlockCache()->GetBlockFromStartAddress(address - 4 * i, MSR.Hex);
|
||||
block = g_jit->GetBlockCache()->GetBlockFromStartAddress(address - 4 * i,
|
||||
PowerPC::ppcState.msr.Hex);
|
||||
if (block)
|
||||
break;
|
||||
}
|
||||
|
@ -264,20 +266,21 @@ void CompileExceptionCheck(ExceptionType type)
|
|||
break;
|
||||
}
|
||||
|
||||
if (PC != 0 && (exception_addresses->find(PC)) == (exception_addresses->end()))
|
||||
if (PowerPC::ppcState.pc != 0 &&
|
||||
(exception_addresses->find(PowerPC::ppcState.pc)) == (exception_addresses->end()))
|
||||
{
|
||||
if (type == ExceptionType::FIFOWrite)
|
||||
{
|
||||
// Check in case the code has been replaced since: do we need to do this?
|
||||
const OpType optype = PPCTables::GetOpInfo(PowerPC::HostRead_U32(PC))->type;
|
||||
const OpType optype = PPCTables::GetOpInfo(PowerPC::HostRead_U32(PowerPC::ppcState.pc))->type;
|
||||
if (optype != OpType::Store && optype != OpType::StoreFP && optype != OpType::StorePS)
|
||||
return;
|
||||
}
|
||||
exception_addresses->insert(PC);
|
||||
exception_addresses->insert(PowerPC::ppcState.pc);
|
||||
|
||||
// Invalidate the JIT block so that it gets recompiled with the external exception check
|
||||
// included.
|
||||
g_jit->GetBlockCache()->InvalidateICache(PC, 4, true);
|
||||
g_jit->GetBlockCache()->InvalidateICache(PowerPC::ppcState.pc, 4, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -191,7 +191,7 @@ static T ReadFromHardware(Memory::MemoryManager& memory, u32 em_address)
|
|||
|
||||
bool wi = false;
|
||||
|
||||
if (!never_translate && MSR.DR)
|
||||
if (!never_translate && PowerPC::ppcState.msr.DR)
|
||||
{
|
||||
auto translated_addr = TranslateAddress<flag>(em_address);
|
||||
if (!translated_addr.Success())
|
||||
|
@ -235,7 +235,7 @@ static T ReadFromHardware(Memory::MemoryManager& memory, u32 em_address)
|
|||
else
|
||||
{
|
||||
ppcState.dCache.Read(em_address, &value, sizeof(T),
|
||||
HID0.DLOCK || flag != XCheckTLBFlag::Read);
|
||||
HID0(PowerPC::ppcState).DLOCK || flag != XCheckTLBFlag::Read);
|
||||
}
|
||||
|
||||
return bswap(value);
|
||||
|
@ -254,7 +254,7 @@ static T ReadFromHardware(Memory::MemoryManager& memory, u32 em_address)
|
|||
else
|
||||
{
|
||||
ppcState.dCache.Read(em_address + 0x10000000, &value, sizeof(T),
|
||||
HID0.DLOCK || flag != XCheckTLBFlag::Read);
|
||||
HID0(PowerPC::ppcState).DLOCK || flag != XCheckTLBFlag::Read);
|
||||
}
|
||||
|
||||
return bswap(value);
|
||||
|
@ -270,7 +270,7 @@ static T ReadFromHardware(Memory::MemoryManager& memory, u32 em_address)
|
|||
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())
|
||||
{
|
||||
CPU::Break();
|
||||
|
@ -303,7 +303,7 @@ static void WriteToHardware(Core::System& system, Memory::MemoryManager& memory,
|
|||
|
||||
bool wi = false;
|
||||
|
||||
if (!never_translate && MSR.DR)
|
||||
if (!never_translate && PowerPC::ppcState.msr.DR)
|
||||
{
|
||||
auto translated_addr = TranslateAddress<flag>(em_address);
|
||||
if (!translated_addr.Success())
|
||||
|
@ -425,7 +425,7 @@ static void WriteToHardware(Core::System& system, Memory::MemoryManager& memory,
|
|||
em_address &= memory.GetRamMask();
|
||||
|
||||
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)
|
||||
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;
|
||||
|
||||
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)
|
||||
std::memcpy(&memory.GetEXRAM()[em_address], &swapped_data, size);
|
||||
|
@ -456,7 +459,7 @@ static void WriteToHardware(Core::System& system, Memory::MemoryManager& memory,
|
|||
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())
|
||||
{
|
||||
CPU::Break();
|
||||
|
@ -486,7 +489,7 @@ u32 Read_Opcode(u32 address)
|
|||
TryReadInstResult TryReadInstruction(u32 address)
|
||||
{
|
||||
bool from_bat = true;
|
||||
if (MSR.IR)
|
||||
if (PowerPC::ppcState.msr.IR)
|
||||
{
|
||||
auto tlb_addr = TranslateAddress<XCheckTLBFlag::Opcode>(address);
|
||||
if (!tlb_addr.Success())
|
||||
|
@ -537,7 +540,7 @@ std::optional<ReadResult<u32>> HostTryReadInstruction(const u32 address,
|
|||
case RequestedAddressSpace::Effective:
|
||||
{
|
||||
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:
|
||||
{
|
||||
|
@ -547,7 +550,7 @@ std::optional<ReadResult<u32>> HostTryReadInstruction(const u32 address,
|
|||
}
|
||||
case RequestedAddressSpace::Virtual:
|
||||
{
|
||||
if (!MSR.DR)
|
||||
if (!PowerPC::ppcState.msr.DR)
|
||||
return std::nullopt;
|
||||
const u32 value = ReadFromHardware<XCheckTLBFlag::OpcodeNoException, u32>(memory, address);
|
||||
return ReadResult<u32>(true, value);
|
||||
|
@ -575,7 +578,7 @@ static void Memcheck(u32 address, u64 var, bool write, size_t size)
|
|||
|
||||
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)
|
||||
return;
|
||||
|
||||
|
@ -658,7 +661,7 @@ static std::optional<ReadResult<T>> HostTryReadUX(const u32 address, RequestedAd
|
|||
case RequestedAddressSpace::Effective:
|
||||
{
|
||||
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:
|
||||
{
|
||||
|
@ -667,7 +670,7 @@ static std::optional<ReadResult<T>> HostTryReadUX(const u32 address, RequestedAd
|
|||
}
|
||||
case RequestedAddressSpace::Virtual:
|
||||
{
|
||||
if (!MSR.DR)
|
||||
if (!PowerPC::ppcState.msr.DR)
|
||||
return std::nullopt;
|
||||
T value = ReadFromHardware<XCheckTLBFlag::NoException, T>(memory, address);
|
||||
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:
|
||||
WriteToHardware<XCheckTLBFlag::NoException>(system, memory, address, var, size);
|
||||
return WriteResult(!!MSR.DR);
|
||||
return WriteResult(!!PowerPC::ppcState.msr.DR);
|
||||
case RequestedAddressSpace::Physical:
|
||||
WriteToHardware<XCheckTLBFlag::NoException, true>(system, memory, address, var, size);
|
||||
return WriteResult(false);
|
||||
case RequestedAddressSpace::Virtual:
|
||||
if (!MSR.DR)
|
||||
if (!PowerPC::ppcState.msr.DR)
|
||||
return std::nullopt;
|
||||
WriteToHardware<XCheckTLBFlag::NoException>(system, memory, address, var, size);
|
||||
return WriteResult(true);
|
||||
|
@ -977,7 +980,7 @@ bool IsOptimizableRAMAddress(const u32 address)
|
|||
if (PowerPC::memchecks.HasAny())
|
||||
return false;
|
||||
|
||||
if (!MSR.DR)
|
||||
if (!PowerPC::ppcState.msr.DR)
|
||||
return false;
|
||||
|
||||
// TODO: This API needs to take an access size
|
||||
|
@ -1029,11 +1032,11 @@ bool HostIsRAMAddress(u32 address, RequestedAddressSpace space)
|
|||
switch (space)
|
||||
{
|
||||
case RequestedAddressSpace::Effective:
|
||||
return IsRAMAddress<XCheckTLBFlag::NoException>(memory, address, MSR.DR);
|
||||
return IsRAMAddress<XCheckTLBFlag::NoException>(memory, address, PowerPC::ppcState.msr.DR);
|
||||
case RequestedAddressSpace::Physical:
|
||||
return IsRAMAddress<XCheckTLBFlag::NoException>(memory, address, false);
|
||||
case RequestedAddressSpace::Virtual:
|
||||
if (!MSR.DR)
|
||||
if (!PowerPC::ppcState.msr.DR)
|
||||
return false;
|
||||
return IsRAMAddress<XCheckTLBFlag::NoException>(memory, address, true);
|
||||
}
|
||||
|
@ -1054,11 +1057,12 @@ bool HostIsInstructionRAMAddress(u32 address, RequestedAddressSpace space)
|
|||
switch (space)
|
||||
{
|
||||
case RequestedAddressSpace::Effective:
|
||||
return IsRAMAddress<XCheckTLBFlag::OpcodeNoException>(memory, address, MSR.IR);
|
||||
return IsRAMAddress<XCheckTLBFlag::OpcodeNoException>(memory, address,
|
||||
PowerPC::ppcState.msr.IR);
|
||||
case RequestedAddressSpace::Physical:
|
||||
return IsRAMAddress<XCheckTLBFlag::OpcodeNoException>(memory, address, false);
|
||||
case RequestedAddressSpace::Virtual:
|
||||
if (!MSR.IR)
|
||||
if (!PowerPC::ppcState.msr.IR)
|
||||
return false;
|
||||
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)
|
||||
{
|
||||
DEBUG_ASSERT((address & 0x1F) == 0);
|
||||
if (MSR.DR)
|
||||
if (PowerPC::ppcState.msr.DR)
|
||||
{
|
||||
auto translated_address = TranslateAddress<XCheckTLBFlag::Write>(address);
|
||||
if (translated_address.result == TranslateAddressResultEnum::DIRECT_STORE_SEGMENT)
|
||||
|
@ -1180,7 +1184,7 @@ void StoreDCacheLine(u32 address)
|
|||
{
|
||||
address &= ~0x1F;
|
||||
|
||||
if (MSR.DR)
|
||||
if (PowerPC::ppcState.msr.DR)
|
||||
{
|
||||
auto translated_address = TranslateAddress<XCheckTLBFlag::Write>(address);
|
||||
if (translated_address.result == TranslateAddressResultEnum::DIRECT_STORE_SEGMENT)
|
||||
|
@ -1204,7 +1208,7 @@ void InvalidateDCacheLine(u32 address)
|
|||
{
|
||||
address &= ~0x1F;
|
||||
|
||||
if (MSR.DR)
|
||||
if (PowerPC::ppcState.msr.DR)
|
||||
{
|
||||
auto translated_address = TranslateAddress<XCheckTLBFlag::Write>(address);
|
||||
if (translated_address.result == TranslateAddressResultEnum::DIRECT_STORE_SEGMENT)
|
||||
|
@ -1226,7 +1230,7 @@ void FlushDCacheLine(u32 address)
|
|||
{
|
||||
address &= ~0x1F;
|
||||
|
||||
if (MSR.DR)
|
||||
if (PowerPC::ppcState.msr.DR)
|
||||
{
|
||||
auto translated_address = TranslateAddress<XCheckTLBFlag::Write>(address);
|
||||
if (translated_address.result == TranslateAddressResultEnum::DIRECT_STORE_SEGMENT)
|
||||
|
@ -1250,7 +1254,7 @@ void TouchDCacheLine(u32 address, bool store)
|
|||
{
|
||||
address &= ~0x1F;
|
||||
|
||||
if (MSR.DR)
|
||||
if (PowerPC::ppcState.msr.DR)
|
||||
{
|
||||
auto translated_address = TranslateAddress<XCheckTLBFlag::Write>(address);
|
||||
if (translated_address.result == TranslateAddressResultEnum::DIRECT_STORE_SEGMENT)
|
||||
|
@ -1275,7 +1279,7 @@ u32 IsOptimizableMMIOAccess(u32 address, u32 access_size)
|
|||
if (PowerPC::memchecks.HasAny())
|
||||
return 0;
|
||||
|
||||
if (!MSR.DR)
|
||||
if (!PowerPC::ppcState.msr.DR)
|
||||
return 0;
|
||||
|
||||
// Translate address
|
||||
|
@ -1298,7 +1302,7 @@ bool IsOptimizableGatherPipeWrite(u32 address)
|
|||
if (PowerPC::memchecks.HasAny())
|
||||
return false;
|
||||
|
||||
if (!MSR.DR)
|
||||
if (!PowerPC::ppcState.msr.DR)
|
||||
return false;
|
||||
|
||||
// Translate address, only check BAT mapping.
|
||||
|
@ -1314,7 +1318,7 @@ bool IsOptimizableGatherPipeWrite(u32 address)
|
|||
|
||||
TranslateResult JitCache_TranslateAddress(u32 address)
|
||||
{
|
||||
if (!MSR.IR)
|
||||
if (!PowerPC::ppcState.msr.IR)
|
||||
return TranslateResult{address};
|
||||
|
||||
// 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())
|
||||
{
|
||||
PanicAlertFmt("Invalid {} {:#010x}, PC = {:#010x}", write ? "write to" : "read from",
|
||||
effective_address, PC);
|
||||
effective_address, PowerPC::ppcState.pc);
|
||||
if (Core::System::GetInstance().IsPauseOnPanicMode())
|
||||
{
|
||||
CPU::Break();
|
||||
|
@ -1387,10 +1391,10 @@ static void GenerateDSIException(u32 effective_address, bool write)
|
|||
static void GenerateISIException(u32 effective_address)
|
||||
{
|
||||
// Address of instruction could not be translated
|
||||
NPC = effective_address;
|
||||
PowerPC::ppcState.npc = effective_address;
|
||||
|
||||
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()
|
||||
|
@ -1733,7 +1737,7 @@ void DBATUpdated()
|
|||
|
||||
dbat_table = {};
|
||||
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)
|
||||
UpdateBATs(dbat_table, SPR_DBAT4U);
|
||||
if (memory.GetFakeVMEM())
|
||||
|
@ -1758,7 +1762,7 @@ void IBATUpdated()
|
|||
|
||||
ibat_table = {};
|
||||
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)
|
||||
UpdateBATs(ibat_table, SPR_IBAT4U);
|
||||
if (memory.GetFakeVMEM())
|
||||
|
|
|
@ -394,17 +394,17 @@ u32 InstructionCache::ReadInstruction(u32 addr)
|
|||
auto& system = Core::System::GetInstance();
|
||||
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);
|
||||
|
||||
u32 value;
|
||||
Read(addr, &value, sizeof(value), HID0.ILOCK);
|
||||
Read(addr, &value, sizeof(value), HID0(PowerPC::ppcState).ILOCK);
|
||||
return Common::swap32(value);
|
||||
}
|
||||
|
||||
void InstructionCache::Invalidate(u32 addr)
|
||||
{
|
||||
if (!HID0.ICE || m_disable_icache)
|
||||
if (!HID0(PowerPC::ppcState).ICE || m_disable_icache)
|
||||
return;
|
||||
|
||||
// Invalidates the whole set
|
||||
|
|
|
@ -51,7 +51,8 @@ GekkoOPInfo* GetOpInfo(UGeckoInstruction inst)
|
|||
case 63:
|
||||
return m_infoTable63[inst.SUBOP10];
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -59,7 +60,8 @@ GekkoOPInfo* GetOpInfo(UGeckoInstruction inst)
|
|||
{
|
||||
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 m_infoTable[inst.OPCD];
|
||||
|
@ -85,7 +87,7 @@ Interpreter::Instruction GetInterpreterOp(UGeckoInstruction inst)
|
|||
return Interpreter::m_op_table63[inst.SUBOP10];
|
||||
default:
|
||||
ASSERT_MSG(POWERPC, 0, "GetInterpreterOp - invalid subtable op {:08x} @ {:08x}", inst.hex,
|
||||
PC);
|
||||
PowerPC::ppcState.pc);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
@ -93,7 +95,8 @@ Interpreter::Instruction GetInterpreterOp(UGeckoInstruction inst)
|
|||
{
|
||||
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 Interpreter::m_op_table[inst.OPCD];
|
||||
|
|
|
@ -45,7 +45,7 @@ static CoreMode s_mode = CoreMode::Interpreter;
|
|||
|
||||
BreakPoints breakpoints;
|
||||
MemChecks memchecks;
|
||||
PPCDebugInterface debug_interface;
|
||||
PPCDebugInterface debug_interface(Core::System::GetInstance());
|
||||
|
||||
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
|
||||
// conflict to mess with them here.
|
||||
|
||||
// rSPR(SPR_DEC) = SystemTimers::GetFakeDecrementer();
|
||||
// *((u64 *)&TL) = SystemTimers::GetFakeTimeBase(); //works since we are little endian and TL
|
||||
// comes first :)
|
||||
// PowerPC::ppcState.spr[SPR_DEC] = SystemTimers::GetFakeDecrementer();
|
||||
// *((u64 *)&TL(PowerPC::ppcState)) = SystemTimers::GetFakeTimeBase(); //works since we are little
|
||||
// endian and TL comes first :)
|
||||
|
||||
p.DoArray(ppcState.gpr);
|
||||
p.Do(ppcState.pc);
|
||||
|
@ -200,19 +200,19 @@ static void ResetRegisters()
|
|||
{
|
||||
v = 0x8000000000000001;
|
||||
}
|
||||
SetXER({});
|
||||
ppcState.SetXER({});
|
||||
|
||||
RoundingModeUpdated();
|
||||
DBATUpdated();
|
||||
IBATUpdated();
|
||||
|
||||
TL = 0;
|
||||
TU = 0;
|
||||
TL(PowerPC::ppcState) = 0;
|
||||
TU(PowerPC::ppcState) = 0;
|
||||
SystemTimers::TimeBaseSet();
|
||||
|
||||
// MSR should be 0x40, but we don't emulate BS1, so it would never be turned off :}
|
||||
ppcState.msr.Hex = 0;
|
||||
rDEC = 0xFFFFFFFF;
|
||||
ppcState.spr[SPR_DEC] = 0xFFFFFFFF;
|
||||
SystemTimers::DecrementerSet();
|
||||
}
|
||||
|
||||
|
@ -394,72 +394,75 @@ void RunLoop()
|
|||
u64 ReadFullTimeBaseValue()
|
||||
{
|
||||
u64 value;
|
||||
std::memcpy(&value, &TL, sizeof(value));
|
||||
std::memcpy(&value, &TL(PowerPC::ppcState), sizeof(value));
|
||||
return 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
|
||||
break;
|
||||
case 1: // Processor cycles
|
||||
PowerPC::ppcState.spr[SPR_PMC1] += cycles;
|
||||
ppc_state.spr[SPR_PMC1] += cycles;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (MMCR0.PMC2SELECT)
|
||||
switch (MMCR0(ppc_state).PMC2SELECT)
|
||||
{
|
||||
case 0: // No change
|
||||
break;
|
||||
case 1: // Processor cycles
|
||||
PowerPC::ppcState.spr[SPR_PMC2] += cycles;
|
||||
ppc_state.spr[SPR_PMC2] += cycles;
|
||||
break;
|
||||
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;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (MMCR1.PMC3SELECT)
|
||||
switch (MMCR1(ppc_state).PMC3SELECT)
|
||||
{
|
||||
case 0: // No change
|
||||
break;
|
||||
case 1: // Processor cycles
|
||||
PowerPC::ppcState.spr[SPR_PMC3] += cycles;
|
||||
ppc_state.spr[SPR_PMC3] += cycles;
|
||||
break;
|
||||
case 11: // Number of FPU instructions completed
|
||||
PowerPC::ppcState.spr[SPR_PMC3] += num_fp_inst;
|
||||
ppc_state.spr[SPR_PMC3] += num_fp_inst;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (MMCR1.PMC4SELECT)
|
||||
switch (MMCR1(ppc_state).PMC4SELECT)
|
||||
{
|
||||
case 0: // No change
|
||||
break;
|
||||
case 1: // Processor cycles
|
||||
PowerPC::ppcState.spr[SPR_PMC4] += cycles;
|
||||
ppc_state.spr[SPR_PMC4] += cycles;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if ((MMCR0.PMC1INTCONTROL && (PowerPC::ppcState.spr[SPR_PMC1] & 0x80000000) != 0) ||
|
||||
(MMCR0.PMCINTCONTROL && (PowerPC::ppcState.spr[SPR_PMC2] & 0x80000000) != 0) ||
|
||||
(MMCR0.PMCINTCONTROL && (PowerPC::ppcState.spr[SPR_PMC3] & 0x80000000) != 0) ||
|
||||
(MMCR0.PMCINTCONTROL && (PowerPC::ppcState.spr[SPR_PMC4] & 0x80000000) != 0))
|
||||
PowerPC::ppcState.Exceptions |= EXCEPTION_PERFORMANCE_MONITOR;
|
||||
if ((MMCR0(ppc_state).PMC1INTCONTROL && (ppc_state.spr[SPR_PMC1] & 0x80000000) != 0) ||
|
||||
(MMCR0(ppc_state).PMCINTCONTROL && (ppc_state.spr[SPR_PMC2] & 0x80000000) != 0) ||
|
||||
(MMCR0(ppc_state).PMCINTCONTROL && (ppc_state.spr[SPR_PMC3] & 0x80000000) != 0) ||
|
||||
(MMCR0(ppc_state).PMCINTCONTROL && (ppc_state.spr[SPR_PMC4] & 0x80000000) != 0))
|
||||
{
|
||||
ppc_state.Exceptions |= EXCEPTION_PERFORMANCE_MONITOR;
|
||||
}
|
||||
}
|
||||
|
||||
void CheckExceptions()
|
||||
|
@ -489,47 +492,47 @@ void CheckExceptions()
|
|||
|
||||
if (exceptions & EXCEPTION_ISI)
|
||||
{
|
||||
SRR0 = NPC;
|
||||
SRR0(PowerPC::ppcState) = PowerPC::ppcState.npc;
|
||||
// Page fault occurred
|
||||
SRR1 = (MSR.Hex & 0x87C0FFFF) | (1 << 30);
|
||||
MSR.LE = MSR.ILE;
|
||||
MSR.Hex &= ~0x04EF36;
|
||||
PC = NPC = 0x00000400;
|
||||
SRR1(PowerPC::ppcState) = (PowerPC::ppcState.msr.Hex & 0x87C0FFFF) | (1 << 30);
|
||||
PowerPC::ppcState.msr.LE = PowerPC::ppcState.msr.ILE;
|
||||
PowerPC::ppcState.msr.Hex &= ~0x04EF36;
|
||||
PowerPC::ppcState.pc = PowerPC::ppcState.npc = 0x00000400;
|
||||
|
||||
DEBUG_LOG_FMT(POWERPC, "EXCEPTION_ISI");
|
||||
ppcState.Exceptions &= ~EXCEPTION_ISI;
|
||||
}
|
||||
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 |= MSR.Hex & 0x87C0FFFF;
|
||||
MSR.LE = MSR.ILE;
|
||||
MSR.Hex &= ~0x04EF36;
|
||||
PC = NPC = 0x00000700;
|
||||
SRR1(PowerPC::ppcState) |= PowerPC::ppcState.msr.Hex & 0x87C0FFFF;
|
||||
PowerPC::ppcState.msr.LE = PowerPC::ppcState.msr.ILE;
|
||||
PowerPC::ppcState.msr.Hex &= ~0x04EF36;
|
||||
PowerPC::ppcState.pc = PowerPC::ppcState.npc = 0x00000700;
|
||||
|
||||
DEBUG_LOG_FMT(POWERPC, "EXCEPTION_PROGRAM");
|
||||
ppcState.Exceptions &= ~EXCEPTION_PROGRAM;
|
||||
}
|
||||
else if (exceptions & EXCEPTION_SYSCALL)
|
||||
{
|
||||
SRR0 = NPC;
|
||||
SRR1 = MSR.Hex & 0x87C0FFFF;
|
||||
MSR.LE = MSR.ILE;
|
||||
MSR.Hex &= ~0x04EF36;
|
||||
PC = NPC = 0x00000C00;
|
||||
SRR0(PowerPC::ppcState) = PowerPC::ppcState.npc;
|
||||
SRR1(PowerPC::ppcState) = PowerPC::ppcState.msr.Hex & 0x87C0FFFF;
|
||||
PowerPC::ppcState.msr.LE = PowerPC::ppcState.msr.ILE;
|
||||
PowerPC::ppcState.msr.Hex &= ~0x04EF36;
|
||||
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;
|
||||
}
|
||||
else if (exceptions & EXCEPTION_FPU_UNAVAILABLE)
|
||||
{
|
||||
// This happens a lot - GameCube OS uses deferred FPU context switching
|
||||
SRR0 = PC; // re-execute the instruction
|
||||
SRR1 = MSR.Hex & 0x87C0FFFF;
|
||||
MSR.LE = MSR.ILE;
|
||||
MSR.Hex &= ~0x04EF36;
|
||||
PC = NPC = 0x00000800;
|
||||
SRR0(PowerPC::ppcState) = PowerPC::ppcState.pc; // re-execute the instruction
|
||||
SRR1(PowerPC::ppcState) = PowerPC::ppcState.msr.Hex & 0x87C0FFFF;
|
||||
PowerPC::ppcState.msr.LE = PowerPC::ppcState.msr.ILE;
|
||||
PowerPC::ppcState.msr.Hex &= ~0x04EF36;
|
||||
PowerPC::ppcState.pc = PowerPC::ppcState.npc = 0x00000800;
|
||||
|
||||
DEBUG_LOG_FMT(POWERPC, "EXCEPTION_FPU_UNAVAILABLE");
|
||||
ppcState.Exceptions &= ~EXCEPTION_FPU_UNAVAILABLE;
|
||||
|
@ -540,11 +543,11 @@ void CheckExceptions()
|
|||
}
|
||||
else if (exceptions & EXCEPTION_DSI)
|
||||
{
|
||||
SRR0 = PC;
|
||||
SRR1 = MSR.Hex & 0x87C0FFFF;
|
||||
MSR.LE = MSR.ILE;
|
||||
MSR.Hex &= ~0x04EF36;
|
||||
PC = NPC = 0x00000300;
|
||||
SRR0(PowerPC::ppcState) = PowerPC::ppcState.pc;
|
||||
SRR1(PowerPC::ppcState) = PowerPC::ppcState.msr.Hex & 0x87C0FFFF;
|
||||
PowerPC::ppcState.msr.LE = PowerPC::ppcState.msr.ILE;
|
||||
PowerPC::ppcState.msr.Hex &= ~0x04EF36;
|
||||
PowerPC::ppcState.pc = PowerPC::ppcState.npc = 0x00000300;
|
||||
// DSISR and DAR regs are changed in GenerateDSIException()
|
||||
|
||||
DEBUG_LOG_FMT(POWERPC, "EXCEPTION_DSI");
|
||||
|
@ -552,11 +555,11 @@ void CheckExceptions()
|
|||
}
|
||||
else if (exceptions & EXCEPTION_ALIGNMENT)
|
||||
{
|
||||
SRR0 = PC;
|
||||
SRR1 = MSR.Hex & 0x87C0FFFF;
|
||||
MSR.LE = MSR.ILE;
|
||||
MSR.Hex &= ~0x04EF36;
|
||||
PC = NPC = 0x00000600;
|
||||
SRR0(PowerPC::ppcState) = PowerPC::ppcState.pc;
|
||||
SRR1(PowerPC::ppcState) = PowerPC::ppcState.msr.Hex & 0x87C0FFFF;
|
||||
PowerPC::ppcState.msr.LE = PowerPC::ppcState.msr.ILE;
|
||||
PowerPC::ppcState.msr.Hex &= ~0x04EF36;
|
||||
PowerPC::ppcState.pc = PowerPC::ppcState.npc = 0x00000600;
|
||||
|
||||
// TODO crazy amount of DSISR options to check out
|
||||
|
||||
|
@ -577,40 +580,41 @@ void CheckExternalExceptions()
|
|||
|
||||
// EXTERNAL INTERRUPT
|
||||
// Handling is delayed until MSR.EE=1.
|
||||
if (exceptions && MSR.EE)
|
||||
if (exceptions && PowerPC::ppcState.msr.EE)
|
||||
{
|
||||
if (exceptions & EXCEPTION_EXTERNAL_INT)
|
||||
{
|
||||
// Pokemon gets this "too early", it hasn't a handler yet
|
||||
SRR0 = NPC;
|
||||
SRR1 = MSR.Hex & 0x87C0FFFF;
|
||||
MSR.LE = MSR.ILE;
|
||||
MSR.Hex &= ~0x04EF36;
|
||||
PC = NPC = 0x00000500;
|
||||
SRR0(PowerPC::ppcState) = PowerPC::ppcState.npc;
|
||||
SRR1(PowerPC::ppcState) = PowerPC::ppcState.msr.Hex & 0x87C0FFFF;
|
||||
PowerPC::ppcState.msr.LE = PowerPC::ppcState.msr.ILE;
|
||||
PowerPC::ppcState.msr.Hex &= ~0x04EF36;
|
||||
PowerPC::ppcState.pc = PowerPC::ppcState.npc = 0x00000500;
|
||||
|
||||
DEBUG_LOG_FMT(POWERPC, "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)
|
||||
{
|
||||
SRR0 = NPC;
|
||||
SRR1 = MSR.Hex & 0x87C0FFFF;
|
||||
MSR.LE = MSR.ILE;
|
||||
MSR.Hex &= ~0x04EF36;
|
||||
PC = NPC = 0x00000F00;
|
||||
SRR0(PowerPC::ppcState) = PowerPC::ppcState.npc;
|
||||
SRR1(PowerPC::ppcState) = PowerPC::ppcState.msr.Hex & 0x87C0FFFF;
|
||||
PowerPC::ppcState.msr.LE = PowerPC::ppcState.msr.ILE;
|
||||
PowerPC::ppcState.msr.Hex &= ~0x04EF36;
|
||||
PowerPC::ppcState.pc = PowerPC::ppcState.npc = 0x00000F00;
|
||||
|
||||
DEBUG_LOG_FMT(POWERPC, "EXCEPTION_PERFORMANCE_MONITOR");
|
||||
ppcState.Exceptions &= ~EXCEPTION_PERFORMANCE_MONITOR;
|
||||
}
|
||||
else if (exceptions & EXCEPTION_DECREMENTER)
|
||||
{
|
||||
SRR0 = NPC;
|
||||
SRR1 = MSR.Hex & 0x87C0FFFF;
|
||||
MSR.LE = MSR.ILE;
|
||||
MSR.Hex &= ~0x04EF36;
|
||||
PC = NPC = 0x00000900;
|
||||
SRR0(PowerPC::ppcState) = PowerPC::ppcState.npc;
|
||||
SRR1(PowerPC::ppcState) = PowerPC::ppcState.msr.Hex & 0x87C0FFFF;
|
||||
PowerPC::ppcState.msr.LE = PowerPC::ppcState.msr.ILE;
|
||||
PowerPC::ppcState.msr.Hex &= ~0x04EF36;
|
||||
PowerPC::ppcState.pc = PowerPC::ppcState.npc = 0x00000900;
|
||||
|
||||
DEBUG_LOG_FMT(POWERPC, "EXCEPTION_DECREMENTER");
|
||||
ppcState.Exceptions &= ~EXCEPTION_DECREMENTER;
|
||||
|
@ -626,7 +630,7 @@ void CheckExternalExceptions()
|
|||
|
||||
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))
|
||||
return;
|
||||
|
@ -642,11 +646,14 @@ void CheckBreakPoints()
|
|||
NOTICE_LOG_FMT(MEMMAP,
|
||||
"BP {:08x} {}({:08x} {:08x} {:08x} {:08x} {:08x} {:08x} {:08x} {:08x} {:08x} "
|
||||
"{:08x}) LR={:08x}",
|
||||
PC, g_symbolDB.GetDescription(PC), GPR(3), GPR(4), GPR(5), GPR(6), GPR(7),
|
||||
GPR(8), GPR(9), GPR(10), GPR(11), GPR(12), LR);
|
||||
PowerPC::ppcState.pc, g_symbolDB.GetDescription(PowerPC::ppcState.pc),
|
||||
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))
|
||||
PowerPC::breakpoints.Remove(PC);
|
||||
if (PowerPC::breakpoints.IsTempBreakPoint(PowerPC::ppcState.pc))
|
||||
PowerPC::breakpoints.Remove(PowerPC::ppcState.pc);
|
||||
}
|
||||
|
||||
void PowerPCState::SetSR(u32 index, u32 value)
|
||||
|
@ -657,14 +664,14 @@ void PowerPCState::SetSR(u32 index, u32 value)
|
|||
|
||||
// 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()
|
||||
|
@ -672,7 +679,7 @@ void RoundingModeUpdated()
|
|||
// The rounding mode is separate for each thread, so this must run on the CPU thread
|
||||
ASSERT(Core::IsCPUThread());
|
||||
|
||||
FPURoundMode::SetSIMDMode(FPSCR.RN, FPSCR.NI);
|
||||
FPURoundMode::SetSIMDMode(PowerPC::ppcState.fpscr.RN, PowerPC::ppcState.fpscr.NI);
|
||||
}
|
||||
|
||||
} // namespace PowerPC
|
||||
|
|
|
@ -185,6 +185,41 @@ struct PowerPCState
|
|||
}
|
||||
|
||||
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
|
||||
|
@ -232,91 +267,28 @@ void RunLoop();
|
|||
u64 ReadFullTimeBaseValue();
|
||||
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.
|
||||
#define HID0 ((UReg_HID0&)PowerPC::ppcState.spr[SPR_HID0])
|
||||
#define HID2 ((UReg_HID2&)PowerPC::ppcState.spr[SPR_HID2])
|
||||
#define HID4 ((UReg_HID4&)PowerPC::ppcState.spr[SPR_HID4])
|
||||
#define DMAU (*(UReg_DMAU*)&PowerPC::ppcState.spr[SPR_DMAU])
|
||||
#define DMAL (*(UReg_DMAL*)&PowerPC::ppcState.spr[SPR_DMAL])
|
||||
#define MMCR0 ((UReg_MMCR0&)PowerPC::ppcState.spr[SPR_MMCR0])
|
||||
#define MMCR1 ((UReg_MMCR1&)PowerPC::ppcState.spr[SPR_MMCR1])
|
||||
#define THRM1 ((UReg_THRM12&)PowerPC::ppcState.spr[SPR_THRM1])
|
||||
#define THRM2 ((UReg_THRM12&)PowerPC::ppcState.spr[SPR_THRM2])
|
||||
#define THRM3 ((UReg_THRM3&)PowerPC::ppcState.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 HID0(ppc_state) ((UReg_HID0&)(ppc_state).spr[SPR_HID0])
|
||||
#define HID2(ppc_state) ((UReg_HID2&)(ppc_state).spr[SPR_HID2])
|
||||
#define HID4(ppc_state) ((UReg_HID4&)(ppc_state).spr[SPR_HID4])
|
||||
#define DMAU(ppc_state) (*(UReg_DMAU*)&(ppc_state).spr[SPR_DMAU])
|
||||
#define DMAL(ppc_state) (*(UReg_DMAL*)&(ppc_state).spr[SPR_DMAL])
|
||||
#define MMCR0(ppc_state) ((UReg_MMCR0&)(ppc_state).spr[SPR_MMCR0])
|
||||
#define MMCR1(ppc_state) ((UReg_MMCR1&)(ppc_state).spr[SPR_MMCR1])
|
||||
#define THRM1(ppc_state) ((UReg_THRM12&)(ppc_state).spr[SPR_THRM1])
|
||||
#define THRM2(ppc_state) ((UReg_THRM12&)(ppc_state).spr[SPR_THRM2])
|
||||
#define THRM3(ppc_state) ((UReg_THRM3&)(ppc_state).spr[SPR_THRM3])
|
||||
|
||||
#define rGPR PowerPC::ppcState.gpr
|
||||
#define rSPR(i) PowerPC::ppcState.spr[i]
|
||||
#define LR PowerPC::ppcState.spr[SPR_LR]
|
||||
#define CTR PowerPC::ppcState.spr[SPR_CTR]
|
||||
#define rDEC PowerPC::ppcState.spr[SPR_DEC]
|
||||
#define SRR0 PowerPC::ppcState.spr[SPR_SRR0]
|
||||
#define SRR1 PowerPC::ppcState.spr[SPR_SRR1]
|
||||
#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);
|
||||
#define LR(ppc_state) (ppc_state).spr[SPR_LR]
|
||||
#define CTR(ppc_state) (ppc_state).spr[SPR_CTR]
|
||||
#define SRR0(ppc_state) (ppc_state).spr[SPR_SRR0]
|
||||
#define SRR1(ppc_state) (ppc_state).spr[SPR_SRR1]
|
||||
#define GQR(ppc_state, x) (ppc_state).spr[SPR_GQR0 + (x)]
|
||||
#define TL(ppc_state) (ppc_state).spr[SPR_TL]
|
||||
#define TU(ppc_state) (ppc_state).spr[SPR_TU]
|
||||
|
||||
void RoundingModeUpdated();
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "Core/HW/SI/SI.h"
|
||||
#include "Core/HW/Sram.h"
|
||||
#include "Core/HW/VideoInterface.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
#include "IOS/USB/Emulated/Skylander.h"
|
||||
#include "VideoCommon/CommandProcessor.h"
|
||||
#include "VideoCommon/Fifo.h"
|
||||
|
@ -32,7 +33,10 @@ namespace Core
|
|||
{
|
||||
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;
|
||||
bool m_sound_stream_running = false;
|
||||
|
@ -53,6 +57,7 @@ struct System::Impl
|
|||
MemoryInterface::MemoryInterfaceState m_memory_interface_state;
|
||||
PixelEngine::PixelEngineManager m_pixel_engine;
|
||||
PixelShaderManager m_pixel_shader_manager;
|
||||
PowerPC::PowerPCState& m_ppc_state;
|
||||
ProcessorInterface::ProcessorInterfaceManager m_processor_interface;
|
||||
SerialInterface::SerialInterfaceState m_serial_interface_state;
|
||||
Sram m_sram;
|
||||
|
@ -178,6 +183,11 @@ PixelShaderManager& System::GetPixelShaderManager() const
|
|||
return m_impl->m_pixel_shader_manager;
|
||||
}
|
||||
|
||||
PowerPC::PowerPCState& System::GetPPCState() const
|
||||
{
|
||||
return m_impl->m_ppc_state;
|
||||
}
|
||||
|
||||
ProcessorInterface::ProcessorInterfaceManager& System::GetProcessorInterface() const
|
||||
{
|
||||
return m_impl->m_processor_interface;
|
||||
|
|
|
@ -63,6 +63,10 @@ namespace PixelEngine
|
|||
{
|
||||
class PixelEngineManager;
|
||||
};
|
||||
namespace PowerPC
|
||||
{
|
||||
struct PowerPCState;
|
||||
}
|
||||
namespace ProcessorInterface
|
||||
{
|
||||
class ProcessorInterfaceManager;
|
||||
|
@ -125,6 +129,7 @@ public:
|
|||
MemoryInterface::MemoryInterfaceState& GetMemoryInterfaceState() const;
|
||||
PixelEngine::PixelEngineManager& GetPixelEngine() const;
|
||||
PixelShaderManager& GetPixelShaderManager() const;
|
||||
PowerPC::PowerPCState& GetPPCState() const;
|
||||
ProcessorInterface::ProcessorInterfaceManager& GetProcessorInterface() const;
|
||||
SerialInterface::SerialInterfaceState& GetSerialInterfaceState() const;
|
||||
Sram& GetSRAM() const;
|
||||
|
|
|
@ -497,10 +497,11 @@ static void ApplyMemoryPatch(u32 offset, const std::vector<u8>& value,
|
|||
if (!original.empty() && !MemoryMatchesAt(offset, original))
|
||||
return;
|
||||
|
||||
auto& system = Core::System::GetInstance();
|
||||
const u32 size = static_cast<u32>(value.size());
|
||||
for (u32 i = 0; i < size; ++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)
|
||||
{
|
||||
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())
|
||||
return;
|
||||
|
||||
auto& system = Core::System::GetInstance();
|
||||
for (u32 i = 0; i < length; i += 4)
|
||||
{
|
||||
// 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 jmp = ((target - blr_address) & 0x03fffffc) | 0x48000000;
|
||||
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)
|
||||
{
|
||||
WARN_LOG_FMT(OSHLE, "Riivolution ocarina patch overlaps HLE hook at {}", blr_address);
|
||||
|
|
|
@ -167,11 +167,11 @@ CodeViewWidget::CodeViewWidget()
|
|||
&CodeViewWidget::FontBasedSizing);
|
||||
|
||||
connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, [this] {
|
||||
m_address = PC;
|
||||
m_address = PowerPC::ppcState.pc;
|
||||
Update();
|
||||
});
|
||||
connect(Host::GetInstance(), &Host::UpdateDisasmDialog, this, [this] {
|
||||
m_address = PC;
|
||||
m_address = PowerPC::ppcState.pc;
|
||||
Update();
|
||||
});
|
||||
|
||||
|
@ -567,9 +567,9 @@ void CodeViewWidget::OnContextMenu()
|
|||
menu->addAction(tr("Restore instruction"), this, &CodeViewWidget::OnRestoreInstruction);
|
||||
|
||||
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_end = std::find(target_it, line.end(), ',');
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "Core/PowerPC/MMU.h"
|
||||
#include "Core/PowerPC/PPCSymbolDB.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
#include "Core/System.h"
|
||||
#include "DolphinQt/Host.h"
|
||||
#include "DolphinQt/Settings.h"
|
||||
|
||||
|
@ -328,7 +329,7 @@ void CodeWidget::UpdateCallstack()
|
|||
|
||||
std::vector<Dolphin_Debugger::CallstackEntry> stack;
|
||||
|
||||
bool success = Dolphin_Debugger::GetCallstack(stack);
|
||||
bool success = Dolphin_Debugger::GetCallstack(Core::System::GetInstance(), stack);
|
||||
|
||||
if (!success)
|
||||
{
|
||||
|
@ -451,11 +452,11 @@ void CodeWidget::StepOver()
|
|||
if (!CPU::IsStepping())
|
||||
return;
|
||||
|
||||
UGeckoInstruction inst = PowerPC::HostRead_Instruction(PC);
|
||||
UGeckoInstruction inst = PowerPC::HostRead_Instruction(PowerPC::ppcState.pc);
|
||||
if (inst.LK)
|
||||
{
|
||||
PowerPC::breakpoints.ClearAllTemporary();
|
||||
PowerPC::breakpoints.Add(PC + 4, true);
|
||||
PowerPC::breakpoints.Add(PowerPC::ppcState.pc + 4, true);
|
||||
CPU::EnableStepping(false);
|
||||
Core::DisplayMessage(tr("Step over in progress...").toStdString(), 2000);
|
||||
}
|
||||
|
@ -471,7 +472,8 @@ static bool WillInstructionReturn(UGeckoInstruction inst)
|
|||
// Is a rfi instruction
|
||||
if (inst.hex == 0x4C000064u)
|
||||
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 =
|
||||
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;
|
||||
|
@ -495,7 +497,7 @@ void CodeWidget::StepOut()
|
|||
// 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
|
||||
// on a breakpoint, skip it.
|
||||
UGeckoInstruction inst = PowerPC::HostRead_Instruction(PC);
|
||||
UGeckoInstruction inst = PowerPC::HostRead_Instruction(PowerPC::ppcState.pc);
|
||||
do
|
||||
{
|
||||
if (WillInstructionReturn(inst))
|
||||
|
@ -507,27 +509,28 @@ void CodeWidget::StepOut()
|
|||
if (inst.LK)
|
||||
{
|
||||
// Step over branches
|
||||
u32 next_pc = PC + 4;
|
||||
u32 next_pc = PowerPC::ppcState.pc + 4;
|
||||
do
|
||||
{
|
||||
PowerPC::SingleStep();
|
||||
} while (PC != next_pc && clock::now() < timeout &&
|
||||
!PowerPC::breakpoints.IsAddressBreakPoint(PC));
|
||||
} while (PowerPC::ppcState.pc != next_pc && clock::now() < timeout &&
|
||||
!PowerPC::breakpoints.IsAddressBreakPoint(PowerPC::ppcState.pc));
|
||||
}
|
||||
else
|
||||
{
|
||||
PowerPC::SingleStep();
|
||||
}
|
||||
|
||||
inst = PowerPC::HostRead_Instruction(PC);
|
||||
} while (clock::now() < timeout && !PowerPC::breakpoints.IsAddressBreakPoint(PC));
|
||||
inst = PowerPC::HostRead_Instruction(PowerPC::ppcState.pc);
|
||||
} while (clock::now() < timeout &&
|
||||
!PowerPC::breakpoints.IsAddressBreakPoint(PowerPC::ppcState.pc));
|
||||
|
||||
PowerPC::SetMode(old_mode);
|
||||
CPU::PauseAndLock(false, false);
|
||||
|
||||
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);
|
||||
else if (clock::now() >= timeout)
|
||||
Core::DisplayMessage(tr("Step out timed out!").toStdString(), 2000);
|
||||
|
@ -537,19 +540,19 @@ void CodeWidget::StepOut()
|
|||
|
||||
void CodeWidget::Skip()
|
||||
{
|
||||
PC += 4;
|
||||
PowerPC::ppcState.pc += 4;
|
||||
ShowPC();
|
||||
}
|
||||
|
||||
void CodeWidget::ShowPC()
|
||||
{
|
||||
m_code_view->SetAddress(PC, CodeViewWidget::SetAddressUpdate::WithUpdate);
|
||||
m_code_view->SetAddress(PowerPC::ppcState.pc, CodeViewWidget::SetAddressUpdate::WithUpdate);
|
||||
Update();
|
||||
}
|
||||
|
||||
void CodeWidget::SetPC()
|
||||
{
|
||||
PC = m_code_view->GetAddress();
|
||||
PowerPC::ppcState.pc = m_code_view->GetAddress();
|
||||
Update();
|
||||
}
|
||||
|
||||
|
|
|
@ -314,17 +314,18 @@ void RegisterWidget::PopulateTable()
|
|||
{
|
||||
// General purpose registers (int)
|
||||
AddRegister(
|
||||
i, 0, RegisterType::gpr, "r" + std::to_string(i), [i] { return GPR(i); },
|
||||
[i](u64 value) { GPR(i) = value; });
|
||||
i, 0, RegisterType::gpr, "r" + std::to_string(i), [i] { return PowerPC::ppcState.gpr[i]; },
|
||||
[i](u64 value) { PowerPC::ppcState.gpr[i] = value; });
|
||||
|
||||
// Floating point registers (double)
|
||||
AddRegister(
|
||||
i, 2, RegisterType::fpr, "f" + std::to_string(i), [i] { return rPS(i).PS0AsU64(); },
|
||||
[i](u64 value) { rPS(i).SetPS0(value); });
|
||||
i, 2, RegisterType::fpr, "f" + std::to_string(i),
|
||||
[i] { return PowerPC::ppcState.ps[i].PS0AsU64(); },
|
||||
[i](u64 value) { PowerPC::ppcState.ps[i].SetPS0(value); });
|
||||
|
||||
AddRegister(
|
||||
i, 4, RegisterType::fpr, "", [i] { return rPS(i).PS1AsU64(); },
|
||||
[i](u64 value) { rPS(i).SetPS1(value); });
|
||||
i, 4, RegisterType::fpr, "", [i] { return PowerPC::ppcState.ps[i].PS1AsU64(); },
|
||||
[i](u64 value) { PowerPC::ppcState.ps[i].SetPS1(value); });
|
||||
}
|
||||
|
||||
// The IBAT and DBAT registers have a large gap between
|
||||
|
@ -421,8 +422,8 @@ void RegisterWidget::PopulateTable()
|
|||
|
||||
// XER
|
||||
AddRegister(
|
||||
21, 5, RegisterType::xer, "XER", [] { return PowerPC::GetXER().Hex; },
|
||||
[](u64 value) { PowerPC::SetXER(UReg_XER(value)); });
|
||||
21, 5, RegisterType::xer, "XER", [] { return PowerPC::ppcState.GetXER().Hex; },
|
||||
[](u64 value) { PowerPC::ppcState.SetXER(UReg_XER(value)); });
|
||||
|
||||
// FPSCR
|
||||
AddRegister(
|
||||
|
|
|
@ -1438,7 +1438,7 @@ void MenuBar::LoadSymbolMap()
|
|||
tr("Loaded symbols from '%1'").arg(existing_map_file_path));
|
||||
}
|
||||
|
||||
HLE::PatchFunctions();
|
||||
HLE::PatchFunctions(system);
|
||||
emit NotifySymbolsUpdated();
|
||||
}
|
||||
|
||||
|
@ -1462,7 +1462,8 @@ void MenuBar::LoadOtherSymbolMap()
|
|||
if (!TryLoadMapFile(file))
|
||||
return;
|
||||
|
||||
HLE::PatchFunctions();
|
||||
auto& system = Core::System::GetInstance();
|
||||
HLE::PatchFunctions(system);
|
||||
emit NotifySymbolsUpdated();
|
||||
}
|
||||
|
||||
|
@ -1478,7 +1479,8 @@ void MenuBar::LoadBadSymbolMap()
|
|||
if (!TryLoadMapFile(file, true))
|
||||
return;
|
||||
|
||||
HLE::PatchFunctions();
|
||||
auto& system = Core::System::GetInstance();
|
||||
HLE::PatchFunctions(system);
|
||||
emit NotifySymbolsUpdated();
|
||||
}
|
||||
|
||||
|
@ -1597,7 +1599,8 @@ void MenuBar::ApplySignatureFile()
|
|||
db.Load(load_path);
|
||||
db.Apply(&g_symbolDB);
|
||||
db.List();
|
||||
HLE::PatchFunctions();
|
||||
auto& system = Core::System::GetInstance();
|
||||
HLE::PatchFunctions(system);
|
||||
emit NotifySymbolsUpdated();
|
||||
}
|
||||
|
||||
|
@ -1636,7 +1639,8 @@ void MenuBar::CombineSignatureFiles()
|
|||
|
||||
void MenuBar::PatchHLEFunctions()
|
||||
{
|
||||
HLE::PatchFunctions();
|
||||
auto& system = Core::System::GetInstance();
|
||||
HLE::PatchFunctions(system);
|
||||
}
|
||||
|
||||
void MenuBar::ClearCache()
|
||||
|
|
|
@ -6,9 +6,6 @@
|
|||
#include <sstream>
|
||||
|
||||
#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 <llvm-c/Disassembler.h>
|
||||
#include <llvm-c/Target.h>
|
||||
|
|
|
@ -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_GPLinkEnable.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)
|
||||
{
|
||||
|
|
|
@ -71,15 +71,15 @@ TEST(JitArm64, FPRF)
|
|||
|
||||
for (const u64 double_input : double_test_values)
|
||||
{
|
||||
const u32 expected_double =
|
||||
RunUpdateFPRF([&] { PowerPC::UpdateFPRFDouble(Common::BitCast<double>(double_input)); });
|
||||
const u32 expected_double = RunUpdateFPRF(
|
||||
[&] { PowerPC::ppcState.UpdateFPRFDouble(Common::BitCast<double>(double_input)); });
|
||||
const u32 actual_double = RunUpdateFPRF([&] { test.fprf_double(double_input); });
|
||||
EXPECT_EQ(expected_double, actual_double);
|
||||
|
||||
const u32 single_input = ConvertToSingle(double_input);
|
||||
|
||||
const u32 expected_single =
|
||||
RunUpdateFPRF([&] { PowerPC::UpdateFPRFSingle(Common::BitCast<float>(single_input)); });
|
||||
const u32 expected_single = RunUpdateFPRF(
|
||||
[&] { PowerPC::ppcState.UpdateFPRFSingle(Common::BitCast<float>(single_input)); });
|
||||
const u32 actual_single = RunUpdateFPRF([&] { test.fprf_single(single_input); });
|
||||
EXPECT_EQ(expected_single, actual_single);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue