Support expanding RAM to 8MB (dev console)

This commit is contained in:
Connor McLaughlin 2021-05-02 20:46:48 +10:00
parent d021850394
commit e382df0d41
21 changed files with 146 additions and 78 deletions

View File

@ -71,8 +71,11 @@ union MEMCTRL
};
};
std::bitset<RAM_CODE_PAGE_COUNT> m_ram_code_bits{};
u8* g_ram = nullptr; // 2MB RAM
std::bitset<RAM_8MB_CODE_PAGE_COUNT> m_ram_code_bits{};
u32 m_ram_code_page_count = 0;
u8* g_ram = nullptr; // 2MB RAM
u32 g_ram_size = 0;
u32 g_ram_mask = 0;
u8 g_bios[BIOS_SIZE]{}; // 512K BIOS ROM
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 void RecalculateMemoryTimings();
static bool AllocateMemory();
static bool AllocateMemory(bool enable_8mb_ram);
static void ReleaseMemory();
static void SetCodePageFastmemProtection(u32 page_index, bool writable);
@ -125,7 +128,7 @@ static void SetCodePageFastmemProtection(u32 page_index, bool writable);
bool Initialize()
{
if (!AllocateMemory())
if (!AllocateMemory(g_settings.enable_8mb_ram))
{
g_host_interface->ReportError("Failed to allocate memory");
return false;
@ -153,7 +156,7 @@ void Shutdown()
void Reset()
{
std::memset(g_ram, 0, RAM_SIZE);
std::memset(g_ram, 0, g_ram_size);
m_MEMCTRL.exp1_base = 0x1F000000;
m_MEMCTRL.exp2_base = 0x1F802000;
m_MEMCTRL.exp1_delay_size.bits = 0x0013243F;
@ -170,12 +173,25 @@ void Reset()
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_exp2_access_time);
sw.Do(&m_bios_access_time);
sw.Do(&m_cdrom_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.DoArray(m_MEMCTRL.regs, countof(m_MEMCTRL.regs));
sw.Do(&m_ram_size_reg);
@ -255,7 +271,7 @@ void RecalculateMemoryTimings()
m_spu_access_time[2] + 1);
}
bool AllocateMemory()
bool AllocateMemory(bool enable_8mb_ram)
{
if (!m_memory_arena.Create(MEMORY_ARENA_SIZE, true, false))
{
@ -264,14 +280,20 @@ bool AllocateMemory()
}
// 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)
{
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;
}
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;
}
@ -279,8 +301,10 @@ void ReleaseMemory()
{
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_mask = 0;
g_ram_size = 0;
}
m_memory_arena.Destroy();
@ -354,15 +378,15 @@ void UpdateFastmemViews(CPUFastmemMode mode)
auto MapRAM = [](u32 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)
{
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;
}
// 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])
{
@ -386,7 +410,7 @@ void UpdateFastmemViews(CPUFastmemMode mode)
auto view = m_memory_arena.CreateReservedView(end_address_inclusive - start_address + 1, map_address);
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;
}
@ -432,7 +456,7 @@ void UpdateFastmemViews(CPUFastmemMode mode)
}
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],
!m_ram_code_bits[FastmemAddressToLUTPageIndex(address)]);
@ -474,7 +498,7 @@ bool CanUseFastmemForAddress(VirtualMemoryAddress address)
#endif
case CPUFastmemMode::LUT:
return (paddr < RAM_SIZE);
return (paddr < g_ram_size);
case CPUFastmemMode::Disabled:
default:
@ -556,7 +580,7 @@ void ClearRAMCodePageFlags()
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);
for (u32 mirror_start : m_fastmem_ram_mirrors)
@ -567,7 +591,7 @@ void ClearRAMCodePageFlags()
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)
@ -575,7 +599,7 @@ bool HasCodePagesInRange(PhysicalMemoryAddress start_address, u32 size)
if (!IsRAMAddress(start_address))
return false;
start_address = (start_address & RAM_MASK);
start_address = (start_address & g_ram_mask);
const u32 end_address = start_address + size;
while (start_address < end_address)
@ -592,10 +616,10 @@ bool HasCodePagesInRange(PhysicalMemoryAddress start_address, u32 size)
std::optional<MemoryRegion> GetMemoryRegionForAddress(PhysicalMemoryAddress address)
{
if (address < RAM_SIZE)
if (address < RAM_2MB_SIZE)
return MemoryRegion::RAM;
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))
return MemoryRegion::EXP1;
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_cast<u32>(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},
{0, RAM_2MB_SIZE},
{RAM_2MB_SIZE, RAM_2MB_SIZE * 2},
{RAM_2MB_SIZE * 2, RAM_2MB_SIZE * 3},
{RAM_2MB_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},
@ -633,11 +657,17 @@ u8* GetMemoryRegionPointer(MemoryRegion region)
switch (region)
{
case MemoryRegion::RAM:
case MemoryRegion::RAMMirror1:
case MemoryRegion::RAMMirror2:
case MemoryRegion::RAMMirror3:
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:
return nullptr;
@ -734,14 +764,13 @@ static TickCount DoInvalidAccess(MemoryAccessType type, MemoryAccessSize size, P
if (type == MemoryAccessType::Read)
value = UINT32_C(0xFFFFFFFF);
return 1;
return (type == MemoryAccessType::Read) ? 1 : 0;
}
template<MemoryAccessType type, MemoryAccessSize size>
ALWAYS_INLINE static TickCount DoRAMAccess(u32 offset, u32& value)
{
// TODO: Configurable mirroring.
offset &= UINT32_C(0x1FFFFF);
offset &= g_ram_mask;
if constexpr (type == MemoryAccessType::Read)
{
if constexpr (size == MemoryAccessSize::Byte)
@ -1270,7 +1299,7 @@ ALWAYS_INLINE_RELEASE bool DoInstructionRead(PhysicalMemoryAddress address, void
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)
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);
}
@ -1860,7 +1889,7 @@ void* GetDirectReadMemoryPointer(VirtualMemoryAddress address, MemoryAccessSize
if (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)

View File

@ -15,8 +15,10 @@ namespace Bus {
enum : u32
{
RAM_BASE = 0x00000000,
RAM_SIZE = 0x200000,
RAM_MASK = RAM_SIZE - 1,
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,
EXP1_BASE = 0x1F000000,
EXP1_SIZE = 0x800000,
@ -78,7 +80,7 @@ enum : TickCount
enum : size_t
{
// Our memory arena contains storage for RAM.
MEMORY_ARENA_SIZE = RAM_SIZE,
MEMORY_ARENA_SIZE = RAM_8MB_SIZE,
// Offsets within the memory arena.
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 = UINT64_C(0x100000000),
#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_SLOTS = FASTMEM_LUT_NUM_PAGES * 2,
@ -107,8 +113,10 @@ bool CanUseFastmemForAddress(VirtualMemoryAddress address);
void SetExpansionROM(std::vector<u8> data);
void SetBIOS(const std::vector<u8>& image);
extern std::bitset<RAM_CODE_PAGE_COUNT> m_ram_code_bits;
extern u8* g_ram; // 2MB RAM
extern std::bitset<RAM_8MB_CODE_PAGE_COUNT> m_ram_code_bits;
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
/// 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.
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.

View File

@ -54,7 +54,7 @@ static T DoMemoryRead(PhysicalMemoryAddress address)
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;
}
@ -84,12 +84,12 @@ static void DoMemoryWrite(PhysicalMemoryAddress address, T value)
{
// Only invalidate code when it changes.
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)
{
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))
CPU::CodeCache::InvalidateBlocksWithPageIndex(code_page_index);
}

View File

@ -55,7 +55,7 @@ ALWAYS_INLINE static u32 GetFastMapIndex(u32 pc)
{
return ((pc & PHYSICAL_MEMORY_ADDRESS_MASK) >= Bus::BIOS_BASE) ?
(FAST_MAP_RAM_SLOT_COUNT + ((pc & Bus::BIOS_MASK) >> 2)) :
((pc & Bus::RAM_MASK) >> 2);
((pc & Bus::g_ram_mask) >> 2);
}
static void CompileDispatcher();
@ -102,7 +102,7 @@ static void UnlinkBlock(CodeBlock* block);
static void ClearState();
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
static HostCodeMap s_host_code_map;
@ -694,7 +694,7 @@ void FastCompileBlockFunction()
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];
for (CodeBlock* block : blocks)
{

View File

@ -18,7 +18,7 @@ namespace CPU {
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_TOTAL_SLOT_COUNT = FAST_MAP_RAM_SLOT_COUNT + FAST_MAP_BIOS_SLOT_COUNT,
};

View File

@ -180,6 +180,9 @@ bool DoState(StateWrapper& sw)
sw.Do(&g_state.icache_data);
}
if (sw.IsReading())
UpdateFastmemBase();
return !sw.HasError();
}

View File

@ -2868,7 +2868,7 @@ CodeGenerator::SpeculativeValue CodeGenerator::SpeculativeReadMemory(VirtualMemo
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));
return value;
}

View File

@ -2004,7 +2004,7 @@ CodeCache::DispatcherFunction CodeGenerator::CompileDispatcher()
m_emit->str(a32::r0, a32::MemOperand(GetHostReg32(RCPUPTR), offsetof(State, current_instruction_pc)));
// 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);
// r2 <- ((pc & BIOS_MASK) >> 2) + FAST_MAP_RAM_SLOT_COUNT

View File

@ -2219,7 +2219,7 @@ CodeCache::DispatcherFunction CodeGenerator::CompileDispatcher()
m_emit->str(a64::w8, a64::MemOperand(GetHostReg64(RCPUPTR), offsetof(State, current_instruction_pc)));
// 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);
// w10 <- ((pc & BIOS_MASK) >> 2) + FAST_MAP_RAM_SLOT_COUNT

View File

@ -44,7 +44,7 @@ Value CodeGenerator::EmitLoadGuestMemory(const CodeBlockInstruction& cbi, const
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
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);
}
else

View File

@ -2968,7 +2968,7 @@ CodeCache::DispatcherFunction CodeGenerator::CompileDispatcher()
// ebx <- (pc & RAM_MASK) >> 2
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);
// ecx <- ((pc & BIOS_MASK) >> 2) + FAST_MAP_RAM_SLOT_COUNT

View File

@ -17,6 +17,11 @@
#endif
Log_SetChannel(DMA);
static u32 GetAddressMask()
{
return Bus::g_ram_mask & 0xFFFFFFFCu;
}
DMA g_dma;
DMA::DMA() = default;
@ -293,6 +298,7 @@ TickCount DMA::GetTransferHaltTicks() const
bool DMA::TransferChannel(Channel channel)
{
ChannelState& cs = m_state[static_cast<u32>(channel)];
const u32 mask = GetAddressMask();
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();
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;
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
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);
}
@ -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),
current_address & ADDRESS_MASK);
current_address & mask);
u8* ram_pointer = Bus::g_ram;
TickCount remaining_ticks = GetTransferSliceTicks();
while (cs.request && remaining_ticks > 0)
{
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);
remaining_ticks -= 10;
const u32 word_count = header >> 24;
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);
if (word_count > 0)
{
@ -349,7 +355,7 @@ bool DMA::TransferChannel(Channel channel)
remaining_ticks -= 5;
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);
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),
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();
u32 blocks_remaining = cs.block_control.request.GetBlockCount();
@ -395,8 +401,7 @@ bool DMA::TransferChannel(Channel channel)
{
blocks_remaining--;
const TickCount ticks =
TransferMemoryToDevice(channel, current_address & ADDRESS_MASK, increment, block_size);
const TickCount ticks = TransferMemoryToDevice(channel, current_address & mask, increment, block_size);
CPU::AddPendingTicks(ticks);
ticks_remaining -= ticks;
@ -409,8 +414,7 @@ bool DMA::TransferChannel(Channel channel)
{
blocks_remaining--;
const TickCount ticks =
TransferDeviceToMemory(channel, current_address & ADDRESS_MASK, increment, block_size);
const TickCount ticks = TransferDeviceToMemory(channel, current_address & mask, increment, block_size);
CPU::AddPendingTicks(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)
{
const u32* src_pointer = reinterpret_cast<u32*>(Bus::g_ram + address);
const u32 mask = GetAddressMask();
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
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++)
{
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;
std::memcpy(&value, &ram_pointer[address], sizeof(u32));
g_gpu->DMAWrite(address, value);
address = (address + increment) & ADDRESS_MASK;
address = (address + increment) & mask;
}
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)
{
const u32 mask = GetAddressMask();
if (channel == Channel::OTC)
{
// 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;
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));
address = (address - 4) & ADDRESS_MASK;
address = (address - 4) & mask;
}
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]);
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
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++)
{
std::memcpy(&ram_pointer[address], &m_transfer_buffer[i], sizeof(u32));
address = (address + increment) & ADDRESS_MASK;
address = (address + increment) & mask;
}
}

View File

@ -475,6 +475,7 @@ std::string HostInterface::GetShaderCacheBasePath() const
void HostInterface::SetDefaultSettings(SettingsInterface& si)
{
si.SetStringValue("Console", "Region", Settings::GetConsoleRegionName(Settings::DEFAULT_CONSOLE_REGION));
si.SetBoolValue("Console", "Enable8MBRAM", false);
si.SetFloatValue("Main", "EmulationSpeed", 1.0f);
si.SetFloatValue("Main", "FastForwardSpeed", 0.0f);

View File

@ -2,7 +2,7 @@
#include "types.h"
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_assert(SAVE_STATE_VERSION >= SAVE_STATE_MINIMUM_VERSION);

View File

@ -149,6 +149,7 @@ void Settings::Load(SettingsInterface& si)
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);
fast_forward_speed = si.GetFloatValue("Main", "FastForwardSpeed", 0.0f);
@ -340,6 +341,7 @@ void Settings::Load(SettingsInterface& si)
void Settings::Save(SettingsInterface& si) const
{
si.SetStringValue("Console", "Region", GetConsoleRegionName(region));
si.SetBoolValue("Console", "Enable8MBRAM", enable_8mb_ram);
si.SetFloatValue("Main", "EmulationSpeed", emulation_speed);
si.SetFloatValue("Main", "FastForwardSpeed", fast_forward_speed);

View File

@ -212,6 +212,7 @@ struct Settings
bool bios_patch_tty_enable = false;
bool bios_patch_fast_boot = false;
bool enable_8mb_ram = false;
std::array<ControllerType, NUM_CONTROLLER_AND_CARD_PORTS> controller_types{};
bool controller_disable_analog_mode_forcing = false;

View File

@ -1874,7 +1874,7 @@ bool DumpRAM(const char* filename)
if (!IsValid())
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)

View File

@ -125,7 +125,7 @@ void CheatManagerDialog::connectUi()
if (index == 0)
{
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)
{

View File

@ -31,6 +31,7 @@ ConsoleSettingsWidget::ConsoleSettingsWidget(QtHostInterface* host_interface, QW
SettingWidgetBinder::BindWidgetToEnumSetting(m_host_interface, m_ui.region, "Console", "Region",
&Settings::ParseConsoleRegionName, &Settings::GetConsoleRegionName,
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",
&Settings::ParseCPUExecutionMode, &Settings::GetCPUExecutionModeName,
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."));
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."));
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(
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 "

View File

@ -42,6 +42,13 @@
<item row="0" column="1">
<widget class="QComboBox" name="region"/>
</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>
</widget>
</item>

View File

@ -1140,7 +1140,7 @@ static T DoMemoryRead(PhysicalMemoryAddress address)
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;
}