From 9fd1d606d74b02816ada3a34366728a738042fe7 Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Wed, 16 Dec 2020 00:12:20 +1000 Subject: [PATCH] Bus: Add memory region access helpers --- src/core/bus.cpp | 121 +++++++++++++++++++++++++++++++++++++++++++++++ src/core/bus.h | 20 ++++++++ 2 files changed, 141 insertions(+) diff --git a/src/core/bus.cpp b/src/core/bus.cpp index 6befe5008..ca6a6a0ee 100644 --- a/src/core/bus.cpp +++ b/src/core/bus.cpp @@ -20,6 +20,7 @@ #include "timers.h" #include #include +#include Log_SetChannel(Bus); namespace Bus { @@ -565,6 +566,125 @@ bool HasCodePagesInRange(PhysicalMemoryAddress start_address, u32 size) return false; } +std::optional GetMemoryRegionForAddress(PhysicalMemoryAddress address) +{ + if (address < RAM_SIZE) + return MemoryRegion::RAM; + else if (address < RAM_MIRROR_END) + return static_cast(static_cast(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, + static_cast(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(region)].first; +} + +PhysicalMemoryAddress GetMemoryRegionEnd(MemoryRegion region) +{ + return s_code_region_ranges[static_cast(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 SearchMemory(PhysicalMemoryAddress start_address, const u8* pattern, + const u8* mask, u32 pattern_length) +{ + std::optional 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(static_cast(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, u32& value) { @@ -1569,6 +1689,7 @@ bool SafeReadInstruction(VirtualMemoryAddress addr, u32* value) case 0x04: // KSEG0 - physical memory cached case 0x05: // KSEG1 - physical memory uncached { + // TODO: Check icache. return DoInstructionRead(addr, value); } diff --git a/src/core/bus.h b/src/core/bus.h index b6ea51148..2fa21d71d 100644 --- a/src/core/bus.h +++ b/src/core/bus.h @@ -4,6 +4,7 @@ #include "types.h" #include #include +#include #include #include @@ -149,4 +150,23 @@ ALWAYS_INLINE TickCount GetDMARAMTickCount(u32 word_count) return static_cast(word_count + ((word_count + 15) / 16)); } +enum class MemoryRegion +{ + RAM, + RAMMirror1, + RAMMirror2, + RAMMirror3, + EXP1, + Scratchpad, + BIOS, + Count +}; + +std::optional GetMemoryRegionForAddress(PhysicalMemoryAddress address); +PhysicalMemoryAddress GetMemoryRegionStart(MemoryRegion region); +PhysicalMemoryAddress GetMemoryRegionEnd(MemoryRegion region); +u8* GetMemoryRegionPointer(MemoryRegion region); +std::optional SearchMemory(PhysicalMemoryAddress start_address, const u8* pattern, + const u8* mask, u32 pattern_length); + } // namespace Bus