summaryrefslogtreecommitdiff
path: root/Source/Core
diff options
context:
space:
mode:
authorAdmiral H. Curtiss <pikachu025@gmail.com>2021-02-27 14:06:59 +0100
committerAdmiral H. Curtiss <pikachu025@gmail.com>2021-07-07 04:26:28 +0200
commitb59fcae70abd7bd14d0a87aef9f07cd2481f905c (patch)
treec78f24325ed2cbac50ba9b5cad64f43e4b0f1abc /Source/Core
parent954f27c5d7289b2b806d0fb94dd105edaa1bb4be (diff)
Core/MMU: Add HostTryRead*() functions.
Diffstat (limited to 'Source/Core')
-rw-r--r--Source/Core/Core/PowerPC/MMU.cpp156
-rw-r--r--Source/Core/Core/PowerPC/MMU.h73
2 files changed, 218 insertions, 11 deletions
diff --git a/Source/Core/Core/PowerPC/MMU.cpp b/Source/Core/Core/PowerPC/MMU.cpp
index 30dbb8105e..ac0cea0cf3 100644
--- a/Source/Core/Core/PowerPC/MMU.cpp
+++ b/Source/Core/Core/PowerPC/MMU.cpp
@@ -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)
diff --git a/Source/Core/Core/PowerPC/MMU.h b/Source/Core/Core/PowerPC/MMU.h
index 82c4f8e7eb..591aec44fd 100644
--- a/Source/Core/Core/PowerPC/MMU.h
+++ b/Source/Core/Core/PowerPC/MMU.h
@@ -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.