mirror of
https://github.com/PCSX2/pcsx2.git
synced 2026-07-11 01:34:17 +02:00
Misc: Add MemoryInterface classes
This commit is contained in:
@@ -19,6 +19,7 @@ target_sources(common PRIVATE
|
||||
HostSys.cpp
|
||||
Image.cpp
|
||||
HTTPDownloader.cpp
|
||||
MemoryInterface.cpp
|
||||
MemorySettingsInterface.cpp
|
||||
MD5Digest.cpp
|
||||
PrecompiledHeader.cpp
|
||||
@@ -58,6 +59,7 @@ target_sources(common PRIVATE
|
||||
LRUCache.h
|
||||
HeapArray.h
|
||||
HTTPDownloader.h
|
||||
MemoryInterface.h
|
||||
MemorySettingsInterface.h
|
||||
MD5Digest.h
|
||||
MRCHelpers.h
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#include "MemoryInterface.h"
|
||||
|
||||
template <MemoryAccessType Value>
|
||||
Value MemoryInterface::Read(u32 address, bool* valid)
|
||||
{
|
||||
if constexpr (std::is_same_v<Value, u8> || std::is_same_v<Value, s8>)
|
||||
return static_cast<Value>(Read8(address, valid));
|
||||
else if constexpr (std::is_same_v<Value, u16> || std::is_same_v<Value, s16>)
|
||||
return static_cast<Value>(Read16(address, valid));
|
||||
else if constexpr (std::is_same_v<Value, u32> || std::is_same_v<Value, s32>)
|
||||
return static_cast<Value>(Read32(address, valid));
|
||||
else if constexpr (std::is_same_v<Value, u64> || std::is_same_v<Value, s64>)
|
||||
return static_cast<Value>(Read64(address, valid));
|
||||
else if constexpr (std::is_same_v<Value, u128>)
|
||||
return Read128(address, valid);
|
||||
else if constexpr (std::is_same_v<Value, s128>)
|
||||
{
|
||||
u128 value = Read128(address, valid);
|
||||
return s128{
|
||||
.lo = static_cast<s64>(value.lo),
|
||||
.hi = static_cast<s64>(value.hi),
|
||||
};
|
||||
}
|
||||
else
|
||||
return Value(0);
|
||||
}
|
||||
|
||||
template <MemoryAccessType Value>
|
||||
bool MemoryInterface::Write(u32 address, Value value)
|
||||
{
|
||||
if constexpr (std::is_same_v<Value, u8> || std::is_same_v<Value, s8>)
|
||||
return Write8(address, static_cast<u8>(value));
|
||||
else if constexpr (std::is_same_v<Value, u16> || std::is_same_v<Value, s16>)
|
||||
return Write16(address, static_cast<u16>(value));
|
||||
else if constexpr (std::is_same_v<Value, u32> || std::is_same_v<Value, s32>)
|
||||
return Write32(address, static_cast<u32>(value));
|
||||
else if constexpr (std::is_same_v<Value, u64> || std::is_same_v<Value, s64>)
|
||||
return Write64(address, static_cast<u64>(value));
|
||||
else if constexpr (std::is_same_v<Value, u128>)
|
||||
return Write128(address, value);
|
||||
else if constexpr (std::is_same_v<Value, s128>)
|
||||
{
|
||||
u128 unsigned_value;
|
||||
unsigned_value.lo = static_cast<u64>(value.lo);
|
||||
unsigned_value.hi = static_cast<u64>(value.hi);
|
||||
return Write128(address, unsigned_value);
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MemoryInterface::IdempotentWrite8(u32 address, u8 value)
|
||||
{
|
||||
bool valid;
|
||||
u8 existing_value = Read8(address, &valid);
|
||||
if (!valid || existing_value == value)
|
||||
return valid;
|
||||
|
||||
return Write8(address, value);
|
||||
}
|
||||
|
||||
bool MemoryInterface::IdempotentWrite16(u32 address, u16 value)
|
||||
{
|
||||
bool valid;
|
||||
u16 existing_value = Read16(address, &valid);
|
||||
if (!valid || existing_value == value)
|
||||
return valid;
|
||||
|
||||
return Write16(address, value);
|
||||
}
|
||||
|
||||
bool MemoryInterface::IdempotentWrite32(u32 address, u32 value)
|
||||
{
|
||||
bool valid;
|
||||
u32 existing_value = Read32(address, &valid);
|
||||
if (!valid || existing_value == value)
|
||||
return valid;
|
||||
|
||||
return Write32(address, value);
|
||||
}
|
||||
|
||||
bool MemoryInterface::IdempotentWrite64(u32 address, u64 value)
|
||||
{
|
||||
bool valid;
|
||||
u64 existing_value = Read64(address, &valid);
|
||||
if (!valid || existing_value == value)
|
||||
return valid;
|
||||
|
||||
return Write64(address, value);
|
||||
}
|
||||
|
||||
bool MemoryInterface::IdempotentWrite128(u32 address, u128 value)
|
||||
{
|
||||
bool valid;
|
||||
u128 existing_value = Read128(address, &valid);
|
||||
if (!valid || existing_value == value)
|
||||
return valid;
|
||||
|
||||
return Write128(address, value);
|
||||
}
|
||||
|
||||
bool MemoryInterface::IdempotentWriteBytes(u32 address, void* src, u32 size)
|
||||
{
|
||||
if (CompareBytes(address, src, size))
|
||||
return true;
|
||||
|
||||
return WriteBytes(address, src, size);
|
||||
}
|
||||
|
||||
template <MemoryAccessType Value>
|
||||
bool MemoryInterface::IdempotentWrite(u32 address, Value value)
|
||||
{
|
||||
bool valid;
|
||||
Value existing_value = Read<Value>(address, &valid);
|
||||
if (!valid || existing_value == value)
|
||||
return valid;
|
||||
|
||||
return Write<Value>(address, value);
|
||||
}
|
||||
|
||||
#define EXPLICITLY_INSTANTIATE_TEMPLATES(type) \
|
||||
template type MemoryInterface::Read<type>(u32 addres, bool* valid); \
|
||||
template bool MemoryInterface::Write<type>(u32 address, type value); \
|
||||
template bool MemoryInterface::IdempotentWrite<type>(u32 address, type value);
|
||||
EXPLICITLY_INSTANTIATE_TEMPLATES(u8)
|
||||
EXPLICITLY_INSTANTIATE_TEMPLATES(s8)
|
||||
EXPLICITLY_INSTANTIATE_TEMPLATES(u16)
|
||||
EXPLICITLY_INSTANTIATE_TEMPLATES(s16)
|
||||
EXPLICITLY_INSTANTIATE_TEMPLATES(u32)
|
||||
EXPLICITLY_INSTANTIATE_TEMPLATES(s32)
|
||||
EXPLICITLY_INSTANTIATE_TEMPLATES(u64)
|
||||
EXPLICITLY_INSTANTIATE_TEMPLATES(s64)
|
||||
EXPLICITLY_INSTANTIATE_TEMPLATES(u128)
|
||||
EXPLICITLY_INSTANTIATE_TEMPLATES(s128)
|
||||
#undef EXPLICITLY_INSTANTIATE_TEMPLATES
|
||||
@@ -0,0 +1,52 @@
|
||||
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Pcsx2Types.h"
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
template <typename Value>
|
||||
concept MemoryAccessType = std::is_same_v<Value, u8> || std::is_same_v<Value, s8> ||
|
||||
std::is_same_v<Value, u16> || std::is_same_v<Value, s16> ||
|
||||
std::is_same_v<Value, u32> || std::is_same_v<Value, s32> ||
|
||||
std::is_same_v<Value, u64> || std::is_same_v<Value, s64> ||
|
||||
std::is_same_v<Value, u128> || std::is_same_v<Value, s128>;
|
||||
|
||||
/// Interface for reading/writing guest memory.
|
||||
class MemoryInterface
|
||||
{
|
||||
public:
|
||||
virtual u8 Read8(u32 address, bool* valid = nullptr) = 0;
|
||||
virtual u16 Read16(u32 address, bool* valid = nullptr) = 0;
|
||||
virtual u32 Read32(u32 address, bool* valid = nullptr) = 0;
|
||||
virtual u64 Read64(u32 address, bool* valid = nullptr) = 0;
|
||||
virtual u128 Read128(u32 address, bool* valid = nullptr) = 0;
|
||||
virtual bool ReadBytes(u32 address, void* dest, u32 size) = 0;
|
||||
|
||||
template <MemoryAccessType Value>
|
||||
Value Read(u32 address, bool* valid = nullptr);
|
||||
|
||||
virtual bool Write8(u32 address, u8 value) = 0;
|
||||
virtual bool Write16(u32 address, u16 value) = 0;
|
||||
virtual bool Write32(u32 address, u32 value) = 0;
|
||||
virtual bool Write64(u32 address, u64 value) = 0;
|
||||
virtual bool Write128(u32 address, u128 value) = 0;
|
||||
virtual bool WriteBytes(u32 address, void* src, u32 size) = 0;
|
||||
|
||||
template <MemoryAccessType Value>
|
||||
bool Write(u32 address, Value value);
|
||||
|
||||
bool IdempotentWrite8(u32 address, u8 value);
|
||||
bool IdempotentWrite16(u32 address, u16 value);
|
||||
bool IdempotentWrite32(u32 address, u32 value);
|
||||
bool IdempotentWrite64(u32 address, u64 value);
|
||||
bool IdempotentWrite128(u32 address, u128 value);
|
||||
bool IdempotentWriteBytes(u32 address, void* src, u32 size);
|
||||
|
||||
template <MemoryAccessType Value>
|
||||
bool IdempotentWrite(u32 address, Value value);
|
||||
|
||||
virtual bool CompareBytes(u32 address, void* src, u32 size) = 0;
|
||||
};
|
||||
@@ -62,6 +62,7 @@
|
||||
</ClCompile>
|
||||
<ClCompile Include="HTTPDownloaderWinHTTP.cpp" />
|
||||
<ClCompile Include="MD5Digest.cpp" />
|
||||
<ClCompile Include="MemoryInterface.cpp" />
|
||||
<ClCompile Include="MemorySettingsInterface.cpp" />
|
||||
<ClCompile Include="ProgressCallback.cpp" />
|
||||
<ClCompile Include="ReadbackSpinManager.cpp" />
|
||||
@@ -141,6 +142,7 @@
|
||||
</ClInclude>
|
||||
<ClInclude Include="HTTPDownloaderWinHTTP.h" />
|
||||
<ClInclude Include="MD5Digest.h" />
|
||||
<ClInclude Include="MemoryInterface.h" />
|
||||
<ClInclude Include="MemorySettingsInterface.h" />
|
||||
<ClInclude Include="ProgressCallback.h" />
|
||||
<ClInclude Include="ScopedGuard.h" />
|
||||
|
||||
@@ -103,6 +103,9 @@
|
||||
<ClCompile Include="HTTPDownloaderWinHTTP.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="MemoryInterface.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="MemorySettingsInterface.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
@@ -303,6 +306,9 @@
|
||||
<ClInclude Include="HeterogeneousContainers.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MemoryInterface.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MemorySettingsInterface.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
|
||||
@@ -538,3 +538,81 @@ std::string iopMemReadString(u32 mem, int maxlen)
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
u8 IOPMemoryInterface::Read8(u32 address, bool* valid)
|
||||
{
|
||||
if (valid)
|
||||
*valid = true;
|
||||
return iopMemRead8(address);
|
||||
}
|
||||
|
||||
u16 IOPMemoryInterface::Read16(u32 address, bool* valid)
|
||||
{
|
||||
if (valid)
|
||||
*valid = true;
|
||||
return iopMemRead16(address);
|
||||
}
|
||||
|
||||
u32 IOPMemoryInterface::Read32(u32 address, bool* valid)
|
||||
{
|
||||
if (valid)
|
||||
*valid = true;
|
||||
return iopMemRead32(address);
|
||||
}
|
||||
|
||||
u64 IOPMemoryInterface::Read64(u32 address, bool* valid)
|
||||
{
|
||||
if (valid)
|
||||
*valid = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
u128 IOPMemoryInterface::Read128(u32 address, bool* valid)
|
||||
{
|
||||
if (valid)
|
||||
*valid = false;
|
||||
return u128::From64(0);
|
||||
}
|
||||
|
||||
bool IOPMemoryInterface::ReadBytes(u32 address, void* dest, u32 size)
|
||||
{
|
||||
return iopMemSafeReadBytes(address, dest, size);
|
||||
}
|
||||
|
||||
bool IOPMemoryInterface::Write8(u32 address, u8 value)
|
||||
{
|
||||
iopMemWrite8(address, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IOPMemoryInterface::Write16(u32 address, u16 value)
|
||||
{
|
||||
iopMemWrite16(address, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IOPMemoryInterface::Write32(u32 address, u32 value)
|
||||
{
|
||||
iopMemWrite32(address, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IOPMemoryInterface::Write64(u32 address, u64 value)
|
||||
{
|
||||
return false;
|
||||
|
||||
}
|
||||
bool IOPMemoryInterface::Write128(u32 address, u128 value)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IOPMemoryInterface::WriteBytes(u32 address, void* src, u32 size)
|
||||
{
|
||||
return iopMemSafeWriteBytes(address, src, size);
|
||||
}
|
||||
|
||||
bool IOPMemoryInterface::CompareBytes(u32 address, void* src, u32 size)
|
||||
{
|
||||
return iopMemSafeCmpBytes(address, src, size) != 0;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
|
||||
#include "MemoryTypes.h"
|
||||
|
||||
#include "common/MemoryInterface.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
extern uptr *psxMemWLUT;
|
||||
@@ -118,3 +120,23 @@ namespace IopMemory
|
||||
extern void iopHwWrite32_Page3( u32 iopaddr, mem32_t data );
|
||||
extern void iopHwWrite32_Page8( u32 iopaddr, mem32_t data );
|
||||
}
|
||||
|
||||
class IOPMemoryInterface final : public MemoryInterface
|
||||
{
|
||||
public:
|
||||
u8 Read8(u32 address, bool* valid = nullptr) override;
|
||||
u16 Read16(u32 address, bool* valid = nullptr) override;
|
||||
u32 Read32(u32 address, bool* valid = nullptr) override;
|
||||
u64 Read64(u32 address, bool* valid = nullptr) override;
|
||||
u128 Read128(u32 address, bool* valid = nullptr) override;
|
||||
bool ReadBytes(u32 address, void* dest, u32 size) override;
|
||||
|
||||
bool Write8(u32 address, u8 value) override;
|
||||
bool Write16(u32 address, u16 value) override;
|
||||
bool Write32(u32 address, u32 value) override;
|
||||
bool Write64(u32 address, u64 value) override;
|
||||
bool Write128(u32 address, u128 value) override;
|
||||
bool WriteBytes(u32 address, void* src, u32 size) override;
|
||||
|
||||
bool CompareBytes(u32 address, void* src, u32 size) override;
|
||||
};
|
||||
|
||||
@@ -1253,3 +1253,85 @@ bool SaveStateBase::memFreeze(Error* error)
|
||||
|
||||
return IsOkay();
|
||||
}
|
||||
|
||||
u8 EEMemoryInterface::Read8(u32 address, bool* valid)
|
||||
{
|
||||
if (valid)
|
||||
*valid = true;
|
||||
return memRead8(address);
|
||||
}
|
||||
|
||||
u16 EEMemoryInterface::Read16(u32 address, bool* valid)
|
||||
{
|
||||
if (valid)
|
||||
*valid = true;
|
||||
return memRead16(address);
|
||||
}
|
||||
|
||||
u32 EEMemoryInterface::Read32(u32 address, bool* valid)
|
||||
{
|
||||
if (valid)
|
||||
*valid = true;
|
||||
return memRead32(address);
|
||||
}
|
||||
|
||||
u64 EEMemoryInterface::Read64(u32 address, bool* valid)
|
||||
{
|
||||
if (valid)
|
||||
*valid = true;
|
||||
return memRead64(address);
|
||||
}
|
||||
|
||||
u128 EEMemoryInterface::Read128(u32 address, bool* valid)
|
||||
{
|
||||
u128 value;
|
||||
memRead128(address, value);
|
||||
if (valid)
|
||||
*valid = true;
|
||||
return value;
|
||||
}
|
||||
|
||||
bool EEMemoryInterface::ReadBytes(u32 address, void* dest, u32 size)
|
||||
{
|
||||
return vtlb_memSafeReadBytes(address, dest, size);
|
||||
}
|
||||
|
||||
bool EEMemoryInterface::Write8(u32 address, u8 value)
|
||||
{
|
||||
memWrite8(address, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EEMemoryInterface::Write16(u32 address, u16 value)
|
||||
{
|
||||
memWrite16(address, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EEMemoryInterface::Write32(u32 address, u32 value)
|
||||
{
|
||||
memWrite32(address, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EEMemoryInterface::Write64(u32 address, u64 value)
|
||||
{
|
||||
memWrite64(address, value);
|
||||
return true;
|
||||
|
||||
}
|
||||
bool EEMemoryInterface::Write128(u32 address, u128 value)
|
||||
{
|
||||
memWrite128(address, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EEMemoryInterface::WriteBytes(u32 address, void* src, u32 size)
|
||||
{
|
||||
return vtlb_memSafeWriteBytes(address, src, size);
|
||||
}
|
||||
|
||||
bool EEMemoryInterface::CompareBytes(u32 address, void* src, u32 size)
|
||||
{
|
||||
return vtlb_memSafeCmpBytes(address, src, size) != 0;
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "vtlb.h"
|
||||
#include "MemoryTypes.h"
|
||||
#include "common/BitUtils.h"
|
||||
#include "common/MemoryInterface.h"
|
||||
|
||||
// This is a table of default virtual map addresses for ps2vm components. These locations
|
||||
// are provided and used to assist in debugging and possibly hacking; as it makes it possible
|
||||
@@ -191,3 +192,23 @@ static __fi void memWrite128(u32 mem, const mem128_t& val) { vtlb_memWrite128(me
|
||||
|
||||
extern void ba0W16(u32 mem, u16 value);
|
||||
extern u16 ba0R16(u32 mem);
|
||||
|
||||
class EEMemoryInterface final : public MemoryInterface
|
||||
{
|
||||
public:
|
||||
u8 Read8(u32 address, bool* valid = nullptr) override;
|
||||
u16 Read16(u32 address, bool* valid = nullptr) override;
|
||||
u32 Read32(u32 address, bool* valid = nullptr) override;
|
||||
u64 Read64(u32 address, bool* valid = nullptr) override;
|
||||
u128 Read128(u32 address, bool* valid = nullptr) override;
|
||||
bool ReadBytes(u32 address, void* dest, u32 size) override;
|
||||
|
||||
bool Write8(u32 address, u8 value) override;
|
||||
bool Write16(u32 address, u16 value) override;
|
||||
bool Write32(u32 address, u32 value) override;
|
||||
bool Write64(u32 address, u64 value) override;
|
||||
bool Write128(u32 address, u128 value) override;
|
||||
bool WriteBytes(u32 address, void* src, u32 size) override;
|
||||
|
||||
bool CompareBytes(u32 address, void* src, u32 size) override;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user