Core/MMU: Add HostTryRead*() functions.
This commit is contained in:
parent
954f27c5d7
commit
b59fcae70a
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "Core/PowerPC/MMU.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
@ -427,6 +428,36 @@ u32 HostRead_Instruction(const u32 address)
|
|||
return ReadFromHardware<XCheckTLBFlag::OpcodeNoException, u32>(address);
|
||||
}
|
||||
|
||||
TryReadResult<u32> HostTryReadInstruction(const u32 address, RequestedAddressSpace space)
|
||||
{
|
||||
if (!HostIsInstructionRAMAddress(address, space))
|
||||
return TryReadResult<u32>();
|
||||
|
||||
switch (space)
|
||||
{
|
||||
case RequestedAddressSpace::Effective:
|
||||
{
|
||||
const u32 value = ReadFromHardware<XCheckTLBFlag::OpcodeNoException, u32>(address);
|
||||
return TryReadResult<u32>(!!MSR.DR, value);
|
||||
}
|
||||
case RequestedAddressSpace::Physical:
|
||||
{
|
||||
const u32 value = ReadFromHardware<XCheckTLBFlag::OpcodeNoException, u32, true>(address);
|
||||
return TryReadResult<u32>(false, value);
|
||||
}
|
||||
case RequestedAddressSpace::Virtual:
|
||||
{
|
||||
if (!MSR.DR)
|
||||
return TryReadResult<u32>();
|
||||
const u32 value = ReadFromHardware<XCheckTLBFlag::OpcodeNoException, u32>(address);
|
||||
return TryReadResult<u32>(true, value);
|
||||
}
|
||||
}
|
||||
|
||||
assert(0);
|
||||
return TryReadResult<u32>();
|
||||
}
|
||||
|
||||
static void Memcheck(u32 address, u32 var, bool write, size_t size)
|
||||
{
|
||||
if (PowerPC::memchecks.HasAny())
|
||||
|
@ -499,6 +530,73 @@ float Read_F32(const u32 address)
|
|||
return Common::BitCast<float>(integral);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static TryReadResult<T> HostTryReadUX(const u32 address, RequestedAddressSpace space)
|
||||
{
|
||||
if (!HostIsRAMAddress(address, space))
|
||||
return TryReadResult<T>();
|
||||
|
||||
switch (space)
|
||||
{
|
||||
case RequestedAddressSpace::Effective:
|
||||
{
|
||||
T value = ReadFromHardware<XCheckTLBFlag::NoException, T>(address);
|
||||
return TryReadResult<T>(!!MSR.DR, std::move(value));
|
||||
}
|
||||
case RequestedAddressSpace::Physical:
|
||||
{
|
||||
T value = ReadFromHardware<XCheckTLBFlag::NoException, T, true>(address);
|
||||
return TryReadResult<T>(false, std::move(value));
|
||||
}
|
||||
case RequestedAddressSpace::Virtual:
|
||||
{
|
||||
if (!MSR.DR)
|
||||
return TryReadResult<T>();
|
||||
T value = ReadFromHardware<XCheckTLBFlag::NoException, T>(address);
|
||||
return TryReadResult<T>(true, std::move(value));
|
||||
}
|
||||
}
|
||||
|
||||
assert(0);
|
||||
return TryReadResult<T>();
|
||||
}
|
||||
|
||||
TryReadResult<u8> HostTryReadU8(u32 address, RequestedAddressSpace space)
|
||||
{
|
||||
return HostTryReadUX<u8>(address, space);
|
||||
}
|
||||
|
||||
TryReadResult<u16> HostTryReadU16(u32 address, RequestedAddressSpace space)
|
||||
{
|
||||
return HostTryReadUX<u16>(address, space);
|
||||
}
|
||||
|
||||
TryReadResult<u32> HostTryReadU32(u32 address, RequestedAddressSpace space)
|
||||
{
|
||||
return HostTryReadUX<u32>(address, space);
|
||||
}
|
||||
|
||||
TryReadResult<u64> HostTryReadU64(u32 address, RequestedAddressSpace space)
|
||||
{
|
||||
return HostTryReadUX<u64>(address, space);
|
||||
}
|
||||
|
||||
TryReadResult<float> HostTryReadF32(u32 address, RequestedAddressSpace space)
|
||||
{
|
||||
const auto result = HostTryReadUX<u32>(address, space);
|
||||
if (!result)
|
||||
return TryReadResult<float>();
|
||||
return TryReadResult<float>(result.translated, Common::BitCast<float>(result.value));
|
||||
}
|
||||
|
||||
TryReadResult<double> HostTryReadF64(u32 address, RequestedAddressSpace space)
|
||||
{
|
||||
const auto result = HostTryReadUX<u64>(address, space);
|
||||
if (!result)
|
||||
return TryReadResult<double>();
|
||||
return TryReadResult<double>(result.translated, Common::BitCast<double>(result.value));
|
||||
}
|
||||
|
||||
u32 Read_U8_ZX(const u32 address)
|
||||
{
|
||||
return Read_U8(address);
|
||||
|
@ -639,6 +737,27 @@ std::string HostGetString(u32 address, size_t size)
|
|||
return s;
|
||||
}
|
||||
|
||||
TryReadResult<std::string> HostTryReadString(u32 address, size_t size, RequestedAddressSpace space)
|
||||
{
|
||||
auto c = HostTryReadU8(address, space);
|
||||
if (!c)
|
||||
return TryReadResult<std::string>();
|
||||
if (c.value == 0)
|
||||
return TryReadResult<std::string>(c.translated, "");
|
||||
|
||||
std::string s;
|
||||
s += static_cast<char>(c.value);
|
||||
while (size == 0 || s.length() < size)
|
||||
{
|
||||
++address;
|
||||
const auto res = HostTryReadU8(address, space);
|
||||
if (!res || res.value == 0)
|
||||
break;
|
||||
s += static_cast<char>(res.value);
|
||||
}
|
||||
return TryReadResult<std::string>(c.translated, std::move(s));
|
||||
}
|
||||
|
||||
bool IsOptimizableRAMAddress(const u32 address)
|
||||
{
|
||||
if (PowerPC::memchecks.HasAny())
|
||||
|
@ -688,15 +807,44 @@ static bool IsRAMAddress(u32 address, bool translate)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool HostIsRAMAddress(u32 address)
|
||||
bool HostIsRAMAddress(u32 address, RequestedAddressSpace space)
|
||||
{
|
||||
return IsRAMAddress<XCheckTLBFlag::NoException>(address, MSR.DR);
|
||||
switch (space)
|
||||
{
|
||||
case RequestedAddressSpace::Effective:
|
||||
return IsRAMAddress<XCheckTLBFlag::NoException>(address, MSR.DR);
|
||||
case RequestedAddressSpace::Physical:
|
||||
return IsRAMAddress<XCheckTLBFlag::NoException>(address, false);
|
||||
case RequestedAddressSpace::Virtual:
|
||||
if (!MSR.DR)
|
||||
return false;
|
||||
return IsRAMAddress<XCheckTLBFlag::NoException>(address, true);
|
||||
}
|
||||
|
||||
assert(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool HostIsInstructionRAMAddress(u32 address)
|
||||
bool HostIsInstructionRAMAddress(u32 address, RequestedAddressSpace space)
|
||||
{
|
||||
// Instructions are always 32bit aligned.
|
||||
return !(address & 3) && IsRAMAddress<XCheckTLBFlag::OpcodeNoException>(address, MSR.IR);
|
||||
if (!(address & 3))
|
||||
return false;
|
||||
|
||||
switch (space)
|
||||
{
|
||||
case RequestedAddressSpace::Effective:
|
||||
return IsRAMAddress<XCheckTLBFlag::OpcodeNoException>(address, MSR.IR);
|
||||
case RequestedAddressSpace::Physical:
|
||||
return IsRAMAddress<XCheckTLBFlag::OpcodeNoException>(address, false);
|
||||
case RequestedAddressSpace::Virtual:
|
||||
if (!MSR.IR)
|
||||
return false;
|
||||
return IsRAMAddress<XCheckTLBFlag::OpcodeNoException>(address, true);
|
||||
}
|
||||
|
||||
assert(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
void DMA_LCToMemory(const u32 mem_address, const u32 cache_address, const u32 num_blocks)
|
||||
|
|
|
@ -14,7 +14,19 @@ namespace PowerPC
|
|||
{
|
||||
// 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.
|
||||
// Use "Host" prefix.
|
||||
|
||||
enum class RequestedAddressSpace
|
||||
{
|
||||
Effective, // whatever the current MMU state is
|
||||
Physical, // as if the MMU was turned off
|
||||
Virtual, // specifically want MMU turned on, fails if off
|
||||
};
|
||||
|
||||
// Reads a value from emulated memory using the currently active MMU settings.
|
||||
// If the read fails (eg. address does not correspond to a mapped address in the current address
|
||||
// space), a PanicAlert will be shown to the user and zero (or an empty string for the string case)
|
||||
// will be returned.
|
||||
u8 HostRead_U8(u32 address);
|
||||
u16 HostRead_U16(u32 address);
|
||||
u32 HostRead_U32(u32 address);
|
||||
|
@ -22,6 +34,54 @@ u64 HostRead_U64(u32 address);
|
|||
float HostRead_F32(u32 address);
|
||||
double HostRead_F64(u32 address);
|
||||
u32 HostRead_Instruction(u32 address);
|
||||
std::string HostGetString(u32 address, size_t size = 0);
|
||||
|
||||
template <typename T>
|
||||
struct TryReadResult
|
||||
{
|
||||
// whether the read succeeded; if false, the other fields should not be touched
|
||||
bool success;
|
||||
|
||||
// whether the address had to be translated (given address was treated as virtual) or not (given
|
||||
// address was treated as physical)
|
||||
bool translated;
|
||||
|
||||
// the actual value that was read
|
||||
T value;
|
||||
|
||||
TryReadResult() : success(false) {}
|
||||
TryReadResult(bool translated_, T&& value_)
|
||||
: success(true), translated(translated_), value(std::move(value_))
|
||||
{
|
||||
}
|
||||
TryReadResult(bool translated_, const T& value_)
|
||||
: success(true), translated(translated_), value(value_)
|
||||
{
|
||||
}
|
||||
explicit operator bool() const { return success; }
|
||||
};
|
||||
|
||||
// Try to read a value from emulated memory at the given address in the given memory space.
|
||||
// If the read succeeds, the returned TryReadResult contains the read value and information on
|
||||
// whether the given address had to be translated or not. Unlike the HostRead functions, this does
|
||||
// not raise a user-visible alert on failure.
|
||||
TryReadResult<u8> HostTryReadU8(u32 address,
|
||||
RequestedAddressSpace space = RequestedAddressSpace::Effective);
|
||||
TryReadResult<u16> HostTryReadU16(u32 address,
|
||||
RequestedAddressSpace space = RequestedAddressSpace::Effective);
|
||||
TryReadResult<u32> HostTryReadU32(u32 address,
|
||||
RequestedAddressSpace space = RequestedAddressSpace::Effective);
|
||||
TryReadResult<u64> HostTryReadU64(u32 address,
|
||||
RequestedAddressSpace space = RequestedAddressSpace::Effective);
|
||||
TryReadResult<float> HostTryReadF32(u32 address,
|
||||
RequestedAddressSpace space = RequestedAddressSpace::Effective);
|
||||
TryReadResult<double>
|
||||
HostTryReadF64(u32 address, RequestedAddressSpace space = RequestedAddressSpace::Effective);
|
||||
TryReadResult<u32>
|
||||
HostTryReadInstruction(u32 address, RequestedAddressSpace space = RequestedAddressSpace::Effective);
|
||||
TryReadResult<std::string>
|
||||
HostTryReadString(u32 address, size_t size = 0,
|
||||
RequestedAddressSpace space = RequestedAddressSpace::Effective);
|
||||
|
||||
void HostWrite_U8(u8 var, u32 address);
|
||||
void HostWrite_U16(u16 var, u32 address);
|
||||
|
@ -30,14 +90,13 @@ void HostWrite_U64(u64 var, u32 address);
|
|||
void HostWrite_F32(float var, u32 address);
|
||||
void HostWrite_F64(double var, u32 address);
|
||||
|
||||
std::string HostGetString(u32 address, size_t size = 0);
|
||||
|
||||
// Returns whether a read or write to the given address will resolve to a RAM
|
||||
// access given the current CPU state.
|
||||
bool HostIsRAMAddress(u32 address);
|
||||
// Returns whether a read or write to the given address will resolve to a RAM access in the given
|
||||
// address space.
|
||||
bool HostIsRAMAddress(u32 address, RequestedAddressSpace space = RequestedAddressSpace::Effective);
|
||||
|
||||
// Same as HostIsRAMAddress, but uses IBAT instead of DBAT.
|
||||
bool HostIsInstructionRAMAddress(u32 address);
|
||||
bool HostIsInstructionRAMAddress(u32 address,
|
||||
RequestedAddressSpace space = RequestedAddressSpace::Effective);
|
||||
|
||||
// Routines for the CPU core to access memory.
|
||||
|
||||
|
|
Loading…
Reference in New Issue