153 lines
3.8 KiB
C++
153 lines
3.8 KiB
C++
/*
|
|
Copyright 2023 flyinghead
|
|
|
|
This file is part of Flycast.
|
|
|
|
Flycast is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
Flycast is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
#include "at93cxx.h"
|
|
|
|
//#define DEBUG_EEPROM 1
|
|
|
|
#ifdef DEBUG_EEPROM
|
|
#define EEPROM_LOG(...) DEBUG_LOG(FLASHROM, __VA_ARGS__)
|
|
#else
|
|
#define EEPROM_LOG(...)
|
|
#endif
|
|
|
|
void AT93CxxSerialEeprom::writeCLK(bool state)
|
|
{
|
|
// CS asserted and CLK rising
|
|
if (!clk && state && cs)
|
|
{
|
|
if (dataOutBits > 0)
|
|
dataOutBits--;
|
|
if (dataOutBits == 0)
|
|
{
|
|
if (command.empty() && !di)
|
|
INFO_LOG(NAOMI, "serial eeprom: Ignoring bit 0 (start bit must be 1)");
|
|
else
|
|
{
|
|
command.push_back(di);
|
|
if (command.size() == 9)
|
|
{
|
|
int opCode = (int)command[1] * 2 + (int)command[2];
|
|
switch (opCode)
|
|
{
|
|
case 0: // write enable/disable, erase all, write all
|
|
{
|
|
int subCode = (int)command[3] * 2 + (int)command[4];
|
|
switch (subCode)
|
|
{
|
|
case 0: // disable write
|
|
EEPROM_LOG("serial eeprom: EWDS");
|
|
writeEnable = false;
|
|
command.clear();
|
|
break;
|
|
case 1: // write all
|
|
expected = 3 + 6 + 16; // 6 bits of address, 16 bits of data
|
|
break;
|
|
case 2: // erase all
|
|
EEPROM_LOG("serial eeprom: ERAL");
|
|
if (writeEnable)
|
|
memset(data, 0xff, size);
|
|
command.clear();
|
|
break;
|
|
case 3: // enable write
|
|
EEPROM_LOG("serial eeprom: EWEN");
|
|
writeEnable = true;
|
|
command.clear();
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case 1: // write
|
|
expected = 3 + 6 + 16; // 6 bits of address, 16 bits of data
|
|
break;
|
|
case 2: // read
|
|
dataOut = Read(getCommandAddress() * 2, 2);
|
|
dataOutBits = 17; // actually 16 but 0 means no data
|
|
EEPROM_LOG("serial eeprom: READ %x: %x", getCommandAddress(), dataOut);
|
|
command.clear();
|
|
break;
|
|
case 3: // erase
|
|
EEPROM_LOG("serial eeprom: ERASE %x", getCommandAddress());
|
|
if (writeEnable)
|
|
*(u16 *)&data[(getCommandAddress() * 2) & mask] = 0xffff;
|
|
command.clear();
|
|
break;
|
|
}
|
|
}
|
|
else if (expected > 0 && (int)command.size() == expected)
|
|
{
|
|
int opCode = (int)command[1] * 2 + (int)command[2];
|
|
switch (opCode)
|
|
{
|
|
case 0: // write all
|
|
{
|
|
u16 v = getCommandData();
|
|
EEPROM_LOG("serial eeprom: WRAL = %x", v);
|
|
if (writeEnable)
|
|
for (u32 i = 0; i < size; i += 2)
|
|
*(u16 *)&data[i & mask] = v;
|
|
}
|
|
break;
|
|
case 1: // write
|
|
EEPROM_LOG("serial eeprom: WRITE %x = %x", getCommandAddress(), getCommandData());
|
|
if (writeEnable)
|
|
*(u16 *)&data[(getCommandAddress() * 2) & mask] = getCommandData();
|
|
break;
|
|
}
|
|
command.clear();
|
|
expected = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
clk = state;
|
|
}
|
|
|
|
void AT93CxxSerialEeprom::Serialize(Serializer& ser) const
|
|
{
|
|
ser << cs;
|
|
ser << clk;
|
|
ser << di;
|
|
ser << (u32)command.size();
|
|
for (bool b : command)
|
|
ser << b;
|
|
ser << expected;
|
|
ser << writeEnable;
|
|
ser << dataOut;
|
|
ser << dataOutBits;
|
|
}
|
|
|
|
void AT93CxxSerialEeprom::Deserialize(Deserializer& deser)
|
|
{
|
|
deser >> cs;
|
|
deser >> clk;
|
|
deser >> di;
|
|
u32 size;
|
|
deser >> size;
|
|
command.resize(size);
|
|
for (u32 i = 0; i < size; i++) {
|
|
bool b;
|
|
deser >> b;
|
|
command[i] = b;
|
|
}
|
|
deser >> expected;
|
|
deser >> writeEnable;
|
|
deser >> dataOut;
|
|
deser >> dataOutBits;
|
|
}
|