mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-23 06:15:38 +00:00
Support expanding RAM to 8MB (dev console)
This commit is contained in:
parent
d021850394
commit
e382df0d41
|
@ -71,8 +71,11 @@ union MEMCTRL
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
std::bitset<RAM_CODE_PAGE_COUNT> m_ram_code_bits{};
|
std::bitset<RAM_8MB_CODE_PAGE_COUNT> m_ram_code_bits{};
|
||||||
|
u32 m_ram_code_page_count = 0;
|
||||||
u8* g_ram = nullptr; // 2MB RAM
|
u8* g_ram = nullptr; // 2MB RAM
|
||||||
|
u32 g_ram_size = 0;
|
||||||
|
u32 g_ram_mask = 0;
|
||||||
u8 g_bios[BIOS_SIZE]{}; // 512K BIOS ROM
|
u8 g_bios[BIOS_SIZE]{}; // 512K BIOS ROM
|
||||||
|
|
||||||
static std::array<TickCount, 3> m_exp1_access_time = {};
|
static std::array<TickCount, 3> m_exp1_access_time = {};
|
||||||
|
@ -106,7 +109,7 @@ static constexpr auto m_fastmem_ram_mirrors =
|
||||||
static std::tuple<TickCount, TickCount, TickCount> CalculateMemoryTiming(MEMDELAY mem_delay, COMDELAY common_delay);
|
static std::tuple<TickCount, TickCount, TickCount> CalculateMemoryTiming(MEMDELAY mem_delay, COMDELAY common_delay);
|
||||||
static void RecalculateMemoryTimings();
|
static void RecalculateMemoryTimings();
|
||||||
|
|
||||||
static bool AllocateMemory();
|
static bool AllocateMemory(bool enable_8mb_ram);
|
||||||
static void ReleaseMemory();
|
static void ReleaseMemory();
|
||||||
|
|
||||||
static void SetCodePageFastmemProtection(u32 page_index, bool writable);
|
static void SetCodePageFastmemProtection(u32 page_index, bool writable);
|
||||||
|
@ -125,7 +128,7 @@ static void SetCodePageFastmemProtection(u32 page_index, bool writable);
|
||||||
|
|
||||||
bool Initialize()
|
bool Initialize()
|
||||||
{
|
{
|
||||||
if (!AllocateMemory())
|
if (!AllocateMemory(g_settings.enable_8mb_ram))
|
||||||
{
|
{
|
||||||
g_host_interface->ReportError("Failed to allocate memory");
|
g_host_interface->ReportError("Failed to allocate memory");
|
||||||
return false;
|
return false;
|
||||||
|
@ -153,7 +156,7 @@ void Shutdown()
|
||||||
|
|
||||||
void Reset()
|
void Reset()
|
||||||
{
|
{
|
||||||
std::memset(g_ram, 0, RAM_SIZE);
|
std::memset(g_ram, 0, g_ram_size);
|
||||||
m_MEMCTRL.exp1_base = 0x1F000000;
|
m_MEMCTRL.exp1_base = 0x1F000000;
|
||||||
m_MEMCTRL.exp2_base = 0x1F802000;
|
m_MEMCTRL.exp2_base = 0x1F802000;
|
||||||
m_MEMCTRL.exp1_delay_size.bits = 0x0013243F;
|
m_MEMCTRL.exp1_delay_size.bits = 0x0013243F;
|
||||||
|
@ -170,12 +173,25 @@ void Reset()
|
||||||
|
|
||||||
bool DoState(StateWrapper& sw)
|
bool DoState(StateWrapper& sw)
|
||||||
{
|
{
|
||||||
|
u32 ram_size = g_ram_size;
|
||||||
|
sw.DoEx(&ram_size, 52, static_cast<u32>(RAM_2MB_SIZE));
|
||||||
|
if (ram_size != g_ram_size)
|
||||||
|
{
|
||||||
|
const bool using_8mb_ram = (ram_size == RAM_8MB_SIZE);
|
||||||
|
ReleaseMemory();
|
||||||
|
if (!AllocateMemory(using_8mb_ram))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
UpdateFastmemViews(m_fastmem_mode);
|
||||||
|
CPU::UpdateFastmemBase();
|
||||||
|
}
|
||||||
|
|
||||||
sw.Do(&m_exp1_access_time);
|
sw.Do(&m_exp1_access_time);
|
||||||
sw.Do(&m_exp2_access_time);
|
sw.Do(&m_exp2_access_time);
|
||||||
sw.Do(&m_bios_access_time);
|
sw.Do(&m_bios_access_time);
|
||||||
sw.Do(&m_cdrom_access_time);
|
sw.Do(&m_cdrom_access_time);
|
||||||
sw.Do(&m_spu_access_time);
|
sw.Do(&m_spu_access_time);
|
||||||
sw.DoBytes(g_ram, RAM_SIZE);
|
sw.DoBytes(g_ram, g_ram_size);
|
||||||
sw.DoBytes(g_bios, BIOS_SIZE);
|
sw.DoBytes(g_bios, BIOS_SIZE);
|
||||||
sw.DoArray(m_MEMCTRL.regs, countof(m_MEMCTRL.regs));
|
sw.DoArray(m_MEMCTRL.regs, countof(m_MEMCTRL.regs));
|
||||||
sw.Do(&m_ram_size_reg);
|
sw.Do(&m_ram_size_reg);
|
||||||
|
@ -255,7 +271,7 @@ void RecalculateMemoryTimings()
|
||||||
m_spu_access_time[2] + 1);
|
m_spu_access_time[2] + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AllocateMemory()
|
bool AllocateMemory(bool enable_8mb_ram)
|
||||||
{
|
{
|
||||||
if (!m_memory_arena.Create(MEMORY_ARENA_SIZE, true, false))
|
if (!m_memory_arena.Create(MEMORY_ARENA_SIZE, true, false))
|
||||||
{
|
{
|
||||||
|
@ -264,14 +280,20 @@ bool AllocateMemory()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the base views.
|
// Create the base views.
|
||||||
g_ram = static_cast<u8*>(m_memory_arena.CreateViewPtr(MEMORY_ARENA_RAM_OFFSET, RAM_SIZE, true, false));
|
const u32 ram_size = enable_8mb_ram ? RAM_8MB_SIZE : RAM_2MB_SIZE;
|
||||||
|
const u32 ram_mask = enable_8mb_ram ? RAM_8MB_MASK : RAM_2MB_MASK;
|
||||||
|
g_ram = static_cast<u8*>(m_memory_arena.CreateViewPtr(MEMORY_ARENA_RAM_OFFSET, ram_size, true, false));
|
||||||
if (!g_ram)
|
if (!g_ram)
|
||||||
{
|
{
|
||||||
Log_ErrorPrint("Failed to create base views of memory");
|
Log_ErrorPrintf("Failed to create base views of memory (%u bytes RAM)", ram_size);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Log_InfoPrintf("RAM is %u bytes at %p", RAM_SIZE, g_ram);
|
g_ram_mask = ram_mask;
|
||||||
|
g_ram_size = ram_size;
|
||||||
|
m_ram_code_page_count = enable_8mb_ram ? RAM_8MB_CODE_PAGE_COUNT : RAM_2MB_CODE_PAGE_COUNT;
|
||||||
|
|
||||||
|
Log_InfoPrintf("RAM is %u bytes at %p", g_ram_size, g_ram);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,8 +301,10 @@ void ReleaseMemory()
|
||||||
{
|
{
|
||||||
if (g_ram)
|
if (g_ram)
|
||||||
{
|
{
|
||||||
m_memory_arena.ReleaseViewPtr(g_ram, RAM_SIZE);
|
m_memory_arena.ReleaseViewPtr(g_ram, g_ram_size);
|
||||||
g_ram = nullptr;
|
g_ram = nullptr;
|
||||||
|
g_ram_mask = 0;
|
||||||
|
g_ram_size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_memory_arena.Destroy();
|
m_memory_arena.Destroy();
|
||||||
|
@ -354,15 +378,15 @@ void UpdateFastmemViews(CPUFastmemMode mode)
|
||||||
|
|
||||||
auto MapRAM = [](u32 base_address) {
|
auto MapRAM = [](u32 base_address) {
|
||||||
u8* map_address = m_fastmem_base + base_address;
|
u8* map_address = m_fastmem_base + base_address;
|
||||||
auto view = m_memory_arena.CreateView(MEMORY_ARENA_RAM_OFFSET, RAM_SIZE, true, false, map_address);
|
auto view = m_memory_arena.CreateView(MEMORY_ARENA_RAM_OFFSET, g_ram_size, true, false, map_address);
|
||||||
if (!view)
|
if (!view)
|
||||||
{
|
{
|
||||||
Log_ErrorPrintf("Failed to map RAM at fastmem area %p (offset 0x%08X)", map_address, RAM_SIZE);
|
Log_ErrorPrintf("Failed to map RAM at fastmem area %p (offset 0x%08X)", map_address, g_ram_size);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// mark all pages with code as non-writable
|
// mark all pages with code as non-writable
|
||||||
for (u32 i = 0; i < RAM_CODE_PAGE_COUNT; i++)
|
for (u32 i = 0; i < m_ram_code_page_count; i++)
|
||||||
{
|
{
|
||||||
if (m_ram_code_bits[i])
|
if (m_ram_code_bits[i])
|
||||||
{
|
{
|
||||||
|
@ -386,7 +410,7 @@ void UpdateFastmemViews(CPUFastmemMode mode)
|
||||||
auto view = m_memory_arena.CreateReservedView(end_address_inclusive - start_address + 1, map_address);
|
auto view = m_memory_arena.CreateReservedView(end_address_inclusive - start_address + 1, map_address);
|
||||||
if (!view)
|
if (!view)
|
||||||
{
|
{
|
||||||
Log_ErrorPrintf("Failed to map RAM at fastmem area %p (offset 0x%08X)", map_address, RAM_SIZE);
|
Log_ErrorPrintf("Failed to map reserved region %p (size 0x%08X)", map_address, end_address_inclusive - start_address + 1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -432,7 +456,7 @@ void UpdateFastmemViews(CPUFastmemMode mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
auto MapRAM = [](u32 base_address) {
|
auto MapRAM = [](u32 base_address) {
|
||||||
for (u32 address = 0; address < RAM_SIZE; address += HOST_PAGE_SIZE)
|
for (u32 address = 0; address < g_ram_size; address += HOST_PAGE_SIZE)
|
||||||
{
|
{
|
||||||
SetLUTFastmemPage(base_address + address, &g_ram[address],
|
SetLUTFastmemPage(base_address + address, &g_ram[address],
|
||||||
!m_ram_code_bits[FastmemAddressToLUTPageIndex(address)]);
|
!m_ram_code_bits[FastmemAddressToLUTPageIndex(address)]);
|
||||||
|
@ -474,7 +498,7 @@ bool CanUseFastmemForAddress(VirtualMemoryAddress address)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
case CPUFastmemMode::LUT:
|
case CPUFastmemMode::LUT:
|
||||||
return (paddr < RAM_SIZE);
|
return (paddr < g_ram_size);
|
||||||
|
|
||||||
case CPUFastmemMode::Disabled:
|
case CPUFastmemMode::Disabled:
|
||||||
default:
|
default:
|
||||||
|
@ -556,7 +580,7 @@ void ClearRAMCodePageFlags()
|
||||||
|
|
||||||
if (m_fastmem_mode == CPUFastmemMode::LUT)
|
if (m_fastmem_mode == CPUFastmemMode::LUT)
|
||||||
{
|
{
|
||||||
for (u32 i = 0; i < RAM_CODE_PAGE_COUNT; i++)
|
for (u32 i = 0; i < m_ram_code_page_count; i++)
|
||||||
{
|
{
|
||||||
const u32 addr = (i * HOST_PAGE_SIZE);
|
const u32 addr = (i * HOST_PAGE_SIZE);
|
||||||
for (u32 mirror_start : m_fastmem_ram_mirrors)
|
for (u32 mirror_start : m_fastmem_ram_mirrors)
|
||||||
|
@ -567,7 +591,7 @@ void ClearRAMCodePageFlags()
|
||||||
|
|
||||||
bool IsCodePageAddress(PhysicalMemoryAddress address)
|
bool IsCodePageAddress(PhysicalMemoryAddress address)
|
||||||
{
|
{
|
||||||
return IsRAMAddress(address) ? m_ram_code_bits[(address & RAM_MASK) / HOST_PAGE_SIZE] : false;
|
return IsRAMAddress(address) ? m_ram_code_bits[(address & g_ram_mask) / HOST_PAGE_SIZE] : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HasCodePagesInRange(PhysicalMemoryAddress start_address, u32 size)
|
bool HasCodePagesInRange(PhysicalMemoryAddress start_address, u32 size)
|
||||||
|
@ -575,7 +599,7 @@ bool HasCodePagesInRange(PhysicalMemoryAddress start_address, u32 size)
|
||||||
if (!IsRAMAddress(start_address))
|
if (!IsRAMAddress(start_address))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
start_address = (start_address & RAM_MASK);
|
start_address = (start_address & g_ram_mask);
|
||||||
|
|
||||||
const u32 end_address = start_address + size;
|
const u32 end_address = start_address + size;
|
||||||
while (start_address < end_address)
|
while (start_address < end_address)
|
||||||
|
@ -592,10 +616,10 @@ bool HasCodePagesInRange(PhysicalMemoryAddress start_address, u32 size)
|
||||||
|
|
||||||
std::optional<MemoryRegion> GetMemoryRegionForAddress(PhysicalMemoryAddress address)
|
std::optional<MemoryRegion> GetMemoryRegionForAddress(PhysicalMemoryAddress address)
|
||||||
{
|
{
|
||||||
if (address < RAM_SIZE)
|
if (address < RAM_2MB_SIZE)
|
||||||
return MemoryRegion::RAM;
|
return MemoryRegion::RAM;
|
||||||
else if (address < RAM_MIRROR_END)
|
else if (address < RAM_MIRROR_END)
|
||||||
return static_cast<MemoryRegion>(static_cast<u32>(MemoryRegion::RAM) + (address / RAM_SIZE));
|
return static_cast<MemoryRegion>(static_cast<u32>(MemoryRegion::RAM) + (address / RAM_2MB_SIZE));
|
||||||
else if (address >= EXP1_BASE && address < (EXP1_BASE + EXP1_SIZE))
|
else if (address >= EXP1_BASE && address < (EXP1_BASE + EXP1_SIZE))
|
||||||
return MemoryRegion::EXP1;
|
return MemoryRegion::EXP1;
|
||||||
else if (address >= CPU::DCACHE_LOCATION && address < (CPU::DCACHE_LOCATION + CPU::DCACHE_SIZE))
|
else if (address >= CPU::DCACHE_LOCATION && address < (CPU::DCACHE_LOCATION + CPU::DCACHE_SIZE))
|
||||||
|
@ -609,10 +633,10 @@ std::optional<MemoryRegion> GetMemoryRegionForAddress(PhysicalMemoryAddress addr
|
||||||
static constexpr std::array<std::pair<PhysicalMemoryAddress, PhysicalMemoryAddress>,
|
static constexpr std::array<std::pair<PhysicalMemoryAddress, PhysicalMemoryAddress>,
|
||||||
static_cast<u32>(MemoryRegion::Count)>
|
static_cast<u32>(MemoryRegion::Count)>
|
||||||
s_code_region_ranges = {{
|
s_code_region_ranges = {{
|
||||||
{0, RAM_SIZE},
|
{0, RAM_2MB_SIZE},
|
||||||
{RAM_SIZE, RAM_SIZE * 2},
|
{RAM_2MB_SIZE, RAM_2MB_SIZE * 2},
|
||||||
{RAM_SIZE * 2, RAM_SIZE * 3},
|
{RAM_2MB_SIZE * 2, RAM_2MB_SIZE * 3},
|
||||||
{RAM_SIZE * 3, RAM_MIRROR_END},
|
{RAM_2MB_SIZE * 3, RAM_MIRROR_END},
|
||||||
{EXP1_BASE, EXP1_BASE + EXP1_SIZE},
|
{EXP1_BASE, EXP1_BASE + EXP1_SIZE},
|
||||||
{CPU::DCACHE_LOCATION, CPU::DCACHE_LOCATION + CPU::DCACHE_SIZE},
|
{CPU::DCACHE_LOCATION, CPU::DCACHE_LOCATION + CPU::DCACHE_SIZE},
|
||||||
{BIOS_BASE, BIOS_BASE + BIOS_SIZE},
|
{BIOS_BASE, BIOS_BASE + BIOS_SIZE},
|
||||||
|
@ -633,11 +657,17 @@ u8* GetMemoryRegionPointer(MemoryRegion region)
|
||||||
switch (region)
|
switch (region)
|
||||||
{
|
{
|
||||||
case MemoryRegion::RAM:
|
case MemoryRegion::RAM:
|
||||||
case MemoryRegion::RAMMirror1:
|
|
||||||
case MemoryRegion::RAMMirror2:
|
|
||||||
case MemoryRegion::RAMMirror3:
|
|
||||||
return g_ram;
|
return g_ram;
|
||||||
|
|
||||||
|
case MemoryRegion::RAMMirror1:
|
||||||
|
return (g_ram + (RAM_2MB_SIZE & g_ram_mask));
|
||||||
|
|
||||||
|
case MemoryRegion::RAMMirror2:
|
||||||
|
return (g_ram + ((RAM_2MB_SIZE * 2) & g_ram_mask));
|
||||||
|
|
||||||
|
case MemoryRegion::RAMMirror3:
|
||||||
|
return (g_ram + ((RAM_8MB_SIZE * 3) & g_ram_mask));
|
||||||
|
|
||||||
case MemoryRegion::EXP1:
|
case MemoryRegion::EXP1:
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
@ -734,14 +764,13 @@ static TickCount DoInvalidAccess(MemoryAccessType type, MemoryAccessSize size, P
|
||||||
if (type == MemoryAccessType::Read)
|
if (type == MemoryAccessType::Read)
|
||||||
value = UINT32_C(0xFFFFFFFF);
|
value = UINT32_C(0xFFFFFFFF);
|
||||||
|
|
||||||
return 1;
|
return (type == MemoryAccessType::Read) ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<MemoryAccessType type, MemoryAccessSize size>
|
template<MemoryAccessType type, MemoryAccessSize size>
|
||||||
ALWAYS_INLINE static TickCount DoRAMAccess(u32 offset, u32& value)
|
ALWAYS_INLINE static TickCount DoRAMAccess(u32 offset, u32& value)
|
||||||
{
|
{
|
||||||
// TODO: Configurable mirroring.
|
offset &= g_ram_mask;
|
||||||
offset &= UINT32_C(0x1FFFFF);
|
|
||||||
if constexpr (type == MemoryAccessType::Read)
|
if constexpr (type == MemoryAccessType::Read)
|
||||||
{
|
{
|
||||||
if constexpr (size == MemoryAccessSize::Byte)
|
if constexpr (size == MemoryAccessSize::Byte)
|
||||||
|
@ -1270,7 +1299,7 @@ ALWAYS_INLINE_RELEASE bool DoInstructionRead(PhysicalMemoryAddress address, void
|
||||||
|
|
||||||
if (address < RAM_MIRROR_END)
|
if (address < RAM_MIRROR_END)
|
||||||
{
|
{
|
||||||
std::memcpy(data, &g_ram[address & RAM_MASK], sizeof(u32) * word_count);
|
std::memcpy(data, &g_ram[address & g_ram_mask], sizeof(u32) * word_count);
|
||||||
if constexpr (add_ticks)
|
if constexpr (add_ticks)
|
||||||
g_state.pending_ticks += (icache_read ? 1 : RAM_READ_TICKS) * word_count;
|
g_state.pending_ticks += (icache_read ? 1 : RAM_READ_TICKS) * word_count;
|
||||||
|
|
||||||
|
@ -1523,7 +1552,7 @@ static ALWAYS_INLINE TickCount DoMemoryAccess(VirtualMemoryAddress address, u32&
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (address < 0x800000)
|
if (address < RAM_MIRROR_END)
|
||||||
{
|
{
|
||||||
return DoRAMAccess<type, size>(address, value);
|
return DoRAMAccess<type, size>(address, value);
|
||||||
}
|
}
|
||||||
|
@ -1860,7 +1889,7 @@ void* GetDirectReadMemoryPointer(VirtualMemoryAddress address, MemoryAccessSize
|
||||||
if (read_ticks)
|
if (read_ticks)
|
||||||
*read_ticks = RAM_READ_TICKS;
|
*read_ticks = RAM_READ_TICKS;
|
||||||
|
|
||||||
return &g_ram[paddr & RAM_MASK];
|
return &g_ram[paddr & g_ram_mask];
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((paddr & DCACHE_LOCATION_MASK) == DCACHE_LOCATION)
|
if ((paddr & DCACHE_LOCATION_MASK) == DCACHE_LOCATION)
|
||||||
|
|
|
@ -15,8 +15,10 @@ namespace Bus {
|
||||||
enum : u32
|
enum : u32
|
||||||
{
|
{
|
||||||
RAM_BASE = 0x00000000,
|
RAM_BASE = 0x00000000,
|
||||||
RAM_SIZE = 0x200000,
|
RAM_2MB_SIZE = 0x200000,
|
||||||
RAM_MASK = RAM_SIZE - 1,
|
RAM_2MB_MASK = RAM_2MB_SIZE - 1,
|
||||||
|
RAM_8MB_SIZE = 0x800000,
|
||||||
|
RAM_8MB_MASK = RAM_8MB_SIZE - 1,
|
||||||
RAM_MIRROR_END = 0x800000,
|
RAM_MIRROR_END = 0x800000,
|
||||||
EXP1_BASE = 0x1F000000,
|
EXP1_BASE = 0x1F000000,
|
||||||
EXP1_SIZE = 0x800000,
|
EXP1_SIZE = 0x800000,
|
||||||
|
@ -78,7 +80,7 @@ enum : TickCount
|
||||||
enum : size_t
|
enum : size_t
|
||||||
{
|
{
|
||||||
// Our memory arena contains storage for RAM.
|
// Our memory arena contains storage for RAM.
|
||||||
MEMORY_ARENA_SIZE = RAM_SIZE,
|
MEMORY_ARENA_SIZE = RAM_8MB_SIZE,
|
||||||
|
|
||||||
// Offsets within the memory arena.
|
// Offsets within the memory arena.
|
||||||
MEMORY_ARENA_RAM_OFFSET = 0,
|
MEMORY_ARENA_RAM_OFFSET = 0,
|
||||||
|
@ -87,8 +89,12 @@ enum : size_t
|
||||||
// Fastmem region size is 4GB to cover the entire 32-bit address space.
|
// Fastmem region size is 4GB to cover the entire 32-bit address space.
|
||||||
FASTMEM_REGION_SIZE = UINT64_C(0x100000000),
|
FASTMEM_REGION_SIZE = UINT64_C(0x100000000),
|
||||||
#endif
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
RAM_CODE_PAGE_COUNT = (RAM_SIZE + (HOST_PAGE_SIZE + 1)) / HOST_PAGE_SIZE,
|
enum : u32
|
||||||
|
{
|
||||||
|
RAM_2MB_CODE_PAGE_COUNT = (RAM_2MB_SIZE + (HOST_PAGE_SIZE + 1)) / HOST_PAGE_SIZE,
|
||||||
|
RAM_8MB_CODE_PAGE_COUNT = (RAM_8MB_SIZE + (HOST_PAGE_SIZE + 1)) / HOST_PAGE_SIZE,
|
||||||
|
|
||||||
FASTMEM_LUT_NUM_PAGES = 0x100000, // 0x100000000 >> 12
|
FASTMEM_LUT_NUM_PAGES = 0x100000, // 0x100000000 >> 12
|
||||||
FASTMEM_LUT_NUM_SLOTS = FASTMEM_LUT_NUM_PAGES * 2,
|
FASTMEM_LUT_NUM_SLOTS = FASTMEM_LUT_NUM_PAGES * 2,
|
||||||
|
@ -107,8 +113,10 @@ bool CanUseFastmemForAddress(VirtualMemoryAddress address);
|
||||||
void SetExpansionROM(std::vector<u8> data);
|
void SetExpansionROM(std::vector<u8> data);
|
||||||
void SetBIOS(const std::vector<u8>& image);
|
void SetBIOS(const std::vector<u8>& image);
|
||||||
|
|
||||||
extern std::bitset<RAM_CODE_PAGE_COUNT> m_ram_code_bits;
|
extern std::bitset<RAM_8MB_CODE_PAGE_COUNT> m_ram_code_bits;
|
||||||
extern u8* g_ram; // 2MB RAM
|
extern u8* g_ram; // 2MB-8MB RAM
|
||||||
|
extern u32 g_ram_size; // Active size of RAM.
|
||||||
|
extern u32 g_ram_mask; // Active address bits for RAM.
|
||||||
extern u8 g_bios[BIOS_SIZE]; // 512K BIOS ROM
|
extern u8 g_bios[BIOS_SIZE]; // 512K BIOS ROM
|
||||||
|
|
||||||
/// Returns true if the address specified is writable (RAM).
|
/// Returns true if the address specified is writable (RAM).
|
||||||
|
@ -120,7 +128,7 @@ ALWAYS_INLINE static bool IsRAMAddress(PhysicalMemoryAddress address)
|
||||||
/// Returns the code page index for a RAM address.
|
/// Returns the code page index for a RAM address.
|
||||||
ALWAYS_INLINE static u32 GetRAMCodePageIndex(PhysicalMemoryAddress address)
|
ALWAYS_INLINE static u32 GetRAMCodePageIndex(PhysicalMemoryAddress address)
|
||||||
{
|
{
|
||||||
return (address & RAM_MASK) / HOST_PAGE_SIZE;
|
return (address & g_ram_mask) / HOST_PAGE_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if the specified page contains code.
|
/// Returns true if the specified page contains code.
|
||||||
|
|
|
@ -54,7 +54,7 @@ static T DoMemoryRead(PhysicalMemoryAddress address)
|
||||||
|
|
||||||
if (address < Bus::RAM_MIRROR_END)
|
if (address < Bus::RAM_MIRROR_END)
|
||||||
{
|
{
|
||||||
std::memcpy(&result, &Bus::g_ram[address & Bus::RAM_MASK], sizeof(result));
|
std::memcpy(&result, &Bus::g_ram[address & Bus::g_ram_mask], sizeof(result));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,12 +84,12 @@ static void DoMemoryWrite(PhysicalMemoryAddress address, T value)
|
||||||
{
|
{
|
||||||
// Only invalidate code when it changes.
|
// Only invalidate code when it changes.
|
||||||
T old_value;
|
T old_value;
|
||||||
std::memcpy(&old_value, &Bus::g_ram[address & Bus::RAM_MASK], sizeof(old_value));
|
std::memcpy(&old_value, &Bus::g_ram[address & Bus::g_ram_mask], sizeof(old_value));
|
||||||
if (old_value != value)
|
if (old_value != value)
|
||||||
{
|
{
|
||||||
std::memcpy(&Bus::g_ram[address & Bus::RAM_MASK], &value, sizeof(value));
|
std::memcpy(&Bus::g_ram[address & Bus::g_ram_mask], &value, sizeof(value));
|
||||||
|
|
||||||
const u32 code_page_index = Bus::GetRAMCodePageIndex(address & Bus::RAM_MASK);
|
const u32 code_page_index = Bus::GetRAMCodePageIndex(address & Bus::g_ram_mask);
|
||||||
if (Bus::IsRAMCodePage(code_page_index))
|
if (Bus::IsRAMCodePage(code_page_index))
|
||||||
CPU::CodeCache::InvalidateBlocksWithPageIndex(code_page_index);
|
CPU::CodeCache::InvalidateBlocksWithPageIndex(code_page_index);
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,7 +55,7 @@ ALWAYS_INLINE static u32 GetFastMapIndex(u32 pc)
|
||||||
{
|
{
|
||||||
return ((pc & PHYSICAL_MEMORY_ADDRESS_MASK) >= Bus::BIOS_BASE) ?
|
return ((pc & PHYSICAL_MEMORY_ADDRESS_MASK) >= Bus::BIOS_BASE) ?
|
||||||
(FAST_MAP_RAM_SLOT_COUNT + ((pc & Bus::BIOS_MASK) >> 2)) :
|
(FAST_MAP_RAM_SLOT_COUNT + ((pc & Bus::BIOS_MASK) >> 2)) :
|
||||||
((pc & Bus::RAM_MASK) >> 2);
|
((pc & Bus::g_ram_mask) >> 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void CompileDispatcher();
|
static void CompileDispatcher();
|
||||||
|
@ -102,7 +102,7 @@ static void UnlinkBlock(CodeBlock* block);
|
||||||
static void ClearState();
|
static void ClearState();
|
||||||
|
|
||||||
static BlockMap s_blocks;
|
static BlockMap s_blocks;
|
||||||
static std::array<std::vector<CodeBlock*>, Bus::RAM_CODE_PAGE_COUNT> m_ram_block_map;
|
static std::array<std::vector<CodeBlock*>, Bus::RAM_8MB_CODE_PAGE_COUNT> m_ram_block_map;
|
||||||
|
|
||||||
#ifdef WITH_RECOMPILER
|
#ifdef WITH_RECOMPILER
|
||||||
static HostCodeMap s_host_code_map;
|
static HostCodeMap s_host_code_map;
|
||||||
|
@ -694,7 +694,7 @@ void FastCompileBlockFunction()
|
||||||
|
|
||||||
void InvalidateBlocksWithPageIndex(u32 page_index)
|
void InvalidateBlocksWithPageIndex(u32 page_index)
|
||||||
{
|
{
|
||||||
DebugAssert(page_index < Bus::RAM_CODE_PAGE_COUNT);
|
DebugAssert(page_index < Bus::RAM_8MB_CODE_PAGE_COUNT);
|
||||||
auto& blocks = m_ram_block_map[page_index];
|
auto& blocks = m_ram_block_map[page_index];
|
||||||
for (CodeBlock* block : blocks)
|
for (CodeBlock* block : blocks)
|
||||||
{
|
{
|
||||||
|
|
|
@ -18,7 +18,7 @@ namespace CPU {
|
||||||
|
|
||||||
enum : u32
|
enum : u32
|
||||||
{
|
{
|
||||||
FAST_MAP_RAM_SLOT_COUNT = Bus::RAM_SIZE / 4,
|
FAST_MAP_RAM_SLOT_COUNT = Bus::RAM_8MB_SIZE / 4,
|
||||||
FAST_MAP_BIOS_SLOT_COUNT = Bus::BIOS_SIZE / 4,
|
FAST_MAP_BIOS_SLOT_COUNT = Bus::BIOS_SIZE / 4,
|
||||||
FAST_MAP_TOTAL_SLOT_COUNT = FAST_MAP_RAM_SLOT_COUNT + FAST_MAP_BIOS_SLOT_COUNT,
|
FAST_MAP_TOTAL_SLOT_COUNT = FAST_MAP_RAM_SLOT_COUNT + FAST_MAP_BIOS_SLOT_COUNT,
|
||||||
};
|
};
|
||||||
|
|
|
@ -180,6 +180,9 @@ bool DoState(StateWrapper& sw)
|
||||||
sw.Do(&g_state.icache_data);
|
sw.Do(&g_state.icache_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sw.IsReading())
|
||||||
|
UpdateFastmemBase();
|
||||||
|
|
||||||
return !sw.HasError();
|
return !sw.HasError();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2868,7 +2868,7 @@ CodeGenerator::SpeculativeValue CodeGenerator::SpeculativeReadMemory(VirtualMemo
|
||||||
|
|
||||||
if (Bus::IsRAMAddress(phys_addr))
|
if (Bus::IsRAMAddress(phys_addr))
|
||||||
{
|
{
|
||||||
u32 ram_offset = phys_addr & Bus::RAM_MASK;
|
u32 ram_offset = phys_addr & Bus::g_ram_mask;
|
||||||
std::memcpy(&value, &Bus::g_ram[ram_offset], sizeof(value));
|
std::memcpy(&value, &Bus::g_ram[ram_offset], sizeof(value));
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2004,7 +2004,7 @@ CodeCache::DispatcherFunction CodeGenerator::CompileDispatcher()
|
||||||
m_emit->str(a32::r0, a32::MemOperand(GetHostReg32(RCPUPTR), offsetof(State, current_instruction_pc)));
|
m_emit->str(a32::r0, a32::MemOperand(GetHostReg32(RCPUPTR), offsetof(State, current_instruction_pc)));
|
||||||
|
|
||||||
// r1 <- (pc & RAM_MASK) >> 2
|
// r1 <- (pc & RAM_MASK) >> 2
|
||||||
m_emit->and_(a32::r1, a32::r0, Bus::RAM_MASK);
|
m_emit->and_(a32::r1, a32::r0, Bus::g_ram_mask);
|
||||||
m_emit->lsr(a32::r1, a32::r1, 2);
|
m_emit->lsr(a32::r1, a32::r1, 2);
|
||||||
|
|
||||||
// r2 <- ((pc & BIOS_MASK) >> 2) + FAST_MAP_RAM_SLOT_COUNT
|
// r2 <- ((pc & BIOS_MASK) >> 2) + FAST_MAP_RAM_SLOT_COUNT
|
||||||
|
|
|
@ -2219,7 +2219,7 @@ CodeCache::DispatcherFunction CodeGenerator::CompileDispatcher()
|
||||||
m_emit->str(a64::w8, a64::MemOperand(GetHostReg64(RCPUPTR), offsetof(State, current_instruction_pc)));
|
m_emit->str(a64::w8, a64::MemOperand(GetHostReg64(RCPUPTR), offsetof(State, current_instruction_pc)));
|
||||||
|
|
||||||
// w9 <- (pc & RAM_MASK) >> 2
|
// w9 <- (pc & RAM_MASK) >> 2
|
||||||
m_emit->and_(a64::w9, a64::w8, Bus::RAM_MASK);
|
m_emit->and_(a64::w9, a64::w8, Bus::g_ram_mask);
|
||||||
m_emit->lsr(a64::w9, a64::w9, 2);
|
m_emit->lsr(a64::w9, a64::w9, 2);
|
||||||
|
|
||||||
// w10 <- ((pc & BIOS_MASK) >> 2) + FAST_MAP_RAM_SLOT_COUNT
|
// w10 <- ((pc & BIOS_MASK) >> 2) + FAST_MAP_RAM_SLOT_COUNT
|
||||||
|
|
|
@ -44,7 +44,7 @@ Value CodeGenerator::EmitLoadGuestMemory(const CodeBlockInstruction& cbi, const
|
||||||
if (g_settings.IsUsingFastmem() && Bus::IsRAMAddress(static_cast<u32>(address.constant_value)))
|
if (g_settings.IsUsingFastmem() && Bus::IsRAMAddress(static_cast<u32>(address.constant_value)))
|
||||||
{
|
{
|
||||||
// have to mask away the high bits for mirrors, since we don't map them in fastmem
|
// have to mask away the high bits for mirrors, since we don't map them in fastmem
|
||||||
EmitLoadGuestRAMFastmem(Value::FromConstantU32(static_cast<u32>(address.constant_value) & Bus::RAM_MASK), size,
|
EmitLoadGuestRAMFastmem(Value::FromConstantU32(static_cast<u32>(address.constant_value) & Bus::g_ram_mask), size,
|
||||||
result);
|
result);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -2968,7 +2968,7 @@ CodeCache::DispatcherFunction CodeGenerator::CompileDispatcher()
|
||||||
|
|
||||||
// ebx <- (pc & RAM_MASK) >> 2
|
// ebx <- (pc & RAM_MASK) >> 2
|
||||||
m_emit->mov(m_emit->ebx, m_emit->eax);
|
m_emit->mov(m_emit->ebx, m_emit->eax);
|
||||||
m_emit->and_(m_emit->ebx, Bus::RAM_MASK);
|
m_emit->and_(m_emit->ebx, Bus::g_ram_mask);
|
||||||
m_emit->shr(m_emit->ebx, 2);
|
m_emit->shr(m_emit->ebx, 2);
|
||||||
|
|
||||||
// ecx <- ((pc & BIOS_MASK) >> 2) + FAST_MAP_RAM_SLOT_COUNT
|
// ecx <- ((pc & BIOS_MASK) >> 2) + FAST_MAP_RAM_SLOT_COUNT
|
||||||
|
|
|
@ -17,6 +17,11 @@
|
||||||
#endif
|
#endif
|
||||||
Log_SetChannel(DMA);
|
Log_SetChannel(DMA);
|
||||||
|
|
||||||
|
static u32 GetAddressMask()
|
||||||
|
{
|
||||||
|
return Bus::g_ram_mask & 0xFFFFFFFCu;
|
||||||
|
}
|
||||||
|
|
||||||
DMA g_dma;
|
DMA g_dma;
|
||||||
|
|
||||||
DMA::DMA() = default;
|
DMA::DMA() = default;
|
||||||
|
@ -293,6 +298,7 @@ TickCount DMA::GetTransferHaltTicks() const
|
||||||
bool DMA::TransferChannel(Channel channel)
|
bool DMA::TransferChannel(Channel channel)
|
||||||
{
|
{
|
||||||
ChannelState& cs = m_state[static_cast<u32>(channel)];
|
ChannelState& cs = m_state[static_cast<u32>(channel)];
|
||||||
|
const u32 mask = GetAddressMask();
|
||||||
|
|
||||||
const bool copy_to_device = cs.channel_control.copy_to_device;
|
const bool copy_to_device = cs.channel_control.copy_to_device;
|
||||||
|
|
||||||
|
@ -307,13 +313,13 @@ bool DMA::TransferChannel(Channel channel)
|
||||||
{
|
{
|
||||||
const u32 word_count = cs.block_control.manual.GetWordCount();
|
const u32 word_count = cs.block_control.manual.GetWordCount();
|
||||||
Log_DebugPrintf("DMA%u: Copying %u words %s 0x%08X", static_cast<u32>(channel), word_count,
|
Log_DebugPrintf("DMA%u: Copying %u words %s 0x%08X", static_cast<u32>(channel), word_count,
|
||||||
copy_to_device ? "from" : "to", current_address & ADDRESS_MASK);
|
copy_to_device ? "from" : "to", current_address & mask);
|
||||||
|
|
||||||
TickCount used_ticks;
|
TickCount used_ticks;
|
||||||
if (copy_to_device)
|
if (copy_to_device)
|
||||||
used_ticks = TransferMemoryToDevice(channel, current_address & ADDRESS_MASK, increment, word_count);
|
used_ticks = TransferMemoryToDevice(channel, current_address & mask, increment, word_count);
|
||||||
else
|
else
|
||||||
used_ticks = TransferDeviceToMemory(channel, current_address & ADDRESS_MASK, increment, word_count);
|
used_ticks = TransferDeviceToMemory(channel, current_address & mask, increment, word_count);
|
||||||
|
|
||||||
CPU::AddPendingTicks(used_ticks);
|
CPU::AddPendingTicks(used_ticks);
|
||||||
}
|
}
|
||||||
|
@ -328,20 +334,20 @@ bool DMA::TransferChannel(Channel channel)
|
||||||
}
|
}
|
||||||
|
|
||||||
Log_DebugPrintf("DMA%u: Copying linked list starting at 0x%08X to device", static_cast<u32>(channel),
|
Log_DebugPrintf("DMA%u: Copying linked list starting at 0x%08X to device", static_cast<u32>(channel),
|
||||||
current_address & ADDRESS_MASK);
|
current_address & mask);
|
||||||
|
|
||||||
u8* ram_pointer = Bus::g_ram;
|
u8* ram_pointer = Bus::g_ram;
|
||||||
TickCount remaining_ticks = GetTransferSliceTicks();
|
TickCount remaining_ticks = GetTransferSliceTicks();
|
||||||
while (cs.request && remaining_ticks > 0)
|
while (cs.request && remaining_ticks > 0)
|
||||||
{
|
{
|
||||||
u32 header;
|
u32 header;
|
||||||
std::memcpy(&header, &ram_pointer[current_address & ADDRESS_MASK], sizeof(header));
|
std::memcpy(&header, &ram_pointer[current_address & mask], sizeof(header));
|
||||||
CPU::AddPendingTicks(10);
|
CPU::AddPendingTicks(10);
|
||||||
remaining_ticks -= 10;
|
remaining_ticks -= 10;
|
||||||
|
|
||||||
const u32 word_count = header >> 24;
|
const u32 word_count = header >> 24;
|
||||||
const u32 next_address = header & UINT32_C(0x00FFFFFF);
|
const u32 next_address = header & UINT32_C(0x00FFFFFF);
|
||||||
Log_TracePrintf(" .. linked list entry at 0x%08X size=%u(%u words) next=0x%08X", current_address & ADDRESS_MASK,
|
Log_TracePrintf(" .. linked list entry at 0x%08X size=%u(%u words) next=0x%08X", current_address & mask,
|
||||||
word_count * UINT32_C(4), word_count, next_address);
|
word_count * UINT32_C(4), word_count, next_address);
|
||||||
if (word_count > 0)
|
if (word_count > 0)
|
||||||
{
|
{
|
||||||
|
@ -349,7 +355,7 @@ bool DMA::TransferChannel(Channel channel)
|
||||||
remaining_ticks -= 5;
|
remaining_ticks -= 5;
|
||||||
|
|
||||||
const TickCount block_ticks =
|
const TickCount block_ticks =
|
||||||
TransferMemoryToDevice(channel, (current_address + sizeof(header)) & ADDRESS_MASK, 4, word_count);
|
TransferMemoryToDevice(channel, (current_address + sizeof(header)) & mask, 4, word_count);
|
||||||
CPU::AddPendingTicks(block_ticks);
|
CPU::AddPendingTicks(block_ticks);
|
||||||
remaining_ticks -= block_ticks;
|
remaining_ticks -= block_ticks;
|
||||||
}
|
}
|
||||||
|
@ -383,7 +389,7 @@ bool DMA::TransferChannel(Channel channel)
|
||||||
Log_DebugPrintf("DMA%u: Copying %u blocks of size %u (%u total words) %s 0x%08X", static_cast<u32>(channel),
|
Log_DebugPrintf("DMA%u: Copying %u blocks of size %u (%u total words) %s 0x%08X", static_cast<u32>(channel),
|
||||||
cs.block_control.request.GetBlockCount(), cs.block_control.request.GetBlockSize(),
|
cs.block_control.request.GetBlockCount(), cs.block_control.request.GetBlockSize(),
|
||||||
cs.block_control.request.GetBlockCount() * cs.block_control.request.GetBlockSize(),
|
cs.block_control.request.GetBlockCount() * cs.block_control.request.GetBlockSize(),
|
||||||
copy_to_device ? "from" : "to", current_address & ADDRESS_MASK);
|
copy_to_device ? "from" : "to", current_address & mask);
|
||||||
|
|
||||||
const u32 block_size = cs.block_control.request.GetBlockSize();
|
const u32 block_size = cs.block_control.request.GetBlockSize();
|
||||||
u32 blocks_remaining = cs.block_control.request.GetBlockCount();
|
u32 blocks_remaining = cs.block_control.request.GetBlockCount();
|
||||||
|
@ -395,8 +401,7 @@ bool DMA::TransferChannel(Channel channel)
|
||||||
{
|
{
|
||||||
blocks_remaining--;
|
blocks_remaining--;
|
||||||
|
|
||||||
const TickCount ticks =
|
const TickCount ticks = TransferMemoryToDevice(channel, current_address & mask, increment, block_size);
|
||||||
TransferMemoryToDevice(channel, current_address & ADDRESS_MASK, increment, block_size);
|
|
||||||
CPU::AddPendingTicks(ticks);
|
CPU::AddPendingTicks(ticks);
|
||||||
ticks_remaining -= ticks;
|
ticks_remaining -= ticks;
|
||||||
|
|
||||||
|
@ -409,8 +414,7 @@ bool DMA::TransferChannel(Channel channel)
|
||||||
{
|
{
|
||||||
blocks_remaining--;
|
blocks_remaining--;
|
||||||
|
|
||||||
const TickCount ticks =
|
const TickCount ticks = TransferDeviceToMemory(channel, current_address & mask, increment, block_size);
|
||||||
TransferDeviceToMemory(channel, current_address & ADDRESS_MASK, increment, block_size);
|
|
||||||
CPU::AddPendingTicks(ticks);
|
CPU::AddPendingTicks(ticks);
|
||||||
ticks_remaining -= ticks;
|
ticks_remaining -= ticks;
|
||||||
|
|
||||||
|
@ -490,8 +494,9 @@ void DMA::UnhaltTransfer(TickCount ticks)
|
||||||
TickCount DMA::TransferMemoryToDevice(Channel channel, u32 address, u32 increment, u32 word_count)
|
TickCount DMA::TransferMemoryToDevice(Channel channel, u32 address, u32 increment, u32 word_count)
|
||||||
{
|
{
|
||||||
const u32* src_pointer = reinterpret_cast<u32*>(Bus::g_ram + address);
|
const u32* src_pointer = reinterpret_cast<u32*>(Bus::g_ram + address);
|
||||||
|
const u32 mask = GetAddressMask();
|
||||||
if (channel != Channel::GPU &&
|
if (channel != Channel::GPU &&
|
||||||
(static_cast<s32>(increment) < 0 || ((address + (increment * word_count)) & ADDRESS_MASK) <= address))
|
(static_cast<s32>(increment) < 0 || ((address + (increment * word_count)) & mask) <= address))
|
||||||
{
|
{
|
||||||
// Use temp buffer if it's wrapping around
|
// Use temp buffer if it's wrapping around
|
||||||
if (m_transfer_buffer.size() < word_count)
|
if (m_transfer_buffer.size() < word_count)
|
||||||
|
@ -502,7 +507,7 @@ TickCount DMA::TransferMemoryToDevice(Channel channel, u32 address, u32 incremen
|
||||||
for (u32 i = 0; i < word_count; i++)
|
for (u32 i = 0; i < word_count; i++)
|
||||||
{
|
{
|
||||||
std::memcpy(&m_transfer_buffer[i], &ram_pointer[address], sizeof(u32));
|
std::memcpy(&m_transfer_buffer[i], &ram_pointer[address], sizeof(u32));
|
||||||
address = (address + increment) & ADDRESS_MASK;
|
address = (address + increment) & mask;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -518,7 +523,7 @@ TickCount DMA::TransferMemoryToDevice(Channel channel, u32 address, u32 incremen
|
||||||
u32 value;
|
u32 value;
|
||||||
std::memcpy(&value, &ram_pointer[address], sizeof(u32));
|
std::memcpy(&value, &ram_pointer[address], sizeof(u32));
|
||||||
g_gpu->DMAWrite(address, value);
|
g_gpu->DMAWrite(address, value);
|
||||||
address = (address + increment) & ADDRESS_MASK;
|
address = (address + increment) & mask;
|
||||||
}
|
}
|
||||||
g_gpu->EndDMAWrite();
|
g_gpu->EndDMAWrite();
|
||||||
}
|
}
|
||||||
|
@ -546,6 +551,8 @@ TickCount DMA::TransferMemoryToDevice(Channel channel, u32 address, u32 incremen
|
||||||
|
|
||||||
TickCount DMA::TransferDeviceToMemory(Channel channel, u32 address, u32 increment, u32 word_count)
|
TickCount DMA::TransferDeviceToMemory(Channel channel, u32 address, u32 increment, u32 word_count)
|
||||||
{
|
{
|
||||||
|
const u32 mask = GetAddressMask();
|
||||||
|
|
||||||
if (channel == Channel::OTC)
|
if (channel == Channel::OTC)
|
||||||
{
|
{
|
||||||
// clear ordering table
|
// clear ordering table
|
||||||
|
@ -553,9 +560,9 @@ TickCount DMA::TransferDeviceToMemory(Channel channel, u32 address, u32 incremen
|
||||||
const u32 word_count_less_1 = word_count - 1;
|
const u32 word_count_less_1 = word_count - 1;
|
||||||
for (u32 i = 0; i < word_count_less_1; i++)
|
for (u32 i = 0; i < word_count_less_1; i++)
|
||||||
{
|
{
|
||||||
u32 value = ((address - 4) & ADDRESS_MASK);
|
u32 value = ((address - 4) & mask);
|
||||||
std::memcpy(&ram_pointer[address], &value, sizeof(value));
|
std::memcpy(&ram_pointer[address], &value, sizeof(value));
|
||||||
address = (address - 4) & ADDRESS_MASK;
|
address = (address - 4) & mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
const u32 terminator = UINT32_C(0xFFFFFF);
|
const u32 terminator = UINT32_C(0xFFFFFF);
|
||||||
|
@ -565,7 +572,7 @@ TickCount DMA::TransferDeviceToMemory(Channel channel, u32 address, u32 incremen
|
||||||
}
|
}
|
||||||
|
|
||||||
u32* dest_pointer = reinterpret_cast<u32*>(&Bus::g_ram[address]);
|
u32* dest_pointer = reinterpret_cast<u32*>(&Bus::g_ram[address]);
|
||||||
if (static_cast<s32>(increment) < 0 || ((address + (increment * word_count)) & ADDRESS_MASK) <= address)
|
if (static_cast<s32>(increment) < 0 || ((address + (increment * word_count)) & mask) <= address)
|
||||||
{
|
{
|
||||||
// Use temp buffer if it's wrapping around
|
// Use temp buffer if it's wrapping around
|
||||||
if (m_transfer_buffer.size() < word_count)
|
if (m_transfer_buffer.size() < word_count)
|
||||||
|
@ -604,7 +611,7 @@ TickCount DMA::TransferDeviceToMemory(Channel channel, u32 address, u32 incremen
|
||||||
for (u32 i = 0; i < word_count; i++)
|
for (u32 i = 0; i < word_count; i++)
|
||||||
{
|
{
|
||||||
std::memcpy(&ram_pointer[address], &m_transfer_buffer[i], sizeof(u32));
|
std::memcpy(&ram_pointer[address], &m_transfer_buffer[i], sizeof(u32));
|
||||||
address = (address + increment) & ADDRESS_MASK;
|
address = (address + increment) & mask;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -475,6 +475,7 @@ std::string HostInterface::GetShaderCacheBasePath() const
|
||||||
void HostInterface::SetDefaultSettings(SettingsInterface& si)
|
void HostInterface::SetDefaultSettings(SettingsInterface& si)
|
||||||
{
|
{
|
||||||
si.SetStringValue("Console", "Region", Settings::GetConsoleRegionName(Settings::DEFAULT_CONSOLE_REGION));
|
si.SetStringValue("Console", "Region", Settings::GetConsoleRegionName(Settings::DEFAULT_CONSOLE_REGION));
|
||||||
|
si.SetBoolValue("Console", "Enable8MBRAM", false);
|
||||||
|
|
||||||
si.SetFloatValue("Main", "EmulationSpeed", 1.0f);
|
si.SetFloatValue("Main", "EmulationSpeed", 1.0f);
|
||||||
si.SetFloatValue("Main", "FastForwardSpeed", 0.0f);
|
si.SetFloatValue("Main", "FastForwardSpeed", 0.0f);
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
static constexpr u32 SAVE_STATE_MAGIC = 0x43435544;
|
static constexpr u32 SAVE_STATE_MAGIC = 0x43435544;
|
||||||
static constexpr u32 SAVE_STATE_VERSION = 51;
|
static constexpr u32 SAVE_STATE_VERSION = 52;
|
||||||
static constexpr u32 SAVE_STATE_MINIMUM_VERSION = 42;
|
static constexpr u32 SAVE_STATE_MINIMUM_VERSION = 42;
|
||||||
|
|
||||||
static_assert(SAVE_STATE_VERSION >= SAVE_STATE_MINIMUM_VERSION);
|
static_assert(SAVE_STATE_VERSION >= SAVE_STATE_MINIMUM_VERSION);
|
||||||
|
|
|
@ -149,6 +149,7 @@ void Settings::Load(SettingsInterface& si)
|
||||||
|
|
||||||
region =
|
region =
|
||||||
ParseConsoleRegionName(si.GetStringValue("Console", "Region", "NTSC-U").c_str()).value_or(DEFAULT_CONSOLE_REGION);
|
ParseConsoleRegionName(si.GetStringValue("Console", "Region", "NTSC-U").c_str()).value_or(DEFAULT_CONSOLE_REGION);
|
||||||
|
enable_8mb_ram = si.GetBoolValue("Console", "Enable8MBRAM", false);
|
||||||
|
|
||||||
emulation_speed = si.GetFloatValue("Main", "EmulationSpeed", 1.0f);
|
emulation_speed = si.GetFloatValue("Main", "EmulationSpeed", 1.0f);
|
||||||
fast_forward_speed = si.GetFloatValue("Main", "FastForwardSpeed", 0.0f);
|
fast_forward_speed = si.GetFloatValue("Main", "FastForwardSpeed", 0.0f);
|
||||||
|
@ -340,6 +341,7 @@ void Settings::Load(SettingsInterface& si)
|
||||||
void Settings::Save(SettingsInterface& si) const
|
void Settings::Save(SettingsInterface& si) const
|
||||||
{
|
{
|
||||||
si.SetStringValue("Console", "Region", GetConsoleRegionName(region));
|
si.SetStringValue("Console", "Region", GetConsoleRegionName(region));
|
||||||
|
si.SetBoolValue("Console", "Enable8MBRAM", enable_8mb_ram);
|
||||||
|
|
||||||
si.SetFloatValue("Main", "EmulationSpeed", emulation_speed);
|
si.SetFloatValue("Main", "EmulationSpeed", emulation_speed);
|
||||||
si.SetFloatValue("Main", "FastForwardSpeed", fast_forward_speed);
|
si.SetFloatValue("Main", "FastForwardSpeed", fast_forward_speed);
|
||||||
|
|
|
@ -212,6 +212,7 @@ struct Settings
|
||||||
|
|
||||||
bool bios_patch_tty_enable = false;
|
bool bios_patch_tty_enable = false;
|
||||||
bool bios_patch_fast_boot = false;
|
bool bios_patch_fast_boot = false;
|
||||||
|
bool enable_8mb_ram = false;
|
||||||
|
|
||||||
std::array<ControllerType, NUM_CONTROLLER_AND_CARD_PORTS> controller_types{};
|
std::array<ControllerType, NUM_CONTROLLER_AND_CARD_PORTS> controller_types{};
|
||||||
bool controller_disable_analog_mode_forcing = false;
|
bool controller_disable_analog_mode_forcing = false;
|
||||||
|
|
|
@ -1874,7 +1874,7 @@ bool DumpRAM(const char* filename)
|
||||||
if (!IsValid())
|
if (!IsValid())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return FileSystem::WriteBinaryFile(filename, Bus::g_ram, Bus::RAM_SIZE);
|
return FileSystem::WriteBinaryFile(filename, Bus::g_ram, Bus::g_ram_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DumpVRAM(const char* filename)
|
bool DumpVRAM(const char* filename)
|
||||||
|
|
|
@ -125,7 +125,7 @@ void CheatManagerDialog::connectUi()
|
||||||
if (index == 0)
|
if (index == 0)
|
||||||
{
|
{
|
||||||
m_ui.scanStartAddress->setText(formatHexValue(0, 8));
|
m_ui.scanStartAddress->setText(formatHexValue(0, 8));
|
||||||
m_ui.scanEndAddress->setText(formatHexValue(Bus::RAM_SIZE, 8));
|
m_ui.scanEndAddress->setText(formatHexValue(Bus::g_ram_size, 8));
|
||||||
}
|
}
|
||||||
else if (index == 1)
|
else if (index == 1)
|
||||||
{
|
{
|
||||||
|
|
|
@ -31,6 +31,7 @@ ConsoleSettingsWidget::ConsoleSettingsWidget(QtHostInterface* host_interface, QW
|
||||||
SettingWidgetBinder::BindWidgetToEnumSetting(m_host_interface, m_ui.region, "Console", "Region",
|
SettingWidgetBinder::BindWidgetToEnumSetting(m_host_interface, m_ui.region, "Console", "Region",
|
||||||
&Settings::ParseConsoleRegionName, &Settings::GetConsoleRegionName,
|
&Settings::ParseConsoleRegionName, &Settings::GetConsoleRegionName,
|
||||||
Settings::DEFAULT_CONSOLE_REGION);
|
Settings::DEFAULT_CONSOLE_REGION);
|
||||||
|
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.enable8MBRAM, "Console", "Enable8MBRAM", false);
|
||||||
SettingWidgetBinder::BindWidgetToEnumSetting(m_host_interface, m_ui.cpuExecutionMode, "CPU", "ExecutionMode",
|
SettingWidgetBinder::BindWidgetToEnumSetting(m_host_interface, m_ui.cpuExecutionMode, "CPU", "ExecutionMode",
|
||||||
&Settings::ParseCPUExecutionMode, &Settings::GetCPUExecutionModeName,
|
&Settings::ParseCPUExecutionMode, &Settings::GetCPUExecutionModeName,
|
||||||
Settings::DEFAULT_CPU_EXECUTION_MODE);
|
Settings::DEFAULT_CPU_EXECUTION_MODE);
|
||||||
|
@ -53,6 +54,15 @@ ConsoleSettingsWidget::ConsoleSettingsWidget(QtHostInterface* host_interface, QW
|
||||||
tr("When this option is chosen, the clock speed set below will be used."));
|
tr("When this option is chosen, the clock speed set below will be used."));
|
||||||
dialog->registerWidgetHelp(m_ui.cpuClockSpeed, tr("Overclocking Percentage"), tr("100%"),
|
dialog->registerWidgetHelp(m_ui.cpuClockSpeed, tr("Overclocking Percentage"), tr("100%"),
|
||||||
tr("Selects the percentage of the normal clock speed the emulated hardware will run at."));
|
tr("Selects the percentage of the normal clock speed the emulated hardware will run at."));
|
||||||
|
dialog->registerWidgetHelp(
|
||||||
|
m_ui.enable8MBRAM, tr("Enable 8MB RAM (Dev Console)"), tr("Unchecked"),
|
||||||
|
tr("Enables an additional 6MB of RAM, usually present on dev consoles. Games have to use a larger heap size for "
|
||||||
|
"this additional RAM to be usable, and may break games which rely on memory mirrors, so it should only be used "
|
||||||
|
"with compatible mods."));
|
||||||
|
dialog->registerWidgetHelp(
|
||||||
|
m_ui.cdromLoadImageToRAM, tr("Preload Image to RAM"), tr("Unchecked"),
|
||||||
|
tr("Loads the game image into RAM. Useful for network paths that may become unreliable during gameplay. In some "
|
||||||
|
"cases also eliminates stutter when games initiate audio track playback."));
|
||||||
dialog->registerWidgetHelp(
|
dialog->registerWidgetHelp(
|
||||||
m_ui.cdromReadSpeedup, tr("CDROM Read Speedup"), tr("None (Double Speed)"),
|
m_ui.cdromReadSpeedup, tr("CDROM Read Speedup"), tr("None (Double Speed)"),
|
||||||
tr("Speeds up CD-ROM reads by the specified factor. Only applies to double-speed reads, and is ignored when audio "
|
tr("Speeds up CD-ROM reads by the specified factor. Only applies to double-speed reads, and is ignored when audio "
|
||||||
|
|
|
@ -42,6 +42,13 @@
|
||||||
<item row="0" column="1">
|
<item row="0" column="1">
|
||||||
<widget class="QComboBox" name="region"/>
|
<widget class="QComboBox" name="region"/>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="1" column="0" colspan="2">
|
||||||
|
<widget class="QCheckBox" name="enable8MBRAM">
|
||||||
|
<property name="text">
|
||||||
|
<string>Enable 8MB RAM (Dev Console)</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
|
|
@ -1140,7 +1140,7 @@ static T DoMemoryRead(PhysicalMemoryAddress address)
|
||||||
|
|
||||||
if (address < Bus::RAM_MIRROR_END)
|
if (address < Bus::RAM_MIRROR_END)
|
||||||
{
|
{
|
||||||
std::memcpy(&result, &Bus::g_ram[address & Bus::RAM_MASK], sizeof(result));
|
std::memcpy(&result, &Bus::g_ram[address & Bus::g_ram_mask], sizeof(result));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue