Bus: Add memory region access helpers

This commit is contained in:
Connor McLaughlin 2020-12-16 00:12:20 +10:00
parent c95ccbcb5e
commit 9fd1d606d7
2 changed files with 141 additions and 0 deletions

View file

@ -20,6 +20,7 @@
#include "timers.h" #include "timers.h"
#include <cstdio> #include <cstdio>
#include <tuple> #include <tuple>
#include <utility>
Log_SetChannel(Bus); Log_SetChannel(Bus);
namespace Bus { namespace Bus {
@ -565,6 +566,125 @@ bool HasCodePagesInRange(PhysicalMemoryAddress start_address, u32 size)
return false; return false;
} }
std::optional<MemoryRegion> GetMemoryRegionForAddress(PhysicalMemoryAddress address)
{
if (address < RAM_SIZE)
return MemoryRegion::RAM;
else if (address < RAM_MIRROR_END)
return static_cast<MemoryRegion>(static_cast<u32>(MemoryRegion::RAM) + (address / RAM_SIZE));
else if (address >= EXP1_BASE && address < (EXP1_BASE + EXP1_SIZE))
return MemoryRegion::EXP1;
else if (address >= CPU::DCACHE_LOCATION && address < (CPU::DCACHE_LOCATION + CPU::DCACHE_SIZE))
return MemoryRegion::Scratchpad;
else if (address >= BIOS_BASE && address < (BIOS_BASE + BIOS_SIZE))
return MemoryRegion::BIOS;
return std::nullopt;
}
static constexpr std::array<std::pair<PhysicalMemoryAddress, PhysicalMemoryAddress>,
static_cast<u32>(MemoryRegion::Count)>
s_code_region_ranges = {{
{0, RAM_SIZE},
{RAM_SIZE, RAM_SIZE * 2},
{RAM_SIZE * 2, RAM_SIZE * 3},
{RAM_SIZE * 3, RAM_MIRROR_END},
{EXP1_BASE, EXP1_BASE + EXP1_SIZE},
{CPU::DCACHE_LOCATION, CPU::DCACHE_LOCATION + CPU::DCACHE_SIZE},
{BIOS_BASE, BIOS_BASE + BIOS_SIZE},
}};
PhysicalMemoryAddress GetMemoryRegionStart(MemoryRegion region)
{
return s_code_region_ranges[static_cast<u32>(region)].first;
}
PhysicalMemoryAddress GetMemoryRegionEnd(MemoryRegion region)
{
return s_code_region_ranges[static_cast<u32>(region)].second;
}
u8* GetMemoryRegionPointer(MemoryRegion region)
{
switch (region)
{
case MemoryRegion::RAM:
case MemoryRegion::RAMMirror1:
case MemoryRegion::RAMMirror2:
case MemoryRegion::RAMMirror3:
return g_ram;
case MemoryRegion::EXP1:
return nullptr;
case MemoryRegion::Scratchpad:
return CPU::g_state.dcache.data();
case MemoryRegion::BIOS:
return g_bios;
default:
return nullptr;
}
}
static ALWAYS_INLINE_RELEASE bool MaskedMemoryCompare(const u8* pattern, const u8* mask, u32 pattern_length,
const u8* mem)
{
if (!mask)
return std::memcmp(mem, pattern, pattern_length) == 0;
for (u32 i = 0; i < pattern_length; i++)
{
if ((mem[i] & mask[i]) != (pattern[i] & mask[i]))
return false;
}
return true;
}
std::optional<PhysicalMemoryAddress> SearchMemory(PhysicalMemoryAddress start_address, const u8* pattern,
const u8* mask, u32 pattern_length)
{
std::optional<MemoryRegion> region = GetMemoryRegionForAddress(start_address);
if (!region.has_value())
return std::nullopt;
PhysicalMemoryAddress current_address = start_address;
MemoryRegion current_region = region.value();
while (current_region != MemoryRegion::Count)
{
const u8* mem = GetMemoryRegionPointer(current_region);
const PhysicalMemoryAddress region_start = GetMemoryRegionStart(current_region);
const PhysicalMemoryAddress region_end = GetMemoryRegionEnd(current_region);
if (mem)
{
PhysicalMemoryAddress region_offset = current_address - region_start;
PhysicalMemoryAddress bytes_remaining = region_end - current_address;
while (bytes_remaining >= pattern_length)
{
if (MaskedMemoryCompare(pattern, mask, pattern_length, mem + region_offset))
return region_start + region_offset;
region_offset++;
bytes_remaining--;
}
}
// skip RAM mirrors
if (current_region == MemoryRegion::RAM)
current_region = MemoryRegion::EXP1;
else
current_region = static_cast<MemoryRegion>(static_cast<int>(current_region) + 1);
if (current_region != MemoryRegion::Count)
current_address = GetMemoryRegionStart(current_region);
}
return std::nullopt;
}
static TickCount DoInvalidAccess(MemoryAccessType type, MemoryAccessSize size, PhysicalMemoryAddress address, static TickCount DoInvalidAccess(MemoryAccessType type, MemoryAccessSize size, PhysicalMemoryAddress address,
u32& value) u32& value)
{ {
@ -1569,6 +1689,7 @@ bool SafeReadInstruction(VirtualMemoryAddress addr, u32* value)
case 0x04: // KSEG0 - physical memory cached case 0x04: // KSEG0 - physical memory cached
case 0x05: // KSEG1 - physical memory uncached case 0x05: // KSEG1 - physical memory uncached
{ {
// TODO: Check icache.
return DoInstructionRead<false, false, 1, false>(addr, value); return DoInstructionRead<false, false, 1, false>(addr, value);
} }

View file

@ -4,6 +4,7 @@
#include "types.h" #include "types.h"
#include <array> #include <array>
#include <bitset> #include <bitset>
#include <optional>
#include <string> #include <string>
#include <vector> #include <vector>
@ -149,4 +150,23 @@ ALWAYS_INLINE TickCount GetDMARAMTickCount(u32 word_count)
return static_cast<TickCount>(word_count + ((word_count + 15) / 16)); return static_cast<TickCount>(word_count + ((word_count + 15) / 16));
} }
enum class MemoryRegion
{
RAM,
RAMMirror1,
RAMMirror2,
RAMMirror3,
EXP1,
Scratchpad,
BIOS,
Count
};
std::optional<MemoryRegion> GetMemoryRegionForAddress(PhysicalMemoryAddress address);
PhysicalMemoryAddress GetMemoryRegionStart(MemoryRegion region);
PhysicalMemoryAddress GetMemoryRegionEnd(MemoryRegion region);
u8* GetMemoryRegionPointer(MemoryRegion region);
std::optional<PhysicalMemoryAddress> SearchMemory(PhysicalMemoryAddress start_address, const u8* pattern,
const u8* mask, u32 pattern_length);
} // namespace Bus } // namespace Bus