From ce68ce57c02dd6720fba4b650f999e850ebb2f99 Mon Sep 17 00:00:00 2001 From: Sour Date: Wed, 9 Jan 2019 20:19:16 -0500 Subject: [PATCH] Core: Refactored nametable RAM management to fix some issues and remove some limitations (This breaks save state compatibility) --- Core/BaseMapper.cpp | 215 ++++++------------ Core/BaseMapper.h | 25 +- Core/Cheapocabra.h | 44 +--- Core/MMC5.h | 39 ++-- Core/Mapper218.h | 7 +- Core/MemoryManager.cpp | 13 +- Core/MemoryManager.h | 2 - Core/Namco163.h | 6 +- Core/Namco163Audio.h | 2 +- Core/SaveStateManager.cpp | 23 +- Core/SaveStateManager.h | 2 +- Core/Sunsoft4.h | 25 +- Core/Types.h | 11 +- Core/UnRom512.h | 6 +- .../Debugger/Controls/ctrlMemoryMapping.cs | 20 +- GUI.NET/InteropEmu.cs | 6 +- 16 files changed, 151 insertions(+), 295 deletions(-) diff --git a/Core/BaseMapper.cpp b/Core/BaseMapper.cpp index 806c7339..f5c8217f 100644 --- a/Core/BaseMapper.cpp +++ b/Core/BaseMapper.cpp @@ -149,7 +149,7 @@ void BaseMapper::SetCpuMemoryMapping(uint16_t startAddr, uint16_t endAddr, uint8 endAddr >>= 8; for(uint16_t i = startAddr; i <= endAddr; i++) { _prgPages[i] = source; - _prgPageAccessType[i] = accessType != -1 ? accessType : (uint8_t)MemoryAccessType::Read; + _prgMemoryAccess[i] = accessType != -1 ? (MemoryAccessType)accessType : MemoryAccessType::Read; source += 0x100; } @@ -215,6 +215,12 @@ void BaseMapper::SetPpuMemoryMapping(uint16_t startAddr, uint16_t endAddr, uint1 pageCount = _chrRamSize / pageSize; defaultAccessType |= MemoryAccessType::Write; break; + + case ChrMemoryType::NametableRam: + pageSize = BaseMapper::NametableSize; + pageCount = BaseMapper::NametableCount; + defaultAccessType |= MemoryAccessType::Write; + break; } if(pageCount == 0) { @@ -250,6 +256,7 @@ void BaseMapper::SetPpuMemoryMapping(uint16_t startAddr, uint16_t endAddr, ChrMe case ChrMemoryType::Default: sourceMemory = _onlyChrRam ? _chrRam : _chrRom; break; case ChrMemoryType::ChrRom: sourceMemory = _chrRom; break; case ChrMemoryType::ChrRam: sourceMemory = _chrRam; break; + case ChrMemoryType::NametableRam: sourceMemory = _nametableRam; break; } int firstSlot = startAddr >> 8; int slotCount = (endAddr - startAddr + 1) >> 8; @@ -272,7 +279,7 @@ void BaseMapper::SetPpuMemoryMapping(uint16_t startAddr, uint16_t endAddr, uint8 endAddr >>= 8; for(uint16_t i = startAddr; i <= endAddr; i++) { _chrPages[i] = sourceMemory; - _chrPageAccessType[i] = accessType != -1 ? accessType : (uint8_t)MemoryAccessType::ReadWrite; + _chrMemoryAccess[i] = accessType != -1 ? (MemoryAccessType)accessType : MemoryAccessType::ReadWrite; if(sourceMemory != nullptr) { sourceMemory += 0x100; @@ -353,16 +360,16 @@ void BaseMapper::SelectChrPage2x(uint16_t slot, uint16_t page, ChrMemoryType mem void BaseMapper::SelectCHRPage(uint16_t slot, uint16_t page, ChrMemoryType memoryType) { - uint16_t pageSize = memoryType == ChrMemoryType::ChrRam ? InternalGetChrRamPageSize() : InternalGetChrPageSize(); + uint16_t pageSize; + if(memoryType == ChrMemoryType::NametableRam) { + pageSize = BaseMapper::NametableSize; + } else { + pageSize = memoryType == ChrMemoryType::ChrRam ? InternalGetChrRamPageSize() : InternalGetChrPageSize(); + } + uint16_t startAddr = slot * pageSize; uint16_t endAddr = startAddr + pageSize - 1; - if(page == ChrSpecialPage::NametableA) { - SetPpuMemoryMapping(startAddr, endAddr, GetNametable(0)); - } else if(page == ChrSpecialPage::NametableB) { - SetPpuMemoryMapping(startAddr, endAddr, GetNametable(1)); - } else { - SetPpuMemoryMapping(startAddr, endAddr, page, memoryType); - } + SetPpuMemoryMapping(startAddr, endAddr, page, memoryType); } void BaseMapper::InitializeRam(void* data, uint32_t length) @@ -499,88 +506,45 @@ void BaseMapper::RemoveRegisterRange(uint16_t startAddr, uint16_t endAddr, Memor void BaseMapper::StreamState(bool saving) { + //Need to get the number of nametables in the state first, before we try to stream the nametable ram array + Stream(_nametableCount); + ArrayInfo chrRam = { _chrRam, _chrRamSize }; ArrayInfo workRam = { _workRam, _workRamSize }; ArrayInfo saveRam = { _saveRam, _saveRamSize }; + ArrayInfo nametableRam = { _nametableRam, _nametableCount * BaseMapper::NametableSize }; - uint32_t prgPages[64]; - uint32_t chrPages[64]; + ArrayInfo prgMemoryOffset = { _prgMemoryOffset, 0x100 }; + ArrayInfo chrMemoryOffset = { _chrMemoryOffset, 0x40 }; + ArrayInfo prgMemoryType = { _prgMemoryType, 0x100 }; + ArrayInfo chrMemoryType = { _chrMemoryType, 0x40 }; + ArrayInfo prgMemoryAccess = { _prgMemoryAccess, 0x100 }; + ArrayInfo chrMemoryAccess = { _chrMemoryAccess, 0x40 }; - ArrayInfo nametableIndexes = { _nametableIndexes, 4 }; + Stream(_mirroringType, chrRam, workRam, saveRam, nametableRam, prgMemoryOffset, chrMemoryOffset, prgMemoryType, chrMemoryType, prgMemoryAccess, chrMemoryAccess); - if(GetStateVersion() < 9) { - ArrayInfo prgPageNumbers = { prgPages, 64 }; - ArrayInfo chrPageNumbers = { chrPages, 64 }; - - Stream(_mirroringType, chrRam, workRam, saveRam, prgPageNumbers, chrPageNumbers, nametableIndexes); - } else { - ArrayInfo prgMemoryOffset = { _prgMemoryOffset, 0x100 }; - ArrayInfo chrMemoryOffset = { _chrMemoryOffset, 0x40 }; - ArrayInfo prgMemoryType = { _prgMemoryType, 0x100 }; - ArrayInfo chrMemoryType = { _chrMemoryType, 0x40 }; - ArrayInfo prgMemoryAccess = { _prgMemoryAccess, 0x100 }; - ArrayInfo chrMemoryAccess = { _chrMemoryAccess, 0x40 }; - - Stream(_mirroringType, chrRam, workRam, saveRam, nametableIndexes, prgMemoryOffset, chrMemoryOffset, prgMemoryType, chrMemoryType, prgMemoryAccess, chrMemoryAccess); - } - - if(GetStateVersion() >= 7) { - bool hasExtraNametable[2] = { _cartNametableRam[0] != nullptr, _cartNametableRam[1] != nullptr }; - Stream(hasExtraNametable[0], hasExtraNametable[1]); - - for(int i = 0; i < 2; i++) { - if(hasExtraNametable[i]) { - if(!_cartNametableRam[i]) { - _cartNametableRam[i] = new uint8_t[0x400]; - } - - ArrayInfo ram = { _cartNametableRam[i], 0x400 }; - Stream(ram); - } - } - } - if(!saving) { - RestorePrgChrState(prgPages, chrPages); - - for(int i = 0; i < 4; i++) { - SetNametable(i, _nametableIndexes[i]); - } + RestorePrgChrState(); } } -void BaseMapper::RestorePrgChrState(uint32_t* prgPages, uint32_t* chrPages) +void BaseMapper::RestorePrgChrState() { - if(GetStateVersion() < 9) { - //Support for older save states - for(uint16_t i = 0; i < 64; i++) { - if(prgPages[i] != 0xEEEEEEEE) { - BaseMapper::SelectPRGPage(i, (uint16_t)prgPages[i]); - } + for(uint16_t i = 0; i < 0x100; i++) { + uint16_t startAddr = i << 8; + if(_prgMemoryAccess[i] != MemoryAccessType::NoAccess) { + SetCpuMemoryMapping(startAddr, startAddr + 0xFF, _prgMemoryType[i], _prgMemoryOffset[i], _prgMemoryAccess[i]); + } else { + RemoveCpuMemoryMapping(startAddr, startAddr + 0xFF); } + } - for(uint16_t i = 0; i < 64; i++) { - if(chrPages[i] != 0xEEEEEEEE) { - BaseMapper::SelectCHRPage(i, (uint16_t)chrPages[i]); - } - } - } else { - for(uint16_t i = 0; i < 0x100; i++) { - uint16_t startAddr = i << 8; - if(_prgMemoryAccess[i] != MemoryAccessType::NoAccess) { - SetCpuMemoryMapping(startAddr, startAddr + 0xFF, _prgMemoryType[i], _prgMemoryOffset[i], _prgMemoryAccess[i]); - } else { - RemoveCpuMemoryMapping(startAddr, startAddr + 0xFF); - } - } - - for(uint16_t i = 0; i < 0x40; i++) { - uint16_t startAddr = i << 8; - if(_chrMemoryAccess[i] != MemoryAccessType::NoAccess) { - SetPpuMemoryMapping(startAddr, startAddr + 0xFF, _chrMemoryType[i], _chrMemoryOffset[i], _chrMemoryAccess[i]); - } else { - RemovePpuMemoryMapping(startAddr, startAddr + 0xFF); - } + for(uint16_t i = 0; i < 0x40; i++) { + uint16_t startAddr = i << 8; + if(_chrMemoryAccess[i] != MemoryAccessType::NoAccess) { + SetPpuMemoryMapping(startAddr, startAddr + 0xFF, _chrMemoryType[i], _chrMemoryOffset[i], _chrMemoryAccess[i]); + } else { + RemovePpuMemoryMapping(startAddr, startAddr + 0xFF); } } } @@ -609,8 +573,6 @@ void BaseMapper::Initialize(RomData &romData) memset(_isWriteRegisterAddr, 0, sizeof(_isWriteRegisterAddr)); AddRegisterRange(RegisterStartAddress(), RegisterEndAddress(), MemoryOperation::Any); - _mirroringType = romData.Info.Mirroring; - _prgSize = (uint32_t)romData.PrgRom.size(); _chrRomSize = (uint32_t)romData.ChrRom.size(); _originalPrgRom = romData.PrgRom; @@ -637,24 +599,18 @@ void BaseMapper::Initialize(RomData &romData) InitializeRam(_saveRam, _saveRamSize); InitializeRam(_workRam, _workRamSize); - memset(_cartNametableRam, 0, sizeof(_cartNametableRam)); - memset(_nametableIndexes, 0, sizeof(_nametableIndexes)); - - for(int i = 0; i <= 0xFF; i++) { - //Allow us to map a different page every 256 bytes - _prgPages[i] = nullptr; - _prgPageAccessType[i] = MemoryAccessType::NoAccess; - _chrPages[i] = nullptr; - _chrPageAccessType[i] = MemoryAccessType::NoAccess; - } + _nametableCount = 2; + _nametableRam = new uint8_t[BaseMapper::NametableSize*BaseMapper::NametableCount]; + InitializeRam(_nametableRam, BaseMapper::NametableSize*BaseMapper::NametableCount); for(int i = 0; i < 0x100; i++) { + //Allow us to map a different page every 256 bytes + _prgPages[i] = nullptr; _prgMemoryOffset[i] = -1; _prgMemoryType[i] = PrgMemoryType::PrgRom; _prgMemoryAccess[i] = MemoryAccessType::NoAccess; - } - for(int i = 0; i < 0x40; i++) { + _chrPages[i] = nullptr; _chrMemoryOffset[i] = -1; _chrMemoryType[i] = ChrMemoryType::Default; _chrMemoryAccess[i] = MemoryAccessType::NoAccess; @@ -687,6 +643,8 @@ void BaseMapper::Initialize(RomData &romData) SetupDefaultWorkRam(); + SetMirroringType(romData.Info.Mirroring); + InitMapper(); InitMapper(romData); @@ -702,14 +660,7 @@ BaseMapper::~BaseMapper() delete[] _prgRom; delete[] _saveRam; delete[] _workRam; - - if(_cartNametableRam[0]) { - delete[] _cartNametableRam[0]; - } - - if(_cartNametableRam[1]) { - delete[] _cartNametableRam[1]; - } + delete[] _nametableRam; } void BaseMapper::ProcessNotification(ConsoleNotificationType type, void* parameter) @@ -746,47 +697,35 @@ void BaseMapper::SetConsole(shared_ptr console) _console = console; } -void BaseMapper::SetDefaultNametables(uint8_t* nametableA, uint8_t* nametableB) +uint8_t* BaseMapper::GetNametable(uint8_t nametableIndex) { - _nesNametableRam[0] = nametableA; - _nesNametableRam[1] = nametableB; - SetMirroringType(_mirroringType); -} - -void BaseMapper::AddNametable(uint8_t index, uint8_t *nametable) -{ - assert(index >= 4); - _cartNametableRam[index - 2] = nametable; -} - -uint8_t* BaseMapper::GetNametable(uint8_t index) -{ - if(index <= 1) { - return _nesNametableRam[index]; - } else { - return _cartNametableRam[index - 2]; + if(nametableIndex >= BaseMapper::NametableCount) { + #ifdef _DEBUG + MessageManager::Log("Invalid nametable index"); + #endif + return _nametableRam; } + _nametableCount = std::max(_nametableCount, nametableIndex); + + return _nametableRam + (nametableIndex * BaseMapper::NametableSize); } void BaseMapper::SetNametable(uint8_t index, uint8_t nametableIndex) { - if(nametableIndex == 2 && _cartNametableRam[0] == nullptr) { - _cartNametableRam[0] = new uint8_t[0x400]; - InitializeRam(_cartNametableRam[0], 0x400); - } - if(nametableIndex == 3 && _cartNametableRam[1] == nullptr) { - _cartNametableRam[1] = new uint8_t[0x400]; - InitializeRam(_cartNametableRam[1], 0x400); + if(nametableIndex >= BaseMapper::NametableCount) { + #ifdef _DEBUG + MessageManager::Log("Invalid nametable index"); + #endif + return; } + _nametableCount = std::max(_nametableCount, nametableIndex); - _nametableIndexes[index] = nametableIndex; - - SetPpuMemoryMapping(0x2000 + index * 0x400, 0x2000 + (index + 1) * 0x400 - 1, GetNametable(nametableIndex)); + SetPpuMemoryMapping(0x2000 + index * 0x400, 0x2000 + (index + 1) * 0x400 - 1, nametableIndex, ChrMemoryType::NametableRam); //Mirror $2000-$2FFF to $3000-$3FFF, while keeping a distinction between the addresses //Previously, $3000-$3FFF was being "redirected" to $2000-$2FFF to avoid MMC3 IRQ issues (which is incorrect) //More info here: https://forums.nesdev.com/viewtopic.php?p=132145#p132145 - SetPpuMemoryMapping(0x3000 + index * 0x400, 0x3000 + (index + 1) * 0x400 - 1, GetNametable(nametableIndex)); + SetPpuMemoryMapping(0x3000 + index * 0x400, 0x3000 + (index + 1) * 0x400 - 1, nametableIndex, ChrMemoryType::NametableRam); } void BaseMapper::SetNametables(uint8_t nametable1Index, uint8_t nametable2Index, uint8_t nametable3Index, uint8_t nametable4Index) @@ -833,7 +772,7 @@ uint8_t BaseMapper::ReadRAM(uint16_t addr) { if(_allowRegisterRead && _isReadRegisterAddr[addr]) { return ReadRegister(addr); - } else if(_prgPageAccessType[addr >> 8] & MemoryAccessType::Read) { + } else if(_prgMemoryAccess[addr >> 8] & MemoryAccessType::Read) { return _prgPages[addr >> 8][(uint8_t)addr]; } else { //assert(false); @@ -848,7 +787,7 @@ uint8_t BaseMapper::PeekRAM(uint16_t addr) uint8_t BaseMapper::DebugReadRAM(uint16_t addr) { - if(_prgPageAccessType[addr >> 8] & MemoryAccessType::Read) { + if(_prgMemoryAccess[addr >> 8] & MemoryAccessType::Read) { return _prgPages[addr >> 8][(uint8_t)addr]; } else { //assert(false); @@ -883,7 +822,7 @@ void BaseMapper::DebugWriteRAM(uint16_t addr, uint8_t value) void BaseMapper::WritePrgRam(uint16_t addr, uint8_t value) { - if(_prgPageAccessType[addr >> 8] & MemoryAccessType::Write) { + if(_prgMemoryAccess[addr >> 8] & MemoryAccessType::Write) { _prgPages[addr >> 8][(uint8_t)addr] = value; } } @@ -896,7 +835,7 @@ void BaseMapper::NotifyVRAMAddressChange(uint16_t addr) uint8_t BaseMapper::InternalReadVRAM(uint16_t addr) { - if(_chrPageAccessType[addr >> 8] & MemoryAccessType::Read) { + if(_chrMemoryAccess[addr >> 8] & MemoryAccessType::Read) { return _chrPages[addr >> 8][(uint8_t)addr]; } @@ -928,7 +867,7 @@ void BaseMapper::DebugWriteVRAM(uint16_t addr, uint8_t value, bool disableSideEf } } else { NotifyVRAMAddressChange(addr); - if(_chrPageAccessType[addr >> 8] & MemoryAccessType::Write) { + if(_chrMemoryAccess[addr >> 8] & MemoryAccessType::Write) { _chrPages[addr >> 8][(uint8_t)addr] = value; } } @@ -938,7 +877,7 @@ void BaseMapper::WriteVRAM(uint16_t addr, uint8_t value) { _console->DebugProcessVramWriteOperation(addr, value); - if(_chrPageAccessType[addr >> 8] & MemoryAccessType::Write) { + if(_chrMemoryAccess[addr >> 8] & MemoryAccessType::Write) { _chrPages[addr >> 8][(uint8_t)addr] = value; } } @@ -1205,10 +1144,6 @@ CartridgeState BaseMapper::GetState() state.ChrMemoryAccess[i] = _chrMemoryAccess[i]; } - for(int i = 0; i < 4; i++) { - state.Nametables[i] = _nametableIndexes[i]; - } - state.WorkRamPageSize = GetWorkRamPageSize(); state.SaveRamPageSize = GetSaveRamPageSize(); diff --git a/Core/BaseMapper.h b/Core/BaseMapper.h index 68d084f2..9f6f6165 100644 --- a/Core/BaseMapper.h +++ b/Core/BaseMapper.h @@ -25,9 +25,8 @@ private: uint16_t InternalGetChrRamPageSize(); bool ValidateAddressRange(uint16_t startAddr, uint16_t endAddr); - uint8_t *_nesNametableRam[2]; - uint8_t *_cartNametableRam[10]; - uint8_t _nametableIndexes[4]; + uint8_t *_nametableRam = nullptr; + uint8_t _nametableCount = 2; bool _onlyChrRam = false; bool _hasBusConflicts = false; @@ -36,23 +35,25 @@ private: bool _isReadRegisterAddr[0x10000]; bool _isWriteRegisterAddr[0x10000]; + MemoryAccessType _prgMemoryAccess[0x100]; uint8_t* _prgPages[0x100]; + + MemoryAccessType _chrMemoryAccess[0x100]; uint8_t* _chrPages[0x100]; - uint8_t _prgPageAccessType[0x100]; - uint8_t _chrPageAccessType[0x100]; int32_t _prgMemoryOffset[0x100]; PrgMemoryType _prgMemoryType[0x100]; - MemoryAccessType _prgMemoryAccess[0x100]; - int32_t _chrMemoryOffset[0x40]; - ChrMemoryType _chrMemoryType[0x40]; - MemoryAccessType _chrMemoryAccess[0x40]; + int32_t _chrMemoryOffset[0x100]; + ChrMemoryType _chrMemoryType[0x100]; vector _originalPrgRom; vector _originalChrRom; protected: + static constexpr uint32_t NametableCount = 0x10; + static constexpr uint32_t NametableSize = 0x400; + RomInfo _romInfo; shared_ptr _mapperControlDevice; @@ -142,10 +143,9 @@ protected: virtual void StreamState(bool saving) override; - void RestorePrgChrState(uint32_t* prgPages, uint32_t* chrPages); + void RestorePrgChrState(); - uint8_t* GetNametable(uint8_t index); - void AddNametable(uint8_t index, uint8_t *nametable); + uint8_t* GetNametable(uint8_t nametableIndex); void SetNametable(uint8_t index, uint8_t nametableIndex); void SetNametables(uint8_t nametable1Index, uint8_t nametable2Index, uint8_t nametable3Index, uint8_t nametable4Index); void SetMirroringType(MirroringType type); @@ -170,7 +170,6 @@ public: virtual void SaveBattery() override; void SetConsole(shared_ptr console); - virtual void SetDefaultNametables(uint8_t* nametableA, uint8_t* nametableB); shared_ptr GetMapperControlDevice(); RomInfo GetRomInfo(); diff --git a/Core/Cheapocabra.h b/Core/Cheapocabra.h index 75ef59f5..6b355392 100644 --- a/Core/Cheapocabra.h +++ b/Core/Cheapocabra.h @@ -5,10 +5,6 @@ //Missing Flash rom support, and only tested via a test rom class Cheapocabra : public BaseMapper { -private: - uint8_t _reg; - uint8_t* _extraNametables[4]; - protected: virtual uint16_t GetPRGPageSize() override { return 0x8000; } virtual uint16_t GetCHRPageSize() override { return 0x2000; } @@ -19,47 +15,17 @@ protected: void InitMapper() override { AddRegisterRange(0x7000, 0x7FFF, MemoryOperation::Write); - for(int i = 0; i < 4; i++) { - _extraNametables[i] = new uint8_t[0x400]; - InitializeRam(_extraNametables[i], 0x400); - AddNametable(4 + i, _extraNametables[i]); - } - _reg = GetPowerOnByte(); - UpdateState(); + WriteRegister(0x5000, GetPowerOnByte()); } - virtual ~Cheapocabra() + void WriteRegister(uint16_t addr, uint8_t value) override { - delete[] _extraNametables[0]; - delete[] _extraNametables[1]; - delete[] _extraNametables[2]; - delete[] _extraNametables[3]; - } - - void StreamState(bool saving) override - { - BaseMapper::StreamState(saving); - ArrayInfo extraNametable0{ _extraNametables[0], 0x400 }; - ArrayInfo extraNametable1{ _extraNametables[1], 0x400 }; - ArrayInfo extraNametable2{ _extraNametables[2], 0x400 }; - ArrayInfo extraNametable3{ _extraNametables[3], 0x400 }; - Stream(_reg, extraNametable0, extraNametable1, extraNametable2, extraNametable3); - } - - void UpdateState() - { - SelectPRGPage(0, _reg & 0x0F); - SelectCHRPage(0, (_reg >> 4) & 0x01); - if(_reg & 0x20) { + SelectPRGPage(0, value & 0x0F); + SelectCHRPage(0, (value >> 4) & 0x01); + if(value & 0x20) { SetNametables(4, 5, 6, 7); } else { SetNametables(0, 1, 2, 3); } } - - void WriteRegister(uint16_t addr, uint8_t value) override - { - _reg = value; - UpdateState(); - } }; \ No newline at end of file diff --git a/Core/MMC5.h b/Core/MMC5.h index e9ed70e9..858bdeec 100644 --- a/Core/MMC5.h +++ b/Core/MMC5.h @@ -8,8 +8,8 @@ class MMC5 : public BaseMapper { private: const uint8_t NtWorkRamIndex = 4; - const uint8_t NtEmptyIndex = 5; - const uint8_t NtFillModeIndex = 6; + const uint8_t NtEmptyIndex = 2; + const uint8_t NtFillModeIndex = 3; unique_ptr _audio; @@ -18,9 +18,6 @@ private: uint8_t _fillModeTile; uint8_t _fillModeColor; - uint8_t *_fillModeNametable; - - uint8_t *_emptyNametable; bool _verticalSplitEnabled; bool _verticalSplitRightSide; @@ -227,7 +224,14 @@ private: NtFillModeIndex //"3 - Fill-mode data" }; - SetNametables(nametables[value & 0x03], nametables[(value >> 2) & 0x03], nametables[(value >> 4) & 0x03], nametables[(value >> 6) & 0x03]); + for(int i = 0; i < 4; i++) { + uint8_t nametableId = nametables[(value >> (i * 2)) & 0x03]; + if(nametableId == NtWorkRamIndex) { + SetPpuMemoryMapping(0x2000+i*0x400, 0x2000+i*0x400+0x3FF, _workRam, MemoryAccessType::ReadWrite); + } else { + SetNametable(i, nametableId); + } + } } void SetExtendedRamMode(uint8_t mode) @@ -252,13 +256,13 @@ private: void SetFillModeTile(uint8_t tile) { _fillModeTile = tile; - memset(_fillModeNametable, tile, 32 * 30); //32 tiles per row, 30 rows + memset(GetNametable(NtFillModeIndex), tile, 32 * 30); //32 tiles per row, 30 rows } void SetFillModeColor(uint8_t color) { _fillModeColor = color; - memset(_fillModeNametable + 32 * 30, color, 64); //Attribute table is 64 bytes + memset(GetNametable(NtFillModeIndex) + 32 * 30, color, 64); //Attribute table is 64 bytes } bool IsSpriteFetch() @@ -317,18 +321,11 @@ protected: _splitTile = 0; _splitTileNumber = -1; - _fillModeNametable = new uint8_t[0x400]; - _emptyNametable = new uint8_t[0x400]; - InitializeRam(_emptyNametable, 0x400); - InitializeRam(_fillModeNametable, 0x400); + memset(GetNametable(NtEmptyIndex), 0, BaseMapper::NametableSize); //"Expansion RAM ($5C00-$5FFF, read/write)" SetCpuMemoryMapping(0x5C00, 0x5FFF, 0, PrgMemoryType::WorkRam); - AddNametable(NtWorkRamIndex, _workRam); - AddNametable(NtEmptyIndex, _emptyNametable); - AddNametable(NtFillModeIndex, _fillModeNametable); - //"Additionally, Romance of the 3 Kingdoms 2 seems to expect it to be in 8k PRG mode ($5100 = $03)." WriteRegister(0x5100, 0x03); @@ -336,29 +333,23 @@ protected: WriteRegister(0x5117, 0xFF); } - virtual ~MMC5() - { - delete[] _fillModeNametable; - delete[] _emptyNametable; - } - void StreamState(bool saving) override { BaseMapper::StreamState(saving); ArrayInfo prgBanks = { _prgBanks, 5 }; ArrayInfo chrBanks = { _chrBanks, 12 }; - ArrayInfo fillModeNametable = { _fillModeNametable, 0x400 }; SnapshotInfo audio{ _audio.get() }; Stream(_prgRamProtect1, _prgRamProtect2, _fillModeTile, _fillModeColor, _verticalSplitEnabled, _verticalSplitRightSide, _verticalSplitDelimiterTile, _verticalSplitScroll, _verticalSplitBank, _multiplierValue1, _multiplierValue2, _nametableMapping, _extendedRamMode, _exAttributeLastNametableFetch, _exAttrLastFetchCounter, _exAttrSelectedChrBank, _prgMode, prgBanks, _chrMode, _chrUpperBits, chrBanks, _lastChrReg, - _spriteFetch, _largeSprites, _irqCounterTarget, _irqEnabled, _previousScanline, _irqCounter, _irqPending, _ppuInFrame, audio, fillModeNametable, + _spriteFetch, _largeSprites, _irqCounterTarget, _irqEnabled, _previousScanline, _irqCounter, _irqPending, _ppuInFrame, audio, _splitInSplitRegion, _splitVerticalScroll, _splitTile, _splitTileNumber, _lastVramOperationType); if(!saving) { UpdatePrgBanks(); + SetNametableMapping(_nametableMapping); } } diff --git a/Core/Mapper218.h b/Core/Mapper218.h index 942c80db..337b8f52 100644 --- a/Core/Mapper218.h +++ b/Core/Mapper218.h @@ -14,11 +14,6 @@ protected: if(GetMirroringType() == MirroringType::FourScreens) { SetMirroringType(_romInfo.NesHeader.Byte6 & 0x01 ? MirroringType::ScreenBOnly : MirroringType::ScreenAOnly); } - } - - void SetDefaultNametables(uint8_t* nametableA, uint8_t* nametableB) override - { - BaseMapper::SetDefaultNametables(nametableA, nametableB); uint16_t mask = 0; switch(GetMirroringType()) { @@ -30,7 +25,7 @@ protected: } for(int i = 0; i < 8; i++) { - SetPpuMemoryMapping(i * 0x400, i * 0x400 + 0x3FF, (i * 0x400) & mask ? GetNametable(1) : GetNametable(0)); + SetPpuMemoryMapping(i*0x400, i*0x400+0x3FF, ((i * 0x400) & mask) ? 1 : 0, ChrMemoryType::NametableRam); } } }; \ No newline at end of file diff --git a/Core/MemoryManager.cpp b/Core/MemoryManager.cpp index 59c80cc5..bfc28ab0 100644 --- a/Core/MemoryManager.cpp +++ b/Core/MemoryManager.cpp @@ -11,11 +11,6 @@ MemoryManager::MemoryManager(shared_ptr console) _internalRAM = new uint8_t[InternalRAMSize]; _internalRamHandler.SetInternalRam(_internalRAM); - for(int i = 0; i < 2; i++) { - _nametableRAM[i] = new uint8_t[NameTableScreenSize]; - _console->GetMapper()->InitializeRam(_nametableRAM[i], NameTableScreenSize); - } - _ramReadHandlers = new IMemoryHandler*[RAMSize]; _ramWriteHandlers = new IMemoryHandler*[RAMSize]; @@ -30,9 +25,6 @@ MemoryManager::MemoryManager(shared_ptr console) MemoryManager::~MemoryManager() { delete[] _internalRAM; - for(int i = 0; i < 2; i++) { - delete[] _nametableRAM[i]; - } delete[] _ramReadHandlers; delete[] _ramWriteHandlers; @@ -41,7 +33,6 @@ MemoryManager::~MemoryManager() void MemoryManager::SetMapper(shared_ptr mapper) { _mapper = mapper; - _mapper->SetDefaultNametables(_nametableRAM[0], _nametableRAM[1]); } void MemoryManager::Reset(bool softReset) @@ -165,9 +156,7 @@ uint32_t MemoryManager::ToAbsolutePrgAddress(uint16_t ramAddr) void MemoryManager::StreamState(bool saving) { ArrayInfo internalRam = { _internalRAM, MemoryManager::InternalRAMSize }; - ArrayInfo nameTable0Ram = { _nametableRAM[0], MemoryManager::NameTableScreenSize }; - ArrayInfo nameTable1Ram = { _nametableRAM[1], MemoryManager::NameTableScreenSize }; - Stream(internalRam, nameTable0Ram, nameTable1Ram); + Stream(internalRam); } uint8_t MemoryManager::GetOpenBus(uint8_t mask) diff --git a/Core/MemoryManager.h b/Core/MemoryManager.h index 4178c834..e142e38e 100644 --- a/Core/MemoryManager.h +++ b/Core/MemoryManager.h @@ -14,13 +14,11 @@ class MemoryManager : public Snapshotable private: static constexpr int RAMSize = 0x10000; static constexpr int VRAMSize = 0x4000; - static constexpr int NameTableScreenSize = 0x400; shared_ptr _console; shared_ptr _mapper; uint8_t *_internalRAM; - uint8_t *_nametableRAM[2]; OpenBusHandler _openBusHandler; InternalRamHandler<0x7FF> _internalRamHandler; diff --git a/Core/Namco163.h b/Core/Namco163.h index 84489231..374d0cf2 100644 --- a/Core/Namco163.h +++ b/Core/Namco163.h @@ -169,7 +169,7 @@ protected: case 0x8000: case 0x8800: case 0x9000: case 0x9800: { uint8_t bankNumber = (addr - 0x8000) >> 11; if(!_lowChrNtMode && value >= 0xE0 && _variant == NamcoVariant::Namco163) { - SelectCHRPage(bankNumber, (value & 0x01) == 0x01 ? ChrSpecialPage::NametableB : ChrSpecialPage::NametableA); + SelectCHRPage(bankNumber, value & 0x01, ChrMemoryType::NametableRam); } else { SelectCHRPage(bankNumber, value); } @@ -179,7 +179,7 @@ protected: case 0xA000: case 0xA800: case 0xB000: case 0xB800: { uint8_t bankNumber = ((addr - 0xA000) >> 11) + 4; if(!_highChrNtMode && value >= 0xE0 && _variant == NamcoVariant::Namco163) { - SelectCHRPage(bankNumber, (value & 0x01) == 0x01 ? ChrSpecialPage::NametableB : ChrSpecialPage::NametableA); + SelectCHRPage(bankNumber, value & 0x01, ChrMemoryType::NametableRam); } else { SelectCHRPage(bankNumber, value); } @@ -199,7 +199,7 @@ protected: } else { uint8_t bankNumber = ((addr - 0xC000) >> 11) + 8; if(value >= 0xE0) { - SelectCHRPage(bankNumber, (value & 0x01) == 0x01 ? ChrSpecialPage::NametableB : ChrSpecialPage::NametableA); + SelectCHRPage(bankNumber, value & 0x01, ChrMemoryType::NametableRam); } else { SelectCHRPage(bankNumber, value); } diff --git a/Core/Namco163Audio.h b/Core/Namco163Audio.h index 1a914b5d..5195b655 100644 --- a/Core/Namco163Audio.h +++ b/Core/Namco163Audio.h @@ -118,7 +118,7 @@ protected: ArrayInfo internalRam{ _internalRam, 0x80 }; ArrayInfo channelOutput{ _channelOutput, 8 }; - Stream(internalRam, channelOutput, _ramPosition, _autoIncrement, _updateCounter, _currentChannel, _lastOutput); + Stream(internalRam, channelOutput, _ramPosition, _autoIncrement, _updateCounter, _currentChannel, _lastOutput, _disableSound); } void ClockAudio() override diff --git a/Core/SaveStateManager.cpp b/Core/SaveStateManager.cpp index e0f000ad..f6b3d435 100644 --- a/Core/SaveStateManager.cpp +++ b/Core/SaveStateManager.cpp @@ -129,27 +129,18 @@ bool SaveStateManager::LoadState(istream &stream, bool hashCheckRequired) } stream.read((char*)&fileFormatVersion, sizeof(fileFormatVersion)); - if(fileFormatVersion < 5) { + if(fileFormatVersion < 10) { MessageManager::DisplayMessage("SaveStates", "SaveStateIncompatibleVersion"); return false; - } else if(fileFormatVersion == 5) { - //No SHA1 field in version 5 - if(hashCheckRequired) { - //Can't manually load < v5 save states, since we can't know what game the save state is for - MessageManager::DisplayMessage("SaveStates", "SaveStateIncompatibleVersion"); - return false; - } } else { int32_t mapperId = -1; int32_t subMapperId = -1; - if(fileFormatVersion >= 8) { - uint16_t id; - uint8_t sid; - stream.read((char*)&id, sizeof(uint16_t)); - stream.read((char*)&sid, sizeof(uint8_t)); - mapperId = id; - subMapperId = sid; - } + uint16_t id; + uint8_t sid; + stream.read((char*)&id, sizeof(uint16_t)); + stream.read((char*)&sid, sizeof(uint8_t)); + mapperId = id; + subMapperId = sid; char hash[41] = {}; stream.read(hash, 40); diff --git a/Core/SaveStateManager.h b/Core/SaveStateManager.h index b144d3cb..5b936177 100644 --- a/Core/SaveStateManager.h +++ b/Core/SaveStateManager.h @@ -14,7 +14,7 @@ private: string GetStateFilepath(int stateIndex); public: - static constexpr uint32_t FileFormatVersion = 9; + static constexpr uint32_t FileFormatVersion = 10; SaveStateManager(shared_ptr console); diff --git a/Core/Sunsoft4.h b/Core/Sunsoft4.h index f869da3d..daa8d3c5 100644 --- a/Core/Sunsoft4.h +++ b/Core/Sunsoft4.h @@ -15,16 +15,18 @@ private: void UpdateNametables() { - AddNametable(4, _chrRom + _ntRegs[0] * 0x400); - AddNametable(5, _chrRom + _ntRegs[1] * 0x400); - if(_useChrForNametables) { - switch(GetMirroringType()) { - case MirroringType::FourScreens: break; //4-screen mirroring is not supported by this mapper - case MirroringType::Vertical: SetNametables(4, 5, 4, 5); break; - case MirroringType::Horizontal: SetNametables(4, 4, 5, 5); break; - case MirroringType::ScreenAOnly: SetNametables(4, 4, 4, 4); break; - case MirroringType::ScreenBOnly: SetNametables(5, 5, 5, 5); break; + for(int i = 0; i < 4; i++) { + uint8_t reg = 0; + switch(GetMirroringType()) { + case MirroringType::FourScreens: break; //4-screen mirroring is not supported by this mapper + case MirroringType::Vertical: reg = i & 0x01; break; + case MirroringType::Horizontal: reg = (i & 0x02) >> 1; break; + case MirroringType::ScreenAOnly: reg = 0; break; + case MirroringType::ScreenBOnly: reg = 1; break; + } + + SetPpuMemoryMapping(0x2000+i*0x400, 0x2000+i*0x400+0x3FF, ChrMemoryType::Default, _ntRegs[reg] * 0x400, _chrRamSize > 0 ? MemoryAccessType::ReadWrite : MemoryAccessType::Read); } } else { //Reset to default mirroring @@ -57,11 +59,6 @@ protected: BaseMapper::StreamState(saving); Stream(_ntRegs[0], _ntRegs[1], _useChrForNametables, _prgRamEnabled, _usingExternalRom, _externalPage); - - if(!saving) { - UpdateNametables(); - UpdateState(); - } } void UpdateState() diff --git a/Core/Types.h b/Core/Types.h index 321edfab..68b0ba2a 100644 --- a/Core/Types.h +++ b/Core/Types.h @@ -78,7 +78,8 @@ enum class ChrMemoryType { Default, ChrRom, - ChrRam + ChrRam, + NametableRam }; enum MemoryAccessType @@ -90,12 +91,6 @@ enum MemoryAccessType ReadWrite = 0x03 }; -enum ChrSpecialPage -{ - NametableA = 0x7000, - NametableB = 0x7001 -}; - enum class MirroringType { Horizontal, @@ -123,8 +118,6 @@ struct CartridgeState ChrMemoryType ChrType[0x40]; MemoryAccessType ChrMemoryAccess[0x40]; - uint32_t Nametables[8]; - uint32_t WorkRamPageSize; uint32_t SaveRamPageSize; diff --git a/Core/UnRom512.h b/Core/UnRom512.h index 662b1fb7..85fc061c 100644 --- a/Core/UnRom512.h +++ b/Core/UnRom512.h @@ -24,15 +24,11 @@ protected: } else { _enableMirroringBit = GetMirroringType() == MirroringType::FourScreens; } - } - void SetDefaultNametables(uint8_t* nametableA, uint8_t* nametableB) override - { - BaseMapper::SetDefaultNametables(nametableA, nametableB); if(GetMirroringType() == MirroringType::FourScreens && _chrRam && _chrRamSize >= 0x8000) { //InfiniteNesLives four-screen mirroring variation, last 8kb of CHR RAM is always mapped to 0x2000-0x3FFF (0x3EFF due to palette) //This "breaks" the "UNROM512_4screen_test" test ROM - was the ROM actually tested on this board? Seems to contradict hardware specs - SetPpuMemoryMapping(0x2000, 0x3FFF, _chrRam + 0x6000); + SetPpuMemoryMapping(0x2000, 0x3FFF, ChrMemoryType::ChrRam, 0x6000, MemoryAccessType::ReadWrite); } } diff --git a/GUI.NET/Debugger/Controls/ctrlMemoryMapping.cs b/GUI.NET/Debugger/Controls/ctrlMemoryMapping.cs index 49d91cee..5c515e96 100644 --- a/GUI.NET/Debugger/Controls/ctrlMemoryMapping.cs +++ b/GUI.NET/Debugger/Controls/ctrlMemoryMapping.cs @@ -135,6 +135,11 @@ namespace Mesen.GUI.Debugger.Controls if(memoryType == null) { regions.Add(new MemoryRegionInfo() { Name = "N/A", Size = currentSize, Color = Color.FromArgb(222, 222, 222) }); + } else if(memoryType == ChrMemoryType.NametableRam) { + int page = (int)(state.ChrMemoryOffset[startIndex] / 0x400); + Color color = alternateColor ? Color.FromArgb(0xF4, 0xC7, 0xD4) : Color.FromArgb(0xD4, 0xA7, 0xB4); + alternateColor = !alternateColor; + regions.Add(new MemoryRegionInfo() { Name = "NT" + page.ToString(), Size = currentSize, Color = color }); } else if(memoryType == ChrMemoryType.ChrRom || memoryType == ChrMemoryType.Default && state.ChrRomSize > 0) { int page = (int)(state.ChrMemoryOffset[startIndex] / state.ChrPageSize); Color color = alternateColor ? Color.FromArgb(0xC4, 0xE7, 0xD4) : Color.FromArgb(0xA4, 0xD7, 0xB4); @@ -150,9 +155,16 @@ namespace Mesen.GUI.Debugger.Controls startIndex = i; }; - for(int i = 0; i < 0x20; i++) { + for(int i = 0; i < 0x30; i++) { if(state.ChrMemoryAccess[i] != MemoryAccessType.NoAccess) { - bool forceNewBlock = (i - startIndex) << 8 >= state.ChrPageSize; + bool forceNewBlock = false; + int blockSize = (i - startIndex) << 8; + if(memoryType == ChrMemoryType.NametableRam && blockSize >= 0x400) { + forceNewBlock = true; + } else if(memoryType != ChrMemoryType.NametableRam && blockSize >= state.ChrPageSize) { + forceNewBlock = true; + } + if(forceNewBlock || memoryType != state.ChrMemoryType[i] || state.ChrMemoryOffset[i] - state.ChrMemoryOffset[i - 1] != 0x100) { addSection(i); } @@ -169,10 +181,6 @@ namespace Mesen.GUI.Debugger.Controls } addSection(-1); - for(int i = 0; i < 4; i++) { - regions.Add(new MemoryRegionInfo() { Name = "NT " + state.Nametables[i].ToString(), Size = 0x400, Color = i % 2 == 0 ? Color.FromArgb(0xF4, 0xC7, 0xD4) : Color.FromArgb(0xD4, 0xA7, 0xB4) }); - } - UpdateRegionArray(regions); } diff --git a/GUI.NET/InteropEmu.cs b/GUI.NET/InteropEmu.cs index 028437ee..98af9707 100644 --- a/GUI.NET/InteropEmu.cs +++ b/GUI.NET/InteropEmu.cs @@ -1227,7 +1227,8 @@ namespace Mesen.GUI { Default, ChrRom, - ChrRam + ChrRam, + NametableRam } public enum MemoryAccessType @@ -1290,9 +1291,6 @@ namespace Mesen.GUI [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x40)] public MemoryAccessType[] ChrMemoryAccess; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] - public UInt32[] Nametables; - public UInt32 WorkRamPageSize; public UInt32 SaveRamPageSize;