UNROM512: Added self flash support
This commit is contained in:
parent
3fde8f8073
commit
b5a0f9a4f1
4 changed files with 205 additions and 8 deletions
|
@ -562,6 +562,7 @@
|
|||
<ClInclude Include="FaridSlrom.h" />
|
||||
<ClInclude Include="FaridUnrom.h" />
|
||||
<ClInclude Include="FdsSystemActionManager.h" />
|
||||
<ClInclude Include="FlashSST39SF040.h" />
|
||||
<ClInclude Include="Gkcx1.h" />
|
||||
<ClInclude Include="HdPackConditions.h" />
|
||||
<ClInclude Include="HistoryViewer.h" />
|
||||
|
|
|
@ -1499,6 +1499,9 @@
|
|||
<ClInclude Include="MMC5MemoryHandler.h">
|
||||
<Filter>Nes\Mappers\MMC</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="FlashSST39SF040.h">
|
||||
<Filter>Nes\Mappers</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
|
|
119
Core/FlashSST39SF040.h
Normal file
119
Core/FlashSST39SF040.h
Normal file
|
@ -0,0 +1,119 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "Snapshotable.h"
|
||||
|
||||
//SST39SF040 chip emulation - used by mapper 30 (UNROM512) & mapper 111 (GTROM)
|
||||
class FlashSST39SF040 : public Snapshotable
|
||||
{
|
||||
private:
|
||||
enum class ChipMode
|
||||
{
|
||||
WaitingForCommand,
|
||||
Write,
|
||||
Erase
|
||||
};
|
||||
|
||||
ChipMode _mode = ChipMode::WaitingForCommand;
|
||||
uint8_t _cycle = 0;
|
||||
uint8_t _softwareId = false;
|
||||
|
||||
//PRG data and size
|
||||
uint8_t* _data;
|
||||
uint32_t _size;
|
||||
|
||||
protected:
|
||||
void StreamState(bool saving)
|
||||
{
|
||||
Stream(_mode, _cycle, _softwareId);
|
||||
}
|
||||
|
||||
public:
|
||||
FlashSST39SF040(uint8_t* data, uint32_t size)
|
||||
{
|
||||
_data = data;
|
||||
_size = size;
|
||||
}
|
||||
|
||||
int16_t Read(uint32_t addr)
|
||||
{
|
||||
if(_softwareId) {
|
||||
switch(addr & 0x1FF) {
|
||||
case 0x00: return 0xBF;
|
||||
case 0x01: return 0xB7;
|
||||
default: return 0xFF;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void ResetState()
|
||||
{
|
||||
_mode = ChipMode::WaitingForCommand;
|
||||
_cycle = 0;
|
||||
}
|
||||
|
||||
void Write(uint32_t addr, uint8_t value)
|
||||
{
|
||||
uint16_t cmd = addr & 0xFFFF;
|
||||
if(_mode == ChipMode::WaitingForCommand) {
|
||||
if(_cycle == 0) {
|
||||
if(cmd == 0x5555 && value == 0xAA) {
|
||||
//1st write, $5555 = $AA
|
||||
_cycle++;
|
||||
} else if(value == 0xF0) {
|
||||
//Software ID exit
|
||||
ResetState();
|
||||
_softwareId = false;
|
||||
}
|
||||
} else if(_cycle == 1 && cmd == 0x2AAA && value == 0x55) {
|
||||
//2nd write, $2AAA = $55
|
||||
_cycle++;
|
||||
} else if(_cycle == 2 && cmd == 0x5555) {
|
||||
//3rd write, determines command type
|
||||
_cycle++;
|
||||
switch(value) {
|
||||
case 0x80: _mode = ChipMode::Erase; break;
|
||||
case 0x90: ResetState(); _softwareId = true; break;
|
||||
case 0xA0: _mode = ChipMode::Write; break;
|
||||
case 0xF0: ResetState(); _softwareId = false; break;
|
||||
}
|
||||
} else {
|
||||
_cycle = 0;
|
||||
}
|
||||
} else if(_mode == ChipMode::Write) {
|
||||
//Write a single byte
|
||||
if(addr < _size) {
|
||||
_data[addr] &= value;
|
||||
}
|
||||
ResetState();
|
||||
} else if(_mode == ChipMode::Erase) {
|
||||
if(_cycle == 3) {
|
||||
//4th write for erase command, $5555 = $AA
|
||||
if(cmd == 0x5555 && value == 0xAA) {
|
||||
_cycle++;
|
||||
} else {
|
||||
ResetState();
|
||||
}
|
||||
} else if(_cycle == 4) {
|
||||
//5th write for erase command, $2AAA = $55
|
||||
if(cmd == 0x2AAA && value == 0x55) {
|
||||
_cycle++;
|
||||
} else {
|
||||
ResetState();
|
||||
}
|
||||
} else if(_cycle == 5) {
|
||||
if(cmd == 0x5555 && value == 0x10) {
|
||||
//Chip erase
|
||||
memset(_data, 0xFF, _size);
|
||||
} else if(value == 0x30) {
|
||||
//Sector erase
|
||||
uint32_t offset = (addr & 0x7F000);
|
||||
if(offset + 0x1000 <= _size) {
|
||||
memset(_data + offset, 0xFF, 0x1000);
|
||||
}
|
||||
}
|
||||
ResetState();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
|
@ -1,23 +1,32 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "BaseMapper.h"
|
||||
#include "FlashSST39SF040.h"
|
||||
#include "../Utilities/IpsPatcher.h"
|
||||
|
||||
//Missing flashing support + only tested on 1 game demo
|
||||
class UnRom512 : public BaseMapper
|
||||
{
|
||||
private:
|
||||
unique_ptr<FlashSST39SF040> _flash;
|
||||
bool _enableMirroringBit;
|
||||
uint8_t _prgBank = 0;
|
||||
vector<uint8_t> _orgPrgRom;
|
||||
|
||||
protected:
|
||||
virtual uint16_t GetPRGPageSize() override { return 0x4000; }
|
||||
virtual uint16_t GetCHRPageSize() override { return 0x2000; }
|
||||
virtual uint16_t RegisterStartAddress() override { return 0x8000; }
|
||||
virtual uint16_t RegisterEndAddress() override { return 0xFFFF; }
|
||||
virtual uint32_t GetChrRamSize() override { return 0x8000; }
|
||||
virtual bool HasBusConflicts() override { return !HasBattery(); }
|
||||
uint16_t GetPRGPageSize() override { return 0x4000; }
|
||||
uint16_t GetCHRPageSize() override { return 0x2000; }
|
||||
uint32_t GetWorkRamSize() override { return 0; }
|
||||
uint32_t GetSaveRamSize() override { return 0; }
|
||||
uint16_t RegisterStartAddress() override { return 0x8000; }
|
||||
uint16_t RegisterEndAddress() override { return 0xFFFF; }
|
||||
uint32_t GetChrRamSize() override { return 0x8000; }
|
||||
bool HasBusConflicts() override { return !HasBattery(); }
|
||||
bool AllowRegisterRead() override { return HasBattery(); }
|
||||
|
||||
void InitMapper() override
|
||||
{
|
||||
_flash.reset(new FlashSST39SF040(_prgRom, _prgSize));
|
||||
SelectPRGPage(0, 0);
|
||||
SelectPRGPage(1, -1);
|
||||
|
||||
_enableMirroringBit = false;
|
||||
|
@ -33,19 +42,84 @@ protected:
|
|||
//This "breaks" the "UNROM512_4screen_test" test ROM - was the ROM actually tested on this board? Seems to contradict hardware specs
|
||||
SetPpuMemoryMapping(0x2000, 0x3FFF, ChrMemoryType::ChrRam, 0x6000, MemoryAccessType::ReadWrite);
|
||||
}
|
||||
|
||||
if(HasBattery()) {
|
||||
AddRegisterRange(0x8000, 0xFFFF, MemoryOperation::Read);
|
||||
_orgPrgRom = vector<uint8_t>(_prgRom, _prgRom + _prgSize);
|
||||
ApplySaveData();
|
||||
}
|
||||
}
|
||||
|
||||
void StreamState(bool saving)
|
||||
{
|
||||
BaseMapper::StreamState(saving);
|
||||
|
||||
SnapshotInfo flash { _flash.get() };
|
||||
Stream(_prgBank, flash);
|
||||
|
||||
if(saving) {
|
||||
vector<uint8_t> prgRom = vector<uint8_t>(_prgRom, _prgRom + _prgSize);
|
||||
vector<uint8_t> ipsData = IpsPatcher::CreatePatch(_orgPrgRom, prgRom);
|
||||
VectorInfo<uint8_t> data { &ipsData };
|
||||
Stream(data);
|
||||
} else {
|
||||
vector<uint8_t> ipsData;
|
||||
VectorInfo<uint8_t> data { &ipsData };
|
||||
Stream(data);
|
||||
|
||||
vector<uint8_t> patchedPrgRom;
|
||||
if(IpsPatcher::PatchBuffer(ipsData, _orgPrgRom, patchedPrgRom)) {
|
||||
memcpy(_prgRom, patchedPrgRom.data(), _prgSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ApplySaveData()
|
||||
{
|
||||
//Apply save data (saved as an IPS file), if found
|
||||
vector<uint8_t> ipsData = _console->GetBatteryManager()->LoadBattery(".ips");
|
||||
if(!ipsData.empty()) {
|
||||
vector<uint8_t> patchedPrgRom;
|
||||
if(IpsPatcher::PatchBuffer(ipsData, _orgPrgRom, patchedPrgRom)) {
|
||||
memcpy(_prgRom, patchedPrgRom.data(), _prgSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SaveBattery() override
|
||||
{
|
||||
if(HasBattery()) {
|
||||
vector<uint8_t> prgRom = vector<uint8_t>(_prgRom, _prgRom + _prgSize);
|
||||
vector<uint8_t> 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(!HasBattery() || addr >= 0xC000) {
|
||||
SelectPRGPage(0, value & 0x1F);
|
||||
_prgBank = value & 0x1F;
|
||||
|
||||
SelectCHRPage(0, (value >> 5) & 0x03);
|
||||
|
||||
if(_enableMirroringBit) {
|
||||
SetMirroringType(value & 0x80 ? MirroringType::ScreenBOnly : MirroringType::ScreenAOnly);
|
||||
}
|
||||
} else {
|
||||
//Unimplemented (flash process)
|
||||
_flash->Write((addr & 0x3FFF) | (_prgBank << 14), value);
|
||||
}
|
||||
}
|
||||
};
|
Loading…
Add table
Reference in a new issue