mirror of
https://github.com/SourMesen/Mesen2.git
synced 2025-04-02 10:21:44 -04:00
181 lines
No EOL
3.6 KiB
C++
181 lines
No EOL
3.6 KiB
C++
#pragma once
|
|
#include "pch.h"
|
|
#include "Utilities/ISerializable.h"
|
|
#include "Utilities/Serializer.h"
|
|
|
|
class Eeprom93Lc56 final : public ISerializable
|
|
{
|
|
private:
|
|
enum class Mode
|
|
{
|
|
Idle,
|
|
Command,
|
|
ReadCommand,
|
|
WriteCommand,
|
|
WriteAllCommand
|
|
};
|
|
|
|
uint8_t* _saveRam = nullptr;
|
|
|
|
Mode _mode = Mode::Idle;
|
|
|
|
bool _chipSelect = false;
|
|
bool _clk = false;
|
|
uint8_t _dataIn = 0;
|
|
bool _writeEnabled = false;
|
|
|
|
uint16_t _commandId = 0;
|
|
uint8_t _bitCount = 0;
|
|
|
|
uint8_t _readAddress = 0;
|
|
int8_t _readCounter = -1;
|
|
|
|
uint16_t _writeData = 0;
|
|
uint8_t _writeCounter = 0;
|
|
|
|
public:
|
|
void SetRam(uint8_t* saveRam)
|
|
{
|
|
_saveRam = saveRam;
|
|
}
|
|
|
|
uint8_t Read()
|
|
{
|
|
uint8_t result = (
|
|
(_chipSelect ? 0x80 : 0) |
|
|
(_clk ? 0x40 : 0) |
|
|
(_dataIn ? 0x02 : 0)
|
|
);
|
|
|
|
if(_mode == Mode::ReadCommand) {
|
|
if(_readCounter < 0) {
|
|
return result | 0x01;
|
|
}
|
|
return result | ((_saveRam[(_readAddress << 1) + (_readCounter >= 8 ? 0 : 1)] >> (7 - (_readCounter & 0x07))) & 0x01);
|
|
} else {
|
|
return result | (_mode == Mode::Idle ? 1 : 0);
|
|
}
|
|
}
|
|
|
|
void Write(uint8_t value)
|
|
{
|
|
uint8_t prevClk = _clk;
|
|
bool clk = (value & 0x40);
|
|
_dataIn = (value & 0x02) >> 1;
|
|
_chipSelect = value & 0x80;
|
|
_clk = clk;
|
|
|
|
if(!_chipSelect) {
|
|
//Chip select is disabled, force idle
|
|
_mode = Mode::Idle;
|
|
return;
|
|
}
|
|
|
|
|
|
if(!clk || prevClk) {
|
|
//Not a rising clock
|
|
return;
|
|
}
|
|
|
|
switch(_mode) {
|
|
case Mode::Idle:
|
|
if(_dataIn) {
|
|
_mode = Mode::Command;
|
|
_commandId = 0;
|
|
_bitCount = 0;
|
|
_writeCounter = 0;
|
|
_writeData = 0;
|
|
_readCounter = -1;
|
|
_readAddress = 0;
|
|
}
|
|
break;
|
|
|
|
case Mode::Command:
|
|
_commandId <<= 1;
|
|
_commandId |= _dataIn;
|
|
_bitCount++;
|
|
|
|
if(_bitCount >= 10) {
|
|
uint8_t id = _commandId >> 6;
|
|
if((id & 0b1100) == 0b1000) {
|
|
_mode = Mode::ReadCommand;
|
|
_readAddress = _commandId & 0x7F;
|
|
} else if((id & 0b1100) == 0b0100) {
|
|
_mode = Mode::WriteCommand;
|
|
} else if((id & 0b1100) == 0b1100) {
|
|
if(_writeEnabled) {
|
|
uint8_t addr = _commandId & 0x7F;
|
|
_saveRam[addr << 1] = 0xFF;
|
|
_saveRam[(addr << 1) + 1] = 0xFF;
|
|
}
|
|
_mode = Mode::Idle;
|
|
} else if((id & 0b1111) == 0b0000) {
|
|
//Disable writes (EWDS)
|
|
_writeEnabled = false;
|
|
_mode = Mode::Idle;
|
|
} else if((id & 0b1111) == 0b0011) {
|
|
//Enable writes (EWEN)
|
|
_writeEnabled = true;
|
|
_mode = Mode::Idle;
|
|
} else if((id & 0b1111) == 0b0010) {
|
|
//Erase all (ERAL)
|
|
if(_writeEnabled) {
|
|
memset(_saveRam, 0xFF, 256);
|
|
}
|
|
_mode = Mode::Idle;
|
|
} else if((id & 0b1111) == 0b0001) {
|
|
//Write all (WRAL)
|
|
_mode = Mode::WriteAllCommand;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case Mode::ReadCommand:
|
|
_readCounter++;
|
|
if(_readCounter == 16) {
|
|
_readAddress = (_readAddress + 1) & 0x7F;
|
|
_readCounter = 0;
|
|
_mode = Mode::Idle;
|
|
}
|
|
break;
|
|
|
|
case Mode::WriteAllCommand:
|
|
case Mode::WriteCommand: {
|
|
_writeData <<= 1;
|
|
_writeData |= _dataIn;
|
|
_writeCounter++;
|
|
if(_writeCounter >= 16) {
|
|
if(_writeEnabled) {
|
|
if(_mode == Mode::WriteAllCommand) {
|
|
for(int i = 0; i < 0x80; i++) {
|
|
_saveRam[i << 1] = _writeData;
|
|
_saveRam[(i << 1) + 1] = _writeData >> 8;
|
|
}
|
|
} else {
|
|
uint8_t addr = _commandId & 0x7F;
|
|
_saveRam[addr << 1] = _writeData;
|
|
_saveRam[(addr << 1) + 1] = _writeData >> 8;
|
|
}
|
|
}
|
|
_mode = Mode::Idle;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Serialize(Serializer& s)
|
|
{
|
|
SV(_mode);
|
|
SV(_chipSelect);
|
|
SV(_clk);
|
|
SV(_dataIn);
|
|
SV(_writeEnabled);
|
|
SV(_commandId);
|
|
SV(_bitCount);
|
|
SV(_readAddress);
|
|
SV(_readCounter);
|
|
SV(_writeData);
|
|
SV(_writeCounter);
|
|
}
|
|
}; |