Merge pull request #1856 from magumagu/correct-translation-disable-2
Make address translation respect the CPU translation mode
This commit is contained in:
commit
0e0a196a1c
|
@ -127,12 +127,12 @@ void MemArena::ReleaseView(void* view, size_t size)
|
|||
}
|
||||
|
||||
|
||||
u8* MemArena::Find4GBBase()
|
||||
u8* MemArena::FindMemoryBase()
|
||||
{
|
||||
#if _ARCH_64
|
||||
#ifdef _WIN32
|
||||
// 64 bit
|
||||
u8* base = (u8*)VirtualAlloc(0, 0xE1000000, MEM_RESERVE, PAGE_READWRITE);
|
||||
u8* base = (u8*)VirtualAlloc(0, 0x400000000, MEM_RESERVE, PAGE_READWRITE);
|
||||
VirtualFree(base, 0, MEM_RELEASE);
|
||||
return base;
|
||||
#else
|
||||
|
@ -250,7 +250,7 @@ u8 *MemoryMap_Setup(MemoryView *views, int num_views, u32 flags, MemArena *arena
|
|||
arena->GrabSHMSegment(total_mem);
|
||||
|
||||
// Now, create views in high memory where there's plenty of space.
|
||||
u8 *base = MemArena::Find4GBBase();
|
||||
u8 *base = MemArena::FindMemoryBase();
|
||||
// This really shouldn't fail - in 64-bit, there will always be enough
|
||||
// address space.
|
||||
if (!Memory_TryBase(base, views, num_views, flags, arena))
|
||||
|
|
|
@ -24,8 +24,8 @@ public:
|
|||
void *CreateView(s64 offset, size_t size, void *base = nullptr);
|
||||
void ReleaseView(void *view, size_t size);
|
||||
|
||||
// This only finds 1 GB in 32-bit
|
||||
static u8 *Find4GBBase();
|
||||
// This finds 1 GB in 32-bit, 16 GB in 64-bit.
|
||||
static u8 *FindMemoryBase();
|
||||
private:
|
||||
|
||||
#ifdef _WIN32
|
||||
|
@ -44,7 +44,7 @@ enum {
|
|||
struct MemoryView
|
||||
{
|
||||
u8** out_ptr;
|
||||
u32 virtual_address;
|
||||
u64 virtual_address;
|
||||
u32 size;
|
||||
u32 flags;
|
||||
void* mapped_ptr;
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
#include "Core/ARDecrypt.h"
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "Core/Core.h"
|
||||
#include "Core/HW/Memmap.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
|
||||
namespace ActionReplay
|
||||
{
|
||||
|
@ -320,7 +320,7 @@ static bool Subtype_RamWriteAndFill(const ARAddr& addr, const u32 data)
|
|||
u32 repeat = data >> 8;
|
||||
for (u32 i = 0; i <= repeat; ++i)
|
||||
{
|
||||
Memory::Write_U8(data & 0xFF, new_addr + i);
|
||||
PowerPC::HostWrite_U8(data & 0xFF, new_addr + i);
|
||||
LogInfo("Wrote %08x to address %08x", data & 0xFF, new_addr + i);
|
||||
}
|
||||
LogInfo("--------");
|
||||
|
@ -334,7 +334,7 @@ static bool Subtype_RamWriteAndFill(const ARAddr& addr, const u32 data)
|
|||
u32 repeat = data >> 16;
|
||||
for (u32 i = 0; i <= repeat; ++i)
|
||||
{
|
||||
Memory::Write_U16(data & 0xFFFF, new_addr + i * 2);
|
||||
PowerPC::HostWrite_U16(data & 0xFFFF, new_addr + i * 2);
|
||||
LogInfo("Wrote %08x to address %08x", data & 0xFFFF, new_addr + i * 2);
|
||||
}
|
||||
LogInfo("--------");
|
||||
|
@ -345,7 +345,7 @@ static bool Subtype_RamWriteAndFill(const ARAddr& addr, const u32 data)
|
|||
case DATATYPE_32BIT: // Dword write
|
||||
LogInfo("32-bit Write");
|
||||
LogInfo("--------");
|
||||
Memory::Write_U32(data, new_addr);
|
||||
PowerPC::HostWrite_U32(data, new_addr);
|
||||
LogInfo("Wrote %08x to address %08x", data, new_addr);
|
||||
LogInfo("--------");
|
||||
break;
|
||||
|
@ -364,7 +364,7 @@ static bool Subtype_RamWriteAndFill(const ARAddr& addr, const u32 data)
|
|||
static bool Subtype_WriteToPointer(const ARAddr& addr, const u32 data)
|
||||
{
|
||||
const u32 new_addr = addr.GCAddress();
|
||||
const u32 ptr = Memory::Read_U32(new_addr);
|
||||
const u32 ptr = PowerPC::HostRead_U32(new_addr);
|
||||
|
||||
LogInfo("Hardware Address: %08x", new_addr);
|
||||
LogInfo("Size: %08x", addr.size);
|
||||
|
@ -380,7 +380,7 @@ static bool Subtype_WriteToPointer(const ARAddr& addr, const u32 data)
|
|||
LogInfo("Pointer: %08x", ptr);
|
||||
LogInfo("Byte: %08x", thebyte);
|
||||
LogInfo("Offset: %08x", offset);
|
||||
Memory::Write_U8(thebyte, ptr + offset);
|
||||
PowerPC::HostWrite_U8(thebyte, ptr + offset);
|
||||
LogInfo("Wrote %08x to address %08x", thebyte, ptr + offset);
|
||||
LogInfo("--------");
|
||||
break;
|
||||
|
@ -395,7 +395,7 @@ static bool Subtype_WriteToPointer(const ARAddr& addr, const u32 data)
|
|||
LogInfo("Pointer: %08x", ptr);
|
||||
LogInfo("Byte: %08x", theshort);
|
||||
LogInfo("Offset: %08x", offset);
|
||||
Memory::Write_U16(theshort, ptr + offset);
|
||||
PowerPC::HostWrite_U16(theshort, ptr + offset);
|
||||
LogInfo("Wrote %08x to address %08x", theshort, ptr + offset);
|
||||
LogInfo("--------");
|
||||
break;
|
||||
|
@ -405,7 +405,7 @@ static bool Subtype_WriteToPointer(const ARAddr& addr, const u32 data)
|
|||
case DATATYPE_32BIT:
|
||||
LogInfo("Write 32-bit to pointer");
|
||||
LogInfo("--------");
|
||||
Memory::Write_U32(data, ptr);
|
||||
PowerPC::HostWrite_U32(data, ptr);
|
||||
LogInfo("Wrote %08x to address %08x", data, ptr);
|
||||
LogInfo("--------");
|
||||
break;
|
||||
|
@ -433,24 +433,24 @@ static bool Subtype_AddCode(const ARAddr& addr, const u32 data)
|
|||
case DATATYPE_8BIT:
|
||||
LogInfo("8-bit Add");
|
||||
LogInfo("--------");
|
||||
Memory::Write_U8(Memory::Read_U8(new_addr) + data, new_addr);
|
||||
LogInfo("Wrote %08x to address %08x", Memory::Read_U8(new_addr) + (data & 0xFF), new_addr);
|
||||
PowerPC::HostWrite_U8(PowerPC::HostRead_U8(new_addr) + data, new_addr);
|
||||
LogInfo("Wrote %08x to address %08x", PowerPC::HostRead_U8(new_addr) + (data & 0xFF), new_addr);
|
||||
LogInfo("--------");
|
||||
break;
|
||||
|
||||
case DATATYPE_16BIT:
|
||||
LogInfo("16-bit Add");
|
||||
LogInfo("--------");
|
||||
Memory::Write_U16(Memory::Read_U16(new_addr) + data, new_addr);
|
||||
LogInfo("Wrote %08x to address %08x", Memory::Read_U16(new_addr) + (data & 0xFFFF), new_addr);
|
||||
PowerPC::HostWrite_U16(PowerPC::HostRead_U16(new_addr) + data, new_addr);
|
||||
LogInfo("Wrote %08x to address %08x", PowerPC::HostRead_U16(new_addr) + (data & 0xFFFF), new_addr);
|
||||
LogInfo("--------");
|
||||
break;
|
||||
|
||||
case DATATYPE_32BIT:
|
||||
LogInfo("32-bit Add");
|
||||
LogInfo("--------");
|
||||
Memory::Write_U32(Memory::Read_U32(new_addr) + data, new_addr);
|
||||
LogInfo("Wrote %08x to address %08x", Memory::Read_U32(new_addr) + data, new_addr);
|
||||
PowerPC::HostWrite_U32(PowerPC::HostRead_U32(new_addr) + data, new_addr);
|
||||
LogInfo("Wrote %08x to address %08x", PowerPC::HostRead_U32(new_addr) + data, new_addr);
|
||||
LogInfo("--------");
|
||||
break;
|
||||
|
||||
|
@ -459,10 +459,10 @@ static bool Subtype_AddCode(const ARAddr& addr, const u32 data)
|
|||
LogInfo("32-bit floating Add");
|
||||
LogInfo("--------");
|
||||
|
||||
const u32 read = Memory::Read_U32(new_addr);
|
||||
const u32 read = PowerPC::HostRead_U32(new_addr);
|
||||
const float fread = *((float*)&read) + (float)data; // data contains an integer value
|
||||
const u32 newval = *((u32*)&fread);
|
||||
Memory::Write_U32(newval, new_addr);
|
||||
PowerPC::HostWrite_U32(newval, new_addr);
|
||||
LogInfo("Old Value %08x", read);
|
||||
LogInfo("Increment %08x", data);
|
||||
LogInfo("New value %08x", newval);
|
||||
|
@ -517,7 +517,7 @@ static bool ZeroCode_FillAndSlide(const u32 val_last, const ARAddr& addr, const
|
|||
LogInfo("--------");
|
||||
for (int i = 0; i < write_num; ++i)
|
||||
{
|
||||
Memory::Write_U8(val & 0xFF, curr_addr);
|
||||
PowerPC::HostWrite_U8(val & 0xFF, curr_addr);
|
||||
curr_addr += addr_incr;
|
||||
val += val_incr;
|
||||
LogInfo("Write %08x to address %08x", val & 0xFF, curr_addr);
|
||||
|
@ -533,7 +533,7 @@ static bool ZeroCode_FillAndSlide(const u32 val_last, const ARAddr& addr, const
|
|||
LogInfo("--------");
|
||||
for (int i=0; i < write_num; ++i)
|
||||
{
|
||||
Memory::Write_U16(val & 0xFFFF, curr_addr);
|
||||
PowerPC::HostWrite_U16(val & 0xFFFF, curr_addr);
|
||||
LogInfo("Write %08x to address %08x", val & 0xFFFF, curr_addr);
|
||||
curr_addr += addr_incr * 2;
|
||||
val += val_incr;
|
||||
|
@ -548,7 +548,7 @@ static bool ZeroCode_FillAndSlide(const u32 val_last, const ARAddr& addr, const
|
|||
LogInfo("--------");
|
||||
for (int i = 0; i < write_num; ++i)
|
||||
{
|
||||
Memory::Write_U32(val, curr_addr);
|
||||
PowerPC::HostWrite_U32(val, curr_addr);
|
||||
LogInfo("Write %08x to address %08x", val, curr_addr);
|
||||
curr_addr += addr_incr * 4;
|
||||
val += val_incr;
|
||||
|
@ -586,8 +586,8 @@ static bool ZeroCode_MemoryCopy(const u32 val_last, const ARAddr& addr, const u3
|
|||
LogInfo("--------");
|
||||
for (int i = 0; i < 138; ++i)
|
||||
{
|
||||
Memory::Write_U8(Memory::Read_U8(addr_src + i), addr_dest + i);
|
||||
LogInfo("Wrote %08x to address %08x", Memory::Read_U8(addr_src + i), addr_dest + i);
|
||||
PowerPC::HostWrite_U8(PowerPC::HostRead_U8(addr_src + i), addr_dest + i);
|
||||
LogInfo("Wrote %08x to address %08x", PowerPC::HostRead_U8(addr_src + i), addr_dest + i);
|
||||
}
|
||||
LogInfo("--------");
|
||||
}
|
||||
|
@ -597,8 +597,8 @@ static bool ZeroCode_MemoryCopy(const u32 val_last, const ARAddr& addr, const u3
|
|||
LogInfo("--------");
|
||||
for (int i=0; i < num_bytes; ++i)
|
||||
{
|
||||
Memory::Write_U8(Memory::Read_U8(addr_src + i), addr_dest + i);
|
||||
LogInfo("Wrote %08x to address %08x", Memory::ReadUnchecked_U8(addr_src + i), addr_dest + i);
|
||||
PowerPC::HostWrite_U8(PowerPC::HostRead_U8(addr_src + i), addr_dest + i);
|
||||
LogInfo("Wrote %08x to address %08x", PowerPC::HostRead_U8(addr_src + i), addr_dest + i);
|
||||
}
|
||||
LogInfo("--------");
|
||||
return true;
|
||||
|
@ -709,16 +709,16 @@ static bool ConditionalCode(const ARAddr& addr, const u32 data, int* const pSkip
|
|||
switch (addr.size)
|
||||
{
|
||||
case DATATYPE_8BIT:
|
||||
result = CompareValues((u32)Memory::Read_U8(new_addr), (data & 0xFF), addr.type);
|
||||
result = CompareValues((u32)PowerPC::HostRead_U8(new_addr), (data & 0xFF), addr.type);
|
||||
break;
|
||||
|
||||
case DATATYPE_16BIT:
|
||||
result = CompareValues((u32)Memory::Read_U16(new_addr), (data & 0xFFFF), addr.type);
|
||||
result = CompareValues((u32)PowerPC::HostRead_U16(new_addr), (data & 0xFFFF), addr.type);
|
||||
break;
|
||||
|
||||
case DATATYPE_32BIT_FLOAT:
|
||||
case DATATYPE_32BIT:
|
||||
result = CompareValues(Memory::Read_U32(new_addr), data, addr.type);
|
||||
result = CompareValues(PowerPC::HostRead_U32(new_addr), data, addr.type);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
|
@ -39,10 +39,10 @@ void CBoot::Load_FST(bool _bIsWii)
|
|||
return;
|
||||
|
||||
// copy first 20 bytes of disc to start of Mem 1
|
||||
VolumeHandler::ReadToPtr(Memory::GetPointer(0x80000000), 0, 0x20, false);
|
||||
DVDInterface::DVDRead(/*offset*/0, /*address*/0, /*length*/0x20, false);
|
||||
|
||||
// copy of game id
|
||||
Memory::Write_U32(Memory::Read_U32(0x80000000), 0x80003180);
|
||||
Memory::Write_U32(Memory::Read_U32(0x0000), 0x3180);
|
||||
|
||||
u32 shift = 0;
|
||||
if (_bIsWii)
|
||||
|
@ -56,7 +56,7 @@ void CBoot::Load_FST(bool _bIsWii)
|
|||
Memory::Write_U32(arenaHigh, 0x00000034);
|
||||
|
||||
// load FST
|
||||
VolumeHandler::ReadToPtr(Memory::GetPointer(arenaHigh), fstOffset, fstSize, _bIsWii);
|
||||
DVDInterface::DVDRead(fstOffset, arenaHigh, fstSize, _bIsWii);
|
||||
Memory::Write_U32(arenaHigh, 0x00000038);
|
||||
Memory::Write_U32(maxFstSize, 0x0000003c);
|
||||
}
|
||||
|
@ -188,9 +188,9 @@ bool CBoot::Load_BS2(const std::string& _rBootROMFilename)
|
|||
// Run the descrambler over the encrypted section containing BS1/BS2
|
||||
CEXIIPL::Descrambler((u8*)data.data()+0x100, 0x1AFE00);
|
||||
|
||||
Memory::CopyToEmu(0x81200000, data.data() + 0x100, 0x700);
|
||||
Memory::CopyToEmu(0x81300000, data.data() + 0x820, 0x1AFE00);
|
||||
PC = 0x81200000;
|
||||
Memory::CopyToEmu(0x01200000, data.data() + 0x100, 0x700);
|
||||
Memory::CopyToEmu(0x01300000, data.data() + 0x820, 0x1AFE00);
|
||||
PC = 0x01200000;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -255,7 +255,7 @@ bool CBoot::BootUp()
|
|||
}
|
||||
|
||||
// Scan for common HLE functions
|
||||
if (_StartupPara.bSkipIdle && !_StartupPara.bEnableDebugging)
|
||||
if (_StartupPara.bSkipIdle && _StartupPara.bHLE_BS2 && !_StartupPara.bEnableDebugging)
|
||||
{
|
||||
PPCAnalyst::FindFunctions(0x80004000, 0x811fffff, &g_symbolDB);
|
||||
SignatureDB db;
|
||||
|
@ -309,6 +309,25 @@ bool CBoot::BootUp()
|
|||
|
||||
if (!BS2Success)
|
||||
{
|
||||
// Set up MSR and the BAT SPR registers.
|
||||
UReg_MSR& m_MSR = ((UReg_MSR&)PowerPC::ppcState.msr);
|
||||
m_MSR.FP = 1;
|
||||
m_MSR.DR = 1;
|
||||
m_MSR.IR = 1;
|
||||
m_MSR.EE = 1;
|
||||
PowerPC::ppcState.spr[SPR_IBAT0U] = 0x80001fff;
|
||||
PowerPC::ppcState.spr[SPR_IBAT0L] = 0x00000002;
|
||||
PowerPC::ppcState.spr[SPR_IBAT4U] = 0x90001fff;
|
||||
PowerPC::ppcState.spr[SPR_IBAT4L] = 0x10000002;
|
||||
PowerPC::ppcState.spr[SPR_DBAT0U] = 0x80001fff;
|
||||
PowerPC::ppcState.spr[SPR_DBAT0L] = 0x00000002;
|
||||
PowerPC::ppcState.spr[SPR_DBAT1U] = 0xc0001fff;
|
||||
PowerPC::ppcState.spr[SPR_DBAT1L] = 0x0000002a;
|
||||
PowerPC::ppcState.spr[SPR_DBAT4U] = 0x90001fff;
|
||||
PowerPC::ppcState.spr[SPR_DBAT4L] = 0x10000002;
|
||||
PowerPC::ppcState.spr[SPR_DBAT5U] = 0xd0001fff;
|
||||
PowerPC::ppcState.spr[SPR_DBAT5L] = 0x1000002a;
|
||||
|
||||
dolLoader.Load();
|
||||
PC = dolLoader.GetEntryPoint();
|
||||
}
|
||||
|
@ -403,7 +422,7 @@ bool CBoot::BootUp()
|
|||
if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bEnableCheats)
|
||||
{
|
||||
HLE::Patch(0x80001800, "HBReload");
|
||||
Memory::CopyToEmu(0x80001804, "STUBHAXX", 8);
|
||||
Memory::CopyToEmu(0x00001804, "STUBHAXX", 8);
|
||||
}
|
||||
|
||||
// Not part of the binary itself, but either we or Gecko OS might insert
|
||||
|
|
|
@ -41,6 +41,9 @@ bool CBoot::EmulatedBS2_GC(bool skipAppLoader)
|
|||
// Set up MSR and the BAT SPR registers.
|
||||
UReg_MSR& m_MSR = ((UReg_MSR&)PowerPC::ppcState.msr);
|
||||
m_MSR.FP = 1;
|
||||
m_MSR.DR = 1;
|
||||
m_MSR.IR = 1;
|
||||
m_MSR.EE = 1;
|
||||
PowerPC::ppcState.spr[SPR_IBAT0U] = 0x80001fff;
|
||||
PowerPC::ppcState.spr[SPR_IBAT0L] = 0x00000002;
|
||||
PowerPC::ppcState.spr[SPR_DBAT0U] = 0x80001fff;
|
||||
|
@ -54,28 +57,28 @@ bool CBoot::EmulatedBS2_GC(bool skipAppLoader)
|
|||
// Write necessary values
|
||||
// Here we write values to memory that the apploader does not take care of. Game info goes
|
||||
// to 0x80000000 according to YAGCD 4.2.
|
||||
DVDInterface::DVDRead(0x00000000, 0x80000000, 0x20, false); // write disc info
|
||||
DVDInterface::DVDRead(/*offset*/0x00000000, /*address*/0x00000000, 0x20, false); // write disc info
|
||||
|
||||
Memory::Write_U32(0x0D15EA5E, 0x80000020); // Booted from bootrom. 0xE5207C22 = booted from jtag
|
||||
Memory::Write_U32(Memory::REALRAM_SIZE, 0x80000028); // Physical Memory Size (24MB on retail)
|
||||
PowerPC::HostWrite_U32(0x0D15EA5E, 0x80000020); // Booted from bootrom. 0xE5207C22 = booted from jtag
|
||||
PowerPC::HostWrite_U32(Memory::REALRAM_SIZE, 0x80000028); // Physical Memory Size (24MB on retail)
|
||||
// TODO determine why some games fail when using a retail ID. (Seem to take different EXI paths, see Ikaruga for example)
|
||||
Memory::Write_U32(0x10000006, 0x8000002C); // Console type - DevKit (retail ID == 0x00000003) see YAGCD 4.2.1.1.2
|
||||
PowerPC::HostWrite_U32(0x10000006, 0x8000002C); // Console type - DevKit (retail ID == 0x00000003) see YAGCD 4.2.1.1.2
|
||||
|
||||
Memory::Write_U32(SConfig::GetInstance().m_LocalCoreStartupParameter.bNTSC
|
||||
PowerPC::HostWrite_U32(SConfig::GetInstance().m_LocalCoreStartupParameter.bNTSC
|
||||
? 0 : 1, 0x800000CC); // Fake the VI Init of the IPL (YAGCD 4.2.1.4)
|
||||
|
||||
Memory::Write_U32(0x01000000, 0x800000d0); // ARAM Size. 16MB main + 4/16/32MB external (retail consoles have no external ARAM)
|
||||
PowerPC::HostWrite_U32(0x01000000, 0x800000d0); // ARAM Size. 16MB main + 4/16/32MB external (retail consoles have no external ARAM)
|
||||
|
||||
Memory::Write_U32(0x09a7ec80, 0x800000F8); // Bus Clock Speed
|
||||
Memory::Write_U32(0x1cf7c580, 0x800000FC); // CPU Clock Speed
|
||||
PowerPC::HostWrite_U32(0x09a7ec80, 0x800000F8); // Bus Clock Speed
|
||||
PowerPC::HostWrite_U32(0x1cf7c580, 0x800000FC); // CPU Clock Speed
|
||||
|
||||
Memory::Write_U32(0x4c000064, 0x80000300); // Write default DFI Handler: rfi
|
||||
Memory::Write_U32(0x4c000064, 0x80000800); // Write default FPU Handler: rfi
|
||||
Memory::Write_U32(0x4c000064, 0x80000C00); // Write default Syscall Handler: rfi
|
||||
PowerPC::HostWrite_U32(0x4c000064, 0x80000300); // Write default DFI Handler: rfi
|
||||
PowerPC::HostWrite_U32(0x4c000064, 0x80000800); // Write default FPU Handler: rfi
|
||||
PowerPC::HostWrite_U32(0x4c000064, 0x80000C00); // Write default Syscall Handler: rfi
|
||||
|
||||
Memory::Write_U64((u64)CEXIIPL::GetGCTime() * (u64)40500000, 0x800030D8); // Preset time base ticks
|
||||
PowerPC::HostWrite_U64((u64)CEXIIPL::GetGCTime() * (u64)40500000, 0x800030D8); // Preset time base ticks
|
||||
// HIO checks this
|
||||
//Memory::Write_U16(0x8200, 0x000030e6); // Console type
|
||||
//PowerPC::HostWrite_U16(0x8200, 0x000030e6); // Console type
|
||||
|
||||
HLE::Patch(0x81300000, "OSReport"); // HLE OSReport for Apploader
|
||||
|
||||
|
@ -89,7 +92,7 @@ bool CBoot::EmulatedBS2_GC(bool skipAppLoader)
|
|||
INFO_LOG(BOOT, "GC BS2: Not running apploader!");
|
||||
return false;
|
||||
}
|
||||
VolumeHandler::ReadToPtr(Memory::GetPointer(0x81200000), iAppLoaderOffset + 0x20, iAppLoaderSize, false);
|
||||
DVDInterface::DVDRead(iAppLoaderOffset + 0x20, 0x01200000, iAppLoaderSize, false);
|
||||
|
||||
// Setup pointers like real BS2 does
|
||||
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bNTSC)
|
||||
|
@ -114,9 +117,9 @@ bool CBoot::EmulatedBS2_GC(bool skipAppLoader)
|
|||
PowerPC::ppcState.gpr[4] = iAppLoaderFuncAddr + 4;
|
||||
PowerPC::ppcState.gpr[5] = iAppLoaderFuncAddr + 8;
|
||||
RunFunction(iAppLoaderEntry);
|
||||
u32 iAppLoaderInit = Memory::ReadUnchecked_U32(iAppLoaderFuncAddr + 0);
|
||||
u32 iAppLoaderMain = Memory::ReadUnchecked_U32(iAppLoaderFuncAddr + 4);
|
||||
u32 iAppLoaderClose = Memory::ReadUnchecked_U32(iAppLoaderFuncAddr + 8);
|
||||
u32 iAppLoaderInit = PowerPC::Read_U32(iAppLoaderFuncAddr + 0);
|
||||
u32 iAppLoaderMain = PowerPC::Read_U32(iAppLoaderFuncAddr + 4);
|
||||
u32 iAppLoaderClose = PowerPC::Read_U32(iAppLoaderFuncAddr + 8);
|
||||
|
||||
// iAppLoaderInit
|
||||
DEBUG_LOG(MASTER_LOG, "Call iAppLoaderInit");
|
||||
|
@ -135,9 +138,9 @@ bool CBoot::EmulatedBS2_GC(bool skipAppLoader)
|
|||
|
||||
RunFunction(iAppLoaderMain);
|
||||
|
||||
u32 iRamAddress = Memory::ReadUnchecked_U32(0x81300004);
|
||||
u32 iLength = Memory::ReadUnchecked_U32(0x81300008);
|
||||
u32 iDVDOffset = Memory::ReadUnchecked_U32(0x8130000c);
|
||||
u32 iRamAddress = PowerPC::Read_U32(0x81300004);
|
||||
u32 iLength = PowerPC::Read_U32(0x81300008);
|
||||
u32 iDVDOffset = PowerPC::Read_U32(0x8130000c);
|
||||
|
||||
INFO_LOG(MASTER_LOG, "DVDRead: offset: %08x memOffset: %08x length: %i", iDVDOffset, iRamAddress, iLength);
|
||||
DVDInterface::DVDRead(iDVDOffset, iRamAddress, iLength, false);
|
||||
|
@ -239,7 +242,7 @@ bool CBoot::SetupWiiMemory(IVolume::ECountry country)
|
|||
0x80000060 Copyright code
|
||||
*/
|
||||
|
||||
DVDInterface::DVDRead(0x00000000, 0x00000000, 0x20, false); // Game Code
|
||||
DVDInterface::DVDRead(0x00000000, 0x00000000, 0x20, false); // Game Code
|
||||
Memory::Write_U32(0x0D15EA5E, 0x00000020); // Another magic word
|
||||
Memory::Write_U32(0x00000001, 0x00000024); // Unknown
|
||||
Memory::Write_U32(Memory::REALRAM_SIZE, 0x00000028); // MEM1 size 24MB
|
||||
|
@ -253,12 +256,12 @@ bool CBoot::SetupWiiMemory(IVolume::ECountry country)
|
|||
Memory::Write_U32(0x8179b500, 0x000000f4); // __start
|
||||
Memory::Write_U32(0x0e7be2c0, 0x000000f8); // Bus speed
|
||||
Memory::Write_U32(0x2B73A840, 0x000000fc); // CPU speed
|
||||
Memory::Write_U16(0x0000, 0x000030e6); // Console type
|
||||
Memory::Write_U16(0x0000, 0x000030e6); // Console type
|
||||
Memory::Write_U32(0x00000000, 0x000030c0); // EXI
|
||||
Memory::Write_U32(0x00000000, 0x000030c4); // EXI
|
||||
Memory::Write_U32(0x00000000, 0x000030dc); // Time
|
||||
Memory::Write_U32(0x00000000, 0x000030d8); // Time
|
||||
Memory::Write_U16(0x8201, 0x000030e6); // Dev console / debug capable
|
||||
Memory::Write_U16(0x8201, 0x000030e6); // Dev console / debug capable
|
||||
Memory::Write_U32(0x00000000, 0x000030f0); // Apploader
|
||||
Memory::Write_U32(0x01800000, 0x00003100); // BAT
|
||||
Memory::Write_U32(0x01800000, 0x00003104); // BAT
|
||||
|
@ -275,7 +278,7 @@ bool CBoot::SetupWiiMemory(IVolume::ECountry country)
|
|||
// 40 is copied from 88 after running apploader
|
||||
Memory::Write_U32(0x00090204, 0x00003140); // IOS revision (IOS9, v2.4)
|
||||
Memory::Write_U32(0x00062507, 0x00003144); // IOS date in USA format (June 25, 2007)
|
||||
Memory::Write_U16(0x0113, 0x0000315e); // Apploader
|
||||
Memory::Write_U16(0x0113, 0x0000315e); // Apploader
|
||||
Memory::Write_U32(0x0000FF16, 0x00003158); // DDR ram vendor code
|
||||
Memory::Write_U32(0x00000000, 0x00003160); // Init semaphore (sysmenu waits for this to clear)
|
||||
Memory::Write_U32(0x00090204, 0x00003188); // Expected IOS revision
|
||||
|
@ -290,7 +293,7 @@ bool CBoot::SetupWiiMemory(IVolume::ECountry country)
|
|||
// Clear exception handler. Why? Don't we begin with only zeros?
|
||||
for (int i = 0x3000; i <= 0x3038; i += 4)
|
||||
{
|
||||
Memory::Write_U32(0x00000000, 0x80000000 + i);
|
||||
Memory::Write_U32(0x00000000, i);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -314,7 +317,7 @@ bool CBoot::EmulatedBS2_Wii()
|
|||
// values as the game boots. This location keep the 4 byte ID for as long
|
||||
// as the game is running. The 6 byte ID at 0x00 is overwritten sometime
|
||||
// after this check during booting.
|
||||
VolumeHandler::ReadToPtr(Memory::GetPointer(0x3180), 0, 4, true);
|
||||
DVDInterface::DVDRead(0, 0x3180, 4, true);
|
||||
|
||||
// Execute the apploader
|
||||
bool apploaderRan = false;
|
||||
|
@ -323,9 +326,12 @@ bool CBoot::EmulatedBS2_Wii()
|
|||
// Set up MSR and the BAT SPR registers.
|
||||
UReg_MSR& m_MSR = ((UReg_MSR&)PowerPC::ppcState.msr);
|
||||
m_MSR.FP = 1;
|
||||
m_MSR.DR = 1;
|
||||
m_MSR.IR = 1;
|
||||
m_MSR.EE = 1;
|
||||
PowerPC::ppcState.spr[SPR_IBAT0U] = 0x80001fff;
|
||||
PowerPC::ppcState.spr[SPR_IBAT0L] = 0x00000002;
|
||||
PowerPC::ppcState.spr[SPR_IBAT4L] = 0x90001fff;
|
||||
PowerPC::ppcState.spr[SPR_IBAT4U] = 0x90001fff;
|
||||
PowerPC::ppcState.spr[SPR_IBAT4L] = 0x10000002;
|
||||
PowerPC::ppcState.spr[SPR_DBAT0U] = 0x80001fff;
|
||||
PowerPC::ppcState.spr[SPR_DBAT0L] = 0x00000002;
|
||||
|
@ -336,9 +342,9 @@ bool CBoot::EmulatedBS2_Wii()
|
|||
PowerPC::ppcState.spr[SPR_DBAT5U] = 0xd0001fff;
|
||||
PowerPC::ppcState.spr[SPR_DBAT5L] = 0x1000002a;
|
||||
|
||||
Memory::Write_U32(0x4c000064, 0x80000300); // Write default DFI Handler: rfi
|
||||
Memory::Write_U32(0x4c000064, 0x80000800); // Write default FPU Handler: rfi
|
||||
Memory::Write_U32(0x4c000064, 0x80000C00); // Write default Syscall Handler: rfi
|
||||
Memory::Write_U32(0x4c000064, 0x00000300); // Write default DSI Handler: rfi
|
||||
Memory::Write_U32(0x4c000064, 0x00000800); // Write default FPU Handler: rfi
|
||||
Memory::Write_U32(0x4c000064, 0x00000C00); // Write default Syscall Handler: rfi
|
||||
|
||||
HLE::Patch(0x81300000, "OSReport"); // HLE OSReport for Apploader
|
||||
|
||||
|
@ -354,7 +360,7 @@ bool CBoot::EmulatedBS2_Wii()
|
|||
ERROR_LOG(BOOT, "Invalid apploader. Probably your image is corrupted.");
|
||||
return false;
|
||||
}
|
||||
VolumeHandler::ReadToPtr(Memory::GetPointer(0x81200000), iAppLoaderOffset + 0x20, iAppLoaderSize, true);
|
||||
DVDInterface::DVDRead(iAppLoaderOffset + 0x20, 0x01200000, iAppLoaderSize, true);
|
||||
|
||||
//call iAppLoaderEntry
|
||||
DEBUG_LOG(BOOT, "Call iAppLoaderEntry");
|
||||
|
@ -364,9 +370,9 @@ bool CBoot::EmulatedBS2_Wii()
|
|||
PowerPC::ppcState.gpr[4] = iAppLoaderFuncAddr + 4;
|
||||
PowerPC::ppcState.gpr[5] = iAppLoaderFuncAddr + 8;
|
||||
RunFunction(iAppLoaderEntry);
|
||||
u32 iAppLoaderInit = Memory::ReadUnchecked_U32(iAppLoaderFuncAddr+0);
|
||||
u32 iAppLoaderMain = Memory::ReadUnchecked_U32(iAppLoaderFuncAddr+4);
|
||||
u32 iAppLoaderClose = Memory::ReadUnchecked_U32(iAppLoaderFuncAddr+8);
|
||||
u32 iAppLoaderInit = PowerPC::Read_U32(iAppLoaderFuncAddr + 0);
|
||||
u32 iAppLoaderMain = PowerPC::Read_U32(iAppLoaderFuncAddr + 4);
|
||||
u32 iAppLoaderClose = PowerPC::Read_U32(iAppLoaderFuncAddr + 8);
|
||||
|
||||
// iAppLoaderInit
|
||||
DEBUG_LOG(BOOT, "Run iAppLoaderInit");
|
||||
|
@ -387,9 +393,9 @@ bool CBoot::EmulatedBS2_Wii()
|
|||
|
||||
RunFunction(iAppLoaderMain);
|
||||
|
||||
u32 iRamAddress = Memory::ReadUnchecked_U32(0x81300004);
|
||||
u32 iLength = Memory::ReadUnchecked_U32(0x81300008);
|
||||
u32 iDVDOffset = Memory::ReadUnchecked_U32(0x8130000c) << 2;
|
||||
u32 iRamAddress = PowerPC::Read_U32(0x81300004);
|
||||
u32 iLength = PowerPC::Read_U32(0x81300008);
|
||||
u32 iDVDOffset = PowerPC::Read_U32(0x8130000c) << 2;
|
||||
|
||||
INFO_LOG(BOOT, "DVDRead: offset: %08x memOffset: %08x length: %i", iDVDOffset, iRamAddress, iLength);
|
||||
DVDInterface::DVDRead(iDVDOffset, iRamAddress, iLength, true);
|
||||
|
@ -404,8 +410,8 @@ bool CBoot::EmulatedBS2_Wii()
|
|||
// Pass the "#002 check"
|
||||
// Apploader writes the IOS version and revision here, we copy it
|
||||
// Fake IOSv9 r2.4 if no version is found (elf loading)
|
||||
u32 firmwareVer = Memory::Read_U32(0x80003188);
|
||||
Memory::Write_U32(firmwareVer ? firmwareVer : 0x00090204, 0x00003140);
|
||||
u32 firmwareVer = PowerPC::Read_U32(0x80003188);
|
||||
PowerPC::Write_U32(firmwareVer ? firmwareVer : 0x00090204, 0x80003140);
|
||||
|
||||
// Load patches and run startup patches
|
||||
PatchEngine::LoadPatches();
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include "Core/Boot/Boot_DOL.h"
|
||||
#include "Core/HW/Memmap.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
|
||||
CDolLoader::CDolLoader(u8* _pBuffer, u32 _Size)
|
||||
: m_isWii(false)
|
||||
|
|
|
@ -107,7 +107,7 @@ bool CBoot::Boot_WiiWAD(const std::string& _pFilename)
|
|||
pDolLoader = std::make_unique<CDolLoader>(pContent->m_Filename);
|
||||
}
|
||||
pDolLoader->Load();
|
||||
PC = pDolLoader->GetEntryPoint() | 0x80000000;
|
||||
PC = pDolLoader->GetEntryPoint();
|
||||
|
||||
// Pass the "#002 check"
|
||||
// Apploader should write the IOS version and revision to 0x3140, and compare it
|
||||
|
|
|
@ -109,7 +109,6 @@ set(SRCS ActionReplay.cpp
|
|||
HW/GPFifo.cpp
|
||||
HW/HW.cpp
|
||||
HW/Memmap.cpp
|
||||
HW/MemmapFunctions.cpp
|
||||
HW/MemoryInterface.cpp
|
||||
HW/MMIO.cpp
|
||||
HW/ProcessorInterface.cpp
|
||||
|
@ -153,6 +152,7 @@ set(SRCS ActionReplay.cpp
|
|||
IPC_HLE/WII_IPC_HLE_Device_usb_kbd.cpp
|
||||
IPC_HLE/WII_IPC_HLE_WiiMote.cpp
|
||||
IPC_HLE/WiiMote_HID_Attr.cpp
|
||||
PowerPC/MMU.cpp
|
||||
PowerPC/PowerPC.cpp
|
||||
PowerPC/PPCAnalyst.cpp
|
||||
PowerPC/PPCCache.cpp
|
||||
|
|
|
@ -140,7 +140,6 @@
|
|||
<ClCompile Include="HW\GPFifo.cpp" />
|
||||
<ClCompile Include="HW\HW.cpp" />
|
||||
<ClCompile Include="HW\Memmap.cpp" />
|
||||
<ClCompile Include="HW\MemmapFunctions.cpp" />
|
||||
<ClCompile Include="HW\MemoryInterface.cpp" />
|
||||
<ClCompile Include="HW\MMIO.cpp" />
|
||||
<ClCompile Include="HW\ProcessorInterface.cpp" />
|
||||
|
@ -245,6 +244,7 @@
|
|||
<ClCompile Include="PowerPC\JitCommon\Jit_Util.cpp" />
|
||||
<ClCompile Include="PowerPC\JitCommon\TrampolineCache.cpp" />
|
||||
<ClCompile Include="PowerPC\JitInterface.cpp" />
|
||||
<ClCompile Include="PowerPC\MMU.cpp" />
|
||||
<ClCompile Include="PowerPC\PowerPC.cpp" />
|
||||
<ClCompile Include="PowerPC\PPCAnalyst.cpp" />
|
||||
<ClCompile Include="PowerPC\PPCCache.cpp" />
|
||||
|
|
|
@ -512,9 +512,6 @@
|
|||
<ClCompile Include="HW\Memmap.cpp">
|
||||
<Filter>HW %28Flipper/Hollywood%29</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HW\MemmapFunctions.cpp">
|
||||
<Filter>HW %28Flipper/Hollywood%29</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HW\MMIO.cpp">
|
||||
<Filter>HW %28Flipper/Hollywood%29</Filter>
|
||||
</ClCompile>
|
||||
|
@ -726,6 +723,8 @@
|
|||
</ClCompile>
|
||||
<ClCompile Include="HW\GCKeyboard.cpp">
|
||||
<Filter>HW %28Flipper/Hollywood%29\GCKeyboard</Filter>
|
||||
<ClCompile Include="PowerPC\MMU.cpp">
|
||||
<Filter>PowerPC</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
|
|
@ -39,27 +39,27 @@ void AddAutoBreakpoints()
|
|||
// Returns true if the address is not a valid RAM address or NULL.
|
||||
static bool IsStackBottom(u32 addr)
|
||||
{
|
||||
return !addr || !Memory::IsRAMAddress(addr);
|
||||
return !addr || !PowerPC::HostIsRAMAddress(addr);
|
||||
}
|
||||
|
||||
static void WalkTheStack(const std::function<void(u32)>& stack_step)
|
||||
{
|
||||
if (!IsStackBottom(PowerPC::ppcState.gpr[1]))
|
||||
{
|
||||
u32 addr = Memory::ReadUnchecked_U32(PowerPC::ppcState.gpr[1]); // SP
|
||||
u32 addr = PowerPC::HostRead_U32(PowerPC::ppcState.gpr[1]); // SP
|
||||
|
||||
// Walk the stack chain
|
||||
for (int count = 0;
|
||||
!IsStackBottom(addr + 4) && (count++ < 20);
|
||||
++count)
|
||||
{
|
||||
u32 func_addr = Memory::ReadUnchecked_U32(addr + 4);
|
||||
u32 func_addr = PowerPC::HostRead_U32(addr + 4);
|
||||
stack_step(func_addr);
|
||||
|
||||
if (IsStackBottom(addr))
|
||||
break;
|
||||
|
||||
addr = Memory::ReadUnchecked_U32(addr);
|
||||
addr = PowerPC::HostRead_U32(addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ static void WalkTheStack(const std::function<void(u32)>& stack_step)
|
|||
// instead of "pointing ahead"
|
||||
bool GetCallstack(std::vector<CallstackEntry> &output)
|
||||
{
|
||||
if (!Core::IsRunning() || !Memory::IsRAMAddress(PowerPC::ppcState.gpr[1]))
|
||||
if (!Core::IsRunning() || !PowerPC::HostIsRAMAddress(PowerPC::ppcState.gpr[1]))
|
||||
return false;
|
||||
|
||||
if (LR == 0)
|
||||
|
|
|
@ -19,26 +19,22 @@
|
|||
|
||||
std::string PPCDebugInterface::Disassemble(unsigned int address)
|
||||
{
|
||||
// Memory::ReadUnchecked_U32 seemed to crash on shutdown
|
||||
// PowerPC::HostRead_U32 seemed to crash on shutdown
|
||||
if (PowerPC::GetState() == PowerPC::CPU_POWERDOWN)
|
||||
return "";
|
||||
|
||||
if (Core::GetState() != Core::CORE_UNINITIALIZED)
|
||||
if (Core::GetState() == Core::CORE_PAUSE)
|
||||
{
|
||||
if (!Memory::IsRAMAddress(address, true, true))
|
||||
if (!PowerPC::HostIsRAMAddress(address))
|
||||
{
|
||||
if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bMMU || !((address & JIT_ICACHE_VMEM_BIT) &&
|
||||
Memory::TranslateAddress<Memory::FLAG_NO_EXCEPTION>(address)))
|
||||
{
|
||||
return "(No RAM here)";
|
||||
}
|
||||
return "(No RAM here)";
|
||||
}
|
||||
|
||||
u32 op = Memory::Read_Instruction(address);
|
||||
u32 op = PowerPC::HostRead_Instruction(address);
|
||||
std::string disasm = GekkoDisassembler::Disassemble(op, address);
|
||||
|
||||
UGeckoInstruction inst;
|
||||
inst.hex = Memory::ReadUnchecked_U32(address);
|
||||
inst.hex = PowerPC::HostRead_U32(address);
|
||||
|
||||
if (inst.OPCD == 1)
|
||||
{
|
||||
|
@ -57,7 +53,7 @@ void PPCDebugInterface::GetRawMemoryString(int memory, unsigned int address, cha
|
|||
{
|
||||
if (Core::GetState() != Core::CORE_UNINITIALIZED)
|
||||
{
|
||||
if (memory || Memory::IsRAMAddress(address, true, true))
|
||||
if (memory || PowerPC::HostIsRAMAddress(address))
|
||||
{
|
||||
snprintf(dest, max_size, "%08X%s", ReadExtraMemory(memory, address), memory ? " (ARAM)" : "");
|
||||
}
|
||||
|
@ -74,7 +70,7 @@ void PPCDebugInterface::GetRawMemoryString(int memory, unsigned int address, cha
|
|||
|
||||
unsigned int PPCDebugInterface::ReadMemory(unsigned int address)
|
||||
{
|
||||
return Memory::ReadUnchecked_U32(address);
|
||||
return PowerPC::HostRead_U32(address);
|
||||
}
|
||||
|
||||
unsigned int PPCDebugInterface::ReadExtraMemory(int memory, unsigned int address)
|
||||
|
@ -82,7 +78,7 @@ unsigned int PPCDebugInterface::ReadExtraMemory(int memory, unsigned int address
|
|||
switch (memory)
|
||||
{
|
||||
case 0:
|
||||
return Memory::ReadUnchecked_U32(address);
|
||||
return PowerPC::HostRead_U32(address);
|
||||
case 1:
|
||||
return (DSP::ReadARAM(address) << 24) |
|
||||
(DSP::ReadARAM(address + 1) << 16) |
|
||||
|
@ -95,7 +91,7 @@ unsigned int PPCDebugInterface::ReadExtraMemory(int memory, unsigned int address
|
|||
|
||||
unsigned int PPCDebugInterface::ReadInstruction(unsigned int address)
|
||||
{
|
||||
return Memory::Read_Instruction(address);
|
||||
return PowerPC::HostRead_Instruction(address);
|
||||
}
|
||||
|
||||
bool PPCDebugInterface::IsAlive()
|
||||
|
@ -170,7 +166,7 @@ void PPCDebugInterface::ToggleMemCheck(unsigned int address)
|
|||
|
||||
void PPCDebugInterface::InsertBLR(unsigned int address, unsigned int value)
|
||||
{
|
||||
Memory::Write_U32(value, address);
|
||||
PowerPC::HostWrite_U32(value, address);
|
||||
}
|
||||
|
||||
void PPCDebugInterface::BreakNow()
|
||||
|
@ -184,7 +180,9 @@ void PPCDebugInterface::BreakNow()
|
|||
// -------------
|
||||
int PPCDebugInterface::GetColor(unsigned int address)
|
||||
{
|
||||
if (!Memory::IsRAMAddress(address, true, true))
|
||||
if (!IsAlive())
|
||||
return 0xFFFFFF;
|
||||
if (!PowerPC::HostIsRAMAddress(address))
|
||||
return 0xeeeeee;
|
||||
static const int colors[6] =
|
||||
{
|
||||
|
|
|
@ -348,6 +348,17 @@ void FifoPlayer::SetupFifo()
|
|||
|
||||
void FifoPlayer::LoadMemory()
|
||||
{
|
||||
UReg_MSR newMSR;
|
||||
newMSR.DR = 1;
|
||||
newMSR.IR = 1;
|
||||
MSR = 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;
|
||||
|
||||
Memory::Clear();
|
||||
|
||||
SetupFifo();
|
||||
|
@ -391,12 +402,12 @@ void FifoPlayer::LoadMemory()
|
|||
|
||||
void FifoPlayer::WriteCP(u32 address, u16 value)
|
||||
{
|
||||
Memory::Write_U16(value, 0xCC000000 | address);
|
||||
PowerPC::Write_U16(value, 0xCC000000 | address);
|
||||
}
|
||||
|
||||
void FifoPlayer::WritePI(u32 address, u32 value)
|
||||
{
|
||||
Memory::Write_U32(value, 0xCC003000 | address);
|
||||
PowerPC::Write_U32(value, 0xCC003000 | address);
|
||||
}
|
||||
|
||||
void FifoPlayer::FlushWGP()
|
||||
|
|
|
@ -90,16 +90,17 @@ static bool InstallCodeHandler()
|
|||
}
|
||||
|
||||
// Install code handler
|
||||
Memory::CopyToEmu(INSTALLER_BASE_ADDRESS, data.data(), data.length());
|
||||
for (size_t i = 0, e = data.length(); i < e; ++i)
|
||||
PowerPC::HostWrite_U8(data[i], (u32)(INSTALLER_BASE_ADDRESS + i));
|
||||
|
||||
// Patch the code handler to the system starting up
|
||||
for (unsigned int h = 0; h < data.length(); h += 4)
|
||||
{
|
||||
// Patch MMIO address
|
||||
if (Memory::ReadUnchecked_U32(INSTALLER_BASE_ADDRESS + h) == (0x3f000000u | ((mmioAddr ^ 1) << 8)))
|
||||
if (PowerPC::HostRead_U32(INSTALLER_BASE_ADDRESS + h) == (0x3f000000u | ((mmioAddr ^ 1) << 8)))
|
||||
{
|
||||
NOTICE_LOG(ACTIONREPLAY, "Patching MMIO access at %08x", INSTALLER_BASE_ADDRESS + h);
|
||||
Memory::Write_U32(0x3f000000u | mmioAddr << 8, INSTALLER_BASE_ADDRESS + h);
|
||||
PowerPC::HostWrite_U32(0x3f000000u | mmioAddr << 8, INSTALLER_BASE_ADDRESS + h);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -107,11 +108,11 @@ static bool InstallCodeHandler()
|
|||
u32 codelist_end_address = INSTALLER_END_ADDRESS;
|
||||
|
||||
// Write a magic value to 'gameid' (codehandleronly does not actually read this).
|
||||
Memory::Write_U32(0xd01f1bad, INSTALLER_BASE_ADDRESS);
|
||||
PowerPC::HostWrite_U32(0xd01f1bad, INSTALLER_BASE_ADDRESS);
|
||||
|
||||
// Create GCT in memory
|
||||
Memory::Write_U32(0x00d0c0de, codelist_base_address);
|
||||
Memory::Write_U32(0x00d0c0de, codelist_base_address + 4);
|
||||
PowerPC::HostWrite_U32(0x00d0c0de, codelist_base_address);
|
||||
PowerPC::HostWrite_U32(0x00d0c0de, codelist_base_address + 4);
|
||||
|
||||
std::lock_guard<std::mutex> lk(active_codes_lock);
|
||||
|
||||
|
@ -126,19 +127,19 @@ static bool InstallCodeHandler()
|
|||
// Make sure we have enough memory to hold the code list
|
||||
if ((codelist_base_address + 24 + i) < codelist_end_address)
|
||||
{
|
||||
Memory::Write_U32(code.address, codelist_base_address + 8 + i);
|
||||
Memory::Write_U32(code.data, codelist_base_address + 12 + i);
|
||||
PowerPC::HostWrite_U32(code.address, codelist_base_address + 8 + i);
|
||||
PowerPC::HostWrite_U32(code.data, codelist_base_address + 12 + i);
|
||||
i += 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Memory::Write_U32(0xff000000, codelist_base_address + 8 + i);
|
||||
Memory::Write_U32(0x00000000, codelist_base_address + 12 + i);
|
||||
PowerPC::HostWrite_U32(0xff000000, codelist_base_address + 8 + i);
|
||||
PowerPC::HostWrite_U32(0x00000000, codelist_base_address + 12 + i);
|
||||
|
||||
// Turn on codes
|
||||
Memory::Write_U8(1, INSTALLER_BASE_ADDRESS + 7);
|
||||
PowerPC::HostWrite_U8(1, INSTALLER_BASE_ADDRESS + 7);
|
||||
|
||||
// Invalidate the icache and any asm codes
|
||||
for (unsigned int j = 0; j < (INSTALLER_END_ADDRESS - INSTALLER_BASE_ADDRESS); j += 32)
|
||||
|
@ -156,7 +157,7 @@ void RunCodeHandler()
|
|||
{
|
||||
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bEnableCheats && active_codes.size() > 0)
|
||||
{
|
||||
if (!code_handler_installed || Memory::Read_U32(INSTALLER_BASE_ADDRESS) - 0xd01f1bad > 5)
|
||||
if (!code_handler_installed || PowerPC::HostRead_U32(INSTALLER_BASE_ADDRESS) - 0xd01f1bad > 5)
|
||||
code_handler_installed = InstallCodeHandler();
|
||||
|
||||
if (!code_handler_installed)
|
||||
|
|
|
@ -63,7 +63,7 @@ void HLEGeckoCodehandler()
|
|||
// robust alternative would be to actually detect memory writes, but that
|
||||
// would be even uglier.)
|
||||
u32 magic = 0xd01f1bad;
|
||||
u32 existing = Memory::Read_U32(0x80001800);
|
||||
u32 existing = PowerPC::HostRead_U32(0x80001800);
|
||||
if (existing - magic == 5)
|
||||
{
|
||||
return;
|
||||
|
@ -72,7 +72,7 @@ void HLEGeckoCodehandler()
|
|||
{
|
||||
existing = magic;
|
||||
}
|
||||
Memory::Write_U32(existing + 1, 0x80001800);
|
||||
PowerPC::HostWrite_U32(existing + 1, 0x80001800);
|
||||
PowerPC::ppcState.iCache.Reset();
|
||||
}
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ void HLE_OSPanic()
|
|||
void HLE_GeneralDebugPrint()
|
||||
{
|
||||
std::string ReportMessage;
|
||||
if (Memory::Read_U32(GPR(3)) > 0x80000000)
|
||||
if (PowerPC::HostRead_U32(GPR(3)) > 0x80000000)
|
||||
{
|
||||
GetStringVA(ReportMessage, 4);
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ void GetStringVA(std::string& _rOutBuffer, u32 strReg)
|
|||
std::string ArgumentBuffer = "";
|
||||
u32 ParameterCounter = strReg+1;
|
||||
u32 FloatingParameterCounter = 1;
|
||||
std::string string = Memory::GetString(GPR(strReg));
|
||||
std::string string = PowerPC::HostGetString(GPR(strReg));
|
||||
|
||||
for(u32 i = 0; i < string.size(); i++)
|
||||
{
|
||||
|
@ -84,7 +84,7 @@ void GetStringVA(std::string& _rOutBuffer, u32 strReg)
|
|||
u64 Parameter;
|
||||
if (ParameterCounter > 10)
|
||||
{
|
||||
Parameter = Memory::Read_U32(GPR(1) + 0x8 + ((ParameterCounter - 11) * 4));
|
||||
Parameter = PowerPC::HostRead_U32(GPR(1) + 0x8 + ((ParameterCounter - 11) * 4));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -101,7 +101,7 @@ void GetStringVA(std::string& _rOutBuffer, u32 strReg)
|
|||
switch (string[i])
|
||||
{
|
||||
case 's':
|
||||
_rOutBuffer += StringFromFormat(ArgumentBuffer.c_str(), Memory::GetString((u32)Parameter).c_str());
|
||||
_rOutBuffer += StringFromFormat(ArgumentBuffer.c_str(), PowerPC::HostGetString((u32)Parameter).c_str());
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
|
@ -135,7 +135,7 @@ void GetStringVA(std::string& _rOutBuffer, u32 strReg)
|
|||
_rOutBuffer += string[i];
|
||||
}
|
||||
}
|
||||
if (_rOutBuffer[_rOutBuffer.length() - 1] == '\n')
|
||||
if (!_rOutBuffer.empty() && _rOutBuffer[_rOutBuffer.length() - 1] == '\n')
|
||||
_rOutBuffer.resize(_rOutBuffer.length() - 1);
|
||||
}
|
||||
|
||||
|
|
|
@ -58,12 +58,12 @@ void DSPDebugInterface::GetRawMemoryString(int memory, unsigned int address, cha
|
|||
|
||||
unsigned int DSPDebugInterface::ReadMemory(unsigned int address)
|
||||
{
|
||||
return 0; //Memory::ReadUnchecked_U32(address);
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int DSPDebugInterface::ReadInstruction(unsigned int address)
|
||||
{
|
||||
return 0; //Memory::Read_Instruction(address);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool DSPDebugInterface::IsAlive()
|
||||
|
|
|
@ -185,7 +185,9 @@ bool DSPLLE::Initialize(bool bWii, bool bDSPThread)
|
|||
return false;
|
||||
|
||||
// DSPLLE directly accesses the fastmem arena.
|
||||
g_dsp.cpu_ram = Memory::base;
|
||||
// TODO: The fastmem arena is only supposed to be used by the JIT:
|
||||
// among other issues, its size is only 1GB on 32-bit targets.
|
||||
g_dsp.cpu_ram = Memory::physical_base;
|
||||
DSPCore_Reset();
|
||||
|
||||
InitInstructionTable();
|
||||
|
|
|
@ -470,7 +470,7 @@ void SetLidOpen(bool _bOpen)
|
|||
|
||||
bool DVDRead(u64 _iDVDOffset, u32 _iRamAddress, u32 _iLength, bool decrypt)
|
||||
{
|
||||
return VolumeHandler::ReadToPtr(Memory::GetPointer(_iRamAddress), _iDVDOffset, _iLength, decrypt);
|
||||
return VolumeHandler::ReadToPtr(Memory::GetPointer(_iRamAddress), _iDVDOffset, _iLength, decrypt);
|
||||
}
|
||||
|
||||
void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
|
||||
|
|
|
@ -53,7 +53,8 @@ static bool bMMU = false;
|
|||
// Init() declarations
|
||||
// ----------------
|
||||
// Store the MemArena here
|
||||
u8* base = nullptr;
|
||||
u8* physical_base = nullptr;
|
||||
u8* logical_base = nullptr;
|
||||
|
||||
// The MemArena class
|
||||
static MemArena g_arena;
|
||||
|
@ -102,17 +103,60 @@ bool IsInitialized()
|
|||
}
|
||||
|
||||
|
||||
// We don't declare the IO region in here since its handled by other means.
|
||||
// Dolphin allocates memory to represent four regions:
|
||||
// - 24MB RAM, available on Gamecube and Wii
|
||||
// - 64MB "EXRAM", RAM only available on Wii
|
||||
// - 64MB FakeVMem, allocated when MMU support is turned off. This is used
|
||||
// to approximate the behavior of a common library which pages memory to
|
||||
// and from the DSP's dedicated RAM, which isn't directly addressable on
|
||||
// GameCube.
|
||||
// - 256KB Locked L1, to represent cache lines allocated out of the L1 data cache
|
||||
// cache in Locked L1 mode. Dolphin does not emulate this hardware feature
|
||||
// accurately; it just pretends there is extra memory at 0xE0000000.
|
||||
//
|
||||
// The 4GB starting at physical_base represents access from the CPU
|
||||
// with address translation turned off. (This is only used by the CPU;
|
||||
// other devices, like the GPU, use other rules, approximated by
|
||||
// Memory::GetPointer.) This memory is laid out as follows:
|
||||
// [0x00000000, 0x01800000) - 24MB RAM
|
||||
// [0x08000000, 0x0C000000) - EFB "mapping" (not handled here)
|
||||
// [0x0C000000, 0x0E000000) - MMIO etc. (not handled here)
|
||||
// [0x10000000, 0x14000000) - 64MB RAM (Wii-only; slightly slower)
|
||||
//
|
||||
// The 4GB starting at logical_base represents access from the CPU
|
||||
// with address translation turned on. Instead of changing the mapping
|
||||
// based on the BAT registers, we approximate the common BAT configuration
|
||||
// used by games:
|
||||
// [0x00000000, 0x01800000) - 24MB RAM, cached access, normally only mapped
|
||||
// during startup by Wii WADs
|
||||
// [0x40000000, 0x50000000) - FakeVMEM
|
||||
// [0x70000000, 0x80000000) - FakeVMEM
|
||||
// [0x80000000, 0x81800000) - 24MB RAM, cached access
|
||||
// [0x90000000, 0x94000000) - 64MB RAM, Wii-only, cached access
|
||||
// [0xC0000000, 0xC1800000) - 24MB RAM, uncached access
|
||||
// [0xC8000000, 0xCC000000) - EFB "mapping" (not handled here)
|
||||
// [0xCC000000, 0xCE000000) - MMIO etc. (not handled here)
|
||||
// [0xD0000000, 0xD4000000) - 64MB RAM, Wii-only, uncached access
|
||||
// [0xE0000000, 0xE0040000) - 256KB locked L1
|
||||
//
|
||||
// TODO: We shouldn't hardcode this mapping; we can generate it dynamically
|
||||
// based on the BAT registers.
|
||||
//
|
||||
// Each of these 4GB regions is followed by 4GB of empty space so overflows
|
||||
// in address computation in the JIT don't access the wrong memory.
|
||||
//
|
||||
// Dolphin doesn't emulate the difference between cached and uncached access.
|
||||
static MemoryView views[] =
|
||||
{
|
||||
{&m_pRAM, 0x00000000, RAM_SIZE, 0},
|
||||
{nullptr, 0x80000000, RAM_SIZE, MV_MIRROR_PREVIOUS},
|
||||
{nullptr, 0xC0000000, RAM_SIZE, MV_MIRROR_PREVIOUS},
|
||||
{&m_pL1Cache, 0xE0000000, L1_CACHE_SIZE, 0},
|
||||
{&m_pFakeVMEM, 0x7E000000, FAKEVMEM_SIZE, MV_FAKE_VMEM},
|
||||
{nullptr, 0x200000000, RAM_SIZE, MV_MIRROR_PREVIOUS},
|
||||
{nullptr, 0x280000000, RAM_SIZE, MV_MIRROR_PREVIOUS},
|
||||
{nullptr, 0x2C0000000, RAM_SIZE, MV_MIRROR_PREVIOUS},
|
||||
{&m_pL1Cache, 0x2E0000000, L1_CACHE_SIZE, 0},
|
||||
{&m_pFakeVMEM, 0x27E000000, FAKEVMEM_SIZE, MV_FAKE_VMEM},
|
||||
{&m_pEXRAM, 0x10000000, EXRAM_SIZE, MV_WII_ONLY},
|
||||
{nullptr, 0x90000000, EXRAM_SIZE, MV_WII_ONLY | MV_MIRROR_PREVIOUS},
|
||||
{nullptr, 0xD0000000, EXRAM_SIZE, MV_WII_ONLY | MV_MIRROR_PREVIOUS},
|
||||
{nullptr, 0x290000000, EXRAM_SIZE, MV_WII_ONLY | MV_MIRROR_PREVIOUS},
|
||||
{nullptr, 0x2D0000000, EXRAM_SIZE, MV_WII_ONLY | MV_MIRROR_PREVIOUS},
|
||||
};
|
||||
static const int num_views = sizeof(views) / sizeof(MemoryView);
|
||||
|
||||
|
@ -129,7 +173,10 @@ void Init()
|
|||
u32 flags = 0;
|
||||
if (wii) flags |= MV_WII_ONLY;
|
||||
if (bFakeVMEM) flags |= MV_FAKE_VMEM;
|
||||
base = MemoryMap_Setup(views, num_views, flags, &g_arena);
|
||||
physical_base = MemoryMap_Setup(views, num_views, flags, &g_arena);
|
||||
#ifndef _ARCH_32
|
||||
logical_base = physical_base + 0x200000000;
|
||||
#endif
|
||||
|
||||
mmio_mapping = new MMIO::Mapping();
|
||||
|
||||
|
@ -164,7 +211,8 @@ void Shutdown()
|
|||
if (bFakeVMEM) flags |= MV_FAKE_VMEM;
|
||||
MemoryMap_Shutdown(views, num_views, flags, &g_arena);
|
||||
g_arena.ReleaseSHMSegment();
|
||||
base = nullptr;
|
||||
physical_base = nullptr;
|
||||
logical_base = nullptr;
|
||||
delete mmio_mapping;
|
||||
INFO_LOG(MEMMAP, "Memory system shut down.");
|
||||
}
|
||||
|
@ -188,12 +236,6 @@ bool AreMemoryBreakpointsActivated()
|
|||
#endif
|
||||
}
|
||||
|
||||
u32 Read_Instruction(const u32 address)
|
||||
{
|
||||
UGeckoInstruction inst = ReadUnchecked_U32(address);
|
||||
return inst.hex;
|
||||
}
|
||||
|
||||
static inline bool ValidCopyRange(u32 address, size_t size)
|
||||
{
|
||||
return (GetPointer(address) != nullptr &&
|
||||
|
@ -228,19 +270,6 @@ void Memset(const u32 _Address, const u8 _iValue, const u32 _iLength)
|
|||
{
|
||||
memset(ptr,_iValue,_iLength);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (u32 i = 0; i < _iLength; i++)
|
||||
Write_U8(_iValue, _Address + i);
|
||||
}
|
||||
}
|
||||
|
||||
void ClearCacheLine(const u32 address)
|
||||
{
|
||||
// FIXME: does this do the right thing if dcbz is run on hardware memory, e.g.
|
||||
// the FIFO? Do games even do that? Probably not, but we should try to be correct...
|
||||
for (u32 i = 0; i < 32; i += 8)
|
||||
Write_U64(0, address + i);
|
||||
}
|
||||
|
||||
std::string GetString(u32 em_address, size_t size)
|
||||
|
@ -260,93 +289,73 @@ std::string GetString(u32 em_address, size_t size)
|
|||
}
|
||||
}
|
||||
|
||||
// GetPointer must always return an address in the bottom 32 bits of address space, so that 64-bit
|
||||
// programs don't have problems directly addressing any part of memory.
|
||||
// TODO re-think with respect to other BAT setups...
|
||||
u8* GetPointer(const u32 address)
|
||||
u8* GetPointer(u32 address)
|
||||
{
|
||||
switch (address >> 28)
|
||||
// TODO: Should we be masking off more bits here? Can all devices access
|
||||
// EXRAM?
|
||||
address &= 0x3FFFFFFF;
|
||||
if (address < REALRAM_SIZE)
|
||||
return m_pRAM + address;
|
||||
|
||||
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bWii)
|
||||
{
|
||||
case 0x0:
|
||||
case 0x8:
|
||||
if ((address & 0xfffffff) < REALRAM_SIZE)
|
||||
return m_pRAM + (address & RAM_MASK);
|
||||
break;
|
||||
case 0xc:
|
||||
switch (address >> 24)
|
||||
{
|
||||
case 0xcc:
|
||||
case 0xcd:
|
||||
_dbg_assert_msg_(MEMMAP, 0, "GetPointer from IO Bridge doesnt work");
|
||||
break;
|
||||
case 0xc8:
|
||||
// EFB. We don't want to return a pointer here since we have no memory mapped for it.
|
||||
break;
|
||||
|
||||
default:
|
||||
if ((address & 0xfffffff) < REALRAM_SIZE)
|
||||
return m_pRAM + (address & RAM_MASK);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x1:
|
||||
case 0x9:
|
||||
case 0xd:
|
||||
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bWii)
|
||||
{
|
||||
if ((address & 0xfffffff) < EXRAM_SIZE)
|
||||
return m_pEXRAM + (address & EXRAM_MASK);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xe:
|
||||
if (address < (0xE0000000 + L1_CACHE_SIZE))
|
||||
return m_pL1Cache + (address & L1_CACHE_MASK);
|
||||
else
|
||||
break;
|
||||
|
||||
default:
|
||||
if (bFakeVMEM)
|
||||
return m_pFakeVMEM + (address & FAKEVMEM_MASK);
|
||||
break;
|
||||
if ((address >> 28) == 0x1 && (address & 0x0fffffff) < EXRAM_SIZE)
|
||||
return m_pEXRAM + (address & EXRAM_MASK);
|
||||
}
|
||||
|
||||
ERROR_LOG(MEMMAP, "Unknown Pointer %#8x PC %#8x LR %#8x", address, PC, LR);
|
||||
PanicAlert("Unknown Pointer 0x%08x PC 0x%08x LR 0x%08x", address, PC, LR);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool IsRAMAddress(const u32 address, bool allow_locked_cache, bool allow_fake_vmem)
|
||||
u8 Read_U8(u32 address)
|
||||
{
|
||||
switch ((address >> 24) & 0xFC)
|
||||
{
|
||||
case 0x00:
|
||||
case 0x80:
|
||||
case 0xC0:
|
||||
if ((address & 0x1FFFFFFF) < RAM_SIZE)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
case 0x10:
|
||||
case 0x90:
|
||||
case 0xD0:
|
||||
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bWii && (address & 0x0FFFFFFF) < EXRAM_SIZE)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
case 0xE0:
|
||||
if (allow_locked_cache && address - 0xE0000000 < L1_CACHE_SIZE)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
case 0x7C:
|
||||
if (allow_fake_vmem && bFakeVMEM && address >= 0x7E000000)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return *GetPointer(address);
|
||||
}
|
||||
|
||||
u16 Read_U16(u32 address)
|
||||
{
|
||||
return Common::swap16(GetPointer(address));
|
||||
}
|
||||
|
||||
u32 Read_U32(u32 address)
|
||||
{
|
||||
return Common::swap32(GetPointer(address));
|
||||
}
|
||||
|
||||
u64 Read_U64(u32 address)
|
||||
{
|
||||
return Common::swap64(GetPointer(address));
|
||||
}
|
||||
|
||||
void Write_U8(u8 value, u32 address)
|
||||
{
|
||||
*GetPointer(address) = value;
|
||||
}
|
||||
|
||||
void Write_U16(u16 value, u32 address)
|
||||
{
|
||||
*(u16*)GetPointer(address) = Common::swap16(value);
|
||||
}
|
||||
|
||||
void Write_U32(u32 value, u32 address)
|
||||
{
|
||||
*(u32*)GetPointer(address) = Common::swap32(value);
|
||||
}
|
||||
|
||||
void Write_U64(u64 value, u32 address)
|
||||
{
|
||||
*(u64*)GetPointer(address) = Common::swap64(value);
|
||||
}
|
||||
|
||||
void Write_U32_Swap(u32 value, u32 address)
|
||||
{
|
||||
*(u32*)GetPointer(address) = value;
|
||||
}
|
||||
|
||||
void Write_U64_Swap(u64 value, u32 address)
|
||||
{
|
||||
*(u64*)GetPointer(address) = value;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -27,7 +27,8 @@ namespace Memory
|
|||
|
||||
// In 64-bit, this might point to "high memory" (above the 32-bit limit),
|
||||
// so be sure to load it into a 64-bit register.
|
||||
extern u8* base;
|
||||
extern u8* physical_base;
|
||||
extern u8* logical_base;
|
||||
|
||||
// These are guaranteed to point to "low memory" addresses (sub-32-bit).
|
||||
extern u8* m_pRAM;
|
||||
|
@ -73,70 +74,22 @@ void DoState(PointerWrap &p);
|
|||
void Clear();
|
||||
bool AreMemoryBreakpointsActivated();
|
||||
|
||||
// ONLY for use by GUI
|
||||
u8 ReadUnchecked_U8(const u32 address);
|
||||
u32 ReadUnchecked_U32(const u32 address);
|
||||
|
||||
void WriteUnchecked_U8(const u8 var, const u32 address);
|
||||
void WriteUnchecked_U32(const u32 var, const u32 address);
|
||||
|
||||
bool IsRAMAddress(const u32 address, bool allow_locked_cache = false, bool allow_fake_vmem = false);
|
||||
|
||||
// used by interpreter to read instructions, uses iCache
|
||||
u32 Read_Opcode(const u32 address);
|
||||
// this is used by Debugger a lot.
|
||||
// For now, just reads from memory!
|
||||
u32 Read_Instruction(const u32 address);
|
||||
|
||||
|
||||
// For use by emulator
|
||||
|
||||
// Routines to access physically addressed memory, designed for use by
|
||||
// emulated hardware outside the CPU. Use "Device_" prefix.
|
||||
std::string GetString(u32 em_address, size_t size = 0);
|
||||
u8* GetPointer(const u32 address);
|
||||
void CopyFromEmu(void* data, u32 address, size_t size);
|
||||
void CopyToEmu(u32 address, const void* data, size_t size);
|
||||
void Memset(const u32 address, const u8 var, const u32 length);
|
||||
u8 Read_U8(const u32 address);
|
||||
u16 Read_U16(const u32 address);
|
||||
u32 Read_U32(const u32 address);
|
||||
u64 Read_U64(const u32 address);
|
||||
|
||||
// Useful helper functions, used by ARM JIT
|
||||
float Read_F32(const u32 address);
|
||||
double Read_F64(const u32 address);
|
||||
|
||||
// used by JIT. Return zero-extended 32bit values
|
||||
u32 Read_U8_ZX(const u32 address);
|
||||
u32 Read_U16_ZX(const u32 address);
|
||||
|
||||
void Write_U8(const u8 var, const u32 address);
|
||||
void Write_U16(const u16 var, const u32 address);
|
||||
void Write_U32(const u32 var, const u32 address);
|
||||
void Write_U64(const u64 var, const u32 address);
|
||||
|
||||
void Write_U16_Swap(const u16 var, const u32 address);
|
||||
void Write_U32_Swap(const u32 var, const u32 address);
|
||||
void Write_U64_Swap(const u64 var, const u32 address);
|
||||
|
||||
// Useful helper functions, used by ARM JIT
|
||||
void Write_F64(const double var, const u32 address);
|
||||
|
||||
std::string GetString(u32 em_address, size_t size = 0);
|
||||
|
||||
u8* GetPointer(const u32 address);
|
||||
void DMA_LCToMemory(const u32 memAddr, const u32 cacheAddr, const u32 numBlocks);
|
||||
void DMA_MemoryToLC(const u32 cacheAddr, const u32 memAddr, const u32 numBlocks);
|
||||
void CopyFromEmu(void* data, u32 address, size_t size);
|
||||
void CopyToEmu(u32 address, const void* data, size_t size);
|
||||
void Memset(const u32 address, const u8 var, const u32 length);
|
||||
void ClearCacheLine(const u32 address); // Zeroes 32 bytes; address should be 32-byte-aligned
|
||||
|
||||
// TLB functions
|
||||
void SDRUpdated();
|
||||
enum XCheckTLBFlag
|
||||
{
|
||||
FLAG_NO_EXCEPTION,
|
||||
FLAG_READ,
|
||||
FLAG_WRITE,
|
||||
FLAG_OPCODE,
|
||||
};
|
||||
template <const XCheckTLBFlag flag> u32 TranslateAddress(const u32 address);
|
||||
void InvalidateTLBEntry(u32 address);
|
||||
extern u32 pagetable_base;
|
||||
extern u32 pagetable_hashmask;
|
||||
}
|
||||
|
|
|
@ -194,7 +194,6 @@ static void PatchEngineCallback(u64 userdata, int cyclesLate)
|
|||
{
|
||||
// Patch mem and run the Action Replay
|
||||
PatchEngine::ApplyFramePatches();
|
||||
PatchEngine::ApplyARPatches();
|
||||
CoreTiming::ScheduleEvent(VideoInterface::GetTicksPerFrame() - cyclesLate, et_PatchEngine);
|
||||
}
|
||||
|
||||
|
|
|
@ -925,7 +925,7 @@ IPCCommandResult CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
|
|||
pDolLoader = std::make_unique<CDolLoader>(pContent->m_Filename);
|
||||
}
|
||||
pDolLoader->Load(); // TODO: Check why sysmenu does not load the DOL correctly
|
||||
PC = pDolLoader->GetEntryPoint() | 0x80000000;
|
||||
PC = pDolLoader->GetEntryPoint();
|
||||
IOSv = ContentLoader.GetIosVersion();
|
||||
bSuccess = true;
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
#include "Core/GeckoCode.h"
|
||||
#include "Core/GeckoCodeConfig.h"
|
||||
#include "Core/PatchEngine.h"
|
||||
#include "Core/HW/Memmap.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
|
||||
using namespace Common;
|
||||
|
||||
|
@ -188,13 +188,13 @@ static void ApplyPatches(const std::vector<Patch> &patches)
|
|||
switch (entry.type)
|
||||
{
|
||||
case PATCH_8BIT:
|
||||
Memory::Write_U8((u8)value, addr);
|
||||
PowerPC::HostWrite_U8((u8)value, addr);
|
||||
break;
|
||||
case PATCH_16BIT:
|
||||
Memory::Write_U16((u16)value, addr);
|
||||
PowerPC::HostWrite_U16((u16)value, addr);
|
||||
break;
|
||||
case PATCH_32BIT:
|
||||
Memory::Write_U32(value, addr);
|
||||
PowerPC::HostWrite_U32(value, addr);
|
||||
break;
|
||||
default:
|
||||
//unknown patchtype
|
||||
|
@ -207,15 +207,20 @@ static void ApplyPatches(const std::vector<Patch> &patches)
|
|||
|
||||
void ApplyFramePatches()
|
||||
{
|
||||
// TODO: Messing with MSR this way is really, really, evil; we should
|
||||
// probably be using some sort of Gecko OS-style hooking mechanism
|
||||
// so the emulated CPU is in a predictable state when we process cheats.
|
||||
u32 oldMSR = MSR;
|
||||
UReg_MSR newMSR = oldMSR;
|
||||
newMSR.IR = 1;
|
||||
newMSR.DR = 1;
|
||||
MSR = newMSR.Hex;
|
||||
ApplyPatches(onFrame);
|
||||
|
||||
// Run the Gecko code handler
|
||||
Gecko::RunCodeHandler();
|
||||
}
|
||||
|
||||
void ApplyARPatches()
|
||||
{
|
||||
ActionReplay::RunAllActive();
|
||||
MSR = oldMSR;
|
||||
}
|
||||
|
||||
void Shutdown()
|
||||
|
|
|
@ -45,7 +45,6 @@ void LoadPatchSection(const std::string& section, std::vector<Patch> &patches,
|
|||
IniFile &globalIni, IniFile &localIni);
|
||||
void LoadPatches();
|
||||
void ApplyFramePatches();
|
||||
void ApplyARPatches();
|
||||
void Shutdown();
|
||||
|
||||
inline int GetPatchTypeCharLength(PatchType type)
|
||||
|
|
|
@ -107,7 +107,7 @@ int Interpreter::SingleStepInner()
|
|||
#endif
|
||||
|
||||
NPC = PC + sizeof(UGeckoInstruction);
|
||||
instCode.hex = Memory::Read_Opcode(PC);
|
||||
instCode.hex = PowerPC::Read_Opcode(PC);
|
||||
|
||||
// Uncomment to trace the interpreter
|
||||
//if ((PC & 0xffffff)>=0x0ab54c && (PC & 0xffffff)<=0x0ab624)
|
||||
|
@ -283,7 +283,7 @@ void Interpreter::unknown_instruction(UGeckoInstruction _inst)
|
|||
{
|
||||
if (_inst.hex != 0)
|
||||
{
|
||||
std::string disasm = GekkoDisassembler::Disassemble(Memory::ReadUnchecked_U32(last_pc), last_pc);
|
||||
std::string disasm = GekkoDisassembler::Disassemble(PowerPC::HostRead_U32(last_pc), last_pc);
|
||||
NOTICE_LOG(POWERPC, "Last PC = %08x : %s", last_pc, disasm.c_str());
|
||||
Dolphin_Debugger::PrintCallstack();
|
||||
_assert_msg_(POWERPC, 0, "\nIntCPU: Unknown instruction %08x at PC = %08x last_PC = %08x LR = %08x\n", _inst.hex, PC, last_pc, LR);
|
||||
|
|
|
@ -36,7 +36,7 @@ u32 Interpreter::Helper_Get_EA_UX(const UGeckoInstruction _inst)
|
|||
|
||||
void Interpreter::lbz(UGeckoInstruction _inst)
|
||||
{
|
||||
u32 temp = (u32)Memory::Read_U8(Helper_Get_EA(_inst));
|
||||
u32 temp = (u32)PowerPC::Read_U8(Helper_Get_EA(_inst));
|
||||
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
|
||||
rGPR[_inst.RD] = temp;
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ void Interpreter::lbz(UGeckoInstruction _inst)
|
|||
void Interpreter::lbzu(UGeckoInstruction _inst)
|
||||
{
|
||||
u32 uAddress = Helper_Get_EA_U(_inst);
|
||||
u32 temp = (u32)Memory::Read_U8(uAddress);
|
||||
u32 temp = (u32)PowerPC::Read_U8(uAddress);
|
||||
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
|
||||
{
|
||||
rGPR[_inst.RD] = temp;
|
||||
|
@ -54,7 +54,7 @@ void Interpreter::lbzu(UGeckoInstruction _inst)
|
|||
|
||||
void Interpreter::lfd(UGeckoInstruction _inst)
|
||||
{
|
||||
u64 temp = Memory::Read_U64(Helper_Get_EA(_inst));
|
||||
u64 temp = PowerPC::Read_U64(Helper_Get_EA(_inst));
|
||||
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
|
||||
riPS0(_inst.FD) = temp;
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ void Interpreter::lfd(UGeckoInstruction _inst)
|
|||
void Interpreter::lfdu(UGeckoInstruction _inst)
|
||||
{
|
||||
u32 uAddress = Helper_Get_EA_U(_inst);
|
||||
u64 temp = Memory::Read_U64(uAddress);
|
||||
u64 temp = PowerPC::Read_U64(uAddress);
|
||||
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
|
||||
{
|
||||
riPS0(_inst.FD) = temp;
|
||||
|
@ -73,7 +73,7 @@ void Interpreter::lfdu(UGeckoInstruction _inst)
|
|||
void Interpreter::lfdux(UGeckoInstruction _inst)
|
||||
{
|
||||
u32 uAddress = Helper_Get_EA_UX(_inst);
|
||||
u64 temp = Memory::Read_U64(uAddress);
|
||||
u64 temp = PowerPC::Read_U64(uAddress);
|
||||
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
|
||||
{
|
||||
riPS0(_inst.FD) = temp;
|
||||
|
@ -83,14 +83,14 @@ void Interpreter::lfdux(UGeckoInstruction _inst)
|
|||
|
||||
void Interpreter::lfdx(UGeckoInstruction _inst)
|
||||
{
|
||||
u64 temp = Memory::Read_U64(Helper_Get_EA_X(_inst));
|
||||
u64 temp = PowerPC::Read_U64(Helper_Get_EA_X(_inst));
|
||||
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
|
||||
riPS0(_inst.FD) = temp;
|
||||
}
|
||||
|
||||
void Interpreter::lfs(UGeckoInstruction _inst)
|
||||
{
|
||||
u32 uTemp = Memory::Read_U32(Helper_Get_EA(_inst));
|
||||
u32 uTemp = PowerPC::Read_U32(Helper_Get_EA(_inst));
|
||||
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
|
||||
{
|
||||
u64 value = ConvertToDouble(uTemp);
|
||||
|
@ -102,7 +102,7 @@ void Interpreter::lfs(UGeckoInstruction _inst)
|
|||
void Interpreter::lfsu(UGeckoInstruction _inst)
|
||||
{
|
||||
u32 uAddress = Helper_Get_EA_U(_inst);
|
||||
u32 uTemp = Memory::Read_U32(uAddress);
|
||||
u32 uTemp = PowerPC::Read_U32(uAddress);
|
||||
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
|
||||
{
|
||||
u64 value = ConvertToDouble(uTemp);
|
||||
|
@ -116,7 +116,7 @@ void Interpreter::lfsu(UGeckoInstruction _inst)
|
|||
void Interpreter::lfsux(UGeckoInstruction _inst)
|
||||
{
|
||||
u32 uAddress = Helper_Get_EA_UX(_inst);
|
||||
u32 uTemp = Memory::Read_U32(uAddress);
|
||||
u32 uTemp = PowerPC::Read_U32(uAddress);
|
||||
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
|
||||
{
|
||||
u64 value = ConvertToDouble(uTemp);
|
||||
|
@ -128,7 +128,7 @@ void Interpreter::lfsux(UGeckoInstruction _inst)
|
|||
|
||||
void Interpreter::lfsx(UGeckoInstruction _inst)
|
||||
{
|
||||
u32 uTemp = Memory::Read_U32(Helper_Get_EA_X(_inst));
|
||||
u32 uTemp = PowerPC::Read_U32(Helper_Get_EA_X(_inst));
|
||||
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
|
||||
{
|
||||
u64 value = ConvertToDouble(uTemp);
|
||||
|
@ -139,7 +139,7 @@ void Interpreter::lfsx(UGeckoInstruction _inst)
|
|||
|
||||
void Interpreter::lha(UGeckoInstruction _inst)
|
||||
{
|
||||
u32 temp = (u32)(s32)(s16)Memory::Read_U16(Helper_Get_EA(_inst));
|
||||
u32 temp = (u32)(s32)(s16)PowerPC::Read_U16(Helper_Get_EA(_inst));
|
||||
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
|
||||
{
|
||||
rGPR[_inst.RD] = temp;
|
||||
|
@ -149,7 +149,7 @@ void Interpreter::lha(UGeckoInstruction _inst)
|
|||
void Interpreter::lhau(UGeckoInstruction _inst)
|
||||
{
|
||||
u32 uAddress = Helper_Get_EA_U(_inst);
|
||||
u32 temp = (u32)(s32)(s16)Memory::Read_U16(uAddress);
|
||||
u32 temp = (u32)(s32)(s16)PowerPC::Read_U16(uAddress);
|
||||
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
|
||||
{
|
||||
rGPR[_inst.RD] = temp;
|
||||
|
@ -159,7 +159,7 @@ void Interpreter::lhau(UGeckoInstruction _inst)
|
|||
|
||||
void Interpreter::lhz(UGeckoInstruction _inst)
|
||||
{
|
||||
u32 temp = (u32)(u16)Memory::Read_U16(Helper_Get_EA(_inst));
|
||||
u32 temp = (u32)(u16)PowerPC::Read_U16(Helper_Get_EA(_inst));
|
||||
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
|
||||
{
|
||||
rGPR[_inst.RD] = temp;
|
||||
|
@ -169,7 +169,7 @@ void Interpreter::lhz(UGeckoInstruction _inst)
|
|||
void Interpreter::lhzu(UGeckoInstruction _inst)
|
||||
{
|
||||
u32 uAddress = Helper_Get_EA_U(_inst);
|
||||
u32 temp = (u32)(u16)Memory::Read_U16(uAddress);
|
||||
u32 temp = (u32)(u16)PowerPC::Read_U16(uAddress);
|
||||
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
|
||||
{
|
||||
rGPR[_inst.RD] = temp;
|
||||
|
@ -183,7 +183,7 @@ void Interpreter::lmw(UGeckoInstruction _inst)
|
|||
u32 uAddress = Helper_Get_EA(_inst);
|
||||
for (int iReg = _inst.RD; iReg <= 31; iReg++, uAddress += 4)
|
||||
{
|
||||
u32 TempReg = Memory::Read_U32(uAddress);
|
||||
u32 TempReg = PowerPC::Read_U32(uAddress);
|
||||
if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI)
|
||||
{
|
||||
PanicAlert("DSI exception in lmw");
|
||||
|
@ -203,7 +203,7 @@ void Interpreter::stmw(UGeckoInstruction _inst)
|
|||
u32 uAddress = Helper_Get_EA(_inst);
|
||||
for (int iReg = _inst.RS; iReg <= 31; iReg++, uAddress+=4)
|
||||
{
|
||||
Memory::Write_U32(rGPR[iReg], uAddress);
|
||||
PowerPC::Write_U32(rGPR[iReg], uAddress);
|
||||
if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI)
|
||||
{
|
||||
PanicAlert("DSI exception in stmw");
|
||||
|
@ -216,7 +216,7 @@ void Interpreter::stmw(UGeckoInstruction _inst)
|
|||
void Interpreter::lwz(UGeckoInstruction _inst)
|
||||
{
|
||||
u32 uAddress = Helper_Get_EA(_inst);
|
||||
u32 temp = Memory::Read_U32(uAddress);
|
||||
u32 temp = PowerPC::Read_U32(uAddress);
|
||||
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
|
||||
{
|
||||
rGPR[_inst.RD] = temp;
|
||||
|
@ -226,7 +226,7 @@ void Interpreter::lwz(UGeckoInstruction _inst)
|
|||
void Interpreter::lwzu(UGeckoInstruction _inst)
|
||||
{
|
||||
u32 uAddress = Helper_Get_EA_U(_inst);
|
||||
u32 temp = Memory::Read_U32(uAddress);
|
||||
u32 temp = PowerPC::Read_U32(uAddress);
|
||||
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
|
||||
{
|
||||
rGPR[_inst.RD] = temp;
|
||||
|
@ -236,13 +236,13 @@ void Interpreter::lwzu(UGeckoInstruction _inst)
|
|||
|
||||
void Interpreter::stb(UGeckoInstruction _inst)
|
||||
{
|
||||
Memory::Write_U8((u8)rGPR[_inst.RS], Helper_Get_EA(_inst));
|
||||
PowerPC::Write_U8((u8)rGPR[_inst.RS], Helper_Get_EA(_inst));
|
||||
}
|
||||
|
||||
void Interpreter::stbu(UGeckoInstruction _inst)
|
||||
{
|
||||
u32 uAddress = Helper_Get_EA_U(_inst);
|
||||
Memory::Write_U8((u8)rGPR[_inst.RS], uAddress);
|
||||
PowerPC::Write_U8((u8)rGPR[_inst.RS], uAddress);
|
||||
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
|
||||
{
|
||||
rGPR[_inst.RA] = uAddress;
|
||||
|
@ -251,13 +251,13 @@ void Interpreter::stbu(UGeckoInstruction _inst)
|
|||
|
||||
void Interpreter::stfd(UGeckoInstruction _inst)
|
||||
{
|
||||
Memory::Write_U64(riPS0(_inst.FS), Helper_Get_EA(_inst));
|
||||
PowerPC::Write_U64(riPS0(_inst.FS), Helper_Get_EA(_inst));
|
||||
}
|
||||
|
||||
void Interpreter::stfdu(UGeckoInstruction _inst)
|
||||
{
|
||||
u32 uAddress = Helper_Get_EA_U(_inst);
|
||||
Memory::Write_U64(riPS0(_inst.FS), uAddress);
|
||||
PowerPC::Write_U64(riPS0(_inst.FS), uAddress);
|
||||
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
|
||||
{
|
||||
rGPR[_inst.RA] = uAddress;
|
||||
|
@ -266,13 +266,13 @@ void Interpreter::stfdu(UGeckoInstruction _inst)
|
|||
|
||||
void Interpreter::stfs(UGeckoInstruction _inst)
|
||||
{
|
||||
Memory::Write_U32(ConvertToSingle(riPS0(_inst.FS)), Helper_Get_EA(_inst));
|
||||
PowerPC::Write_U32(ConvertToSingle(riPS0(_inst.FS)), Helper_Get_EA(_inst));
|
||||
}
|
||||
|
||||
void Interpreter::stfsu(UGeckoInstruction _inst)
|
||||
{
|
||||
u32 uAddress = Helper_Get_EA_U(_inst);
|
||||
Memory::Write_U32(ConvertToSingle(riPS0(_inst.FS)), uAddress);
|
||||
PowerPC::Write_U32(ConvertToSingle(riPS0(_inst.FS)), uAddress);
|
||||
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
|
||||
{
|
||||
rGPR[_inst.RA] = uAddress;
|
||||
|
@ -281,13 +281,13 @@ void Interpreter::stfsu(UGeckoInstruction _inst)
|
|||
|
||||
void Interpreter::sth(UGeckoInstruction _inst)
|
||||
{
|
||||
Memory::Write_U16((u16)rGPR[_inst.RS], Helper_Get_EA(_inst));
|
||||
PowerPC::Write_U16((u16)rGPR[_inst.RS], Helper_Get_EA(_inst));
|
||||
}
|
||||
|
||||
void Interpreter::sthu(UGeckoInstruction _inst)
|
||||
{
|
||||
u32 uAddress = Helper_Get_EA_U(_inst);
|
||||
Memory::Write_U16((u16)rGPR[_inst.RS], uAddress);
|
||||
PowerPC::Write_U16((u16)rGPR[_inst.RS], uAddress);
|
||||
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
|
||||
{
|
||||
rGPR[_inst.RA] = uAddress;
|
||||
|
@ -296,13 +296,13 @@ void Interpreter::sthu(UGeckoInstruction _inst)
|
|||
|
||||
void Interpreter::stw(UGeckoInstruction _inst)
|
||||
{
|
||||
Memory::Write_U32(rGPR[_inst.RS], Helper_Get_EA(_inst));
|
||||
PowerPC::Write_U32(rGPR[_inst.RS], Helper_Get_EA(_inst));
|
||||
}
|
||||
|
||||
void Interpreter::stwu(UGeckoInstruction _inst)
|
||||
{
|
||||
u32 uAddress = Helper_Get_EA_U(_inst);
|
||||
Memory::Write_U32(rGPR[_inst.RS], uAddress);
|
||||
PowerPC::Write_U32(rGPR[_inst.RS], uAddress);
|
||||
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
|
||||
{
|
||||
rGPR[_inst.RA] = uAddress;
|
||||
|
@ -318,8 +318,8 @@ void Interpreter::dcbf(UGeckoInstruction _inst)
|
|||
{
|
||||
//This should tell GFX backend to throw out any cached data here
|
||||
// !!! SPEEDUP HACK for OSProtectRange !!!
|
||||
/* u32 tmp1 = Memory::Read_U32(PC+4);
|
||||
u32 tmp2 = Memory::Read_U32(PC+8);
|
||||
/* u32 tmp1 = PowerPC::HostRead_U32(PC+4);
|
||||
u32 tmp2 = PowerPC::HostRead_U32(PC+8);
|
||||
|
||||
if ((tmp1 == 0x38630020) &&
|
||||
(tmp2 == 0x4200fff8))
|
||||
|
@ -377,7 +377,7 @@ void Interpreter::dcbz(UGeckoInstruction _inst)
|
|||
{
|
||||
// HACK but works... we think
|
||||
if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bDCBZOFF)
|
||||
Memory::ClearCacheLine(Helper_Get_EA_X(_inst) & (~31));
|
||||
PowerPC::ClearCacheLine(Helper_Get_EA_X(_inst) & (~31));
|
||||
if (!JitInterface::GetCore())
|
||||
PowerPC::CheckExceptions();
|
||||
}
|
||||
|
@ -403,7 +403,7 @@ void Interpreter::eciwx(UGeckoInstruction _inst)
|
|||
// _assert_msg_(POWERPC,0,"eciwx - fill r%i with word @ %08x from device %02x",
|
||||
// _inst.RS, EA, PowerPC::ppcState.spr[SPR_EAR] & 0x1f);
|
||||
|
||||
rGPR[_inst.RS] = Memory::Read_U32(EA);
|
||||
rGPR[_inst.RS] = PowerPC::Read_U32(EA);
|
||||
}
|
||||
|
||||
void Interpreter::ecowx(UGeckoInstruction _inst)
|
||||
|
@ -425,7 +425,7 @@ void Interpreter::ecowx(UGeckoInstruction _inst)
|
|||
// _assert_msg_(POWERPC,0,"ecowx - send stw request (%08x@%08x) to device %02x",
|
||||
// rGPR[_inst.RS], EA, PowerPC::ppcState.spr[SPR_EAR] & 0x1f);
|
||||
|
||||
Memory::Write_U32(rGPR[_inst.RS], EA);
|
||||
PowerPC::Write_U32(rGPR[_inst.RS], EA);
|
||||
}
|
||||
|
||||
void Interpreter::eieio(UGeckoInstruction _inst)
|
||||
|
@ -445,7 +445,7 @@ void Interpreter::icbi(UGeckoInstruction _inst)
|
|||
void Interpreter::lbzux(UGeckoInstruction _inst)
|
||||
{
|
||||
u32 uAddress = Helper_Get_EA_UX(_inst);
|
||||
u32 temp = (u32)Memory::Read_U8(uAddress);
|
||||
u32 temp = (u32)PowerPC::Read_U8(uAddress);
|
||||
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
|
||||
{
|
||||
rGPR[_inst.RD] = temp;
|
||||
|
@ -455,7 +455,7 @@ void Interpreter::lbzux(UGeckoInstruction _inst)
|
|||
|
||||
void Interpreter::lbzx(UGeckoInstruction _inst)
|
||||
{
|
||||
u32 temp = (u32)Memory::Read_U8(Helper_Get_EA_X(_inst));
|
||||
u32 temp = (u32)PowerPC::Read_U8(Helper_Get_EA_X(_inst));
|
||||
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
|
||||
{
|
||||
rGPR[_inst.RD] = temp;
|
||||
|
@ -465,7 +465,7 @@ void Interpreter::lbzx(UGeckoInstruction _inst)
|
|||
void Interpreter::lhaux(UGeckoInstruction _inst)
|
||||
{
|
||||
u32 uAddress = Helper_Get_EA_UX(_inst);
|
||||
s32 temp = (s32)(s16)Memory::Read_U16(uAddress);
|
||||
s32 temp = (s32)(s16)PowerPC::Read_U16(uAddress);
|
||||
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
|
||||
{
|
||||
rGPR[_inst.RD] = temp;
|
||||
|
@ -475,7 +475,7 @@ void Interpreter::lhaux(UGeckoInstruction _inst)
|
|||
|
||||
void Interpreter::lhax(UGeckoInstruction _inst)
|
||||
{
|
||||
s32 temp = (s32)(s16)Memory::Read_U16(Helper_Get_EA_X(_inst));
|
||||
s32 temp = (s32)(s16)PowerPC::Read_U16(Helper_Get_EA_X(_inst));
|
||||
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
|
||||
{
|
||||
rGPR[_inst.RD] = temp;
|
||||
|
@ -484,7 +484,7 @@ void Interpreter::lhax(UGeckoInstruction _inst)
|
|||
|
||||
void Interpreter::lhbrx(UGeckoInstruction _inst)
|
||||
{
|
||||
u32 temp = (u32)Common::swap16(Memory::Read_U16(Helper_Get_EA_X(_inst)));
|
||||
u32 temp = (u32)Common::swap16(PowerPC::Read_U16(Helper_Get_EA_X(_inst)));
|
||||
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
|
||||
{
|
||||
rGPR[_inst.RD] = temp;
|
||||
|
@ -494,7 +494,7 @@ void Interpreter::lhbrx(UGeckoInstruction _inst)
|
|||
void Interpreter::lhzux(UGeckoInstruction _inst)
|
||||
{
|
||||
u32 uAddress = Helper_Get_EA_UX(_inst);
|
||||
u32 temp = (u32)Memory::Read_U16(uAddress);
|
||||
u32 temp = (u32)PowerPC::Read_U16(uAddress);
|
||||
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
|
||||
{
|
||||
rGPR[_inst.RD] = temp;
|
||||
|
@ -504,7 +504,7 @@ void Interpreter::lhzux(UGeckoInstruction _inst)
|
|||
|
||||
void Interpreter::lhzx(UGeckoInstruction _inst)
|
||||
{
|
||||
u32 temp = (u32)Memory::Read_U16(Helper_Get_EA_X(_inst));
|
||||
u32 temp = (u32)PowerPC::Read_U16(Helper_Get_EA_X(_inst));
|
||||
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
|
||||
{
|
||||
rGPR[_inst.RD] = temp;
|
||||
|
@ -525,7 +525,7 @@ void Interpreter::lswx(UGeckoInstruction _inst)
|
|||
rGPR[r] = 0;
|
||||
do
|
||||
{
|
||||
u32 TempValue = Memory::Read_U8(EA) << (24 - i);
|
||||
u32 TempValue = PowerPC::Read_U8(EA) << (24 - i);
|
||||
if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI)
|
||||
{
|
||||
PanicAlert("DSI exception in lswx.");
|
||||
|
@ -549,7 +549,7 @@ void Interpreter::lswx(UGeckoInstruction _inst)
|
|||
|
||||
void Interpreter::lwbrx(UGeckoInstruction _inst)
|
||||
{
|
||||
u32 temp = Common::swap32(Memory::Read_U32(Helper_Get_EA_X(_inst)));
|
||||
u32 temp = Common::swap32(PowerPC::Read_U32(Helper_Get_EA_X(_inst)));
|
||||
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
|
||||
{
|
||||
rGPR[_inst.RD] = temp;
|
||||
|
@ -559,7 +559,7 @@ void Interpreter::lwbrx(UGeckoInstruction _inst)
|
|||
void Interpreter::lwzux(UGeckoInstruction _inst)
|
||||
{
|
||||
u32 uAddress = Helper_Get_EA_UX(_inst);
|
||||
u32 temp = Memory::Read_U32(uAddress);
|
||||
u32 temp = PowerPC::Read_U32(uAddress);
|
||||
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
|
||||
{
|
||||
rGPR[_inst.RD] = temp;
|
||||
|
@ -570,7 +570,7 @@ void Interpreter::lwzux(UGeckoInstruction _inst)
|
|||
void Interpreter::lwzx(UGeckoInstruction _inst)
|
||||
{
|
||||
u32 uAddress = Helper_Get_EA_X(_inst);
|
||||
u32 temp = Memory::Read_U32(uAddress);
|
||||
u32 temp = PowerPC::Read_U32(uAddress);
|
||||
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
|
||||
{
|
||||
rGPR[_inst.RD] = temp;
|
||||
|
@ -580,7 +580,7 @@ void Interpreter::lwzx(UGeckoInstruction _inst)
|
|||
void Interpreter::stbux(UGeckoInstruction _inst)
|
||||
{
|
||||
u32 uAddress = Helper_Get_EA_UX(_inst);
|
||||
Memory::Write_U8((u8)rGPR[_inst.RS], uAddress);
|
||||
PowerPC::Write_U8((u8)rGPR[_inst.RS], uAddress);
|
||||
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
|
||||
{
|
||||
rGPR[_inst.RA] = uAddress;
|
||||
|
@ -589,13 +589,13 @@ void Interpreter::stbux(UGeckoInstruction _inst)
|
|||
|
||||
void Interpreter::stbx(UGeckoInstruction _inst)
|
||||
{
|
||||
Memory::Write_U8((u8)rGPR[_inst.RS], Helper_Get_EA_X(_inst));
|
||||
PowerPC::Write_U8((u8)rGPR[_inst.RS], Helper_Get_EA_X(_inst));
|
||||
}
|
||||
|
||||
void Interpreter::stfdux(UGeckoInstruction _inst)
|
||||
{
|
||||
u32 uAddress = Helper_Get_EA_UX(_inst);
|
||||
Memory::Write_U64(riPS0(_inst.FS), uAddress);
|
||||
PowerPC::Write_U64(riPS0(_inst.FS), uAddress);
|
||||
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
|
||||
{
|
||||
rGPR[_inst.RA] = uAddress;
|
||||
|
@ -604,7 +604,7 @@ void Interpreter::stfdux(UGeckoInstruction _inst)
|
|||
|
||||
void Interpreter::stfdx(UGeckoInstruction _inst)
|
||||
{
|
||||
Memory::Write_U64(riPS0(_inst.FS), Helper_Get_EA_X(_inst));
|
||||
PowerPC::Write_U64(riPS0(_inst.FS), Helper_Get_EA_X(_inst));
|
||||
}
|
||||
|
||||
// Stores Floating points into Integers indeXed
|
||||
|
@ -612,14 +612,14 @@ void Interpreter::stfiwx(UGeckoInstruction _inst)
|
|||
{
|
||||
u32 uAddress = Helper_Get_EA_X(_inst);
|
||||
|
||||
Memory::Write_U32((u32)riPS0(_inst.FS), uAddress);
|
||||
PowerPC::Write_U32((u32)riPS0(_inst.FS), uAddress);
|
||||
}
|
||||
|
||||
|
||||
void Interpreter::stfsux(UGeckoInstruction _inst)
|
||||
{
|
||||
u32 uAddress = Helper_Get_EA_UX(_inst);
|
||||
Memory::Write_U32(ConvertToSingle(riPS0(_inst.FS)), uAddress);
|
||||
PowerPC::Write_U32(ConvertToSingle(riPS0(_inst.FS)), uAddress);
|
||||
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
|
||||
{
|
||||
rGPR[_inst.RA] = uAddress;
|
||||
|
@ -628,18 +628,18 @@ void Interpreter::stfsux(UGeckoInstruction _inst)
|
|||
|
||||
void Interpreter::stfsx(UGeckoInstruction _inst)
|
||||
{
|
||||
Memory::Write_U32(ConvertToSingle(riPS0(_inst.FS)), Helper_Get_EA_X(_inst));
|
||||
PowerPC::Write_U32(ConvertToSingle(riPS0(_inst.FS)), Helper_Get_EA_X(_inst));
|
||||
}
|
||||
|
||||
void Interpreter::sthbrx(UGeckoInstruction _inst)
|
||||
{
|
||||
Memory::Write_U16(Common::swap16((u16)rGPR[_inst.RS]), Helper_Get_EA_X(_inst));
|
||||
PowerPC::Write_U16(Common::swap16((u16)rGPR[_inst.RS]), Helper_Get_EA_X(_inst));
|
||||
}
|
||||
|
||||
void Interpreter::sthux(UGeckoInstruction _inst)
|
||||
{
|
||||
u32 uAddress = Helper_Get_EA_UX(_inst);
|
||||
Memory::Write_U16((u16)rGPR[_inst.RS], uAddress);
|
||||
PowerPC::Write_U16((u16)rGPR[_inst.RS], uAddress);
|
||||
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
|
||||
{
|
||||
rGPR[_inst.RA] = uAddress;
|
||||
|
@ -648,7 +648,7 @@ void Interpreter::sthux(UGeckoInstruction _inst)
|
|||
|
||||
void Interpreter::sthx(UGeckoInstruction _inst)
|
||||
{
|
||||
Memory::Write_U16((u16)rGPR[_inst.RS], Helper_Get_EA_X(_inst));
|
||||
PowerPC::Write_U16((u16)rGPR[_inst.RS], Helper_Get_EA_X(_inst));
|
||||
}
|
||||
|
||||
// __________________________________________________________________________________________________
|
||||
|
@ -679,7 +679,7 @@ void Interpreter::lswi(UGeckoInstruction _inst)
|
|||
rGPR[r] = 0;
|
||||
}
|
||||
|
||||
u32 TempValue = Memory::Read_U8(EA) << (24 - i);
|
||||
u32 TempValue = PowerPC::Read_U8(EA) << (24 - i);
|
||||
if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI)
|
||||
{
|
||||
PanicAlert("DSI exception in lsw.");
|
||||
|
@ -723,7 +723,7 @@ void Interpreter::stswi(UGeckoInstruction _inst)
|
|||
r++;
|
||||
r &= 31;
|
||||
}
|
||||
Memory::Write_U8((rGPR[r] >> (24 - i)) & 0xFF, EA);
|
||||
PowerPC::Write_U8((rGPR[r] >> (24 - i)) & 0xFF, EA);
|
||||
if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI)
|
||||
{
|
||||
return;
|
||||
|
@ -747,7 +747,7 @@ void Interpreter::stswx(UGeckoInstruction _inst)
|
|||
|
||||
while (n > 0)
|
||||
{
|
||||
Memory::Write_U8((rGPR[r] >> (24 - i)) & 0xFF, EA);
|
||||
PowerPC::Write_U8((rGPR[r] >> (24 - i)) & 0xFF, EA);
|
||||
|
||||
EA++;
|
||||
n--;
|
||||
|
@ -763,7 +763,7 @@ void Interpreter::stswx(UGeckoInstruction _inst)
|
|||
void Interpreter::stwbrx(UGeckoInstruction _inst)
|
||||
{
|
||||
u32 uAddress = Helper_Get_EA_X(_inst);
|
||||
Memory::Write_U32(Common::swap32(rGPR[_inst.RS]), uAddress);
|
||||
PowerPC::Write_U32(Common::swap32(rGPR[_inst.RS]), uAddress);
|
||||
}
|
||||
|
||||
|
||||
|
@ -773,7 +773,7 @@ void Interpreter::stwbrx(UGeckoInstruction _inst)
|
|||
void Interpreter::lwarx(UGeckoInstruction _inst)
|
||||
{
|
||||
u32 uAddress = Helper_Get_EA_X(_inst);
|
||||
u32 temp = Memory::Read_U32(uAddress);
|
||||
u32 temp = PowerPC::Read_U32(uAddress);
|
||||
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
|
||||
{
|
||||
rGPR[_inst.RD] = temp;
|
||||
|
@ -792,7 +792,7 @@ void Interpreter::stwcxd(UGeckoInstruction _inst)
|
|||
|
||||
if (uAddress == g_reserveAddr)
|
||||
{
|
||||
Memory::Write_U32(rGPR[_inst.RS], uAddress);
|
||||
PowerPC::Write_U32(rGPR[_inst.RS], uAddress);
|
||||
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
|
||||
{
|
||||
g_bReserve = false;
|
||||
|
@ -808,7 +808,7 @@ void Interpreter::stwcxd(UGeckoInstruction _inst)
|
|||
void Interpreter::stwux(UGeckoInstruction _inst)
|
||||
{
|
||||
u32 uAddress = Helper_Get_EA_UX(_inst);
|
||||
Memory::Write_U32(rGPR[_inst.RS], uAddress);
|
||||
PowerPC::Write_U32(rGPR[_inst.RS], uAddress);
|
||||
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
|
||||
{
|
||||
rGPR[_inst.RA] = uAddress;
|
||||
|
@ -818,7 +818,7 @@ void Interpreter::stwux(UGeckoInstruction _inst)
|
|||
void Interpreter::stwx(UGeckoInstruction _inst)
|
||||
{
|
||||
u32 uAddress = Helper_Get_EA_X(_inst);
|
||||
Memory::Write_U32(rGPR[_inst.RS], uAddress);
|
||||
PowerPC::Write_U32(rGPR[_inst.RS], uAddress);
|
||||
}
|
||||
|
||||
void Interpreter::sync(UGeckoInstruction _inst)
|
||||
|
@ -838,7 +838,7 @@ void Interpreter::tlbie(UGeckoInstruction _inst)
|
|||
{
|
||||
// Invalidate TLB entry
|
||||
u32 _Address = rGPR[_inst.RB];
|
||||
Memory::InvalidateTLBEntry(_Address);
|
||||
PowerPC::InvalidateTLBEntry(_Address);
|
||||
}
|
||||
|
||||
void Interpreter::tlbsync(UGeckoInstruction _inst)
|
||||
|
|
|
@ -53,7 +53,7 @@ void Interpreter::Helper_Quantize(const u32 _Addr, const double _fValue, const E
|
|||
switch (_quantizeType)
|
||||
{
|
||||
case QUANTIZE_FLOAT:
|
||||
Memory::Write_U32(ConvertToSingleFTZ(*(u64*)&_fValue), _Addr);
|
||||
PowerPC::Write_U32(ConvertToSingleFTZ(*(u64*)&_fValue), _Addr);
|
||||
break;
|
||||
|
||||
// used for THP player
|
||||
|
@ -61,7 +61,7 @@ void Interpreter::Helper_Quantize(const u32 _Addr, const double _fValue, const E
|
|||
{
|
||||
float fResult = (float)_fValue * m_quantizeTable[_uScale];
|
||||
MathUtil::Clamp(&fResult, 0.0f, 255.0f);
|
||||
Memory::Write_U8((u8)fResult, _Addr);
|
||||
PowerPC::Write_U8((u8)fResult, _Addr);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -69,7 +69,7 @@ void Interpreter::Helper_Quantize(const u32 _Addr, const double _fValue, const E
|
|||
{
|
||||
float fResult = (float)_fValue * m_quantizeTable[_uScale];
|
||||
MathUtil::Clamp(&fResult, 0.0f, 65535.0f);
|
||||
Memory::Write_U16((u16)fResult, _Addr);
|
||||
PowerPC::Write_U16((u16)fResult, _Addr);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -77,7 +77,7 @@ void Interpreter::Helper_Quantize(const u32 _Addr, const double _fValue, const E
|
|||
{
|
||||
float fResult = (float)_fValue * m_quantizeTable[_uScale];
|
||||
MathUtil::Clamp(&fResult, -128.0f, 127.0f);
|
||||
Memory::Write_U8((u8)(s8)fResult, _Addr);
|
||||
PowerPC::Write_U8((u8)(s8)fResult, _Addr);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -85,7 +85,7 @@ void Interpreter::Helper_Quantize(const u32 _Addr, const double _fValue, const E
|
|||
{
|
||||
float fResult = (float)_fValue * m_quantizeTable[_uScale];
|
||||
MathUtil::Clamp(&fResult, -32768.0f, 32767.0f);
|
||||
Memory::Write_U16((u16)(s16)fResult, _Addr);
|
||||
PowerPC::Write_U16((u16)(s16)fResult, _Addr);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -103,26 +103,26 @@ float Interpreter::Helper_Dequantize(const u32 _Addr, const EQuantizeType _quant
|
|||
{
|
||||
case QUANTIZE_FLOAT:
|
||||
{
|
||||
u32 dwValue = Memory::Read_U32(_Addr);
|
||||
u32 dwValue = PowerPC::Read_U32(_Addr);
|
||||
fResult = *(float*)&dwValue;
|
||||
}
|
||||
break;
|
||||
|
||||
case QUANTIZE_U8:
|
||||
fResult = static_cast<float>(Memory::Read_U8(_Addr)) * m_dequantizeTable[_uScale];
|
||||
fResult = static_cast<float>(PowerPC::Read_U8(_Addr)) * m_dequantizeTable[_uScale];
|
||||
break;
|
||||
|
||||
case QUANTIZE_U16:
|
||||
fResult = static_cast<float>(Memory::Read_U16(_Addr)) * m_dequantizeTable[_uScale];
|
||||
fResult = static_cast<float>(PowerPC::Read_U16(_Addr)) * m_dequantizeTable[_uScale];
|
||||
break;
|
||||
|
||||
case QUANTIZE_S8:
|
||||
fResult = static_cast<float>((s8)Memory::Read_U8(_Addr)) * m_dequantizeTable[_uScale];
|
||||
fResult = static_cast<float>((s8)PowerPC::Read_U8(_Addr)) * m_dequantizeTable[_uScale];
|
||||
break;
|
||||
|
||||
// used for THP player
|
||||
case QUANTIZE_S16:
|
||||
fResult = static_cast<float>((s16)Memory::Read_U16(_Addr)) * m_dequantizeTable[_uScale];
|
||||
fResult = static_cast<float>((s16)PowerPC::Read_U16(_Addr)) * m_dequantizeTable[_uScale];
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
|
@ -425,5 +425,5 @@ void Interpreter::ps_cmpo1(UGeckoInstruction _inst)
|
|||
void Interpreter::dcbz_l(UGeckoInstruction _inst)
|
||||
{
|
||||
//FAKE: clear memory instead of clearing the cache block
|
||||
Memory::Memset(Helper_Get_EA_X(_inst) & (~31), 0, 32);
|
||||
PowerPC::ClearCacheLine(Helper_Get_EA_X(_inst) & (~31));
|
||||
}
|
||||
|
|
|
@ -329,9 +329,9 @@ void Interpreter::mtspr(UGeckoInstruction _inst)
|
|||
if (iLength == 0)
|
||||
iLength = 128;
|
||||
if (DMAL.DMA_LD)
|
||||
Memory::DMA_MemoryToLC(dwCacheAddress, dwMemAddress, iLength);
|
||||
PowerPC::DMA_MemoryToLC(dwCacheAddress, dwMemAddress, iLength);
|
||||
else
|
||||
Memory::DMA_LCToMemory(dwMemAddress, dwCacheAddress, iLength);
|
||||
PowerPC::DMA_LCToMemory(dwMemAddress, dwCacheAddress, iLength);
|
||||
}
|
||||
DMAL.DMA_T = 0;
|
||||
break;
|
||||
|
@ -351,7 +351,7 @@ void Interpreter::mtspr(UGeckoInstruction _inst)
|
|||
|
||||
// Page table base etc
|
||||
case SPR_SDR:
|
||||
Memory::SDRUpdated();
|
||||
PowerPC::SDRUpdated();
|
||||
break;
|
||||
|
||||
case SPR_XER:
|
||||
|
|
|
@ -180,6 +180,7 @@ void Jit64::Init()
|
|||
jo.accurateSinglePrecision = true;
|
||||
js.memcheck = SConfig::GetInstance().m_LocalCoreStartupParameter.bMMU;
|
||||
js.fastmemLoadStore = NULL;
|
||||
js.compilerPC = 0;
|
||||
|
||||
gpr.SetEmitter(this);
|
||||
fpr.SetEmitter(this);
|
||||
|
@ -539,6 +540,7 @@ void Jit64::Jit(u32 em_address)
|
|||
NPC = nextPC;
|
||||
PowerPC::ppcState.Exceptions |= EXCEPTION_ISI;
|
||||
PowerPC::CheckExceptions();
|
||||
WARN_LOG(POWERPC, "ISI exception at 0x%08x", nextPC);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ void Jit64AsmRoutineManager::Generate()
|
|||
MOV(64, MDisp(RSP, 8), Imm32((u32)-1));
|
||||
|
||||
// Two statically allocated registers.
|
||||
MOV(64, R(RMEM), Imm64((u64)Memory::base));
|
||||
//MOV(64, R(RMEM), Imm64((u64)Memory::physical_base));
|
||||
MOV(64, R(RPPCSTATE), Imm64((u64)&PowerPC::ppcState + 0x80));
|
||||
|
||||
const u8* outerLoop = GetCodePtr();
|
||||
|
@ -83,8 +83,26 @@ void Jit64AsmRoutineManager::Generate()
|
|||
SetJumpTarget(skipToRealDispatch);
|
||||
|
||||
dispatcherNoCheck = GetCodePtr();
|
||||
|
||||
// Switch to the correct memory base, in case MSR.DR has changed.
|
||||
// TODO: Is there a more efficient place to put this? We don't
|
||||
// need to do this for indirect jumps, just exceptions etc.
|
||||
TEST(32, PPCSTATE(msr), Imm32(1 << (31 - 27)));
|
||||
FixupBranch physmem = J_CC(CC_NZ);
|
||||
MOV(64, R(RMEM), Imm64((u64)Memory::physical_base));
|
||||
FixupBranch membaseend = J();
|
||||
SetJumpTarget(physmem);
|
||||
MOV(64, R(RMEM), Imm64((u64)Memory::logical_base));
|
||||
SetJumpTarget(membaseend);
|
||||
|
||||
MOV(32, R(RSCRATCH), PPCSTATE(pc));
|
||||
|
||||
// TODO: We need to handle code which executes the same PC with
|
||||
// different values of MSR.IR. It probably makes sense to handle
|
||||
// MSR.DR here too, to allow IsOptimizableRAMAddress-based
|
||||
// optimizations safe, because IR and DR are usually set/cleared together.
|
||||
// TODO: Branching based on the 20 most significant bits of instruction
|
||||
// addresses without translating them is wrong.
|
||||
u64 icache = (u64)jit->GetBlockCache()->iCache.data();
|
||||
u64 icacheVmem = (u64)jit->GetBlockCache()->iCacheVMEM.data();
|
||||
u64 icacheEx = (u64)jit->GetBlockCache()->iCacheEx.data();
|
||||
|
@ -251,5 +269,5 @@ void Jit64AsmRoutineManager::GenerateCommon()
|
|||
ADD(32, 1, M(&m_gatherPipeCount));
|
||||
RET();
|
||||
SetJumpTarget(skip_fast_write);
|
||||
CALL((void *)&Memory::Write_U8);*/
|
||||
CALL((void *)&PowerPC::Write_U8);*/
|
||||
}
|
||||
|
|
|
@ -108,6 +108,8 @@ void Jit64::lXXx(UGeckoInstruction inst)
|
|||
// (mb2): I agree,
|
||||
// IMHO those Idles should always be skipped and replaced by a more controllable "native" Idle methode
|
||||
// ... maybe the throttle one already do that :p
|
||||
// TODO: We shouldn't use a debug read here. It should be possible to get
|
||||
// the following instructions out of the JIT state.
|
||||
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bSkipIdle &&
|
||||
PowerPC::GetState() != PowerPC::CPU_STEPPING &&
|
||||
inst.OPCD == 32 &&
|
||||
|
@ -335,7 +337,7 @@ void Jit64::dcbz(UGeckoInstruction inst)
|
|||
MOV(32, M(&PC), Imm32(jit->js.compilerPC));
|
||||
BitSet32 registersInUse = CallerSavedRegistersInUse();
|
||||
ABI_PushRegistersAndAdjustStack(registersInUse, 0);
|
||||
ABI_CallFunctionR((void *)&Memory::ClearCacheLine, RSCRATCH);
|
||||
ABI_CallFunctionR((void *)&PowerPC::ClearCacheLine, RSCRATCH);
|
||||
ABI_PopRegistersAndAdjustStack(registersInUse, 0);
|
||||
FixupBranch exit = J(true);
|
||||
|
||||
|
|
|
@ -380,9 +380,8 @@ void Jit64::mtmsr(UGeckoInstruction inst)
|
|||
SetJumpTarget(noExceptionsPending);
|
||||
SetJumpTarget(eeDisabled);
|
||||
|
||||
WriteExit(js.compilerPC + 4);
|
||||
|
||||
js.firstFPInstructionFound = false;
|
||||
MOV(32, R(RSCRATCH), Imm32(js.compilerPC + 4));
|
||||
WriteExitDestInRSCRATCH();
|
||||
}
|
||||
|
||||
void Jit64::mfmsr(UGeckoInstruction inst)
|
||||
|
|
|
@ -500,7 +500,7 @@ static void regMarkMemAddress(RegInfo& RI, InstLoc I, InstLoc AI, unsigned OpNum
|
|||
if (isImm(*AI))
|
||||
{
|
||||
unsigned addr = RI.Build->GetImmValue(AI);
|
||||
if (Memory::IsRAMAddress(addr))
|
||||
if (PowerPC::IsOptimizableRAMAddress(addr))
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -520,7 +520,7 @@ static std::pair<OpArg, u32> regBuildMemAddress(RegInfo& RI, InstLoc I, InstLoc
|
|||
if (isImm(*AI))
|
||||
{
|
||||
unsigned addr = RI.Build->GetImmValue(AI);
|
||||
if (Memory::IsRAMAddress(addr))
|
||||
if (PowerPC::IsOptimizableRAMAddress(addr))
|
||||
{
|
||||
if (dest)
|
||||
*dest = regFindFreeReg(RI);
|
||||
|
|
|
@ -521,6 +521,7 @@ void JitIL::Jit(u32 em_address)
|
|||
NPC = nextPC;
|
||||
PowerPC::ppcState.Exceptions |= EXCEPTION_ISI;
|
||||
PowerPC::CheckExceptions();
|
||||
WARN_LOG(POWERPC, "ISI exception at 0x%08x", nextPC);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -189,7 +189,7 @@ bool JitArm::DisasmLoadStore(const u8* ptr, u32* flags, ARMReg* rD, ARMReg* V1)
|
|||
|
||||
bool JitArm::HandleFault(uintptr_t access_address, SContext* ctx)
|
||||
{
|
||||
if (access_address < (uintptr_t)Memory::base)
|
||||
if (access_address < (uintptr_t)Memory::physical_base)
|
||||
PanicAlertT("Exception handler - access below memory space. 0x%08x", access_address);
|
||||
return BackPatch(ctx);
|
||||
}
|
||||
|
@ -323,12 +323,12 @@ u32 JitArm::EmitBackpatchRoutine(ARMXEmitter* emit, u32 flags, bool fastmem, boo
|
|||
emit->MOV(R1, addr);
|
||||
emit->VCVT(S0, RS, 0);
|
||||
emit->VMOV(R0, S0);
|
||||
emit->MOVI2R(temp, (u32)&Memory::Write_U32);
|
||||
emit->MOVI2R(temp, (u32)&PowerPC::Write_U32);
|
||||
emit->BL(temp);
|
||||
}
|
||||
else
|
||||
{
|
||||
emit->MOVI2R(temp, (u32)&Memory::Write_F64);
|
||||
emit->MOVI2R(temp, (u32)&PowerPC::Write_F64);
|
||||
#if !defined(__ARM_PCS_VFP) // SoftFP returns in R0 and R1
|
||||
emit->VMOV(R0, RS);
|
||||
emit->MOV(R2, addr);
|
||||
|
@ -347,7 +347,7 @@ u32 JitArm::EmitBackpatchRoutine(ARMXEmitter* emit, u32 flags, bool fastmem, boo
|
|||
emit->MOV(R0, addr);
|
||||
if (flags & BackPatchInfo::FLAG_SIZE_F32)
|
||||
{
|
||||
emit->MOVI2R(temp, (u32)&Memory::Read_U32);
|
||||
emit->MOVI2R(temp, (u32)&PowerPC::Read_U32);
|
||||
emit->BL(temp);
|
||||
emit->VMOV(S0, R0);
|
||||
emit->VCVT(RS, S0, 0);
|
||||
|
@ -355,7 +355,7 @@ u32 JitArm::EmitBackpatchRoutine(ARMXEmitter* emit, u32 flags, bool fastmem, boo
|
|||
}
|
||||
else
|
||||
{
|
||||
emit->MOVI2R(temp, (u32)&Memory::Read_F64);
|
||||
emit->MOVI2R(temp, (u32)&PowerPC::Read_F64);
|
||||
emit->BL(temp);
|
||||
|
||||
#if !defined(__ARM_PCS_VFP) // SoftFP returns in R0 and R1
|
||||
|
@ -373,11 +373,11 @@ u32 JitArm::EmitBackpatchRoutine(ARMXEmitter* emit, u32 flags, bool fastmem, boo
|
|||
emit->MOV(R1, addr);
|
||||
|
||||
if (flags & BackPatchInfo::FLAG_SIZE_32)
|
||||
emit->MOVI2R(temp, (u32)&Memory::Write_U32);
|
||||
emit->MOVI2R(temp, (u32)&PowerPC::Write_U32);
|
||||
else if (flags & BackPatchInfo::FLAG_SIZE_16)
|
||||
emit->MOVI2R(temp, (u32)&Memory::Write_U16);
|
||||
emit->MOVI2R(temp, (u32)&PowerPC::Write_U16);
|
||||
else
|
||||
emit->MOVI2R(temp, (u32)&Memory::Write_U8);
|
||||
emit->MOVI2R(temp, (u32)&PowerPC::Write_U8);
|
||||
|
||||
emit->BL(temp);
|
||||
emit->POP(4, R0, R1, R2, R3);
|
||||
|
@ -388,11 +388,11 @@ u32 JitArm::EmitBackpatchRoutine(ARMXEmitter* emit, u32 flags, bool fastmem, boo
|
|||
emit->MOV(R0, addr);
|
||||
|
||||
if (flags & BackPatchInfo::FLAG_SIZE_32)
|
||||
emit->MOVI2R(temp, (u32)&Memory::Read_U32);
|
||||
emit->MOVI2R(temp, (u32)&PowerPC::Read_U32);
|
||||
else if (flags & BackPatchInfo::FLAG_SIZE_16)
|
||||
emit->MOVI2R(temp, (u32)&Memory::Read_U16);
|
||||
emit->MOVI2R(temp, (u32)&PowerPC::Read_U16);
|
||||
else if (flags & BackPatchInfo::FLAG_SIZE_8)
|
||||
emit->MOVI2R(temp, (u32)&Memory::Read_U8);
|
||||
emit->MOVI2R(temp, (u32)&PowerPC::Read_U8);
|
||||
|
||||
emit->BL(temp);
|
||||
emit->MOV(temp, R0);
|
||||
|
|
|
@ -145,7 +145,7 @@ void JitArm::SafeStoreFromReg(s32 dest, u32 value, s32 regOffset, int accessSize
|
|||
STR(R11, R14);
|
||||
jit->js.fifoBytesThisBlock += accessSize >> 3;
|
||||
}
|
||||
else if (Memory::IsRAMAddress(imm_addr))
|
||||
else if (PowerPC::IsOptimizableRAMAddress(imm_addr))
|
||||
{
|
||||
MOVI2R(rA, imm_addr);
|
||||
EmitBackpatchRoutine(this, flags, SConfig::GetInstance().m_LocalCoreStartupParameter.bFastmem, true, RS);
|
||||
|
@ -450,9 +450,9 @@ void JitArm::lXX(UGeckoInstruction inst)
|
|||
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bSkipIdle &&
|
||||
inst.OPCD == 32 &&
|
||||
(inst.hex & 0xFFFF0000) == 0x800D0000 &&
|
||||
(Memory::ReadUnchecked_U32(js.compilerPC + 4) == 0x28000000 ||
|
||||
(SConfig::GetInstance().m_LocalCoreStartupParameter.bWii && Memory::ReadUnchecked_U32(js.compilerPC + 4) == 0x2C000000)) &&
|
||||
Memory::ReadUnchecked_U32(js.compilerPC + 8) == 0x4182fff8)
|
||||
(PowerPC::HostRead_U32(js.compilerPC + 4) == 0x28000000 ||
|
||||
(SConfig::GetInstance().m_LocalCoreStartupParameter.bWii && PowerPC::HostRead_U32(js.compilerPC + 4) == 0x2C000000)) &&
|
||||
PowerPC::HostRead_U32(js.compilerPC + 8) == 0x4182fff8)
|
||||
{
|
||||
// if it's still 0, we can wait until the next event
|
||||
TST(RD, RD);
|
||||
|
@ -536,7 +536,7 @@ void JitArm::dcbst(UGeckoInstruction inst)
|
|||
// memory location. Do not invalidate the JIT cache in this case as the memory
|
||||
// will be the same.
|
||||
// dcbt = 0x7c00022c
|
||||
FALLBACK_IF((Memory::ReadUnchecked_U32(js.compilerPC - 4) & 0x7c00022c) != 0x7c00022c);
|
||||
FALLBACK_IF((PowerPC::HostRead_U32(js.compilerPC - 4) & 0x7c00022c) != 0x7c00022c);
|
||||
}
|
||||
|
||||
void JitArm::icbi(UGeckoInstruction inst)
|
||||
|
|
|
@ -183,7 +183,7 @@ void JitArm::lfXX(UGeckoInstruction inst)
|
|||
|
||||
EmitBackpatchRoutine(this, flags,
|
||||
SConfig::GetInstance().m_LocalCoreStartupParameter.bFastmem,
|
||||
!(is_immediate && Memory::IsRAMAddress(imm_addr)), v0, v1);
|
||||
!(is_immediate && PowerPC::IsOptimizableRAMAddress(imm_addr)), v0, v1);
|
||||
|
||||
SetJumpTarget(DoNotLoad);
|
||||
}
|
||||
|
@ -384,7 +384,7 @@ void JitArm::stfXX(UGeckoInstruction inst)
|
|||
jit->js.fifoBytesThisBlock += accessSize >> 3;
|
||||
|
||||
}
|
||||
else if (Memory::IsRAMAddress(imm_addr))
|
||||
else if (PowerPC::IsOptimizableRAMAddress(imm_addr))
|
||||
{
|
||||
MOVI2R(addr, imm_addr);
|
||||
EmitBackpatchRoutine(this, flags, SConfig::GetInstance().m_LocalCoreStartupParameter.bFastmem, false, v0);
|
||||
|
|
|
@ -29,20 +29,20 @@ JitArmAsmRoutineManager asm_routines;
|
|||
|
||||
static void WriteDual32(u32 value1, u32 value2, u32 address)
|
||||
{
|
||||
Memory::Write_U32(value1, address);
|
||||
Memory::Write_U32(value2, address + 4);
|
||||
PowerPC::Write_U32(value1, address);
|
||||
PowerPC::Write_U32(value2, address + 4);
|
||||
}
|
||||
|
||||
static void WriteDual16(u32 value1, u32 value2, u32 address)
|
||||
{
|
||||
Memory::Write_U16(value1, address);
|
||||
Memory::Write_U16(value2, address + 2);
|
||||
PowerPC::Write_U16(value1, address);
|
||||
PowerPC::Write_U16(value2, address + 2);
|
||||
}
|
||||
|
||||
static void WriteDual8(u32 value1, u32 value2, u32 address)
|
||||
{
|
||||
Memory::Write_U8(value1, address);
|
||||
Memory::Write_U8(value2, address + 1);
|
||||
PowerPC::Write_U8(value1, address);
|
||||
PowerPC::Write_U8(value2, address + 1);
|
||||
}
|
||||
|
||||
void JitArmAsmRoutineManager::Generate()
|
||||
|
@ -56,7 +56,7 @@ void JitArmAsmRoutineManager::Generate()
|
|||
SUB(_SP, _SP, 4);
|
||||
|
||||
MOVI2R(R9, (u32)&PowerPC::ppcState.spr[0]);
|
||||
MOVI2R(R8, (u32)Memory::base);
|
||||
MOVI2R(R8, (u32)Memory::physical_base);
|
||||
|
||||
FixupBranch skipToRealDispatcher = B();
|
||||
dispatcher = GetCodePtr();
|
||||
|
@ -465,7 +465,7 @@ void JitArmAsmRoutineManager::GenerateCommon()
|
|||
PUSH(5, R0, R1, R2, R3, _LR);
|
||||
VMOV(R0, S0);
|
||||
MOV(R1, R10);
|
||||
MOVI2R(R10, (u32)&Memory::Write_U32);
|
||||
MOVI2R(R10, (u32)&PowerPC::Write_U32);
|
||||
BL(R10);
|
||||
|
||||
POP(5, R0, R1, R2, R3, _PC);
|
||||
|
@ -493,7 +493,7 @@ void JitArmAsmRoutineManager::GenerateCommon()
|
|||
PUSH(5, R0, R1, R2, R3, _LR);
|
||||
VMOV(R0, S0);
|
||||
MOV(R1, R10);
|
||||
MOVI2R(R10, (u32)&Memory::Write_U8);
|
||||
MOVI2R(R10, (u32)&PowerPC::Write_U8);
|
||||
BL(R10);
|
||||
POP(5, R0, R1, R2, R3, _PC);
|
||||
}
|
||||
|
@ -521,7 +521,7 @@ void JitArmAsmRoutineManager::GenerateCommon()
|
|||
PUSH(5, R0, R1, R2, R3, _LR);
|
||||
VMOV(R0, S0);
|
||||
MOV(R1, R10);
|
||||
MOVI2R(R10, (u32)&Memory::Write_U16);
|
||||
MOVI2R(R10, (u32)&PowerPC::Write_U16);
|
||||
BL(R10);
|
||||
|
||||
POP(5, R0, R1, R2, R3, _PC);
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "Common/StringUtil.h"
|
||||
|
||||
#include "Core/HW/Memmap.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
#include "Core/PowerPC/JitArm64/Jit.h"
|
||||
#include "Core/PowerPC/JitArmCommon/BackPatch.h"
|
||||
|
||||
|
@ -127,7 +128,8 @@ u32 JitArm64::EmitBackpatchRoutine(ARM64XEmitter* emit, u32 flags, bool fastmem,
|
|||
|
||||
if (fastmem)
|
||||
{
|
||||
MOVK(addr, ((u64)Memory::base >> 32) & 0xFFFF, SHIFT_32);
|
||||
u8* base = UReg_MSR(MSR).DR ? Memory::logical_base : Memory::physical_base;
|
||||
MOVK(addr, ((u64)base >> 32) & 0xFFFF, SHIFT_32);
|
||||
|
||||
if (flags & BackPatchInfo::FLAG_STORE &&
|
||||
flags & (BackPatchInfo::FLAG_SIZE_F32 | BackPatchInfo::FLAG_SIZE_F64))
|
||||
|
@ -215,12 +217,12 @@ u32 JitArm64::EmitBackpatchRoutine(ARM64XEmitter* emit, u32 flags, bool fastmem,
|
|||
{
|
||||
float_emit.FCVT(32, 64, Q0, RS);
|
||||
float_emit.UMOV(32, W0, Q0, 0);
|
||||
emit->MOVI2R(X30, (u64)&Memory::Write_U32);
|
||||
emit->MOVI2R(X30, (u64)&PowerPC::Write_U32);
|
||||
emit->BLR(X30);
|
||||
}
|
||||
else
|
||||
{
|
||||
emit->MOVI2R(X30, (u64)&Memory::Write_U64);
|
||||
emit->MOVI2R(X30, (u64)&PowerPC::Write_U64);
|
||||
float_emit.UMOV(64, X0, RS, 0);
|
||||
emit->BLR(X30);
|
||||
}
|
||||
|
@ -232,14 +234,14 @@ u32 JitArm64::EmitBackpatchRoutine(ARM64XEmitter* emit, u32 flags, bool fastmem,
|
|||
ARM64FloatEmitter float_emit(emit);
|
||||
if (flags & BackPatchInfo::FLAG_SIZE_F32)
|
||||
{
|
||||
emit->MOVI2R(X30, (u64)&Memory::Read_U32);
|
||||
emit->MOVI2R(X30, (u64)&PowerPC::Read_U32);
|
||||
emit->BLR(X30);
|
||||
float_emit.DUP(32, RS, X0);
|
||||
float_emit.FCVTL(64, RS, RS);
|
||||
}
|
||||
else
|
||||
{
|
||||
emit->MOVI2R(X30, (u64)&Memory::Read_F64);
|
||||
emit->MOVI2R(X30, (u64)&PowerPC::Read_F64);
|
||||
emit->BLR(X30);
|
||||
float_emit.INS(64, RS, 0, X0);
|
||||
}
|
||||
|
@ -249,22 +251,22 @@ u32 JitArm64::EmitBackpatchRoutine(ARM64XEmitter* emit, u32 flags, bool fastmem,
|
|||
emit->MOV(W0, RS);
|
||||
|
||||
if (flags & BackPatchInfo::FLAG_SIZE_32)
|
||||
emit->MOVI2R(X30, (u64)&Memory::Write_U32);
|
||||
emit->MOVI2R(X30, (u64)&PowerPC::Write_U32);
|
||||
else if (flags & BackPatchInfo::FLAG_SIZE_16)
|
||||
emit->MOVI2R(X30, (u64)&Memory::Write_U16);
|
||||
emit->MOVI2R(X30, (u64)&PowerPC::Write_U16);
|
||||
else
|
||||
emit->MOVI2R(X30, (u64)&Memory::Write_U8);
|
||||
emit->MOVI2R(X30, (u64)&PowerPC::Write_U8);
|
||||
|
||||
emit->BLR(X30);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (flags & BackPatchInfo::FLAG_SIZE_32)
|
||||
emit->MOVI2R(X30, (u64)&Memory::Read_U32);
|
||||
emit->MOVI2R(X30, (u64)&PowerPC::Read_U32);
|
||||
else if (flags & BackPatchInfo::FLAG_SIZE_16)
|
||||
emit->MOVI2R(X30, (u64)&Memory::Read_U16);
|
||||
emit->MOVI2R(X30, (u64)&PowerPC::Read_U16);
|
||||
else if (flags & BackPatchInfo::FLAG_SIZE_8)
|
||||
emit->MOVI2R(X30, (u64)&Memory::Read_U8);
|
||||
emit->MOVI2R(X30, (u64)&PowerPC::Read_U8);
|
||||
|
||||
emit->BLR(X30);
|
||||
|
||||
|
@ -302,9 +304,10 @@ u32 JitArm64::EmitBackpatchRoutine(ARM64XEmitter* emit, u32 flags, bool fastmem,
|
|||
|
||||
bool JitArm64::HandleFault(uintptr_t access_address, SContext* ctx)
|
||||
{
|
||||
if (access_address < (uintptr_t)Memory::base)
|
||||
if (!(access_address >= (uintptr_t)Memory::physical_base && access_address < (uintptr_t)Memory::physical_base + 0x100010000) &&
|
||||
!(access_address >= (uintptr_t)Memory::logical_base && access_address < (uintptr_t)Memory::logical_base + 0x100010000))
|
||||
{
|
||||
ERROR_LOG(DYNA_REC, "Exception handler - access below memory space. PC: 0x%016llx 0x%016lx < 0x%016lx", ctx->CTX_PC, access_address, (uintptr_t)Memory::base);
|
||||
ERROR_LOG(DYNA_REC, "Exception handler - access below memory space. PC: 0x%016llx 0x%016lx < 0x%016lx", ctx->CTX_PC, access_address, (uintptr_t)Memory::physical_base);
|
||||
|
||||
DoBacktrace(access_address, ctx);
|
||||
return false;
|
||||
|
|
|
@ -147,7 +147,7 @@ void JitArm64::SafeLoadToReg(u32 dest, s32 addr, s32 offsetReg, u32 flags, s32 o
|
|||
if (update)
|
||||
MOV(gpr.R(addr), addr_reg);
|
||||
|
||||
if (is_immediate && Memory::IsRAMAddress(imm_addr))
|
||||
if (is_immediate && PowerPC::IsOptimizableRAMAddress(imm_addr))
|
||||
{
|
||||
EmitBackpatchRoutine(this, flags, true, false, dest_reg, XA);
|
||||
}
|
||||
|
@ -288,7 +288,7 @@ void JitArm64::SafeStoreFromReg(s32 dest, u32 value, s32 regOffset, u32 flags, s
|
|||
|
||||
ARM64Reg XA = EncodeRegTo64(addr_reg);
|
||||
|
||||
if (is_immediate && Memory::IsRAMAddress(imm_addr))
|
||||
if (is_immediate && PowerPC::IsOptimizableRAMAddress(imm_addr))
|
||||
{
|
||||
MOVI2R(XA, imm_addr);
|
||||
|
||||
|
@ -401,9 +401,9 @@ void JitArm64::lXX(UGeckoInstruction inst)
|
|||
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bSkipIdle &&
|
||||
inst.OPCD == 32 &&
|
||||
(inst.hex & 0xFFFF0000) == 0x800D0000 &&
|
||||
(Memory::ReadUnchecked_U32(js.compilerPC + 4) == 0x28000000 ||
|
||||
(SConfig::GetInstance().m_LocalCoreStartupParameter.bWii && Memory::ReadUnchecked_U32(js.compilerPC + 4) == 0x2C000000)) &&
|
||||
Memory::ReadUnchecked_U32(js.compilerPC + 8) == 0x4182fff8)
|
||||
(PowerPC::HostRead_U32(js.compilerPC + 4) == 0x28000000 ||
|
||||
(SConfig::GetInstance().m_LocalCoreStartupParameter.bWii && PowerPC::HostRead_U32(js.compilerPC + 4) == 0x2C000000)) &&
|
||||
PowerPC::HostRead_U32(js.compilerPC + 8) == 0x4182fff8)
|
||||
{
|
||||
// if it's still 0, we can wait until the next event
|
||||
FixupBranch noIdle = CBNZ(gpr.R(d));
|
||||
|
|
|
@ -181,7 +181,7 @@ void JitArm64::lfXX(UGeckoInstruction inst)
|
|||
fprs_in_use[0] = 0; // Q0
|
||||
fprs_in_use[VD - Q0] = 0;
|
||||
|
||||
if (is_immediate && Memory::IsRAMAddress(imm_addr))
|
||||
if (is_immediate && PowerPC::IsOptimizableRAMAddress(imm_addr))
|
||||
{
|
||||
EmitBackpatchRoutine(this, flags, true, false, VD, XA);
|
||||
}
|
||||
|
@ -399,7 +399,7 @@ void JitArm64::stfXX(UGeckoInstruction inst)
|
|||
jit->js.fifoBytesThisBlock += accessSize >> 3;
|
||||
|
||||
}
|
||||
else if (Memory::IsRAMAddress(imm_addr))
|
||||
else if (PowerPC::IsOptimizableRAMAddress(imm_addr))
|
||||
{
|
||||
EmitBackpatchRoutine(this, flags, true, false, V0, XA);
|
||||
}
|
||||
|
|
|
@ -113,14 +113,14 @@ void JitArm64AsmRoutineManager::GenerateCommon()
|
|||
BRK(100);
|
||||
const u8* loadPairedFloatTwo = GetCodePtr();
|
||||
{
|
||||
MOVK(addr_reg, ((u64)Memory::base >> 32) & 0xFFFF, SHIFT_32);
|
||||
MOVK(addr_reg, ((u64)Memory::logical_base >> 32) & 0xFFFF, SHIFT_32);
|
||||
float_emit.LD1(32, 1, D0, addr_reg);
|
||||
float_emit.REV32(8, D0, D0);
|
||||
RET(X30);
|
||||
}
|
||||
const u8* loadPairedU8Two = GetCodePtr();
|
||||
{
|
||||
MOVK(addr_reg, ((u64)Memory::base >> 32) & 0xFFFF, SHIFT_32);
|
||||
MOVK(addr_reg, ((u64)Memory::logical_base >> 32) & 0xFFFF, SHIFT_32);
|
||||
float_emit.LDR(16, INDEX_UNSIGNED, D0, addr_reg, 0);
|
||||
float_emit.UXTL(8, D0, D0);
|
||||
float_emit.UXTL(16, D0, D0);
|
||||
|
@ -134,7 +134,7 @@ void JitArm64AsmRoutineManager::GenerateCommon()
|
|||
}
|
||||
const u8* loadPairedS8Two = GetCodePtr();
|
||||
{
|
||||
MOVK(addr_reg, ((u64)Memory::base >> 32) & 0xFFFF, SHIFT_32);
|
||||
MOVK(addr_reg, ((u64)Memory::logical_base >> 32) & 0xFFFF, SHIFT_32);
|
||||
float_emit.LDR(16, INDEX_UNSIGNED, D0, addr_reg, 0);
|
||||
float_emit.SXTL(8, D0, D0);
|
||||
float_emit.SXTL(16, D0, D0);
|
||||
|
@ -148,7 +148,7 @@ void JitArm64AsmRoutineManager::GenerateCommon()
|
|||
}
|
||||
const u8* loadPairedU16Two = GetCodePtr();
|
||||
{
|
||||
MOVK(addr_reg, ((u64)Memory::base >> 32) & 0xFFFF, SHIFT_32);
|
||||
MOVK(addr_reg, ((u64)Memory::logical_base >> 32) & 0xFFFF, SHIFT_32);
|
||||
float_emit.LD1(16, 1, D0, addr_reg);
|
||||
float_emit.REV16(8, D0, D0);
|
||||
float_emit.UXTL(16, D0, D0);
|
||||
|
@ -162,7 +162,7 @@ void JitArm64AsmRoutineManager::GenerateCommon()
|
|||
}
|
||||
const u8* loadPairedS16Two = GetCodePtr();
|
||||
{
|
||||
MOVK(addr_reg, ((u64)Memory::base >> 32) & 0xFFFF, SHIFT_32);
|
||||
MOVK(addr_reg, ((u64)Memory::logical_base >> 32) & 0xFFFF, SHIFT_32);
|
||||
float_emit.LD1(16, 1, D0, addr_reg);
|
||||
float_emit.REV16(8, D0, D0);
|
||||
float_emit.SXTL(16, D0, D0);
|
||||
|
@ -177,14 +177,14 @@ void JitArm64AsmRoutineManager::GenerateCommon()
|
|||
|
||||
const u8* loadPairedFloatOne = GetCodePtr();
|
||||
{
|
||||
MOVK(addr_reg, ((u64)Memory::base >> 32) & 0xFFFF, SHIFT_32);
|
||||
MOVK(addr_reg, ((u64)Memory::logical_base >> 32) & 0xFFFF, SHIFT_32);
|
||||
float_emit.LDR(32, INDEX_UNSIGNED, D0, addr_reg, 0);
|
||||
float_emit.REV32(8, D0, D0);
|
||||
RET(X30);
|
||||
}
|
||||
const u8* loadPairedU8One = GetCodePtr();
|
||||
{
|
||||
MOVK(addr_reg, ((u64)Memory::base >> 32) & 0xFFFF, SHIFT_32);
|
||||
MOVK(addr_reg, ((u64)Memory::logical_base >> 32) & 0xFFFF, SHIFT_32);
|
||||
float_emit.LDR(8, INDEX_UNSIGNED, D0, addr_reg, 0);
|
||||
float_emit.UXTL(8, D0, D0);
|
||||
float_emit.UXTL(16, D0, D0);
|
||||
|
@ -198,7 +198,7 @@ void JitArm64AsmRoutineManager::GenerateCommon()
|
|||
}
|
||||
const u8* loadPairedS8One = GetCodePtr();
|
||||
{
|
||||
MOVK(addr_reg, ((u64)Memory::base >> 32) & 0xFFFF, SHIFT_32);
|
||||
MOVK(addr_reg, ((u64)Memory::logical_base >> 32) & 0xFFFF, SHIFT_32);
|
||||
float_emit.LDR(8, INDEX_UNSIGNED, D0, addr_reg, 0);
|
||||
float_emit.SXTL(8, D0, D0);
|
||||
float_emit.SXTL(16, D0, D0);
|
||||
|
@ -212,7 +212,7 @@ void JitArm64AsmRoutineManager::GenerateCommon()
|
|||
}
|
||||
const u8* loadPairedU16One = GetCodePtr();
|
||||
{
|
||||
MOVK(addr_reg, ((u64)Memory::base >> 32) & 0xFFFF, SHIFT_32);
|
||||
MOVK(addr_reg, ((u64)Memory::logical_base >> 32) & 0xFFFF, SHIFT_32);
|
||||
float_emit.LDR(16, INDEX_UNSIGNED, D0, addr_reg, 0);
|
||||
float_emit.REV16(8, D0, D0);
|
||||
float_emit.UXTL(16, D0, D0);
|
||||
|
@ -226,7 +226,7 @@ void JitArm64AsmRoutineManager::GenerateCommon()
|
|||
}
|
||||
const u8* loadPairedS16One = GetCodePtr();
|
||||
{
|
||||
MOVK(addr_reg, ((u64)Memory::base >> 32) & 0xFFFF, SHIFT_32);
|
||||
MOVK(addr_reg, ((u64)Memory::logical_base >> 32) & 0xFFFF, SHIFT_32);
|
||||
float_emit.LDR(16, INDEX_UNSIGNED, D0, addr_reg, 0);
|
||||
float_emit.REV16(8, D0, D0);
|
||||
float_emit.SXTL(16, D0, D0);
|
||||
|
@ -272,7 +272,7 @@ void JitArm64AsmRoutineManager::GenerateCommon()
|
|||
FixupBranch argh = B(CC_NEQ);
|
||||
|
||||
float_emit.REV32(8, D0, D0);
|
||||
MOVK(addr_reg, ((u64)Memory::base >> 32) & 0xFFFF, SHIFT_32);
|
||||
MOVK(addr_reg, ((u64)Memory::logical_base >> 32) & 0xFFFF, SHIFT_32);
|
||||
float_emit.ST1(64, Q0, 0, addr_reg, SP);
|
||||
RET(X30);
|
||||
|
||||
|
@ -282,7 +282,7 @@ void JitArm64AsmRoutineManager::GenerateCommon()
|
|||
float_emit.ABI_PushRegisters(fprs);
|
||||
float_emit.UMOV(64, X0, Q0, 0);
|
||||
ORR(X0, SP, X0, ArithOption(X0, ST_ROR, 32));
|
||||
MOVI2R(X30, (u64)Memory::Write_U64);
|
||||
MOVI2R(X30, (u64)PowerPC::Write_U64);
|
||||
BLR(X30);
|
||||
float_emit.ABI_PopRegisters(fprs);
|
||||
ABI_PopRegisters(gprs);
|
||||
|
@ -304,7 +304,7 @@ void JitArm64AsmRoutineManager::GenerateCommon()
|
|||
TST(DecodeReg(addr_reg), 6, 1);
|
||||
FixupBranch argh = B(CC_NEQ);
|
||||
|
||||
MOVK(addr_reg, ((u64)Memory::base >> 32) & 0xFFFF, SHIFT_32);
|
||||
MOVK(addr_reg, ((u64)Memory::logical_base >> 32) & 0xFFFF, SHIFT_32);
|
||||
float_emit.ST1(16, Q0, 0, addr_reg, SP);
|
||||
RET(X30);
|
||||
|
||||
|
@ -313,7 +313,7 @@ void JitArm64AsmRoutineManager::GenerateCommon()
|
|||
float_emit.ABI_PushRegisters(fprs);
|
||||
float_emit.UMOV(16, W0, Q0, 0);
|
||||
REV16(W0, W0);
|
||||
MOVI2R(X30, (u64)Memory::Write_U16);
|
||||
MOVI2R(X30, (u64)PowerPC::Write_U16);
|
||||
BLR(X30);
|
||||
float_emit.ABI_PopRegisters(fprs);
|
||||
ABI_PopRegisters(gprs);
|
||||
|
@ -335,7 +335,7 @@ void JitArm64AsmRoutineManager::GenerateCommon()
|
|||
TST(DecodeReg(addr_reg), 6, 1);
|
||||
FixupBranch argh = B(CC_NEQ);
|
||||
|
||||
MOVK(addr_reg, ((u64)Memory::base >> 32) & 0xFFFF, SHIFT_32);
|
||||
MOVK(addr_reg, ((u64)Memory::logical_base >> 32) & 0xFFFF, SHIFT_32);
|
||||
float_emit.ST1(16, Q0, 0, addr_reg, SP);
|
||||
RET(X30);
|
||||
|
||||
|
@ -344,7 +344,7 @@ void JitArm64AsmRoutineManager::GenerateCommon()
|
|||
float_emit.ABI_PushRegisters(fprs);
|
||||
float_emit.UMOV(16, W0, Q0, 0);
|
||||
REV16(W0, W0);
|
||||
MOVI2R(X30, (u64)Memory::Write_U16);
|
||||
MOVI2R(X30, (u64)PowerPC::Write_U16);
|
||||
BLR(X30);
|
||||
float_emit.ABI_PopRegisters(fprs);
|
||||
ABI_PopRegisters(gprs);
|
||||
|
@ -366,7 +366,7 @@ void JitArm64AsmRoutineManager::GenerateCommon()
|
|||
|
||||
TST(DecodeReg(addr_reg), 6, 1);
|
||||
FixupBranch argh = B(CC_NEQ);
|
||||
MOVK(addr_reg, ((u64)Memory::base >> 32) & 0xFFFF, SHIFT_32);
|
||||
MOVK(addr_reg, ((u64)Memory::logical_base >> 32) & 0xFFFF, SHIFT_32);
|
||||
float_emit.ST1(32, Q0, 0, addr_reg, SP);
|
||||
RET(X30);
|
||||
|
||||
|
@ -375,7 +375,7 @@ void JitArm64AsmRoutineManager::GenerateCommon()
|
|||
float_emit.ABI_PushRegisters(fprs);
|
||||
float_emit.REV32(8, D0, D0);
|
||||
float_emit.UMOV(32, W0, Q0, 0);
|
||||
MOVI2R(X30, (u64)Memory::Write_U32);
|
||||
MOVI2R(X30, (u64)PowerPC::Write_U32);
|
||||
BLR(X30);
|
||||
float_emit.ABI_PopRegisters(fprs);
|
||||
ABI_PopRegisters(gprs);
|
||||
|
@ -396,7 +396,7 @@ void JitArm64AsmRoutineManager::GenerateCommon()
|
|||
|
||||
TST(DecodeReg(addr_reg), 6, 1);
|
||||
FixupBranch argh = B(CC_NEQ);
|
||||
MOVK(addr_reg, ((u64)Memory::base >> 32) & 0xFFFF, SHIFT_32);
|
||||
MOVK(addr_reg, ((u64)Memory::logical_base >> 32) & 0xFFFF, SHIFT_32);
|
||||
float_emit.ST1(32, Q0, 0, addr_reg, SP);
|
||||
RET(X30);
|
||||
|
||||
|
@ -405,7 +405,7 @@ void JitArm64AsmRoutineManager::GenerateCommon()
|
|||
float_emit.ABI_PushRegisters(fprs);
|
||||
float_emit.REV32(8, D0, D0);
|
||||
float_emit.UMOV(32, W0, Q0, 0);
|
||||
MOVI2R(X30, (u64)Memory::Write_U32);
|
||||
MOVI2R(X30, (u64)PowerPC::Write_U32);
|
||||
BLR(X30);
|
||||
float_emit.ABI_PopRegisters(fprs);
|
||||
ABI_PopRegisters(gprs);
|
||||
|
@ -421,7 +421,7 @@ void JitArm64AsmRoutineManager::GenerateCommon()
|
|||
FixupBranch argh = B(CC_NEQ);
|
||||
|
||||
float_emit.REV32(8, D0, D0);
|
||||
MOVK(addr_reg, ((u64)Memory::base >> 32) & 0xFFFF, SHIFT_32);
|
||||
MOVK(addr_reg, ((u64)Memory::logical_base >> 32) & 0xFFFF, SHIFT_32);
|
||||
float_emit.STR(32, INDEX_UNSIGNED, D0, addr_reg, 0);
|
||||
RET(X30);
|
||||
|
||||
|
@ -430,7 +430,7 @@ void JitArm64AsmRoutineManager::GenerateCommon()
|
|||
ABI_PushRegisters(gprs);
|
||||
float_emit.ABI_PushRegisters(fprs);
|
||||
float_emit.UMOV(32, W0, Q0, 0);
|
||||
MOVI2R(X30, (u64)&Memory::Write_U32);
|
||||
MOVI2R(X30, (u64)&PowerPC::Write_U32);
|
||||
BLR(X30);
|
||||
float_emit.ABI_PopRegisters(fprs);
|
||||
ABI_PopRegisters(gprs);
|
||||
|
@ -451,7 +451,7 @@ void JitArm64AsmRoutineManager::GenerateCommon()
|
|||
|
||||
TST(DecodeReg(addr_reg), 6, 1);
|
||||
FixupBranch argh = B(CC_NEQ);
|
||||
MOVK(addr_reg, ((u64)Memory::base >> 32) & 0xFFFF, SHIFT_32);
|
||||
MOVK(addr_reg, ((u64)Memory::logical_base >> 32) & 0xFFFF, SHIFT_32);
|
||||
float_emit.ST1(8, Q0, 0, addr_reg);
|
||||
RET(X30);
|
||||
|
||||
|
@ -459,7 +459,7 @@ void JitArm64AsmRoutineManager::GenerateCommon()
|
|||
ABI_PushRegisters(gprs);
|
||||
float_emit.ABI_PushRegisters(fprs);
|
||||
float_emit.UMOV(32, W0, Q0, 0);
|
||||
MOVI2R(X30, (u64)&Memory::Write_U8);
|
||||
MOVI2R(X30, (u64)&PowerPC::Write_U8);
|
||||
BLR(X30);
|
||||
float_emit.ABI_PopRegisters(fprs);
|
||||
ABI_PopRegisters(gprs);
|
||||
|
@ -480,7 +480,7 @@ void JitArm64AsmRoutineManager::GenerateCommon()
|
|||
|
||||
TST(DecodeReg(addr_reg), 6, 1);
|
||||
FixupBranch argh = B(CC_NEQ);
|
||||
MOVK(addr_reg, ((u64)Memory::base >> 32) & 0xFFFF, SHIFT_32);
|
||||
MOVK(addr_reg, ((u64)Memory::logical_base >> 32) & 0xFFFF, SHIFT_32);
|
||||
float_emit.ST1(8, Q0, 0, addr_reg);
|
||||
RET(X30);
|
||||
|
||||
|
@ -488,7 +488,7 @@ void JitArm64AsmRoutineManager::GenerateCommon()
|
|||
ABI_PushRegisters(gprs);
|
||||
float_emit.ABI_PushRegisters(fprs);
|
||||
float_emit.SMOV(32, W0, Q0, 0);
|
||||
MOVI2R(X30, (u64)&Memory::Write_U8);
|
||||
MOVI2R(X30, (u64)&PowerPC::Write_U8);
|
||||
BLR(X30);
|
||||
float_emit.ABI_PopRegisters(fprs);
|
||||
ABI_PopRegisters(gprs);
|
||||
|
@ -508,7 +508,7 @@ void JitArm64AsmRoutineManager::GenerateCommon()
|
|||
|
||||
TST(DecodeReg(addr_reg), 6, 1);
|
||||
FixupBranch argh = B(CC_NEQ);
|
||||
MOVK(addr_reg, ((u64)Memory::base >> 32) & 0xFFFF, SHIFT_32);
|
||||
MOVK(addr_reg, ((u64)Memory::logical_base >> 32) & 0xFFFF, SHIFT_32);
|
||||
float_emit.REV16(8, D0, D0);
|
||||
float_emit.ST1(16, Q0, 0, addr_reg);
|
||||
RET(X30);
|
||||
|
@ -517,7 +517,7 @@ void JitArm64AsmRoutineManager::GenerateCommon()
|
|||
ABI_PushRegisters(gprs);
|
||||
float_emit.ABI_PushRegisters(fprs);
|
||||
float_emit.UMOV(32, W0, Q0, 0);
|
||||
MOVI2R(X30, (u64)&Memory::Write_U16);
|
||||
MOVI2R(X30, (u64)&PowerPC::Write_U16);
|
||||
BLR(X30);
|
||||
float_emit.ABI_PopRegisters(fprs);
|
||||
ABI_PopRegisters(gprs);
|
||||
|
@ -537,7 +537,7 @@ void JitArm64AsmRoutineManager::GenerateCommon()
|
|||
|
||||
TST(DecodeReg(addr_reg), 6, 1);
|
||||
FixupBranch argh = B(CC_NEQ);
|
||||
MOVK(addr_reg, ((u64)Memory::base >> 32) & 0xFFFF, SHIFT_32);
|
||||
MOVK(addr_reg, ((u64)Memory::logical_base >> 32) & 0xFFFF, SHIFT_32);
|
||||
float_emit.REV16(8, D0, D0);
|
||||
float_emit.ST1(16, Q0, 0, addr_reg);
|
||||
RET(X30);
|
||||
|
@ -546,7 +546,7 @@ void JitArm64AsmRoutineManager::GenerateCommon()
|
|||
ABI_PushRegisters(gprs);
|
||||
float_emit.ABI_PushRegisters(fprs);
|
||||
float_emit.SMOV(32, W0, Q0, 0);
|
||||
MOVI2R(X30, (u64)&Memory::Write_U16);
|
||||
MOVI2R(X30, (u64)&PowerPC::Write_U16);
|
||||
BLR(X30);
|
||||
float_emit.ABI_PopRegisters(fprs);
|
||||
ABI_PopRegisters(gprs);
|
||||
|
|
|
@ -30,8 +30,11 @@ static void BackPatchError(const std::string &text, u8 *codePtr, u32 emAddress)
|
|||
bool Jitx86Base::HandleFault(uintptr_t access_address, SContext* ctx)
|
||||
{
|
||||
// TODO: do we properly handle off-the-end?
|
||||
if (access_address >= (uintptr_t)Memory::base && access_address < (uintptr_t)Memory::base + 0x100010000)
|
||||
return BackPatch((u32)(access_address - (uintptr_t)Memory::base), ctx);
|
||||
if (access_address >= (uintptr_t)Memory::physical_base && access_address < (uintptr_t)Memory::physical_base + 0x100010000)
|
||||
return BackPatch((u32)(access_address - (uintptr_t)Memory::physical_base), ctx);
|
||||
if (access_address >= (uintptr_t)Memory::logical_base && access_address < (uintptr_t)Memory::logical_base + 0x100010000)
|
||||
return BackPatch((u32)(access_address - (uintptr_t)Memory::logical_base), ctx);
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -71,12 +71,12 @@ u8 *EmuCodeBlock::UnsafeLoadToReg(X64Reg reg_value, OpArg opAddress, int accessS
|
|||
opAddress = R(reg_value);
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
memOperand = MComplex(RMEM, opAddress.GetSimpleReg(), SCALE_1, offset);
|
||||
}
|
||||
else if (opAddress.IsImm())
|
||||
{
|
||||
memOperand = MDisp(RMEM, (opAddress.offset + offset) & 0x3FFFFFFF);
|
||||
MOV(32, R(reg_value), Imm32((u32)(opAddress.offset + offset)));
|
||||
memOperand = MRegSum(RMEM, reg_value);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -308,9 +308,9 @@ void EmuCodeBlock::SafeLoadToReg(X64Reg reg_value, const Gen::OpArg & opAddress,
|
|||
// access the RAM buffer and load from there).
|
||||
// 2. If the address is in the MMIO range, find the appropriate
|
||||
// MMIO handler and generate the code to load using the handler.
|
||||
// 3. Otherwise, just generate a call to Memory::Read_* with the
|
||||
// 3. Otherwise, just generate a call to PowerPC::Read_* with the
|
||||
// address hardcoded.
|
||||
if (Memory::IsRAMAddress(address))
|
||||
if (PowerPC::IsOptimizableRAMAddress(address))
|
||||
{
|
||||
UnsafeLoadToReg(reg_value, opAddress, accessSize, offset, signExtend);
|
||||
}
|
||||
|
@ -324,10 +324,10 @@ void EmuCodeBlock::SafeLoadToReg(X64Reg reg_value, const Gen::OpArg & opAddress,
|
|||
ABI_PushRegistersAndAdjustStack(registersInUse, 0);
|
||||
switch (accessSize)
|
||||
{
|
||||
case 64: ABI_CallFunctionC((void *)&Memory::Read_U64, address); break;
|
||||
case 32: ABI_CallFunctionC((void *)&Memory::Read_U32, address); break;
|
||||
case 16: ABI_CallFunctionC((void *)&Memory::Read_U16_ZX, address); break;
|
||||
case 8: ABI_CallFunctionC((void *)&Memory::Read_U8_ZX, address); break;
|
||||
case 64: ABI_CallFunctionC((void *)&PowerPC::Read_U64, address); break;
|
||||
case 32: ABI_CallFunctionC((void *)&PowerPC::Read_U32, address); break;
|
||||
case 16: ABI_CallFunctionC((void *)&PowerPC::Read_U16_ZX, address); break;
|
||||
case 8: ABI_CallFunctionC((void *)&PowerPC::Read_U8_ZX, address); break;
|
||||
}
|
||||
ABI_PopRegistersAndAdjustStack(registersInUse, 0);
|
||||
|
||||
|
@ -366,16 +366,16 @@ void EmuCodeBlock::SafeLoadToReg(X64Reg reg_value, const Gen::OpArg & opAddress,
|
|||
switch (accessSize)
|
||||
{
|
||||
case 64:
|
||||
ABI_CallFunctionR((void *)&Memory::Read_U64, reg_addr);
|
||||
ABI_CallFunctionR((void *)&PowerPC::Read_U64, reg_addr);
|
||||
break;
|
||||
case 32:
|
||||
ABI_CallFunctionR((void *)&Memory::Read_U32, reg_addr);
|
||||
ABI_CallFunctionR((void *)&PowerPC::Read_U32, reg_addr);
|
||||
break;
|
||||
case 16:
|
||||
ABI_CallFunctionR((void *)&Memory::Read_U16_ZX, reg_addr);
|
||||
ABI_CallFunctionR((void *)&PowerPC::Read_U16_ZX, reg_addr);
|
||||
break;
|
||||
case 8:
|
||||
ABI_CallFunctionR((void *)&Memory::Read_U8_ZX, reg_addr);
|
||||
ABI_CallFunctionR((void *)&PowerPC::Read_U8_ZX, reg_addr);
|
||||
break;
|
||||
}
|
||||
ABI_PopRegistersAndAdjustStack(registersInUse, rsp_alignment);
|
||||
|
@ -490,7 +490,7 @@ bool EmuCodeBlock::WriteToConstAddress(int accessSize, OpArg arg, u32 address, B
|
|||
UnsafeWriteGatherPipe(accessSize);
|
||||
return false;
|
||||
}
|
||||
else if (Memory::IsRAMAddress(address))
|
||||
else if (PowerPC::IsOptimizableRAMAddress(address))
|
||||
{
|
||||
WriteToConstRamAddress(accessSize, arg, address);
|
||||
return false;
|
||||
|
@ -504,16 +504,16 @@ bool EmuCodeBlock::WriteToConstAddress(int accessSize, OpArg arg, u32 address, B
|
|||
switch (accessSize)
|
||||
{
|
||||
case 64:
|
||||
ABI_CallFunctionAC(64, (void *)&Memory::Write_U64, arg, address);
|
||||
ABI_CallFunctionAC(64, (void *)&PowerPC::Write_U64, arg, address);
|
||||
break;
|
||||
case 32:
|
||||
ABI_CallFunctionAC(32, (void *)&Memory::Write_U32, arg, address);
|
||||
ABI_CallFunctionAC(32, (void *)&PowerPC::Write_U32, arg, address);
|
||||
break;
|
||||
case 16:
|
||||
ABI_CallFunctionAC(16, (void *)&Memory::Write_U16, arg, address);
|
||||
ABI_CallFunctionAC(16, (void *)&PowerPC::Write_U16, arg, address);
|
||||
break;
|
||||
case 8:
|
||||
ABI_CallFunctionAC(8, (void *)&Memory::Write_U8, arg, address);
|
||||
ABI_CallFunctionAC(8, (void *)&PowerPC::Write_U8, arg, address);
|
||||
break;
|
||||
}
|
||||
ABI_PopRegistersAndAdjustStack(registersInUse, 0);
|
||||
|
@ -599,16 +599,16 @@ void EmuCodeBlock::SafeWriteRegToReg(OpArg reg_value, X64Reg reg_addr, int acces
|
|||
switch (accessSize)
|
||||
{
|
||||
case 64:
|
||||
ABI_CallFunctionRR(swap ? ((void *)&Memory::Write_U64) : ((void *)&Memory::Write_U64_Swap), reg, reg_addr);
|
||||
ABI_CallFunctionRR(swap ? ((void *)&PowerPC::Write_U64) : ((void *)&PowerPC::Write_U64_Swap), reg, reg_addr);
|
||||
break;
|
||||
case 32:
|
||||
ABI_CallFunctionRR(swap ? ((void *)&Memory::Write_U32) : ((void *)&Memory::Write_U32_Swap), reg, reg_addr);
|
||||
ABI_CallFunctionRR(swap ? ((void *)&PowerPC::Write_U32) : ((void *)&PowerPC::Write_U32_Swap), reg, reg_addr);
|
||||
break;
|
||||
case 16:
|
||||
ABI_CallFunctionRR(swap ? ((void *)&Memory::Write_U16) : ((void *)&Memory::Write_U16_Swap), reg, reg_addr);
|
||||
ABI_CallFunctionRR(swap ? ((void *)&PowerPC::Write_U16) : ((void *)&PowerPC::Write_U16_Swap), reg, reg_addr);
|
||||
break;
|
||||
case 8:
|
||||
ABI_CallFunctionRR((void *)&Memory::Write_U8, reg, reg_addr);
|
||||
ABI_CallFunctionRR((void *)&PowerPC::Write_U8, reg, reg_addr);
|
||||
break;
|
||||
}
|
||||
ABI_PopRegistersAndAdjustStack(registersInUse, rsp_alignment);
|
||||
|
@ -626,7 +626,8 @@ void EmuCodeBlock::WriteToConstRamAddress(int accessSize, OpArg arg, u32 address
|
|||
if (arg.IsImm())
|
||||
{
|
||||
arg = SwapImmediate(accessSize, arg);
|
||||
MOV(accessSize, MDisp(RMEM, address & 0x3FFFFFFF), arg);
|
||||
MOV(32, R(RSCRATCH), Imm32(address));
|
||||
MOV(accessSize, MRegSum(RMEM, RSCRATCH), arg);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -640,10 +641,11 @@ void EmuCodeBlock::WriteToConstRamAddress(int accessSize, OpArg arg, u32 address
|
|||
reg = arg.GetSimpleReg();
|
||||
}
|
||||
|
||||
MOV(32, R(RSCRATCH2), Imm32(address));
|
||||
if (swap)
|
||||
SwapAndStore(accessSize, MDisp(RMEM, address & 0x3FFFFFFF), reg);
|
||||
SwapAndStore(accessSize, MRegSum(RMEM, RSCRATCH2), reg);
|
||||
else
|
||||
MOV(accessSize, MDisp(RMEM, address & 0x3FFFFFFF), R(reg));
|
||||
MOV(accessSize, MRegSum(RMEM, RSCRATCH2), R(reg));
|
||||
}
|
||||
|
||||
void EmuCodeBlock::ForceSinglePrecisionS(X64Reg output, X64Reg input)
|
||||
|
|
|
@ -66,16 +66,16 @@ const u8* TrampolineCache::GenerateReadTrampoline(const InstructionInfo &info, B
|
|||
switch (info.operandSize)
|
||||
{
|
||||
case 8:
|
||||
CALL((void *)&Memory::Read_U64);
|
||||
CALL((void*)&PowerPC::Read_U64);
|
||||
break;
|
||||
case 4:
|
||||
CALL((void *)&Memory::Read_U32);
|
||||
CALL((void*)&PowerPC::Read_U32);
|
||||
break;
|
||||
case 2:
|
||||
CALL((void *)&Memory::Read_U16);
|
||||
CALL((void*)&PowerPC::Read_U16);
|
||||
break;
|
||||
case 1:
|
||||
CALL((void *)&Memory::Read_U8);
|
||||
CALL((void*)&PowerPC::Read_U8);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -154,16 +154,16 @@ const u8* TrampolineCache::GenerateWriteTrampoline(const InstructionInfo &info,
|
|||
switch (info.operandSize)
|
||||
{
|
||||
case 8:
|
||||
CALL((void *)&Memory::Write_U64);
|
||||
CALL((void *)&PowerPC::Write_U64);
|
||||
break;
|
||||
case 4:
|
||||
CALL((void *)&Memory::Write_U32);
|
||||
CALL((void *)&PowerPC::Write_U32);
|
||||
break;
|
||||
case 2:
|
||||
CALL((void *)&Memory::Write_U16);
|
||||
CALL((void *)&PowerPC::Write_U16);
|
||||
break;
|
||||
case 1:
|
||||
CALL((void *)&Memory::Write_U8);
|
||||
CALL((void *)&PowerPC::Write_U8);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -142,11 +142,12 @@ void JitILBase::bcx(UGeckoInstruction inst)
|
|||
// The main Idle skipping is done in the LoadStore code, but there is an optimization here.
|
||||
// If idle skipping is enabled, then this branch will only be reached when the branch is not
|
||||
// taken.
|
||||
// TODO: We shouldn't use debug reads here.
|
||||
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bSkipIdle &&
|
||||
inst.hex == 0x4182fff8 &&
|
||||
(Memory::ReadUnchecked_U32(js.compilerPC - 8) & 0xFFFF0000) == 0x800D0000 &&
|
||||
(Memory::ReadUnchecked_U32(js.compilerPC - 4) == 0x28000000 ||
|
||||
(SConfig::GetInstance().m_LocalCoreStartupParameter.bWii && Memory::ReadUnchecked_U32(js.compilerPC - 4) == 0x2C000000))
|
||||
(PowerPC::HostRead_U32(js.compilerPC - 8) & 0xFFFF0000) == 0x800D0000 &&
|
||||
(PowerPC::HostRead_U32(js.compilerPC - 4) == 0x28000000 ||
|
||||
(SConfig::GetInstance().m_LocalCoreStartupParameter.bWii && PowerPC::HostRead_U32(js.compilerPC - 4) == 0x2C000000))
|
||||
)
|
||||
{
|
||||
// Uh, Do nothing.
|
||||
|
|
|
@ -34,15 +34,17 @@ void JitILBase::lXz(UGeckoInstruction inst)
|
|||
|
||||
IREmitter::InstLoc val;
|
||||
|
||||
// Idle Skipping. This really should be done somewhere else.
|
||||
// Either lower in the IR or higher in PPCAnalyist
|
||||
// Idle Skipping.
|
||||
// TODO: This really should be done somewhere else. Either lower in the IR
|
||||
// or higher in PPCAnalyst
|
||||
// TODO: We shouldn't use debug reads here.
|
||||
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bSkipIdle &&
|
||||
PowerPC::GetState() != PowerPC::CPU_STEPPING &&
|
||||
inst.OPCD == 32 && // Lwx
|
||||
(inst.hex & 0xFFFF0000) == 0x800D0000 &&
|
||||
(Memory::ReadUnchecked_U32(js.compilerPC + 4) == 0x28000000 ||
|
||||
(SConfig::GetInstance().m_LocalCoreStartupParameter.bWii && Memory::ReadUnchecked_U32(js.compilerPC + 4) == 0x2C000000)) &&
|
||||
Memory::ReadUnchecked_U32(js.compilerPC + 8) == 0x4182fff8)
|
||||
(PowerPC::HostRead_U32(js.compilerPC + 4) == 0x28000000 ||
|
||||
(SConfig::GetInstance().m_LocalCoreStartupParameter.bWii && PowerPC::HostRead_U32(js.compilerPC + 4) == 0x2C000000)) &&
|
||||
PowerPC::HostRead_U32(js.compilerPC + 8) == 0x4182fff8)
|
||||
{
|
||||
val = ibuild.EmitLoad32(addr);
|
||||
ibuild.EmitIdleBranch(val, ibuild.EmitIntConst(js.compilerPC));
|
||||
|
@ -138,7 +140,9 @@ void JitILBase::dcbst(UGeckoInstruction inst)
|
|||
// memory location. Do not invalidate the JIT cache in this case as the memory
|
||||
// will be the same.
|
||||
// dcbt = 0x7c00022c
|
||||
FALLBACK_IF((Memory::ReadUnchecked_U32(js.compilerPC - 4) & 0x7c00022c) != 0x7c00022c);
|
||||
// TODO: We shouldn't use a debug read here; it should be possible to get the
|
||||
// previous instruction from the JIT state.
|
||||
FALLBACK_IF((PowerPC::HostRead_U32(js.compilerPC - 4) & 0x7c00022c) != 0x7c00022c);
|
||||
}
|
||||
|
||||
// Zero cache line.
|
||||
|
|
|
@ -207,27 +207,6 @@ namespace JitInterface
|
|||
jit->GetBlockCache()->InvalidateICache(address, size, forced);
|
||||
}
|
||||
|
||||
u32 ReadOpcodeJIT(u32 _Address)
|
||||
{
|
||||
if (bMMU && !bFakeVMEM && (_Address & Memory::ADDR_MASK_MEM1))
|
||||
{
|
||||
_Address = Memory::TranslateAddress<Memory::FLAG_OPCODE>(_Address);
|
||||
if (_Address == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
u32 inst;
|
||||
// Bypass the icache for the external interrupt exception handler
|
||||
// -- this is stupid, should respect HID0
|
||||
if ( (_Address & 0x0FFFFF00) == 0x00000500 )
|
||||
inst = Memory::ReadUnchecked_U32(_Address);
|
||||
else
|
||||
inst = PowerPC::ppcState.iCache.ReadInstruction(_Address);
|
||||
return inst;
|
||||
}
|
||||
|
||||
void CompileExceptionCheck(ExceptionType type)
|
||||
{
|
||||
if (!jit)
|
||||
|
@ -250,7 +229,7 @@ namespace JitInterface
|
|||
if (type == ExceptionType::EXCEPTIONS_FIFO_WRITE)
|
||||
{
|
||||
// Check in case the code has been replaced since: do we need to do this?
|
||||
int optype = GetOpInfo(Memory::ReadUnchecked_U32(PC))->type;
|
||||
int optype = GetOpInfo(PowerPC::HostRead_U32(PC))->type;
|
||||
if (optype != OPTYPE_STORE && optype != OPTYPE_STOREFP && (optype != OPTYPE_STOREPS))
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -29,9 +29,6 @@ namespace JitInterface
|
|||
// Memory Utilities
|
||||
bool HandleFault(uintptr_t access_address, SContext* ctx);
|
||||
|
||||
// used by JIT to read instructions
|
||||
u32 ReadOpcodeJIT(const u32 _Address);
|
||||
|
||||
// Clearing CodeCache
|
||||
void ClearCache();
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
#include "Core/PowerPC/GDBStub.h"
|
||||
#endif
|
||||
|
||||
namespace Memory
|
||||
namespace PowerPC
|
||||
{
|
||||
|
||||
#define HW_PAGE_SIZE 4096
|
||||
|
@ -66,6 +66,14 @@ inline u32 bswap(u32 val) { return Common::swap32(val); }
|
|||
inline u64 bswap(u64 val) { return Common::swap64(val); }
|
||||
// =================
|
||||
|
||||
enum XCheckTLBFlag
|
||||
{
|
||||
FLAG_NO_EXCEPTION,
|
||||
FLAG_READ,
|
||||
FLAG_WRITE,
|
||||
FLAG_OPCODE,
|
||||
};
|
||||
template <const XCheckTLBFlag flag> static u32 TranslateAddress(const u32 address);
|
||||
|
||||
// Nasty but necessary. Super Mario Galaxy pointer relies on this stuff.
|
||||
static u32 EFB_Read(const u32 addr)
|
||||
|
@ -111,39 +119,62 @@ static void EFB_Write(u32 data, u32 addr)
|
|||
static void GenerateDSIException(u32 _EffectiveAddress, bool _bWrite);
|
||||
|
||||
template <XCheckTLBFlag flag, typename T>
|
||||
__forceinline T ReadFromHardware(const u32 em_address)
|
||||
__forceinline static T ReadFromHardware(const u32 em_address)
|
||||
{
|
||||
int segment = em_address >> 28;
|
||||
bool performTranslation = UReg_MSR(MSR).DR;
|
||||
|
||||
// Quick check for an address that can't meet any of the following conditions,
|
||||
// to speed up the MMU path.
|
||||
if (!BitSet32(0xCFC)[segment])
|
||||
if (!BitSet32(0xCFC)[segment] && performTranslation)
|
||||
{
|
||||
// TODO: Figure out the fastest order of tests for both read and write (they are probably different).
|
||||
if ((em_address & 0xC8000000) == 0xC8000000)
|
||||
if (flag == FLAG_READ && (em_address & 0xF8000000) == 0xC8000000)
|
||||
{
|
||||
if (em_address < 0xcc000000)
|
||||
return EFB_Read(em_address);
|
||||
else
|
||||
return (T)mmio_mapping->Read<typename std::make_unsigned<T>::type>(em_address);
|
||||
return (T)Memory::mmio_mapping->Read<typename std::make_unsigned<T>::type>(em_address);
|
||||
}
|
||||
else if (segment == 0x8 || segment == 0xC || segment == 0x0)
|
||||
if ((segment == 0x0 || segment == 0x8 || segment == 0xC) && (em_address & 0x0FFFFFFF) < Memory::REALRAM_SIZE)
|
||||
{
|
||||
return bswap((*(const T*)&m_pRAM[em_address & RAM_MASK]));
|
||||
return bswap((*(const T*)&Memory::m_pRAM[em_address & 0x0FFFFFFF]));
|
||||
}
|
||||
else if (m_pEXRAM && (segment == 0x9 || segment == 0xD || segment == 0x1))
|
||||
if (Memory::m_pEXRAM && (segment == 0x9 || segment == 0xD) && (em_address & 0x0FFFFFFF) < Memory::EXRAM_SIZE)
|
||||
{
|
||||
return bswap((*(const T*)&m_pEXRAM[em_address & EXRAM_MASK]));
|
||||
return bswap((*(const T*)&Memory::m_pEXRAM[em_address & 0x0FFFFFFF]));
|
||||
}
|
||||
else if (segment == 0xE && (em_address < (0xE0000000 + L1_CACHE_SIZE)))
|
||||
if (segment == 0xE && (em_address < (0xE0000000 + Memory::L1_CACHE_SIZE)))
|
||||
{
|
||||
return bswap((*(const T*)&m_pL1Cache[em_address & L1_CACHE_MASK]));
|
||||
return bswap((*(const T*)&Memory::m_pL1Cache[em_address & 0x0FFFFFFF]));
|
||||
}
|
||||
}
|
||||
|
||||
if (bFakeVMEM && (segment == 0x7 || segment == 0x4))
|
||||
if (Memory::bFakeVMEM && performTranslation && (segment == 0x7 || segment == 0x4))
|
||||
{
|
||||
// fake VMEM
|
||||
return bswap((*(const T*)&m_pFakeVMEM[em_address & FAKEVMEM_MASK]));
|
||||
return bswap((*(const T*)&Memory::m_pFakeVMEM[em_address & Memory::FAKEVMEM_MASK]));
|
||||
}
|
||||
|
||||
if (!performTranslation)
|
||||
{
|
||||
if (flag == FLAG_READ && (em_address & 0xF8000000) == 0x08000000)
|
||||
{
|
||||
if (em_address < 0x0c000000)
|
||||
return EFB_Read(em_address);
|
||||
else
|
||||
return (T)Memory::mmio_mapping->Read<typename std::make_unsigned<T>::type>(em_address | 0xC0000000);
|
||||
}
|
||||
if (em_address < Memory::REALRAM_SIZE)
|
||||
{
|
||||
return bswap((*(const T*)&Memory::m_pRAM[em_address]));
|
||||
}
|
||||
if (Memory::m_pEXRAM && segment == 0x1 && (em_address & 0x0FFFFFFF) < Memory::EXRAM_SIZE)
|
||||
{
|
||||
return bswap((*(const T*)&Memory::m_pEXRAM[em_address & 0x0FFFFFFF]));
|
||||
}
|
||||
PanicAlert("Unable to resolve read address %x PC %x", em_address, PC);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// MMU: Do page table translation
|
||||
|
@ -177,27 +208,29 @@ __forceinline T ReadFromHardware(const u32 em_address)
|
|||
{
|
||||
if (addr == em_address_next_page)
|
||||
tlb_addr = tlb_addr_next_page;
|
||||
var = (var << 8) | Memory::base[tlb_addr];
|
||||
var = (var << 8) | Memory::physical_base[tlb_addr];
|
||||
}
|
||||
return var;
|
||||
}
|
||||
|
||||
// The easy case!
|
||||
return bswap(*(const T*)&Memory::base[tlb_addr]);
|
||||
return bswap(*(const T*)&Memory::physical_base[tlb_addr]);
|
||||
}
|
||||
|
||||
|
||||
template <XCheckTLBFlag flag, typename T>
|
||||
__forceinline void WriteToHardware(u32 em_address, const T data)
|
||||
__forceinline static void WriteToHardware(u32 em_address, const T data)
|
||||
{
|
||||
int segment = em_address >> 28;
|
||||
// Quick check for an address that can't meet any of the following conditions,
|
||||
// to speed up the MMU path.
|
||||
if (!BitSet32(0xCFC)[segment])
|
||||
bool performTranslation = UReg_MSR(MSR).DR;
|
||||
|
||||
if (!BitSet32(0xCFC)[segment] && performTranslation)
|
||||
{
|
||||
// First, let's check for FIFO writes, since they are probably the most common
|
||||
// reason we end up in this function:
|
||||
if ((em_address & 0xFFFFF000) == 0xCC008000)
|
||||
if (flag == FLAG_WRITE && (em_address & 0xFFFFF000) == 0xCC008000)
|
||||
{
|
||||
switch (sizeof(T))
|
||||
{
|
||||
|
@ -207,7 +240,7 @@ __forceinline void WriteToHardware(u32 em_address, const T data)
|
|||
case 8: GPFifo::Write64((u64)data, em_address); return;
|
||||
}
|
||||
}
|
||||
if ((em_address & 0xC8000000) == 0xC8000000)
|
||||
if (flag == FLAG_WRITE && (em_address & 0xF8000000) == 0xC8000000)
|
||||
{
|
||||
if (em_address < 0xcc000000)
|
||||
{
|
||||
|
@ -217,31 +250,71 @@ __forceinline void WriteToHardware(u32 em_address, const T data)
|
|||
}
|
||||
else
|
||||
{
|
||||
mmio_mapping->Write(em_address, data);
|
||||
Memory::mmio_mapping->Write(em_address, data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (segment == 0x8 || segment == 0xC || segment == 0x0)
|
||||
if ((segment == 0x8 || segment == 0xC) && (em_address & 0x0FFFFFFF) < Memory::REALRAM_SIZE)
|
||||
{
|
||||
*(T*)&m_pRAM[em_address & RAM_MASK] = bswap(data);
|
||||
*(T*)&Memory::m_pRAM[em_address & 0x0FFFFFFF] = bswap(data);
|
||||
return;
|
||||
}
|
||||
else if (m_pEXRAM && (segment == 0x9 || segment == 0xD || segment == 0x1))
|
||||
if (Memory::m_pEXRAM && (segment == 0x9 || segment == 0xD) && (em_address & 0x0FFFFFFF) < Memory::EXRAM_SIZE)
|
||||
{
|
||||
*(T*)&m_pEXRAM[em_address & EXRAM_MASK] = bswap(data);
|
||||
*(T*)&Memory::m_pEXRAM[em_address & 0x0FFFFFFF] = bswap(data);
|
||||
return;
|
||||
}
|
||||
else if (segment == 0xE && (em_address < (0xE0000000 + L1_CACHE_SIZE)))
|
||||
if (segment == 0xE && (em_address < (0xE0000000 + Memory::L1_CACHE_SIZE)))
|
||||
{
|
||||
*(T*)&m_pL1Cache[em_address & L1_CACHE_MASK] = bswap(data);
|
||||
*(T*)&Memory::m_pL1Cache[em_address & 0x0FFFFFFF] = bswap(data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (bFakeVMEM && (segment == 0x7 || segment == 0x4))
|
||||
if (Memory::bFakeVMEM && performTranslation && (segment == 0x7 || segment == 0x4))
|
||||
{
|
||||
// fake VMEM
|
||||
*(T*)&m_pFakeVMEM[em_address & FAKEVMEM_MASK] = bswap(data);
|
||||
*(T*)&Memory::m_pFakeVMEM[em_address & Memory::FAKEVMEM_MASK] = bswap(data);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!performTranslation)
|
||||
{
|
||||
if (flag == FLAG_WRITE && (em_address & 0xFFFFF000) == 0x0C008000)
|
||||
{
|
||||
switch (sizeof(T))
|
||||
{
|
||||
case 1: GPFifo::Write8((u8)data, em_address); return;
|
||||
case 2: GPFifo::Write16((u16)data, em_address); return;
|
||||
case 4: GPFifo::Write32((u32)data, em_address); return;
|
||||
case 8: GPFifo::Write64((u64)data, em_address); return;
|
||||
}
|
||||
}
|
||||
if (flag == FLAG_WRITE && (em_address & 0xF8000000) == 0x08000000)
|
||||
{
|
||||
if (em_address < 0x0c000000)
|
||||
{
|
||||
// TODO: This only works correctly for 32-bit writes.
|
||||
EFB_Write((u32)data, em_address);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
Memory::mmio_mapping->Write(em_address | 0xC0000000, data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (em_address < Memory::REALRAM_SIZE)
|
||||
{
|
||||
*(T*)&Memory::m_pRAM[em_address] = bswap(data);
|
||||
return;
|
||||
}
|
||||
if (Memory::m_pEXRAM && segment == 0x1 && (em_address & 0x0FFFFFFF) < Memory::EXRAM_SIZE)
|
||||
{
|
||||
*(T*)&Memory::m_pEXRAM[em_address & 0x0FFFFFFF] = bswap(data);
|
||||
return;
|
||||
}
|
||||
PanicAlert("Unable to resolve write address %x PC %x", em_address, PC);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -272,13 +345,13 @@ __forceinline void WriteToHardware(u32 em_address, const T data)
|
|||
{
|
||||
if (addr == em_address_next_page)
|
||||
tlb_addr = tlb_addr_next_page;
|
||||
Memory::base[tlb_addr] = (u8)val;
|
||||
Memory::physical_base[tlb_addr] = (u8)val;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// The easy case!
|
||||
*(T*)&Memory::base[tlb_addr] = bswap(data);
|
||||
*(T*)&Memory::physical_base[tlb_addr] = bswap(data);
|
||||
}
|
||||
// =====================
|
||||
|
||||
|
@ -292,30 +365,59 @@ static void GenerateISIException(u32 effective_address);
|
|||
|
||||
u32 Read_Opcode(u32 address)
|
||||
{
|
||||
if (address == 0x00000000)
|
||||
TryReadInstResult result = TryReadInstruction(address);
|
||||
if (!result.valid)
|
||||
{
|
||||
// FIXME use assert?
|
||||
PanicAlert("Program tried to read an opcode from [00000000]. It has crashed.");
|
||||
return 0x00000000;
|
||||
GenerateISIException(address);
|
||||
return 0;
|
||||
}
|
||||
return result.hex;
|
||||
}
|
||||
|
||||
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bMMU &&
|
||||
(address & ADDR_MASK_MEM1))
|
||||
TryReadInstResult TryReadInstruction(u32 address)
|
||||
{
|
||||
bool from_bat = true;
|
||||
if (UReg_MSR(MSR).IR)
|
||||
{
|
||||
// TODO: Check for MSR instruction address translation flag before translating
|
||||
u32 tlb_addr = TranslateAddress<FLAG_OPCODE>(address);
|
||||
if (tlb_addr == 0)
|
||||
// TODO: Use real translation.
|
||||
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bMMU && (address & Memory::ADDR_MASK_MEM1))
|
||||
{
|
||||
GenerateISIException(address);
|
||||
return 0;
|
||||
u32 tlb_addr = TranslateAddress<FLAG_OPCODE>(address);
|
||||
if (tlb_addr == 0)
|
||||
{
|
||||
return TryReadInstResult{ false, false, 0 };
|
||||
}
|
||||
else
|
||||
{
|
||||
address = tlb_addr;
|
||||
from_bat = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
address = tlb_addr;
|
||||
int segment = address >> 28;
|
||||
if ((segment == 0x8 || segment == 0x0) && (address & 0x0FFFFFFF) < Memory::REALRAM_SIZE)
|
||||
address = address & 0x3FFFFFFF;
|
||||
else if (segment == 0x9 && (address & 0x0FFFFFFF) < Memory::EXRAM_SIZE)
|
||||
address = address & 0x3FFFFFFF;
|
||||
else
|
||||
return TryReadInstResult{ false, false, 0 };
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (address & 0xC0000000)
|
||||
ERROR_LOG(MEMMAP, "Strange program counter with address translation off: 0x%08x", address);
|
||||
}
|
||||
|
||||
return PowerPC::ppcState.iCache.ReadInstruction(address);
|
||||
u32 hex = PowerPC::ppcState.iCache.ReadInstruction(address);
|
||||
return TryReadInstResult{ true, from_bat, hex };
|
||||
}
|
||||
|
||||
u32 HostRead_Instruction(const u32 address)
|
||||
{
|
||||
UGeckoInstruction inst = HostRead_U32(address);
|
||||
return inst.hex;
|
||||
}
|
||||
|
||||
static __forceinline void Memcheck(u32 address, u32 var, bool write, int size)
|
||||
|
@ -442,30 +544,103 @@ void Write_F64(const double var, const u32 address)
|
|||
cvt.d = var;
|
||||
Write_U64(cvt.i, address);
|
||||
}
|
||||
u8 ReadUnchecked_U8(const u32 address)
|
||||
|
||||
u8 HostRead_U8(const u32 address)
|
||||
{
|
||||
u8 var = ReadFromHardware<FLAG_NO_EXCEPTION, u8>(address);
|
||||
return var;
|
||||
}
|
||||
|
||||
u16 HostRead_U16(const u32 address)
|
||||
{
|
||||
u16 var = ReadFromHardware<FLAG_NO_EXCEPTION, u16>(address);
|
||||
return var;
|
||||
}
|
||||
|
||||
u32 ReadUnchecked_U32(const u32 address)
|
||||
u32 HostRead_U32(const u32 address)
|
||||
{
|
||||
u32 var = ReadFromHardware<FLAG_NO_EXCEPTION, u32>(address);
|
||||
return var;
|
||||
}
|
||||
|
||||
void WriteUnchecked_U8(const u8 var, const u32 address)
|
||||
void HostWrite_U8(const u8 var, const u32 address)
|
||||
{
|
||||
WriteToHardware<FLAG_NO_EXCEPTION, u8>(address, var);
|
||||
}
|
||||
|
||||
void HostWrite_U16(const u16 var, const u32 address)
|
||||
{
|
||||
WriteToHardware<FLAG_NO_EXCEPTION, u16>(address, var);
|
||||
}
|
||||
|
||||
void WriteUnchecked_U32(const u32 var, const u32 address)
|
||||
void HostWrite_U32(const u32 var, const u32 address)
|
||||
{
|
||||
WriteToHardware<FLAG_NO_EXCEPTION, u32>(address, var);
|
||||
}
|
||||
|
||||
void HostWrite_U64(const u64 var, const u32 address)
|
||||
{
|
||||
WriteToHardware<FLAG_NO_EXCEPTION, u64>(address, var);
|
||||
}
|
||||
|
||||
std::string HostGetString(u32 address, size_t size)
|
||||
{
|
||||
std::string s;
|
||||
do
|
||||
{
|
||||
if (!HostIsRAMAddress(address))
|
||||
break;
|
||||
u8 res = HostRead_U8(address);
|
||||
if (!res)
|
||||
break;
|
||||
++address;
|
||||
} while (size == 0 || s.length() < size);
|
||||
return s;
|
||||
}
|
||||
|
||||
bool IsOptimizableRAMAddress(const u32 address)
|
||||
{
|
||||
if (!UReg_MSR(MSR).DR)
|
||||
return false;
|
||||
|
||||
int segment = address >> 28;
|
||||
|
||||
return (((segment == 0x8 || segment == 0xC || segment == 0x0) && (address & 0x0FFFFFFF) < Memory::REALRAM_SIZE) ||
|
||||
(Memory::m_pEXRAM && (segment == 0x9 || segment == 0xD) && (address & 0x0FFFFFFF) < Memory::EXRAM_SIZE) ||
|
||||
(segment == 0xE && (address < (0xE0000000 + Memory::L1_CACHE_SIZE))));
|
||||
}
|
||||
|
||||
bool HostIsRAMAddress(u32 address)
|
||||
{
|
||||
// TODO: This needs to be rewritten; it makes incorrect assumptions
|
||||
// about BATs and page tables.
|
||||
bool performTranslation = UReg_MSR(MSR).DR;
|
||||
int segment = address >> 28;
|
||||
if (performTranslation)
|
||||
{
|
||||
if ((segment == 0x8 || segment == 0xC || segment == 0x0) && (address & 0x0FFFFFFF) < Memory::REALRAM_SIZE)
|
||||
return true;
|
||||
else if (Memory::m_pEXRAM && (segment == 0x9 || segment == 0xD) && (address & 0x0FFFFFFF) < Memory::EXRAM_SIZE)
|
||||
return true;
|
||||
else if (Memory::bFakeVMEM && (segment == 0x7 || segment == 0x4))
|
||||
return true;
|
||||
else if (segment == 0xE && (address < (0xE0000000 + Memory::L1_CACHE_SIZE)))
|
||||
return true;
|
||||
|
||||
address = TranslateAddress<FLAG_NO_EXCEPTION>(address);
|
||||
if (!address)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (segment == 0x0 && (address & 0x0FFFFFFF) < Memory::REALRAM_SIZE)
|
||||
return true;
|
||||
else if (Memory::m_pEXRAM && segment == 0x1 && (address & 0x0FFFFFFF) < Memory::EXRAM_SIZE)
|
||||
return true;
|
||||
return false;
|
||||
|
||||
|
||||
}
|
||||
|
||||
void DMA_LCToMemory(const u32 memAddr, const u32 cacheAddr, const u32 numBlocks)
|
||||
{
|
||||
// TODO: It's not completely clear this is the right spot for this code;
|
||||
|
@ -475,7 +650,7 @@ void DMA_LCToMemory(const u32 memAddr, const u32 cacheAddr, const u32 numBlocks)
|
|||
// Avatar: The Last Airbender (GC) uses this for videos.
|
||||
if ((memAddr & 0x0F000000) == 0x08000000)
|
||||
{
|
||||
for (u32 i = 0; i < 32 * numBlocks; i+=4)
|
||||
for (u32 i = 0; i < 32 * numBlocks; i += 4)
|
||||
{
|
||||
u32 data = bswap(*(u32*)(Memory::m_pL1Cache + ((cacheAddr + i) & 0x3FFFF)));
|
||||
EFB_Write(data, memAddr + i);
|
||||
|
@ -490,7 +665,7 @@ void DMA_LCToMemory(const u32 memAddr, const u32 cacheAddr, const u32 numBlocks)
|
|||
for (u32 i = 0; i < 32 * numBlocks; i += 4)
|
||||
{
|
||||
u32 data = bswap(*(u32*)(Memory::m_pL1Cache + ((cacheAddr + i) & 0x3FFFF)));
|
||||
mmio_mapping->Write(memAddr + i, data);
|
||||
Memory::mmio_mapping->Write(memAddr + i, data);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -526,7 +701,7 @@ void DMA_MemoryToLC(const u32 cacheAddr, const u32 memAddr, const u32 numBlocks)
|
|||
{
|
||||
for (u32 i = 0; i < 32 * numBlocks; i += 4)
|
||||
{
|
||||
u32 data = mmio_mapping->Read<u32>(memAddr + i);
|
||||
u32 data = Memory::mmio_mapping->Read<u32>(memAddr + i);
|
||||
*(u32*)(Memory::m_pL1Cache + ((cacheAddr + i) & 0x3FFFF)) = bswap(data);
|
||||
}
|
||||
return;
|
||||
|
@ -538,6 +713,14 @@ void DMA_MemoryToLC(const u32 cacheAddr, const u32 memAddr, const u32 numBlocks)
|
|||
memcpy(dst, src, 32 * numBlocks);
|
||||
}
|
||||
|
||||
void ClearCacheLine(const u32 address)
|
||||
{
|
||||
// FIXME: does this do the right thing if dcbz is run on hardware memory, e.g.
|
||||
// the FIFO? Do games even do that? Probably not, but we should try to be correct...
|
||||
for (u32 i = 0; i < 32; i += 8)
|
||||
Write_U64(0, address + i);
|
||||
}
|
||||
|
||||
// *********************************************************************************
|
||||
// Warning: Test Area
|
||||
//
|
||||
|
@ -785,10 +968,6 @@ static __forceinline u32 TranslatePageAddress(const u32 address, const XCheckTLB
|
|||
u32 VSID = SR_VSID(sr); // 24 bit
|
||||
u32 api = EA_API(address); // 6 bit (part of page_index)
|
||||
|
||||
// Direct access to the fastmem Arena
|
||||
// FIXME: is this the best idea for clean code?
|
||||
u8* base_mem = Memory::base;
|
||||
|
||||
// hash function no 1 "xor" .360
|
||||
u32 hash = (VSID ^ page_index);
|
||||
u32 pte1 = bswap((VSID << 7) | api | PTE1_V);
|
||||
|
@ -806,10 +985,10 @@ static __forceinline u32 TranslatePageAddress(const u32 address, const XCheckTLB
|
|||
|
||||
for (int i = 0; i < 8; i++, pteg_addr += 8)
|
||||
{
|
||||
if (pte1 == *(u32*)&base_mem[pteg_addr])
|
||||
if (pte1 == *(u32*)&Memory::physical_base[pteg_addr])
|
||||
{
|
||||
UPTE2 PTE2;
|
||||
PTE2.Hex = bswap((*(u32*)&base_mem[(pteg_addr + 4)]));
|
||||
PTE2.Hex = bswap((*(u32*)&Memory::physical_base[pteg_addr + 4]));
|
||||
|
||||
// set the access bits
|
||||
switch (flag)
|
||||
|
@ -821,7 +1000,7 @@ static __forceinline u32 TranslatePageAddress(const u32 address, const XCheckTLB
|
|||
}
|
||||
|
||||
if (flag != FLAG_NO_EXCEPTION)
|
||||
*(u32*)&base_mem[(pteg_addr + 4)] = bswap(PTE2.Hex);
|
||||
*(u32*)&Memory::physical_base[pteg_addr + 4] = bswap(PTE2.Hex);
|
||||
|
||||
// We already updated the TLB entry if this was caused by a C bit.
|
||||
if (res != TLB_UPDATE_C)
|
||||
|
@ -895,16 +1074,12 @@ static u32 TranslateBlockAddress(const u32 address, const XCheckTLBFlag flag)
|
|||
|
||||
// Translate effective address using BAT or PAT. Returns 0 if the address cannot be translated.
|
||||
template <const XCheckTLBFlag flag>
|
||||
u32 TranslateAddress(const u32 address)
|
||||
__forceinline u32 TranslateAddress(const u32 address)
|
||||
{
|
||||
// Check MSR[IR] bit before translating instruction addresses. Rogue Leader clears IR and DR??
|
||||
//if ((_Flag == FLAG_OPCODE) && !(MSR & (1 << (31 - 26)))) return _Address;
|
||||
|
||||
// Check MSR[DR] bit before translating data addresses
|
||||
//if (((_Flag == FLAG_READ) || (_Flag == FLAG_WRITE)) && !(MSR & (1 << (31 - 27)))) return _Address;
|
||||
|
||||
// Technically we should do this, but almost no games, even heavy MMU ones, use any custom BATs whatsoever,
|
||||
// so only do it where it's really needed.
|
||||
// TODO: bBAT in theory should allow dynamic changes to the BAT registers.
|
||||
// In reality, the option is mostly useless at the moment because we don't
|
||||
// always translate addresses when we should. ReadFromHardware/WriteFromHardware,
|
||||
// fastmem, the JIT cache, and some misc code in the JIT assume default BATs.
|
||||
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bBAT)
|
||||
{
|
||||
u32 tlb_addr = TranslateBlockAddress(address, flag);
|
||||
|
@ -914,8 +1089,4 @@ u32 TranslateAddress(const u32 address)
|
|||
return TranslatePageAddress(address, flag);
|
||||
}
|
||||
|
||||
template u32 TranslateAddress<Memory::FLAG_NO_EXCEPTION>(const u32 address);
|
||||
template u32 TranslateAddress<Memory::FLAG_READ>(const u32 address);
|
||||
template u32 TranslateAddress<Memory::FLAG_WRITE>(const u32 address);
|
||||
template u32 TranslateAddress<Memory::FLAG_OPCODE>(const u32 address);
|
||||
} // namespace
|
|
@ -96,7 +96,7 @@ bool AnalyzeFunction(u32 startAddr, Symbol &func, int max_size)
|
|||
if (func.size >= CODEBUFFER_SIZE * 4) //weird
|
||||
return false;
|
||||
|
||||
UGeckoInstruction instr = (UGeckoInstruction)Memory::ReadUnchecked_U32(addr);
|
||||
UGeckoInstruction instr = (UGeckoInstruction)PowerPC::HostRead_U32(addr);
|
||||
if (max_size && func.size > max_size)
|
||||
{
|
||||
func.address = startAddr;
|
||||
|
@ -275,7 +275,7 @@ static void FindFunctionsFromBranches(u32 startAddr, u32 endAddr, SymbolDB *func
|
|||
{
|
||||
for (u32 addr = startAddr; addr < endAddr; addr+=4)
|
||||
{
|
||||
UGeckoInstruction instr = (UGeckoInstruction)Memory::ReadUnchecked_U32(addr);
|
||||
UGeckoInstruction instr = (UGeckoInstruction)PowerPC::HostRead_U32(addr);
|
||||
|
||||
if (PPCTables::IsValidInstruction(instr))
|
||||
{
|
||||
|
@ -288,7 +288,7 @@ static void FindFunctionsFromBranches(u32 startAddr, u32 endAddr, SymbolDB *func
|
|||
u32 target = SignExt26(instr.LI << 2);
|
||||
if (!instr.AA)
|
||||
target += addr;
|
||||
if (Memory::IsRAMAddress(target))
|
||||
if (PowerPC::HostIsRAMAddress(target))
|
||||
{
|
||||
func_db->AddFunction(target);
|
||||
}
|
||||
|
@ -314,9 +314,9 @@ static void FindFunctionsAfterBLR(PPCSymbolDB *func_db)
|
|||
while (true)
|
||||
{
|
||||
// skip zeroes that sometimes pad function to 16 byte boundary (e.g. Donkey Kong Country Returns)
|
||||
while (Memory::Read_Instruction(location) == 0 && ((location & 0xf) != 0))
|
||||
while (PowerPC::HostRead_Instruction(location) == 0 && ((location & 0xf) != 0))
|
||||
location += 4;
|
||||
if (PPCTables::IsValidInstruction(Memory::Read_Instruction(location)))
|
||||
if (PPCTables::IsValidInstruction(PowerPC::HostRead_Instruction(location)))
|
||||
{
|
||||
//check if this function is already mapped
|
||||
Symbol *f = func_db->AddFunction(location);
|
||||
|
@ -649,176 +649,156 @@ u32 PPCAnalyzer::Analyze(u32 address, CodeBlock *block, CodeBuffer *buffer, u32
|
|||
block->m_num_instructions = 0;
|
||||
block->m_gqr_used = BitSet8(0);
|
||||
|
||||
if (address == 0)
|
||||
{
|
||||
// Memory exception occurred during instruction fetch
|
||||
block->m_memory_exception = true;
|
||||
return address;
|
||||
}
|
||||
|
||||
bool virtualAddr = SConfig::GetInstance().m_LocalCoreStartupParameter.bMMU && (address & JIT_ICACHE_VMEM_BIT);
|
||||
if (virtualAddr)
|
||||
{
|
||||
if (!Memory::TranslateAddress<Memory::FLAG_NO_EXCEPTION>(address))
|
||||
{
|
||||
// Memory exception occurred during instruction fetch
|
||||
block->m_memory_exception = true;
|
||||
return address;
|
||||
}
|
||||
}
|
||||
|
||||
CodeOp *code = buffer->codebuffer;
|
||||
|
||||
bool found_exit = false;
|
||||
u32 return_address = 0;
|
||||
u32 numFollows = 0;
|
||||
u32 num_inst = 0;
|
||||
bool prev_inst_from_bat = true;
|
||||
|
||||
for (u32 i = 0; i < blockSize; ++i)
|
||||
{
|
||||
UGeckoInstruction inst = JitInterface::ReadOpcodeJIT(address);
|
||||
|
||||
if (inst.hex != 0)
|
||||
auto result = PowerPC::TryReadInstruction(address);
|
||||
if (!result.valid)
|
||||
{
|
||||
// Slight hack: the JIT block cache currently assumes all blocks end at the same place,
|
||||
// but broken blocks due to page faults break this assumption. Avoid this by just ending
|
||||
// all virtual memory instruction blocks at page boundaries.
|
||||
// FIXME: improve the JIT block cache so we don't need to do this.
|
||||
if (virtualAddr && i > 0 && (address & 0xfff) == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
num_inst++;
|
||||
memset(&code[i], 0, sizeof(CodeOp));
|
||||
GekkoOPInfo *opinfo = GetOpInfo(inst);
|
||||
if (!opinfo)
|
||||
{
|
||||
PanicAlert("Invalid PowerPC opcode: %x.", inst.hex);
|
||||
Crash();
|
||||
}
|
||||
|
||||
code[i].opinfo = opinfo;
|
||||
code[i].address = address;
|
||||
code[i].inst = inst;
|
||||
code[i].branchTo = -1;
|
||||
code[i].branchToIndex = -1;
|
||||
code[i].skip = false;
|
||||
block->m_stats->numCycles += opinfo->numCycles;
|
||||
|
||||
SetInstructionStats(block, &code[i], opinfo, i);
|
||||
|
||||
bool follow = false;
|
||||
u32 destination = 0;
|
||||
|
||||
bool conditional_continue = false;
|
||||
|
||||
// Do we inline leaf functions?
|
||||
if (HasOption(OPTION_LEAF_INLINE))
|
||||
{
|
||||
if (inst.OPCD == 18 && blockSize > 1)
|
||||
{
|
||||
//Is bx - should we inline? yes!
|
||||
if (inst.AA)
|
||||
destination = SignExt26(inst.LI << 2);
|
||||
else
|
||||
destination = address + SignExt26(inst.LI << 2);
|
||||
if (destination != block->m_address)
|
||||
follow = true;
|
||||
}
|
||||
else if (inst.OPCD == 19 && inst.SUBOP10 == 16 &&
|
||||
(inst.BO & (1 << 4)) && (inst.BO & (1 << 2)) &&
|
||||
return_address != 0)
|
||||
{
|
||||
// bclrx with unconditional branch = return
|
||||
follow = true;
|
||||
destination = return_address;
|
||||
return_address = 0;
|
||||
|
||||
if (inst.LK)
|
||||
return_address = address + 4;
|
||||
}
|
||||
else if (inst.OPCD == 31 && inst.SUBOP10 == 467)
|
||||
{
|
||||
// mtspr
|
||||
const u32 index = (inst.SPRU << 5) | (inst.SPRL & 0x1F);
|
||||
if (index == SPR_LR)
|
||||
{
|
||||
// We give up to follow the return address
|
||||
// because we have to check the register usage.
|
||||
return_address = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Find the optimal value for FUNCTION_FOLLOWING_THRESHOLD.
|
||||
// If it is small, the performance will be down.
|
||||
// If it is big, the size of generated code will be big and
|
||||
// cache clearning will happen many times.
|
||||
// TODO: Investivate the reason why
|
||||
// "0" is fastest in some games, MP2 for example.
|
||||
if (numFollows > FUNCTION_FOLLOWING_THRESHOLD)
|
||||
follow = false;
|
||||
}
|
||||
|
||||
if (HasOption(OPTION_CONDITIONAL_CONTINUE))
|
||||
{
|
||||
if (inst.OPCD == 16 &&
|
||||
((inst.BO & BO_DONT_DECREMENT_FLAG) == 0 || (inst.BO & BO_DONT_CHECK_CONDITION) == 0))
|
||||
{
|
||||
// bcx with conditional branch
|
||||
conditional_continue = true;
|
||||
}
|
||||
else if (inst.OPCD == 19 && inst.SUBOP10 == 16 &&
|
||||
((inst.BO & BO_DONT_DECREMENT_FLAG) == 0 || (inst.BO & BO_DONT_CHECK_CONDITION) == 0))
|
||||
{
|
||||
// bclrx with conditional branch
|
||||
conditional_continue = true;
|
||||
}
|
||||
else if (inst.OPCD == 3 ||
|
||||
(inst.OPCD == 31 && inst.SUBOP10 == 4))
|
||||
{
|
||||
// tw/twi tests and raises an exception
|
||||
conditional_continue = true;
|
||||
}
|
||||
else if (inst.OPCD == 19 && inst.SUBOP10 == 528 &&
|
||||
(inst.BO_2 & BO_DONT_CHECK_CONDITION) == 0)
|
||||
{
|
||||
// Rare bcctrx with conditional branch
|
||||
// Seen in NES games
|
||||
conditional_continue = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!follow)
|
||||
{
|
||||
address += 4;
|
||||
if (!conditional_continue && opinfo->flags & FL_ENDBLOCK) //right now we stop early
|
||||
{
|
||||
found_exit = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// XXX: We don't support inlining yet.
|
||||
#if 0
|
||||
else
|
||||
{
|
||||
numFollows++;
|
||||
// We don't "code[i].skip = true" here
|
||||
// because bx may store a certain value to the link register.
|
||||
// Instead, we skip a part of bx in Jit**::bx().
|
||||
address = destination;
|
||||
merged_addresses[size_of_merged_addresses++] = address;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
// ISI exception or other critical memory exception occured (game over)
|
||||
// We can continue on in MMU mode though, so don't spam this error in that case.
|
||||
if (!virtualAddr)
|
||||
ERROR_LOG(DYNA_REC, "Instruction hex was 0!");
|
||||
if (i == 0)
|
||||
block->m_memory_exception = true;
|
||||
break;
|
||||
}
|
||||
UGeckoInstruction inst = result.hex;
|
||||
|
||||
// Slight hack: the JIT block cache currently assumes all blocks end at the same place,
|
||||
// but broken blocks due to page faults break this assumption. Avoid this by just ending
|
||||
// all virtual memory instruction blocks at page boundaries.
|
||||
// FIXME: improve the JIT block cache so we don't need to do this.
|
||||
if ((!result.from_bat || !prev_inst_from_bat) && i > 0 && (address & 0xfff) == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
prev_inst_from_bat = result.from_bat;
|
||||
|
||||
num_inst++;
|
||||
memset(&code[i], 0, sizeof(CodeOp));
|
||||
GekkoOPInfo *opinfo = GetOpInfo(inst);
|
||||
if (!opinfo)
|
||||
{
|
||||
PanicAlert("Invalid PowerPC opcode: %x.", inst.hex);
|
||||
Crash();
|
||||
}
|
||||
|
||||
code[i].opinfo = opinfo;
|
||||
code[i].address = address;
|
||||
code[i].inst = inst;
|
||||
code[i].branchTo = -1;
|
||||
code[i].branchToIndex = -1;
|
||||
code[i].skip = false;
|
||||
block->m_stats->numCycles += opinfo->numCycles;
|
||||
|
||||
SetInstructionStats(block, &code[i], opinfo, i);
|
||||
|
||||
bool follow = false;
|
||||
u32 destination = 0;
|
||||
|
||||
bool conditional_continue = false;
|
||||
|
||||
// Do we inline leaf functions?
|
||||
if (HasOption(OPTION_LEAF_INLINE))
|
||||
{
|
||||
if (inst.OPCD == 18 && blockSize > 1)
|
||||
{
|
||||
//Is bx - should we inline? yes!
|
||||
if (inst.AA)
|
||||
destination = SignExt26(inst.LI << 2);
|
||||
else
|
||||
destination = address + SignExt26(inst.LI << 2);
|
||||
if (destination != block->m_address)
|
||||
follow = true;
|
||||
}
|
||||
else if (inst.OPCD == 19 && inst.SUBOP10 == 16 &&
|
||||
(inst.BO & (1 << 4)) && (inst.BO & (1 << 2)) &&
|
||||
return_address != 0)
|
||||
{
|
||||
// bclrx with unconditional branch = return
|
||||
follow = true;
|
||||
destination = return_address;
|
||||
return_address = 0;
|
||||
|
||||
if (inst.LK)
|
||||
return_address = address + 4;
|
||||
}
|
||||
else if (inst.OPCD == 31 && inst.SUBOP10 == 467)
|
||||
{
|
||||
// mtspr
|
||||
const u32 index = (inst.SPRU << 5) | (inst.SPRL & 0x1F);
|
||||
if (index == SPR_LR)
|
||||
{
|
||||
// We give up to follow the return address
|
||||
// because we have to check the register usage.
|
||||
return_address = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Find the optimal value for FUNCTION_FOLLOWING_THRESHOLD.
|
||||
// If it is small, the performance will be down.
|
||||
// If it is big, the size of generated code will be big and
|
||||
// cache clearning will happen many times.
|
||||
// TODO: Investivate the reason why
|
||||
// "0" is fastest in some games, MP2 for example.
|
||||
if (numFollows > FUNCTION_FOLLOWING_THRESHOLD)
|
||||
follow = false;
|
||||
}
|
||||
|
||||
if (HasOption(OPTION_CONDITIONAL_CONTINUE))
|
||||
{
|
||||
if (inst.OPCD == 16 &&
|
||||
((inst.BO & BO_DONT_DECREMENT_FLAG) == 0 || (inst.BO & BO_DONT_CHECK_CONDITION) == 0))
|
||||
{
|
||||
// bcx with conditional branch
|
||||
conditional_continue = true;
|
||||
}
|
||||
else if (inst.OPCD == 19 && inst.SUBOP10 == 16 &&
|
||||
((inst.BO & BO_DONT_DECREMENT_FLAG) == 0 || (inst.BO & BO_DONT_CHECK_CONDITION) == 0))
|
||||
{
|
||||
// bclrx with conditional branch
|
||||
conditional_continue = true;
|
||||
}
|
||||
else if (inst.OPCD == 3 ||
|
||||
(inst.OPCD == 31 && inst.SUBOP10 == 4))
|
||||
{
|
||||
// tw/twi tests and raises an exception
|
||||
conditional_continue = true;
|
||||
}
|
||||
else if (inst.OPCD == 19 && inst.SUBOP10 == 528 &&
|
||||
(inst.BO_2 & BO_DONT_CHECK_CONDITION) == 0)
|
||||
{
|
||||
// Rare bcctrx with conditional branch
|
||||
// Seen in NES games
|
||||
conditional_continue = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!follow)
|
||||
{
|
||||
address += 4;
|
||||
if (!conditional_continue && opinfo->flags & FL_ENDBLOCK) //right now we stop early
|
||||
{
|
||||
found_exit = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// XXX: We don't support inlining yet.
|
||||
#if 0
|
||||
else
|
||||
{
|
||||
numFollows++;
|
||||
// We don't "code[i].skip = true" here
|
||||
// because bx may store a certain value to the link register.
|
||||
// Instead, we skip a part of bx in Jit**::bx().
|
||||
address = destination;
|
||||
merged_addresses[size_of_merged_addresses++] = address;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
block->m_num_instructions = num_inst;
|
||||
|
|
|
@ -100,7 +100,7 @@ namespace PowerPC
|
|||
u32 InstructionCache::ReadInstruction(u32 addr)
|
||||
{
|
||||
if (!HID0.ICE) // instruction cache is disabled
|
||||
return Memory::ReadUnchecked_U32(addr);
|
||||
return Memory::Read_U32(addr);
|
||||
u32 set = (addr >> 5) & 0x7f;
|
||||
u32 tag = addr >> 12;
|
||||
|
||||
|
@ -121,7 +121,7 @@ namespace PowerPC
|
|||
if (t == 0xff) // load to the cache
|
||||
{
|
||||
if (HID0.ILOCK) // instruction cache is locked
|
||||
return Memory::ReadUnchecked_U32(addr);
|
||||
return Memory::Read_U32(addr);
|
||||
// select a way
|
||||
if (valid[set] != 0xff)
|
||||
t = way_from_valid[valid[set]];
|
||||
|
|
|
@ -86,7 +86,7 @@ void PPCSymbolDB::AddKnownSymbol(u32 startAddr, u32 size, const std::string& nam
|
|||
|
||||
Symbol *PPCSymbolDB::GetSymbolFromAddr(u32 addr)
|
||||
{
|
||||
if (!Memory::IsRAMAddress(addr))
|
||||
if (!PowerPC::HostIsRAMAddress(addr))
|
||||
return nullptr;
|
||||
|
||||
XFuncMap::iterator it = functions.find(addr);
|
||||
|
@ -333,11 +333,11 @@ bool PPCSymbolDB::LoadMap(const std::string& filename, bool bad)
|
|||
if (!good)
|
||||
{
|
||||
// check for BLR before function
|
||||
u32 opcode = Memory::Read_Instruction(vaddress - 4);
|
||||
u32 opcode = PowerPC::HostRead_Instruction(vaddress - 4);
|
||||
if (opcode == 0x4e800020)
|
||||
{
|
||||
// check for BLR at end of function
|
||||
opcode = Memory::Read_Instruction(vaddress + size - 4);
|
||||
opcode = PowerPC::HostRead_Instruction(vaddress + size - 4);
|
||||
if (opcode == 0x4e800020)
|
||||
good = true;
|
||||
}
|
||||
|
|
|
@ -192,6 +192,75 @@ void UpdatePerformanceMonitor(u32 cycles, u32 num_load_stores, u32 num_fp_inst);
|
|||
#define riPS0(i) (*(u64*)(&PowerPC::ppcState.ps[i][0]))
|
||||
#define riPS1(i) (*(u64*)(&PowerPC::ppcState.ps[i][1]))
|
||||
|
||||
// Routines for debugger UI, cheats, etc. to access emulated memory from the
|
||||
// perspective of the CPU. Not for use by core emulation routines.
|
||||
// Use "Host_" prefix.
|
||||
u8 HostRead_U8(const u32 address);
|
||||
u16 HostRead_U16(const u32 address);
|
||||
u32 HostRead_U32(const u32 address);
|
||||
u32 HostRead_Instruction(const u32 address);
|
||||
|
||||
void HostWrite_U8(const u8 var, const u32 address);
|
||||
void HostWrite_U16(const u16 var, const u32 address);
|
||||
void HostWrite_U32(const u32 var, const u32 address);
|
||||
void HostWrite_U64(const u64 var, const u32 address);
|
||||
|
||||
// Returns whether a read or write to the given address will resolve to a RAM
|
||||
// access given the current CPU state.
|
||||
bool HostIsRAMAddress(const u32 address);
|
||||
|
||||
std::string HostGetString(u32 em_address, size_t size = 0);
|
||||
|
||||
// Routines for the CPU core to access memory.
|
||||
|
||||
// Used by interpreter to read instructions, uses iCache
|
||||
u32 Read_Opcode(const u32 address);
|
||||
struct TryReadInstResult
|
||||
{
|
||||
bool valid;
|
||||
bool from_bat;
|
||||
u32 hex;
|
||||
};
|
||||
TryReadInstResult TryReadInstruction(const u32 address);
|
||||
|
||||
u8 Read_U8(const u32 address);
|
||||
u16 Read_U16(const u32 address);
|
||||
u32 Read_U32(const u32 address);
|
||||
u64 Read_U64(const u32 address);
|
||||
|
||||
// Useful helper functions, used by ARM JIT
|
||||
float Read_F32(const u32 address);
|
||||
double Read_F64(const u32 address);
|
||||
|
||||
// used by JIT. Return zero-extended 32bit values
|
||||
u32 Read_U8_ZX(const u32 address);
|
||||
u32 Read_U16_ZX(const u32 address);
|
||||
|
||||
void Write_U8(const u8 var, const u32 address);
|
||||
void Write_U16(const u16 var, const u32 address);
|
||||
void Write_U32(const u32 var, const u32 address);
|
||||
void Write_U64(const u64 var, const u32 address);
|
||||
|
||||
void Write_U16_Swap(const u16 var, const u32 address);
|
||||
void Write_U32_Swap(const u32 var, const u32 address);
|
||||
void Write_U64_Swap(const u64 var, const u32 address);
|
||||
|
||||
// Useful helper functions, used by ARM JIT
|
||||
void Write_F64(const double var, const u32 address);
|
||||
|
||||
void DMA_LCToMemory(const u32 memAddr, const u32 cacheAddr, const u32 numBlocks);
|
||||
void DMA_MemoryToLC(const u32 cacheAddr, const u32 memAddr, const u32 numBlocks);
|
||||
void ClearCacheLine(const u32 address); // Zeroes 32 bytes; address should be 32-byte-aligned
|
||||
|
||||
// TLB functions
|
||||
void SDRUpdated();
|
||||
void InvalidateTLBEntry(u32 address);
|
||||
|
||||
// Result changes based on the BAT registers and MSR.DR. Returns whether
|
||||
// it's safe to optimize a read or write to this address to an unguarded
|
||||
// memory access. Does not consider page tables.
|
||||
bool IsOptimizableRAMAddress(const u32 address);
|
||||
|
||||
} // namespace
|
||||
|
||||
enum CRBits
|
||||
|
|
|
@ -150,7 +150,7 @@ void SignatureDB::Initialize(PPCSymbolDB *symbol_db, const std::string& prefix)
|
|||
u32 sum = 0;
|
||||
for (u32 offset = offsetStart; offset <= offsetEnd; offset += 4)
|
||||
{
|
||||
u32 opcode = Memory::Read_Instruction(offset);
|
||||
u32 opcode = PowerPC::HostRead_Instruction(offset);
|
||||
u32 op = opcode & 0xFC000000;
|
||||
u32 op2 = 0;
|
||||
u32 op3 = 0;
|
||||
|
|
|
@ -298,7 +298,7 @@ void CCodeWindow::StepOver()
|
|||
{
|
||||
if (CCPU::IsStepping())
|
||||
{
|
||||
UGeckoInstruction inst = Memory::Read_Instruction(PC);
|
||||
UGeckoInstruction inst = PowerPC::HostRead_Instruction(PC);
|
||||
if (inst.LK)
|
||||
{
|
||||
PowerPC::breakpoints.ClearAllTemporary();
|
||||
|
@ -329,7 +329,7 @@ void CCodeWindow::StepOut()
|
|||
u64 steps = 0;
|
||||
PowerPC::CoreMode oldMode = PowerPC::GetMode();
|
||||
PowerPC::SetMode(PowerPC::MODE_INTERPRETER);
|
||||
UGeckoInstruction inst = Memory::Read_Instruction(PC);
|
||||
UGeckoInstruction inst = PowerPC::HostRead_Instruction(PC);
|
||||
while (inst.hex != 0x4e800020 && steps < timeout) // check for blr
|
||||
{
|
||||
if (inst.LK)
|
||||
|
@ -347,7 +347,7 @@ void CCodeWindow::StepOut()
|
|||
PowerPC::SingleStep();
|
||||
++steps;
|
||||
}
|
||||
inst = Memory::Read_Instruction(PC);
|
||||
inst = PowerPC::HostRead_Instruction(PC);
|
||||
}
|
||||
|
||||
PowerPC::SingleStep();
|
||||
|
@ -604,7 +604,7 @@ void CCodeWindow::OnJitMenu(wxCommandEvent& event)
|
|||
bool found = false;
|
||||
for (u32 addr = 0x80000000; addr < 0x80180000; addr += 4)
|
||||
{
|
||||
const char *name = PPCTables::GetInstructionName(Memory::ReadUnchecked_U32(addr));
|
||||
const char *name = PPCTables::GetInstructionName(PowerPC::HostRead_U32(addr));
|
||||
if (name && (wx_name == name))
|
||||
{
|
||||
NOTICE_LOG(POWERPC, "Found %s at %08x", wx_name.c_str(), addr);
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
#include "Common/CommonTypes.h"
|
||||
#include "Common/DebugInterface.h"
|
||||
#include "Common/StringUtil.h"
|
||||
#include "Core/HW/Memmap.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
#include "DolphinWX/Frame.h"
|
||||
#include "DolphinWX/Globals.h"
|
||||
#include "DolphinWX/WxUtils.h"
|
||||
|
@ -324,7 +324,7 @@ void CMemoryView::OnPaint(wxPaintEvent& event)
|
|||
dc.SetTextForeground(*wxBLACK);
|
||||
}
|
||||
|
||||
if (!Memory::IsRAMAddress(address))
|
||||
if (!PowerPC::HostIsRAMAddress(address))
|
||||
continue;
|
||||
|
||||
if (debugger->IsAlive())
|
||||
|
|
|
@ -181,7 +181,7 @@ void CMemoryWindow::SetMemoryValue(wxCommandEvent& event)
|
|||
return;
|
||||
}
|
||||
|
||||
Memory::Write_U32(val, addr);
|
||||
PowerPC::HostWrite_U32(val, addr);
|
||||
memview->Refresh();
|
||||
}
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ static u32 GetWatchAddr(int count)
|
|||
|
||||
static u32 GetWatchValue(int count)
|
||||
{
|
||||
return Memory::ReadUnchecked_U32(GetWatchAddr(count));
|
||||
return PowerPC::HostRead_U32(GetWatchAddr(count));
|
||||
}
|
||||
|
||||
static void AddWatchAddr(int count, u32 value)
|
||||
|
@ -71,7 +71,7 @@ static void SetWatchName(int count, const std::string& value)
|
|||
|
||||
static void SetWatchValue(int count, u32 value)
|
||||
{
|
||||
Memory::WriteUnchecked_U32(value, GetWatchAddr(count));
|
||||
PowerPC::HostWrite_U32(value, GetWatchAddr(count));
|
||||
}
|
||||
|
||||
static wxString GetValueByRowCol(int row, int col)
|
||||
|
@ -102,8 +102,8 @@ static wxString GetValueByRowCol(int row, int col)
|
|||
case 4:
|
||||
{
|
||||
u32 addr = GetWatchAddr(row);
|
||||
if (Memory::IsRAMAddress(addr))
|
||||
return Memory::GetString(addr, 32).c_str();
|
||||
if (PowerPC::HostIsRAMAddress(addr))
|
||||
return PowerPC::HostGetString(addr, 32).c_str();
|
||||
else
|
||||
return wxEmptyString;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue