Merge pull request #11429 from AdmiralCurtiss/globals-ppc

Reduce usage of ppcState global.
This commit is contained in:
Pierre Bourdon 2023-01-27 19:06:30 +01:00 committed by GitHub
commit 41272dc5f1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
69 changed files with 1717 additions and 1427 deletions

View File

@ -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);

View File

@ -458,22 +458,23 @@ bool CBoot::Load_BS2(Core::System& system, const std::string& boot_rom_filename)
memory.CopyToEmu(0x01200000, data.data() + 0x100, 0x700);
memory.CopyToEmu(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;
}

View File

@ -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);

View File

@ -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!

View File

@ -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;

View File

@ -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();
}

View File

@ -44,6 +44,10 @@ static void EmptyTimedCallback(Core::System& system, u64 userdata, s64 cyclesLat
{
}
CoreTimingManager::CoreTimingManager(Core::System& system) : m_system(system)
{
}
// Changing the CPU speed in Dolphin isn't actually done by changing the physical clock rate,
// 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

View File

@ -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;

View File

@ -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)";

View File

@ -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();

View File

@ -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()

View File

@ -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;
};

View File

@ -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();

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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++)
{

View File

@ -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;

View File

@ -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:

View File

@ -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);

View File

@ -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();

View File

@ -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.

View File

@ -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;

View File

@ -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)

View File

@ -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;
}

View File

@ -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)

View File

@ -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);

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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;
}

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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

View File

@ -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();
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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)

View File

@ -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);

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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());
}

View File

@ -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();

View File

@ -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);

View File

@ -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)
{

View File

@ -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;

View File

@ -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)
{

View File

@ -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);

View File

@ -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();

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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())

View File

@ -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

View File

@ -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];

View File

@ -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

View File

@ -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();

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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(), ',');

View File

@ -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();
}

View File

@ -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(

View File

@ -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()

View File

@ -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>

View File

@ -684,7 +684,8 @@ void CommandProcessorManager::HandleUnknownOpcode(u8 cmd_byte, const u8* buffer,
fifo.bFF_Breakpoint.load(std::memory_order_relaxed) ? "true" : "false",
fifo.bFF_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)
{

View File

@ -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);
}