bus.h (7431B)
1 // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com> 2 // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) 3 4 #pragma once 5 6 #include "types.h" 7 8 #include "common/bitfield.h" 9 10 #include <array> 11 #include <bitset> 12 #include <optional> 13 #include <span> 14 #include <string> 15 #include <string_view> 16 #include <vector> 17 18 class Error; 19 20 class StateWrapper; 21 22 namespace Bus { 23 24 enum : u32 25 { 26 RAM_BASE = 0x00000000, 27 RAM_2MB_SIZE = 0x200000, 28 RAM_2MB_MASK = RAM_2MB_SIZE - 1, 29 RAM_8MB_SIZE = 0x800000, 30 RAM_8MB_MASK = RAM_8MB_SIZE - 1, 31 RAM_MIRROR_END = 0x800000, 32 RAM_MIRROR_SIZE = 0x800000, 33 EXP1_BASE = 0x1F000000, 34 EXP1_SIZE = 0x800000, 35 EXP1_MASK = EXP1_SIZE - 1, 36 HW_BASE = 0x1F801000, 37 HW_SIZE = 0x1000, 38 MEMCTRL_BASE = 0x1F801000, 39 MEMCTRL_SIZE = 0x40, 40 MEMCTRL_MASK = MEMCTRL_SIZE - 1, 41 PAD_BASE = 0x1F801040, 42 PAD_SIZE = 0x10, 43 PAD_MASK = PAD_SIZE - 1, 44 SIO_BASE = 0x1F801050, 45 SIO_SIZE = 0x10, 46 SIO_MASK = SIO_SIZE - 1, 47 MEMCTRL2_BASE = 0x1F801060, 48 MEMCTRL2_SIZE = 0x10, 49 MEMCTRL2_MASK = MEMCTRL2_SIZE - 1, 50 INTC_BASE = 0x1F801070, 51 INTC_SIZE = 0x10, 52 INTERRUPT_CONTROLLER_MASK = INTC_SIZE - 1, 53 DMA_BASE = 0x1F801080, 54 DMA_SIZE = 0x80, 55 DMA_MASK = DMA_SIZE - 1, 56 TIMERS_BASE = 0x1F801100, 57 TIMERS_SIZE = 0x40, 58 TIMERS_MASK = TIMERS_SIZE - 1, 59 CDROM_BASE = 0x1F801800, 60 CDROM_SIZE = 0x10, 61 CDROM_MASK = CDROM_SIZE - 1, 62 GPU_BASE = 0x1F801810, 63 GPU_SIZE = 0x10, 64 GPU_MASK = GPU_SIZE - 1, 65 MDEC_BASE = 0x1F801820, 66 MDEC_SIZE = 0x10, 67 MDEC_MASK = MDEC_SIZE - 1, 68 SPU_BASE = 0x1F801C00, 69 SPU_SIZE = 0x400, 70 SPU_MASK = SPU_SIZE - 1, 71 SIO2_BASE = 0x1F808000, 72 SIO2_SIZE = 0x1000, 73 SIO2_MASK = SIO2_SIZE - 1, 74 EXP2_BASE = 0x1F802000, 75 EXP2_SIZE = 0x2000, 76 EXP2_MASK = EXP2_SIZE - 1, 77 EXP3_BASE = 0x1FA00000, 78 EXP3_SIZE = 0x200000, 79 EXP3_MASK = EXP3_SIZE - 1, 80 BIOS_BASE = 0x1FC00000, 81 BIOS_SIZE = 0x80000, 82 BIOS_MIRROR_SIZE = 0x400000, 83 BIOS_MASK = 0x7FFFF, 84 }; 85 86 enum : u32 87 { 88 MEMCTRL_REG_COUNT = 9 89 }; 90 91 enum : TickCount 92 { 93 RAM_READ_TICKS = 6 94 }; 95 96 enum : u32 97 { 98 RAM_2MB_CODE_PAGE_COUNT = (RAM_2MB_SIZE + (HOST_PAGE_SIZE - 1)) / HOST_PAGE_SIZE, 99 RAM_8MB_CODE_PAGE_COUNT = (RAM_8MB_SIZE + (HOST_PAGE_SIZE - 1)) / HOST_PAGE_SIZE, 100 101 MEMORY_LUT_PAGE_SIZE = 4096, 102 MEMORY_LUT_PAGE_SHIFT = 12, 103 MEMORY_LUT_PAGE_MASK = MEMORY_LUT_PAGE_SIZE - 1, 104 MEMORY_LUT_SIZE = 0x100000, // 0x100000000 >> 12 105 MEMORY_LUT_SLOTS = MEMORY_LUT_SIZE * 3 * 2, // [size][read_write] 106 107 FASTMEM_LUT_PAGE_SIZE = 4096, 108 FASTMEM_LUT_PAGE_MASK = FASTMEM_LUT_PAGE_SIZE - 1, 109 FASTMEM_LUT_PAGE_SHIFT = 12, 110 FASTMEM_LUT_SIZE = 0x100000, // 0x100000000 >> 12 111 FASTMEM_LUT_SLOTS = FASTMEM_LUT_SIZE * 2, // [isc] 112 }; 113 114 #ifdef ENABLE_MMAP_FASTMEM 115 // Fastmem region size is 4GB to cover the entire 32-bit address space. 116 static constexpr size_t FASTMEM_ARENA_SIZE = UINT64_C(0x100000000); 117 #endif 118 119 bool AllocateMemory(bool export_shared_memory, Error* error); 120 void ReleaseMemory(); 121 122 /// Frees and re-allocates the memory map for the process. 123 /// This should be called when shared memory exports are enabled. 124 bool ReallocateMemoryMap(bool export_shared_memory, Error* error); 125 126 /// Cleans up/deletes the shared memory object for this process. 127 /// Should be called when the process crashes, to avoid leaking. 128 void CleanupMemoryMap(); 129 130 bool Initialize(); 131 void Shutdown(); 132 void Reset(); 133 bool DoState(StateWrapper& sw); 134 135 using MemoryReadHandler = u32 (*)(VirtualMemoryAddress address); 136 using MemoryWriteHandler = void (*)(VirtualMemoryAddress, u32); 137 138 void** GetMemoryHandlers(bool isolate_cache, bool swap_caches); 139 140 template<typename FP> 141 ALWAYS_INLINE_RELEASE static FP* OffsetHandlerArray(void** handlers, MemoryAccessSize size, MemoryAccessType type) 142 { 143 return reinterpret_cast<FP*>(handlers + 144 (((static_cast<size_t>(size) * 2) + static_cast<size_t>(type)) * MEMORY_LUT_SIZE)); 145 } 146 147 CPUFastmemMode GetFastmemMode(); 148 void* GetFastmemBase(bool isc); 149 void UpdateFastmemViews(CPUFastmemMode mode); 150 bool CanUseFastmemForAddress(VirtualMemoryAddress address); 151 152 void SetExpansionROM(std::vector<u8> data); 153 154 extern std::bitset<RAM_8MB_CODE_PAGE_COUNT> g_ram_code_bits; 155 extern u8* g_ram; // 2MB-8MB RAM 156 extern u8* g_unprotected_ram; // RAM without page protection, use for debugger access. 157 extern u32 g_ram_size; // Active size of RAM. 158 extern u32 g_ram_mapped_size; // Maximum mapped address for RAM, determined by RAM size register. 159 extern u32 g_ram_mask; // Active address bits for RAM. 160 extern u8* g_bios; // 512K BIOS ROM 161 extern std::array<TickCount, 3> g_exp1_access_time; 162 extern std::array<TickCount, 3> g_exp2_access_time; 163 extern std::array<TickCount, 3> g_bios_access_time; 164 extern std::array<TickCount, 3> g_cdrom_access_time; 165 extern std::array<TickCount, 3> g_spu_access_time; 166 167 /// Returns true if the address specified is writable (RAM). 168 ALWAYS_INLINE static bool IsRAMAddress(PhysicalMemoryAddress address) 169 { 170 return address < RAM_MIRROR_END; 171 } 172 173 /// Returns the code page index for a RAM address. 174 ALWAYS_INLINE static u32 GetRAMCodePageIndex(PhysicalMemoryAddress address) 175 { 176 return (address & g_ram_mask) / HOST_PAGE_SIZE; 177 } 178 179 /// Returns true if the specified page contains code. 180 bool IsRAMCodePage(u32 index); 181 182 /// Flags a RAM region as code, so we know when to invalidate blocks. 183 void SetRAMCodePage(u32 index); 184 185 /// Unflags a RAM region as code, the code cache will no longer be notified when writes occur. 186 void ClearRAMCodePage(u32 index); 187 188 /// Clears all code bits for RAM regions. 189 void ClearRAMCodePageFlags(); 190 191 /// Returns true if the specified address is in a code page. 192 bool IsCodePageAddress(PhysicalMemoryAddress address); 193 194 /// Returns true if the range specified overlaps with a code page. 195 bool HasCodePagesInRange(PhysicalMemoryAddress start_address, u32 size); 196 197 /// Returns the number of cycles stolen by DMA RAM access. 198 ALWAYS_INLINE TickCount GetDMARAMTickCount(u32 word_count) 199 { 200 // DMA is using DRAM Hyper Page mode, allowing it to access DRAM rows at 1 clock cycle per word (effectively around 201 // 17 clks per 16 words, due to required row address loading, probably plus some further minimal overload due to 202 // refresh cycles). This is making DMA much faster than CPU memory accesses (CPU DRAM access takes 1 opcode cycle 203 // plus 6 waitstates, ie. 7 cycles in total). 204 return static_cast<TickCount>(word_count + ((word_count + 15) / 16)); 205 } 206 207 /// Returns a pointer to the cycle count for a non-RAM memory access. 208 const TickCount* GetMemoryAccessTimePtr(PhysicalMemoryAddress address, MemoryAccessSize size); 209 210 enum class MemoryRegion 211 { 212 RAM, 213 RAMMirror1, 214 RAMMirror2, 215 RAMMirror3, 216 EXP1, 217 Scratchpad, 218 BIOS, 219 Count 220 }; 221 222 std::optional<MemoryRegion> GetMemoryRegionForAddress(PhysicalMemoryAddress address); 223 PhysicalMemoryAddress GetMemoryRegionStart(MemoryRegion region); 224 PhysicalMemoryAddress GetMemoryRegionEnd(MemoryRegion region); 225 u8* GetMemoryRegionPointer(MemoryRegion region); 226 std::optional<PhysicalMemoryAddress> SearchMemory(PhysicalMemoryAddress start_address, const u8* pattern, 227 const u8* mask, u32 pattern_length); 228 229 // TTY Logging. 230 void AddTTYCharacter(char ch); 231 void AddTTYString(std::string_view str); 232 233 /// Injects a PS-EXE into memory at its specified load location. If set_pc is set, execution will be redirected. 234 bool InjectExecutable(std::span<const u8> buffer, bool set_pc, Error* error); 235 236 } // namespace Bus