diff --git a/pcsx2-qt/Settings/AdvancedSettingsWidget.cpp b/pcsx2-qt/Settings/AdvancedSettingsWidget.cpp index 0aeb64ff30..b1811c76de 100644 --- a/pcsx2-qt/Settings/AdvancedSettingsWidget.cpp +++ b/pcsx2-qt/Settings/AdvancedSettingsWidget.cpp @@ -100,8 +100,8 @@ AdvancedSettingsWidget::AdvancedSettingsWidget(SettingsWindow* settings_dialog, "end of the block, not on the instruction which caused the exception. Refer to the console to see the address where the invalid " "access occurred.")); - dialog()->registerWidgetHelp(m_ui.extraMemory, tr("Enable 128MB RAM (Dev Console)"), tr("Unchecked"), - tr("Exposes an additional 96MB of memory to the virtual machine.")); + dialog()->registerWidgetHelp(m_ui.extraMemory, tr("Enable Extended RAM (Dev Console)"), tr("Unchecked"), + tr("Exposes additional memory to the virtual machine, expanding the EE and IOP memory to 128MB and 8MB respectively.")); dialog()->registerWidgetHelp(m_ui.vu0RoundingMode, tr("VU0 Rounding Mode"), tr("Chop/Zero (Default)"), tr("Changes how PCSX2 handles rounding while emulating the Emotion Engine's Vector Unit 0 (EE VU0). " "The default value handles the vast majority of games; modifying this setting when a game is not having a visible problem will cause stability issues and/or crashes.")); diff --git a/pcsx2-qt/Settings/AdvancedSettingsWidget.ui b/pcsx2-qt/Settings/AdvancedSettingsWidget.ui index e5cd7b2b13..6992e77364 100644 --- a/pcsx2-qt/Settings/AdvancedSettingsWidget.ui +++ b/pcsx2-qt/Settings/AdvancedSettingsWidget.ui @@ -176,7 +176,7 @@ - Enable 128MB RAM (Dev Console) + Enable Extended RAM (Dev Console) diff --git a/pcsx2/DebugTools/BiosDebugData.cpp b/pcsx2/DebugTools/BiosDebugData.cpp index e6d0bd4b99..84fbb11d60 100644 --- a/pcsx2/DebugTools/BiosDebugData.cpp +++ b/pcsx2/DebugTools/BiosDebugData.cpp @@ -79,10 +79,9 @@ std::vector getIOPModules() for (int i = 0; maddr != 0; i++) { - if (maddr >= 0x200000) + if (maddr >= Ps2MemSize::ExposedIopRam) { // outside of memory - // change if we ever support IOP ram extension return {}; } diff --git a/pcsx2/DebugTools/DebugInterface.cpp b/pcsx2/DebugTools/DebugInterface.cpp index 0c6fffd3ab..76ff126ac5 100644 --- a/pcsx2/DebugTools/DebugInterface.cpp +++ b/pcsx2/DebugTools/DebugInterface.cpp @@ -1039,7 +1039,7 @@ bool R3000DebugInterface::isValidAddress(u32 addr) return true; } - if (addr < 0x200000) + if (addr < Ps2MemSize::ExposedIopRam) { return true; } diff --git a/pcsx2/IopMem.cpp b/pcsx2/IopMem.cpp index c633e8bfab..2145d9f74d 100644 --- a/pcsx2/IopMem.cpp +++ b/pcsx2/IopMem.cpp @@ -52,10 +52,11 @@ void iopMemReset() // at 0x0, 0x8000, and 0xa000: for (int i = 0; i < 0x0080; i++) { - psxMemWLUT[i + 0x0000] = (uptr)&iopMem->Main[(i & 0x1f) << 16]; + u32 mask = (Ps2MemSize::ExposedIopRam / _64kb) - 1; + psxMemWLUT[i + 0x0000] = (uptr)&iopMem->Main[(i & mask) << 16]; // RLUTs, accessed through WLUT. - psxMemWLUT[i + 0x2000] = (uptr)&iopMem->Main[(i & 0x1f) << 16]; + psxMemWLUT[i + 0x2000] = (uptr)&iopMem->Main[(i & mask) << 16]; } // A few single-page allocations for things we store in special locations. diff --git a/pcsx2/IopMem.h b/pcsx2/IopMem.h index f4c148214b..ba2a6cbf96 100644 --- a/pcsx2/IopMem.h +++ b/pcsx2/IopMem.h @@ -37,7 +37,7 @@ static __fi const T* iopVirtMemR( u32 mem ) // Obtains a pointer to the IOP's physical mapping (bypasses the TLB) static __fi u8* iopPhysMem( u32 addr ) { - return &iopMem->Main[addr & 0x1fffff]; + return &iopMem->Main[addr & (Ps2MemSize::ExposedIopRam - 1)]; } #define psxSs8(mem) iopMem->Sif[(mem) & 0x00ff] diff --git a/pcsx2/Memory.cpp b/pcsx2/Memory.cpp index ec6ad55bab..0c54a12c30 100644 --- a/pcsx2/Memory.cpp +++ b/pcsx2/Memory.cpp @@ -45,6 +45,7 @@ BIOS namespace Ps2MemSize { u32 ExposedRam = MainRam; + u32 ExposedIopRam = IopRam; } // namespace Ps2MemSize namespace SysMemory @@ -305,6 +306,7 @@ void memSetExtraMemMode(bool mode) // update the amount of RAM exposed to the VM Ps2MemSize::ExposedRam = mode ? Ps2MemSize::TotalRam : Ps2MemSize::MainRam; + Ps2MemSize::ExposedIopRam = mode ? Ps2MemSize::TotalIopRam: Ps2MemSize::IopRam; } void memSetKernelMode() { diff --git a/pcsx2/MemoryTypes.h b/pcsx2/MemoryTypes.h index cb04c60953..8365b13121 100644 --- a/pcsx2/MemoryTypes.h +++ b/pcsx2/MemoryTypes.h @@ -16,11 +16,14 @@ namespace Ps2MemSize static constexpr u32 Scratch = _16kb; static constexpr u32 IopRam = _1mb * 2; // 2MB main ram on the IOP. + static constexpr u32 ExtraIopRam = _1mb * 6; // 2MB main ram on the IOP. + static constexpr u32 TotalIopRam = _8mb; // 2MB main ram on the IOP. static constexpr u32 IopHardware = _64kb; static constexpr u32 GSregs = 0x00002000; // 8k for the GS registers and stuff. extern u32 ExposedRam; + extern u32 ExposedIopRam; } // namespace Ps2MemSize typedef u8 mem8_t; @@ -32,12 +35,11 @@ typedef u128 mem128_t; // Needs to fit within EEmemSize of Memory.h struct EEVM_MemoryAllocMess { - u8 Main[Ps2MemSize::MainRam]; // Main memory (hard-wired to 32MB) - u8 ExtraMemory[Ps2MemSize::ExtraRam]; // Extra memory (32MB up to 128MB => 96MB). - u8 Scratch[Ps2MemSize::Scratch]; // Scratchpad! - u8 ROM[Ps2MemSize::Rom]; // Boot rom (4MB) - u8 ROM1[Ps2MemSize::Rom1]; // DVD player (4MB) - u8 ROM2[Ps2MemSize::Rom2]; // Chinese extensions + u8 Main[Ps2MemSize::TotalRam]; // Main memory + u8 Scratch[Ps2MemSize::Scratch]; // Scratchpad! + u8 ROM[Ps2MemSize::Rom]; // Boot rom (4MB) + u8 ROM1[Ps2MemSize::Rom1]; // DVD player (4MB) + u8 ROM2[Ps2MemSize::Rom2]; // Chinese extensions // Two 1 megabyte (max DMA) buffers for reading and writing to high memory (>32MB). // Such accesses are not documented as causing bus errors but as the memory does @@ -51,9 +53,9 @@ struct EEVM_MemoryAllocMess // Needs to fit within IOPmemSize of Memory.h struct IopVM_MemoryAllocMess { - u8 Main[Ps2MemSize::IopRam]; // Main memory (hard-wired to 2MB) - u8 P[_64kb]; // I really have no idea what this is... --air - u8 Sif[0x100]; // a few special SIF/SBUS registers (likely not needed) + u8 Main[Ps2MemSize::TotalRam]; // Main memory + u8 P[_64kb]; // I really have no idea what this is... --air + u8 Sif[0x100]; // a few special SIF/SBUS registers (likely not needed) }; diff --git a/pcsx2/SaveState.cpp b/pcsx2/SaveState.cpp index 208da9292d..8014b0a86f 100644 --- a/pcsx2/SaveState.cpp +++ b/pcsx2/SaveState.cpp @@ -537,7 +537,7 @@ public: const char* GetFilename() const override { return "iopMemory.bin"; } u8* GetDataPtr() const override { return iopMem->Main; } - uint GetDataSize() const override { return sizeof(iopMem->Main); } + uint GetDataSize() const override { return Ps2MemSize::ExposedIopRam; } }; class SavestateEntry_HwRegs final : public MemorySavestateEntry diff --git a/pcsx2/USB/qemu-usb/usb-ohci.cpp b/pcsx2/USB/qemu-usb/usb-ohci.cpp index 2fc9d3c89a..d57096eb8b 100644 --- a/pcsx2/USB/qemu-usb/usb-ohci.cpp +++ b/pcsx2/USB/qemu-usb/usb-ohci.cpp @@ -282,7 +282,7 @@ void ohci_hard_reset(OHCIState* ohci) /* Get an array of dwords from main memory */ __fi static int get_dwords(u32 addr, u32* buf, u32 num) { - if ((addr + (num * sizeof(u32))) > sizeof(iopMem->Main)) + if ((addr + (num * sizeof(u32))) > Ps2MemSize::ExposedIopRam) return 0; std::memcpy(buf, iopMem->Main + addr, num * sizeof(u32)); @@ -292,7 +292,7 @@ __fi static int get_dwords(u32 addr, u32* buf, u32 num) /* Get an array of words from main memory */ __fi static int get_words(u32 addr, u16* buf, u32 num) { - if ((addr + (num * sizeof(u16))) > sizeof(iopMem->Main)) + if ((addr + (num * sizeof(u16))) > Ps2MemSize::ExposedIopRam) return 0; std::memcpy(buf, iopMem->Main + addr, num * sizeof(u16)); @@ -302,7 +302,7 @@ __fi static int get_words(u32 addr, u16* buf, u32 num) /* Put an array of dwords in to main memory */ __fi static int put_dwords(u32 addr, u32* buf, u32 num) { - if ((addr + (num * sizeof(u32))) > sizeof(iopMem->Main)) + if ((addr + (num * sizeof(u32))) > Ps2MemSize::ExposedIopRam) return 0; std::memcpy(iopMem->Main + addr, buf, num * sizeof(u32)); @@ -312,7 +312,7 @@ __fi static int put_dwords(u32 addr, u32* buf, u32 num) /* Put an array of dwords in to main memory */ __fi static int put_words(u32 addr, u16* buf, u32 num) { - if ((addr + (num * sizeof(u16))) > sizeof(iopMem->Main)) + if ((addr + (num * sizeof(u16))) > Ps2MemSize::ExposedIopRam) return 0; std::memcpy(iopMem->Main + addr, buf, num * sizeof(u16)); @@ -362,7 +362,7 @@ static int ohci_copy_td(OHCIState* ohci, struct ohci_td* td, uint8_t* buf, u32 l u32 ptr = td->cbp; const u32 n = std::min(0x1000 - (ptr & 0xfff), len); - if ((ptr + n) > sizeof(iopMem->Main)) + if ((ptr + n) > Ps2MemSize::ExposedIopRam) return 1; if (write) @@ -376,7 +376,7 @@ static int ohci_copy_td(OHCIState* ohci, struct ohci_td* td, uint8_t* buf, u32 l buf += n; len -= n; - if ((ptr + n) > sizeof(iopMem->Main)) + if ((ptr + n) > Ps2MemSize::ExposedIopRam) return 1; if (write) @@ -394,7 +394,7 @@ static int ohci_copy_iso_td(OHCIState* ohci, u32 start_addr, u32 end_addr, u32 ptr = start_addr; const u32 n = std::min(0x1000 - (ptr & 0xfff), len); - if ((ptr + n) > sizeof(iopMem->Main)) + if ((ptr + n) > Ps2MemSize::ExposedIopRam) return 1; if (write) @@ -408,7 +408,7 @@ static int ohci_copy_iso_td(OHCIState* ohci, u32 start_addr, u32 end_addr, buf += n; len -= n; - if ((ptr + n) > sizeof(iopMem->Main)) + if ((ptr + n) > Ps2MemSize::ExposedIopRam) return 1; if (write) @@ -1099,7 +1099,7 @@ void ohci_frame_boundary(void* opaque) { OHCIState* ohci = (OHCIState*)opaque; - if (ohci->hcca + sizeof(ohci_hcca) > sizeof(iopMem->Main)) + if (ohci->hcca + sizeof(ohci_hcca) > Ps2MemSize::ExposedIopRam) { Console.Error("ohci->hcca pointer is out of range."); return; diff --git a/pcsx2/VMManager.cpp b/pcsx2/VMManager.cpp index 3e13593a41..b1f42c6533 100644 --- a/pcsx2/VMManager.cpp +++ b/pcsx2/VMManager.cpp @@ -3290,7 +3290,7 @@ void VMManager::WarnAboutUnsafeSettings() if (EmuConfig.Cpu.ExtraMemory) { append(ICON_PF_MICROCHIP, - TRANSLATE_SV("VMManager", "128MB RAM is enabled. Compatibility with some games may be affected.")); + TRANSLATE_SV("VMManager", "Extended RAM is enabled. Compatibility with some games may be affected.")); } if (!EmuConfig.EnableGameFixes) { diff --git a/pcsx2/ps2/Iop/IopHwRead.cpp b/pcsx2/ps2/Iop/IopHwRead.cpp index 61aef6d08a..d67f40f0a9 100644 --- a/pcsx2/ps2/Iop/IopHwRead.cpp +++ b/pcsx2/ps2/Iop/IopHwRead.cpp @@ -94,19 +94,28 @@ mem8_t iopHwRead8_Page1( u32 addr ) ////////////////////////////////////////////////////////////////////////////////////////// // -mem8_t iopHwRead8_Page3( u32 addr ) +mem8_t iopHwRead8_Page3(u32 addr) { // all addresses are assumed to be prefixed with 0x1f803xxx: - pxAssume( (addr >> 12) == 0x1f803 ); + pxAssume((addr >> 12) == 0x1f803); + + const u32 masked_addr = addr & 0x0fff; mem8_t ret; - if( addr == 0x1f803100 ) // PS/EE/IOP conf related - //ret = 0x10; // Dram 2M - ret = 0xFF; //all high bus is the corect default state for CEX PS2! - else - ret = psxHu8( addr ); + switch (masked_addr) + { + case 0x100: // TOOL config switches + ret = 0; + break; + case 0x204: // TOOL board id + ret = 0x7c; + break; + default: + ret = psxHu8(addr); + break; + } - IopHwTraceLog( addr, ret, true ); + IopHwTraceLog(addr, ret, true); return ret; } diff --git a/pcsx2/x86/iR3000A.cpp b/pcsx2/x86/iR3000A.cpp index afc5b87e4a..ea2562c01d 100644 --- a/pcsx2/x86/iR3000A.cpp +++ b/pcsx2/x86/iR3000A.cpp @@ -8,6 +8,7 @@ #include "IopBios.h" #include "IopHw.h" #include "Common.h" +#include "common/HeapArray.h" #include "VMManager.h" #include @@ -840,37 +841,39 @@ void psxRecompileCodeConst3(R3000AFNPTR constcode, R3000AFNPTR_INFO constscode, noconstcode(info); } -static u8* m_recBlockAlloc = NULL; +static DynamicHeapArray recLutReserve; +static size_t recLutEntries; +static bool extraRam = false; -static const uint m_recBlockAllocSize = - (((Ps2MemSize::IopRam + Ps2MemSize::Rom + Ps2MemSize::Rom1 + Ps2MemSize::Rom2) / 4) * sizeof(BASEBLOCK)); +static void recReserveRAM() +{ + // Goal: Allocate BASEBLOCKs for every possible branch target in IOP memory. + // Any 4-byte aligned address makes a valid branch target as per MIPS design (all instructions are + // always 4 bytes long). + + recLutEntries = + ((Ps2MemSize::ExposedIopRam + Ps2MemSize::Rom + Ps2MemSize::Rom1 + Ps2MemSize::Rom2) / 4); + + if (recLutReserve.size() != recLutEntries) + recLutReserve.resize(recLutEntries); + + BASEBLOCK* curpos = recLutReserve.data(); + recRAM = curpos; + curpos += (Ps2MemSize::ExposedIopRam / 4); + recROM = curpos; + curpos += (Ps2MemSize::Rom / 4); + recROM1 = curpos; + curpos += (Ps2MemSize::Rom1 / 4); + recROM2 = curpos; + curpos += (Ps2MemSize::Rom2 / 4); +} static void recReserve() { recPtr = SysMemory::GetIOPRec(); recPtrEnd = SysMemory::GetIOPRecEnd() - _64kb; - // Goal: Allocate BASEBLOCKs for every possible branch target in IOP memory. - // Any 4-byte aligned address makes a valid branch target as per MIPS design (all instructions are - // always 4 bytes long). - - if (!m_recBlockAlloc) - { - // We're on 64-bit, if these memory allocations fail, we're in real trouble. - m_recBlockAlloc = (u8*)_aligned_malloc(m_recBlockAllocSize, 4096); - if (!m_recBlockAlloc) - pxFailRel("Failed to allocate R3000A BASEBLOCK lookup tables"); - } - - u8* curpos = m_recBlockAlloc; - recRAM = (BASEBLOCK*)curpos; - curpos += (Ps2MemSize::IopRam / 4) * sizeof(BASEBLOCK); - recROM = (BASEBLOCK*)curpos; - curpos += (Ps2MemSize::Rom / 4) * sizeof(BASEBLOCK); - recROM1 = (BASEBLOCK*)curpos; - curpos += (Ps2MemSize::Rom1 / 4) * sizeof(BASEBLOCK); - recROM2 = (BASEBLOCK*)curpos; - curpos += (Ps2MemSize::Rom2 / 4) * sizeof(BASEBLOCK); + recReserveRAM(); pxAssertRel(!s_pInstCache, "InstCache not allocated"); s_nInstCacheSize = 128; @@ -883,12 +886,18 @@ void recResetIOP() { DevCon.WriteLn("iR3000A Recompiler reset."); + if (CHECK_EXTRAMEM != extraRam) + { + recReserveRAM(); + extraRam = !extraRam; + } + xSetPtr(SysMemory::GetIOPRec()); _DynGen_Dispatchers(); recPtr = xGetPtr(); - iopClearRecLUT((BASEBLOCK*)m_recBlockAlloc, - (((Ps2MemSize::IopRam + Ps2MemSize::Rom + Ps2MemSize::Rom1 + Ps2MemSize::Rom2) / 4))); + iopClearRecLUT(reinterpret_cast(recLutReserve.data()), + Ps2MemSize::ExposedIopRam + Ps2MemSize::Rom + Ps2MemSize::Rom1 + Ps2MemSize::Rom2); for (int i = 0; i < 0x10000; i++) recLUT_SetPage(psxRecLUT, 0, 0, 0, i, 0); @@ -899,13 +908,15 @@ void recResetIOP() // the pc indexer into it's lower common denominator. // We're only mapping 20 pages here in 4 places. - // 0x80 comes from : (Ps2MemSize::IopRam / 0x10000) * 4 + // 0x80 comes from : (Ps2MemSize::IopRam / _64kb) * 4 for (int i = 0; i < 0x80; i++) { - recLUT_SetPage(psxRecLUT, psxhwLUT, recRAM, 0x0000, i, i & 0x1f); - recLUT_SetPage(psxRecLUT, psxhwLUT, recRAM, 0x8000, i, i & 0x1f); - recLUT_SetPage(psxRecLUT, psxhwLUT, recRAM, 0xa000, i, i & 0x1f); + u32 mask = (Ps2MemSize::ExposedIopRam / _64kb) - 1; + + recLUT_SetPage(psxRecLUT, psxhwLUT, recRAM, 0x0000, i, i & mask); + recLUT_SetPage(psxRecLUT, psxhwLUT, recRAM, 0x8000, i, i & mask); + recLUT_SetPage(psxRecLUT, psxhwLUT, recRAM, 0xa000, i, i & mask); } for (int i = 0x1fc0; i < 0x2000; i++) @@ -940,7 +951,7 @@ void recResetIOP() static void recShutdown() { - safe_aligned_free(m_recBlockAlloc); + recLutReserve.deallocate(); safe_free(s_pInstCache); s_nInstCacheSize = 0; @@ -951,7 +962,7 @@ static void recShutdown() static void iopClearRecLUT(BASEBLOCK* base, int count) { - for (int i = 0; i < count; i++) + for (int i = 0; i < count / 4; i++) base[i].SetFnptr((uptr)iopJITCompile); } @@ -1039,7 +1050,7 @@ static __fi u32 psxRecClearMem(u32 pc) } } - iopClearRecLUT(PSX_GETBLOCK(lowerextent), (upperextent - lowerextent) / 4); + iopClearRecLUT(PSX_GETBLOCK(lowerextent), upperextent - lowerextent); return upperextent - pc; } diff --git a/pcsx2/x86/iR3000Atables.cpp b/pcsx2/x86/iR3000Atables.cpp index 6ad9bae50b..902a3c2af9 100644 --- a/pcsx2/x86/iR3000Atables.cpp +++ b/pcsx2/x86/iR3000Atables.cpp @@ -1115,7 +1115,7 @@ static void rpsxLoad(int size, bool sign) is_ram_read.SetTarget(); // read from psM directly - xAND(arg1regd, 0x1fffff); + xAND(arg1regd, Ps2MemSize::ExposedIopRam - 1); auto addr = xComplexAddress(rax, iopMem->Main, arg1reg); switch (size)