diff --git a/Core/BaseCartridge.cpp b/Core/BaseCartridge.cpp index becf15b..508001c 100644 --- a/Core/BaseCartridge.cpp +++ b/Core/BaseCartridge.cpp @@ -57,7 +57,7 @@ shared_ptr BaseCartridge::CreateCartridge(Console* console, Virtu cart->_romPath = romFile; if(FolderUtilities::GetExtension(romFile.GetFileName()) == ".bs") { - cart->_bsxMemPack.reset(new BsxMemoryPack(romData)); + cart->_bsxMemPack.reset(new BsxMemoryPack(console, romData, false)); if(!FirmwareHelper::LoadBsxFirmware(console, &cart->_prgRom, cart->_prgRomSize)) { return nullptr; } @@ -329,6 +329,10 @@ void BaseCartridge::SaveBattery() if(_coprocessor && _hasBattery) { _coprocessor->SaveBattery(); } + + if(_bsxMemPack) { + _bsxMemPack->SaveBattery(); + } } void BaseCartridge::Init(MemoryMappings &mm) @@ -363,6 +367,7 @@ void BaseCartridge::Init(MemoryMappings &mm) void BaseCartridge::RegisterHandlers(MemoryMappings &mm) { if(MapSpecificCarts(mm) || _coprocessorType == CoprocessorType::GSU || _coprocessorType == CoprocessorType::SDD1 || _coprocessorType == CoprocessorType::SPC7110 || _coprocessorType == CoprocessorType::CX4) { + MapBsxMemoryPack(mm); return; } @@ -403,6 +408,8 @@ void BaseCartridge::RegisterHandlers(MemoryMappings &mm) mm.RegisterHandler(0x70, 0x7D, 0x0000, 0x7FFF, _saveRamHandlers); mm.RegisterHandler(0xA0, 0xBF, 0x6000, 0x7FFF, _saveRamHandlers); } + + MapBsxMemoryPack(mm); } void BaseCartridge::LoadEmbeddedFirmware() @@ -444,7 +451,7 @@ void BaseCartridge::InitCoprocessor() if(!_bsxMemPack) { //Create an empty memory pack if the BIOS was loaded directly (instead of a .bs file) vector emptyMemPack; - _bsxMemPack.reset(new BsxMemoryPack(emptyMemPack)); + _bsxMemPack.reset(new BsxMemoryPack(_console, emptyMemPack, false)); } _coprocessor.reset(new BsxCart(_console, _bsxMemPack.get())); @@ -489,6 +496,32 @@ bool BaseCartridge::MapSpecificCarts(MemoryMappings &mm) return false; } +void BaseCartridge::MapBsxMemoryPack(MemoryMappings& mm) +{ + string code = GetGameCode(); + if(!_bsxMemPack && code.size() == 4 && code[0] == 'Z' && _cartInfo.DeveloperId == 0x33) { + //Game with data pack slot (e.g Sound Novel Tsukuuru, etc.) + vector saveData = _console->GetBatteryManager()->LoadBattery(".bs"); + if(saveData.empty()) { + //Make a 1 megabyte flash cartridge by default (use $FF for all bytes) + saveData.resize(0x100000, 0xFF); + } + _bsxMemPack.reset(new BsxMemoryPack(_console, saveData, true)); + + if(_flags & CartFlags::LoRom) { + mm.RegisterHandler(0xC0, 0xEF, 0x0000, 0x7FFF, _bsxMemPack->GetMemoryHandlers()); + mm.RegisterHandler(0xC0, 0xEF, 0x8000, 0xFFFF, _bsxMemPack->GetMemoryHandlers()); + } else { + mm.RegisterHandler(0x20, 0x3F, 0x8000, 0xFFFF, _bsxMemPack->GetMemoryHandlers(), 8); + mm.RegisterHandler(0x60, 0x7D, 0x0000, 0xFFFF, _bsxMemPack->GetMemoryHandlers()); + mm.RegisterHandler(0xA0, 0xBF, 0x8000, 0xFFFF, _bsxMemPack->GetMemoryHandlers(), 8); + mm.RegisterHandler(0xE0, 0xFF, 0x0000, 0xFFFF, _bsxMemPack->GetMemoryHandlers()); + } + + //TODO: SA-1 cartridges, etc. + } +} + void BaseCartridge::ApplyConfigOverrides() { string name = GetCartName(); @@ -539,16 +572,16 @@ void BaseCartridge::Serialize(Serializer &s) string BaseCartridge::GetGameCode() { string code; - if(_cartInfo.GameCode[0] >= ' ') { + if(_cartInfo.GameCode[0] > ' ') { code += _cartInfo.GameCode[0]; } - if(_cartInfo.GameCode[1] >= ' ') { + if(_cartInfo.GameCode[1] > ' ') { code += _cartInfo.GameCode[1]; } - if(_cartInfo.GameCode[2] >= ' ') { + if(_cartInfo.GameCode[2] > ' ') { code += _cartInfo.GameCode[2]; } - if(_cartInfo.GameCode[3] >= ' ') { + if(_cartInfo.GameCode[3] > ' ') { code += _cartInfo.GameCode[3]; } return code; diff --git a/Core/BaseCartridge.h b/Core/BaseCartridge.h index eaa1dce..938bdf9 100644 --- a/Core/BaseCartridge.h +++ b/Core/BaseCartridge.h @@ -62,7 +62,8 @@ private: CoprocessorType GetSt01xVersion(); CoprocessorType GetDspVersion(); - bool MapSpecificCarts(MemoryMappings &mm); + bool MapSpecificCarts(MemoryMappings& mm); + void MapBsxMemoryPack(MemoryMappings& mm); void ApplyConfigOverrides(); void LoadRom(); diff --git a/Core/BsxMemoryPack.cpp b/Core/BsxMemoryPack.cpp index f7728de..30e219f 100644 --- a/Core/BsxMemoryPack.cpp +++ b/Core/BsxMemoryPack.cpp @@ -1,12 +1,16 @@ #include "stdafx.h" #include "BsxMemoryPack.h" +#include "Console.h" +#include "BatteryManager.h" #include "../Utilities/IpsPatcher.h" -BsxMemoryPack::BsxMemoryPack(vector& data) +BsxMemoryPack::BsxMemoryPack(Console* console, vector& data, bool persistFlash) { + _console = console; _orgData = data; _dataSize = (uint32_t)data.size(); _data = new uint8_t[_dataSize]; + _persistFlash = persistFlash; memcpy(_data, data.data(), _dataSize); _calculatedSize = std::min(0x0C, (uint8_t)log2(_dataSize >> 10)); @@ -21,6 +25,13 @@ BsxMemoryPack::~BsxMemoryPack() delete[] _data; } +void BsxMemoryPack::SaveBattery() +{ + if(_persistFlash) { + _console->GetBatteryManager()->SaveBattery(".bs", _data, _dataSize); + } +} + void BsxMemoryPack::Serialize(Serializer& s) { s.Stream(_enableCsr, _enableEsr, _enableVendorInfo, _writeByte, _command); @@ -105,12 +116,10 @@ BsxMemoryPack::BsxMemoryPackHandler::BsxMemoryPackHandler(BsxMemoryPack* memPack uint8_t BsxMemoryPack::BsxMemoryPackHandler::Read(uint32_t addr) { - if(addr >= 0xC00000) { - if(_memPack->_enableEsr) { - switch(addr & 0xFFFF) { - case 0x0002: return 0xC0; - case 0x0004: return 0x82; - } + if(_offset == 0 && _memPack->_enableEsr) { + switch(addr & 0xFFF) { + case 0x0002: return 0xC0; + case 0x0004: return 0x82; } } @@ -143,7 +152,7 @@ void BsxMemoryPack::BsxMemoryPackHandler::Write(uint32_t addr, uint8_t value) uint8_t currentByte = RamHandler::Read(addr); RamHandler::Write(addr, value & currentByte); _memPack->_writeByte = false; - } else if(addr == 0xC00000) { + } else if(_offset == 0 && (addr & 0xFFF) == 0) { _memPack->ProcessCommand(value, _page); } } diff --git a/Core/BsxMemoryPack.h b/Core/BsxMemoryPack.h index c5c4629..f49ccfc 100644 --- a/Core/BsxMemoryPack.h +++ b/Core/BsxMemoryPack.h @@ -5,9 +5,12 @@ #include "../Utilities/ISerializable.h" class BsxMemoryPackHandler; +class Console; class BsxMemoryPack : public ISerializable { +private: + Console* _console = nullptr; vector _orgData; uint8_t* _data = nullptr; uint32_t _dataSize = 0; @@ -15,6 +18,7 @@ class BsxMemoryPack : public ISerializable uint8_t _calculatedSize = 0x0C; + bool _persistFlash = false; bool _enableCsr = false; bool _enableEsr = false; bool _enableVendorInfo = false; @@ -22,9 +26,11 @@ class BsxMemoryPack : public ISerializable uint16_t _command = 0; public: - BsxMemoryPack(vector& data); + BsxMemoryPack(Console* console, vector& data, bool persistFlash); virtual ~BsxMemoryPack(); + void SaveBattery(); + void Serialize(Serializer& s) override; void ProcessCommand(uint8_t value, uint32_t page); diff --git a/Core/CartTypes.h b/Core/CartTypes.h index 4c32875..71bf090 100644 --- a/Core/CartTypes.h +++ b/Core/CartTypes.h @@ -18,7 +18,7 @@ struct SnesCartInformation uint8_t SramSize; uint8_t DestinationCode; - uint8_t Reserved2; + uint8_t DeveloperId; uint8_t Version; uint8_t ChecksumComplement[2]; diff --git a/Core/RamHandler.h b/Core/RamHandler.h index e798526..1476f57 100644 --- a/Core/RamHandler.h +++ b/Core/RamHandler.h @@ -7,9 +7,11 @@ class RamHandler : public IMemoryHandler { private: uint8_t * _ram; - uint32_t _offset; uint32_t _mask; +protected: + uint32_t _offset; + public: RamHandler(uint8_t *ram, uint32_t offset, uint32_t size, SnesMemoryType memoryType) {