#pragma once #include "stdafx.h" #include "BaseMapper.h" #include "FlashSST39SF040.h" #include "../Utilities/IpsPatcher.h" class Cheapocabra : public BaseMapper { private: unique_ptr _flash; uint8_t _prgReg = 0; vector _orgPrgRom; protected: uint16_t GetPRGPageSize() override { return 0x8000; } uint16_t GetCHRPageSize() override { return 0x2000; } uint32_t GetWorkRamSize() override { return 0; } uint32_t GetSaveRamSize() override { return 0; } uint16_t RegisterStartAddress() override { return 0x5000; } uint16_t RegisterEndAddress() override { return 0x5FFF; } uint32_t GetChrRamSize() override { return 0x4000; } bool AllowRegisterRead() override { return true; } void InitMapper() override { AddRegisterRange(0x7000, 0x7FFF, MemoryOperation::Write); _flash.reset(new FlashSST39SF040(_prgRom, _prgSize)); AddRegisterRange(0x8000, 0xFFFF, MemoryOperation::Any); RemoveRegisterRange(0x5000, 0x5FFF, MemoryOperation::Read); WriteRegister(0x5000, GetPowerOnByte()); _orgPrgRom = vector(_prgRom, _prgRom + _prgSize); ApplySaveData(); } void StreamState(bool saving) override { BaseMapper::StreamState(saving); SnapshotInfo flash { _flash.get() }; Stream(_prgReg, flash); } void ApplySaveData() { //Apply save data (saved as an IPS file), if found vector ipsData = _console->GetBatteryManager()->LoadBattery(".ips"); if(!ipsData.empty()) { vector patchedPrgRom; if(IpsPatcher::PatchBuffer(ipsData, _orgPrgRom, patchedPrgRom)) { memcpy(_prgRom, patchedPrgRom.data(), _prgSize); } } } void SaveBattery() override { vector prgRom = vector(_prgRom, _prgRom + _prgSize); vector ipsData = IpsPatcher::CreatePatch(_orgPrgRom, prgRom); if(ipsData.size() > 8) { _console->GetBatteryManager()->SaveBattery(".ips", ipsData.data(), (uint32_t)ipsData.size()); } } uint8_t ReadRegister(uint16_t addr) override { int16_t value = _flash->Read(addr); if(value >= 0) { return (uint8_t)value; } return BaseMapper::InternalReadRam(addr); } void WriteRegister(uint16_t addr, uint8_t value) override { if(addr < 0x8000) { _prgReg = value & 0x0F; SelectPRGPage(0, _prgReg); SelectCHRPage(0, (value >> 4) & 0x01); for(int i = 0; i < 8; i++) { SetNametable(i, ((value & 0x20) ? 8 : 0) + i); } } else { _flash->Write((_prgReg << 15) | (addr & 0x7FFF), value); } } };