duckstation

duckstation, but archived from the revision just before upstream changed it to a proprietary software project, this version is the libre one
git clone https://git.neptards.moe/u3shit/duckstation.git
Log | Files | Refs | README | LICENSE

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