mirror of
https://github.com/libretro/MesenCE.git
synced 2026-11-11 17:26:45 -10:00
175 lines
4.3 KiB
C++
175 lines
4.3 KiB
C++
#include "pch.h"
|
|
#include "WS/WsMemoryManager.h"
|
|
#include "WS/Carts/WsCartWonderWitch.h"
|
|
#include "Shared/BatteryManager.h"
|
|
#include "Shared/Emulator.h"
|
|
|
|
//TODOWS sector protection
|
|
//TODOWS timing, more accurate status reads during programming
|
|
//TODOWS more verification with datasheet and hardware
|
|
|
|
WsCartWonderWitch::WsCartWonderWitch(WsRtc* rtc) : WsCartBandai2003(rtc)
|
|
{
|
|
_hasCustomReadHandler = true;
|
|
_hasCustomWriteHandler = true;
|
|
_saveFlashRom = false;
|
|
}
|
|
|
|
void WsCartWonderWitch::LoadBattery()
|
|
{
|
|
WsCartBandai2003::LoadBattery();
|
|
_emu->GetBatteryManager()->LoadBattery(".flash", _prgRom, _prgRomSize);
|
|
}
|
|
|
|
void WsCartWonderWitch::SaveBattery()
|
|
{
|
|
WsCartBandai2003::SaveBattery();
|
|
if(_saveFlashRom) {
|
|
_emu->GetBatteryManager()->SaveBattery(".flash", _prgRom, _prgRomSize);
|
|
}
|
|
}
|
|
|
|
uint32_t WsCartWonderWitch::GetPhysicalAddress(uint32_t addr)
|
|
{
|
|
if(addr >= 0x40000) {
|
|
return (GetSelectedBank(0) << 20) | (addr & 0xFFFFF);
|
|
} else {
|
|
return (GetSelectedBank(addr >> 16) << 16) | (addr & 0xFFFF);
|
|
}
|
|
}
|
|
|
|
bool WsCartWonderWitch::InternalReadCart(uint32_t addr, uint8_t& value)
|
|
{
|
|
if(addr < 0x10000) {
|
|
return false;
|
|
}
|
|
|
|
bool sram = ((addr >> 16) == 1) && !_state.RomInRamBank;
|
|
uint32_t physAddr = GetPhysicalAddress(addr);
|
|
|
|
if(sram) {
|
|
value = _saveRam[physAddr & (_saveRamSize - 1)];
|
|
return true;
|
|
}
|
|
|
|
physAddr &= _prgRomSize - 1;
|
|
|
|
uint8_t sector = physAddr >= 0x60000 ? 1 : 0;
|
|
|
|
value = _prgRom[physAddr];
|
|
if(_mode[sector] == Mode::Fast) {
|
|
value = (value & 0x80) | 0x04;
|
|
} else if(_mode[sector] == Mode::Autoselect) {
|
|
//TODOWS support word bus reads correctly
|
|
if((physAddr & 0x87) == 0x00) {
|
|
value = 0x04;
|
|
} else if((physAddr & 0x87) == 0x02) {
|
|
value = 0x0C;
|
|
} else if((physAddr & 0x87) == 0x04) {
|
|
value = 0x00;
|
|
}
|
|
//TODOWS what is read at other addresses?
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool WsCartWonderWitch::InternalWriteCart(uint32_t addr, uint8_t value)
|
|
{
|
|
if(addr < 0x10000) {
|
|
return false;
|
|
}
|
|
|
|
bool sram = ((addr >> 16) == 1) && !_state.RomInRamBank;
|
|
uint32_t physAddr = GetPhysicalAddress(addr);
|
|
|
|
if(sram) {
|
|
_saveRam[physAddr & (_saveRamSize - 1)] = value;
|
|
return true;
|
|
}
|
|
|
|
physAddr &= _prgRomSize - 1;
|
|
|
|
uint8_t sector = physAddr >= 0x60000 ? 1 : 0;
|
|
if(_mode[sector] == Mode::Program) {
|
|
_saveFlashRom = true;
|
|
_prgRom[physAddr] &= value;
|
|
_mode[sector] = Mode::Read;
|
|
} else if(_mode[sector] == Mode::FastProgram) {
|
|
_saveFlashRom = true;
|
|
_prgRom[physAddr] &= value;
|
|
_mode[sector] = Mode::Fast;
|
|
} else if(_mode[sector] == Mode::Fast) {
|
|
if(value == 0xA0) {
|
|
_mode[sector] = Mode::FastProgram;
|
|
} else if(value == 0x90) {
|
|
_mode[sector] = Mode::Read;
|
|
}
|
|
} else {
|
|
//TODOWS how does this operate in erase mode?
|
|
if(value == 0xF0) {
|
|
_mode[sector] = Mode::Read;
|
|
}
|
|
|
|
if(_unlock == 0 && value == 0xAA && (physAddr & 0xFFF) == 0xAAA) {
|
|
_unlock = 1;
|
|
} else if(_unlock == 1) {
|
|
_unlock = (value == 0x55 && (physAddr & 0xFFF) == 0x555) ? 2 : 0;
|
|
} else if(_unlock == 2) {
|
|
if(_mode[sector] == Mode::Erase) {
|
|
if(value == 0x10) {
|
|
_saveFlashRom = true;
|
|
memset(_prgRom, 0xFF, _prgRomSize);
|
|
} else if(value == 0x30) {
|
|
uint32_t offset, size;
|
|
if(physAddr < 0x60000) {
|
|
offset = physAddr & 0x70000;
|
|
size = 0x10000;
|
|
} else if(physAddr < 0x64000) {
|
|
offset = 0x60000;
|
|
size = 0x4000;
|
|
} else if(physAddr < 0x6c000) {
|
|
offset = 0x64000;
|
|
size = 0x8000;
|
|
} else if(physAddr < 0x74000) {
|
|
offset = physAddr & 0x7e000;
|
|
size = 0x2000;
|
|
} else if(physAddr < 0x7c000) {
|
|
offset = 0x74000;
|
|
size = 0x8000;
|
|
} else {
|
|
offset = 0x7c000;
|
|
size = 0x4000;
|
|
}
|
|
_saveFlashRom = true;
|
|
memset(_prgRom + offset, 0xFF, size);
|
|
}
|
|
_mode[sector] = Mode::Read;
|
|
} else {
|
|
switch(value) {
|
|
case 0x90: _mode[sector] = Mode::Autoselect; break;
|
|
case 0xA0: _mode[sector] = Mode::Program; break;
|
|
case 0x80: _mode[sector] = Mode::Erase; break;
|
|
case 0x20: _mode[sector] = Mode::Fast; break;
|
|
}
|
|
}
|
|
|
|
_unlock = 0;
|
|
if(_mode[0] != Mode::Read && _mode[1] != Mode::Read) {
|
|
_mode[sector ^ 1] = Mode::Read;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void WsCartWonderWitch::Serialize(Serializer& s)
|
|
{
|
|
WsCartBandai2003::Serialize(s);
|
|
SV(_unlock);
|
|
SVArray(_mode, 2);
|
|
SV(_saveFlashRom);
|
|
|
|
//TODOWS rom would need to be in save state data for rewind/step back/etc. to work properly after the rom is modified
|
|
}
|