#pragma once
#include "types.h"
#include <array>
#include <bitset>
#include <optional>
#include <span>
#include <string_view>
class Error;
class StateWrapper;
namespace Bus {
enum : u32
{
RAM_BASE = 0x00000000,
RAM_2MB_SIZE = 0x200000,
RAM_2MB_MASK = RAM_2MB_SIZE - 1,
RAM_8MB_SIZE = 0x800000,
RAM_8MB_MASK = RAM_8MB_SIZE - 1,
RAM_MIRROR_END = 0x800000,
RAM_MIRROR_SIZE = 0x800000,
EXP1_BASE = 0x1F000000,
EXP1_SIZE = 0x800000,
EXP1_MASK = EXP1_SIZE - 1,
HW_BASE = 0x1F801000,
HW_SIZE = 0x1000,
MEMCTRL_BASE = 0x1F801000,
MEMCTRL_SIZE = 0x40,
MEMCTRL_MASK = MEMCTRL_SIZE - 1,
PAD_BASE = 0x1F801040,
PAD_SIZE = 0x10,
PAD_MASK = PAD_SIZE - 1,
SIO_BASE = 0x1F801050,
SIO_SIZE = 0x10,
SIO_MASK = SIO_SIZE - 1,
MEMCTRL2_BASE = 0x1F801060,
MEMCTRL2_SIZE = 0x10,
MEMCTRL2_MASK = MEMCTRL2_SIZE - 1,
INTC_BASE = 0x1F801070,
INTC_SIZE = 0x10,
INTERRUPT_CONTROLLER_MASK = INTC_SIZE - 1,
DMA_BASE = 0x1F801080,
DMA_SIZE = 0x80,
DMA_MASK = DMA_SIZE - 1,
TIMERS_BASE = 0x1F801100,
TIMERS_SIZE = 0x40,
TIMERS_MASK = TIMERS_SIZE - 1,
CDROM_BASE = 0x1F801800,
CDROM_SIZE = 0x10,
CDROM_MASK = CDROM_SIZE - 1,
GPU_BASE = 0x1F801810,
GPU_SIZE = 0x10,
GPU_MASK = GPU_SIZE - 1,
MDEC_BASE = 0x1F801820,
MDEC_SIZE = 0x10,
MDEC_MASK = MDEC_SIZE - 1,
SPU_BASE = 0x1F801C00,
SPU_SIZE = 0x400,
SPU_MASK = SPU_SIZE - 1,
SIO2_BASE = 0x1F808000,
SIO2_SIZE = 0x1000,
SIO2_MASK = SIO2_SIZE - 1,
EXP2_BASE = 0x1F802000,
EXP2_SIZE = 0x2000,
EXP2_MASK = EXP2_SIZE - 1,
EXP3_BASE = 0x1FA00000,
EXP3_SIZE = 0x200000,
EXP3_MASK = EXP3_SIZE - 1,
BIOS_BASE = 0x1FC00000,
BIOS_SIZE = 0x80000,
BIOS_MIRROR_SIZE = 0x400000,
BIOS_MASK = 0x7FFFF,
};
enum : u32
{
MEMCTRL_REG_COUNT = 9
};
enum : TickCount
{
RAM_READ_TICKS = 6
};
enum : u32
{
RAM_2MB_CODE_PAGE_COUNT = (RAM_2MB_SIZE + (MIN_HOST_PAGE_SIZE - 1)) / MIN_HOST_PAGE_SIZE,
RAM_8MB_CODE_PAGE_COUNT = (RAM_8MB_SIZE + (MIN_HOST_PAGE_SIZE - 1)) / MIN_HOST_PAGE_SIZE,
MEMORY_LUT_PAGE_SIZE = 4096,
MEMORY_LUT_PAGE_SHIFT = 12,
MEMORY_LUT_PAGE_MASK = MEMORY_LUT_PAGE_SIZE - 1,
MEMORY_LUT_SIZE = 0x100000,
MEMORY_LUT_SLOTS = MEMORY_LUT_SIZE * 3 * 2,
FASTMEM_LUT_PAGE_SIZE = 4096,
FASTMEM_LUT_PAGE_MASK = FASTMEM_LUT_PAGE_SIZE - 1,
FASTMEM_LUT_PAGE_SHIFT = 12,
FASTMEM_LUT_SIZE = 0x100000,
FASTMEM_LUT_SLOTS = FASTMEM_LUT_SIZE * 2,
};
#ifdef ENABLE_MMAP_FASTMEM
inline constexpr size_t FASTMEM_ARENA_SIZE = UINT64_C(0x100000000);
#endif
bool AllocateMemory(bool export_shared_memory, Error* error);
void ReleaseMemory();
bool ReallocateMemoryMap(bool export_shared_memory, Error* error);
void CleanupMemoryMap();
void Initialize();
void Shutdown();
void Reset();
bool DoState(StateWrapper& sw);
using MemoryReadHandler = u32 (*)(VirtualMemoryAddress address);
using MemoryWriteHandler = void (*)(VirtualMemoryAddress, u32);
void** GetMemoryHandlers(bool isolate_cache, bool swap_caches);
template<typename FP>
ALWAYS_INLINE_RELEASE FP* OffsetHandlerArray(void** handlers, MemoryAccessSize size, MemoryAccessType type)
{
return reinterpret_cast<FP*>(handlers +
(((static_cast<size_t>(size) * 2) + static_cast<size_t>(type)) * MEMORY_LUT_SIZE));
}
void* GetFastmemBase(bool isc);
void RemapFastmemViews();
bool CanUseFastmemForAddress(VirtualMemoryAddress address);
extern std::bitset<RAM_8MB_CODE_PAGE_COUNT> g_ram_code_bits;
extern u8* g_ram;
extern u8* g_unprotected_ram;
extern u32 g_ram_size;
extern u32 g_ram_mapped_size;
extern u32 g_ram_mask;
extern u8* g_bios;
extern std::array<TickCount, 3> g_exp1_access_time;
extern std::array<TickCount, 3> g_exp2_access_time;
extern std::array<TickCount, 3> g_bios_access_time;
extern std::array<TickCount, 3> g_cdrom_access_time;
extern std::array<TickCount, 3> g_spu_access_time;
ALWAYS_INLINE bool IsRAMAddress(PhysicalMemoryAddress address)
{
return address < RAM_MIRROR_END;
}
ALWAYS_INLINE u32 GetRAMCodePageIndex(PhysicalMemoryAddress address)
{
return (address & g_ram_mask) >> HOST_PAGE_SHIFT;
}
ALWAYS_INLINE bool IsRAMCodePage(u32 index)
{
return g_ram_code_bits[index];
}
void SetRAMCodePage(u32 index);
void ClearRAMCodePage(u32 index);
void ClearRAMCodePageFlags();
bool IsCodePageAddress(PhysicalMemoryAddress address);
bool HasCodePagesInRange(PhysicalMemoryAddress start_address, u32 size);
ALWAYS_INLINE TickCount GetDMARAMTickCount(u32 word_count)
{
return static_cast<TickCount>(word_count + ((word_count + 15) / 16));
}
const TickCount* GetMemoryAccessTimePtr(PhysicalMemoryAddress address, MemoryAccessSize size);
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);
bool IsMemoryRegionWritable(MemoryRegion region);
u8* GetMemoryRegionPointer(MemoryRegion region);
std::optional<PhysicalMemoryAddress> SearchMemory(PhysicalMemoryAddress start_address, const u8* pattern,
const u8* mask, u32 pattern_length);
void AddTTYCharacter(char ch);
void AddTTYString(std::string_view str);
bool InjectExecutable(std::span<const u8> buffer, bool set_pc, Error* error);
}