mirror of
https://github.com/libretro/Mesen.git
synced 2024-11-27 11:00:50 +00:00
119 lines
2.5 KiB
C++
119 lines
2.5 KiB
C++
#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 & 0x7FFF;
|
|
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();
|
|
}
|
|
}
|
|
}
|
|
}; |