Cores/Nds/NDS.CartSave.cs
namespace Emulotl.Nds;
public sealed partial class NDS
{
private byte[] SRAM;
private uint SRAMLength;
private int SRAMType;
private byte SRAMStatus;
private byte SRAMCmd;
private uint SRAMAddr;
private uint SRAMPos;
private uint SRAMSaveAddr;
private uint SRAMSaveLen;
private bool SRAMSelected;
private bool IsIRCart;
private byte IRCmd;
private uint IRPos;
private void ResetCartSave()
{
int savememtype = NdsSaveDatabase.SaveMemType( _rom );
int len = NdsSaveDatabase.Length( savememtype );
int type = NdsSaveDatabase.SramType( savememtype );
_save.Setup( len, type );
SRAM = _save.Data;
SRAMLength = (uint)_save.Data.Length;
SRAMType = _save.Type;
SRAMStatus = 0;
SRAMCmd = 0;
SRAMAddr = 0;
SRAMPos = 0;
SRAMSaveAddr = 0;
SRAMSaveLen = 0;
SRAMSelected = false;
IsIRCart = _rom != null && _rom.Length > 0x0C && _rom[0x0C] == (byte)'I';
IRCmd = 0;
IRPos = 0;
}
private void SaveSPISelect()
{
SRAMPos = 0;
IRPos = 0;
}
private void SaveSPIRelease()
{
if ( (SRAMStatus & (1 << 1)) != 0 && SRAMSaveLen > 0 )
{
_save.MarkDirty();
SRAMStatus &= unchecked((byte)~(1 << 1));
SRAMSaveAddr = 0;
SRAMSaveLen = 0;
}
}
private byte SaveSPITransmitReceive( byte val )
{
if ( !IsIRCart )
return SaveFlashTransmitReceive( val );
if ( IRPos == 0 )
{
IRCmd = val;
IRPos++;
return 0;
}
IRPos++;
return IRCmd switch
{
0x00 => SaveFlashTransmitReceive( val ),
0x08 => 0xAA,
_ => 0,
};
}
private byte SaveFlashTransmitReceive( byte val )
{
if ( SRAMType == 0 ) return 0;
byte ret = 0xFF;
if ( SRAMPos == 0 )
{
switch ( val )
{
case 0x04: SRAMStatus &= unchecked((byte)~(1 << 1)); return 0;
case 0x06: SRAMStatus |= 1 << 1; return 0;
default:
SRAMCmd = val;
SRAMAddr = 0;
break;
}
}
else
{
ret = SRAMType switch
{
1 => SRAMWrite_EEPROMTiny( val ),
2 => SRAMWrite_EEPROM( val ),
3 => SRAMWrite_FLASH( val ),
_ => 0xFF,
};
}
SRAMPos++;
return ret;
}
private byte SRAMWrite_EEPROMTiny( byte val )
{
switch ( SRAMCmd )
{
case 0x01:
if ( SRAMPos == 1 )
SRAMStatus = (byte)((SRAMStatus & 0x01) | (val & 0x0C));
return 0;
case 0x05:
return (byte)(SRAMStatus | 0xF0);
case 0x02:
case 0x0A:
if ( SRAMPos < 2 )
{
SRAMAddr = val;
SRAMSaveAddr = SRAMAddr + (SRAMCmd == 0x0A ? 0x100u : 0);
SRAMSaveLen = 0;
}
else
{
if ( (SRAMStatus & (1 << 1)) != 0 )
{
SRAM[(SRAMAddr + (SRAMCmd == 0x0A ? 0x100u : 0)) & 0x1FF] = val;
SRAMSaveLen++;
}
SRAMAddr++;
}
return 0;
case 0x03:
case 0x0B:
if ( SRAMPos < 2 )
{
SRAMAddr = val;
return 0;
}
else
{
byte ret = SRAM[(SRAMAddr + (SRAMCmd == 0x0B ? 0x100u : 0)) & 0x1FF];
SRAMAddr++;
return ret;
}
case 0x9F:
return 0xFF;
default:
return 0xFF;
}
}
private byte SRAMWrite_EEPROM( byte val )
{
uint addrsize = 2;
if ( SRAMLength > 65536 ) addrsize++;
switch ( SRAMCmd )
{
case 0x01:
if ( SRAMPos == 1 )
SRAMStatus = (byte)((SRAMStatus & 0x01) | (val & 0x0C));
return 0;
case 0x05:
return SRAMStatus;
case 0x02:
if ( SRAMPos <= addrsize )
{
SRAMAddr <<= 8;
SRAMAddr |= val;
SRAMSaveAddr = SRAMAddr;
SRAMSaveLen = 0;
}
else
{
if ( (SRAMStatus & (1 << 1)) != 0 )
{
SRAM[SRAMAddr & (SRAMLength - 1)] = val;
SRAMSaveLen++;
}
SRAMAddr++;
}
return 0;
case 0x03:
if ( SRAMPos <= addrsize )
{
SRAMAddr <<= 8;
SRAMAddr |= val;
return 0;
}
else
{
byte ret = SRAM[SRAMAddr & (SRAMLength - 1)];
SRAMAddr++;
return ret;
}
case 0x9F:
return 0xFF;
default:
return 0xFF;
}
}
private byte SRAMWrite_FLASH( byte val )
{
switch ( SRAMCmd )
{
case 0x05:
return SRAMStatus;
case 0x02:
if ( SRAMPos <= 3 )
{
SRAMAddr <<= 8;
SRAMAddr |= val;
SRAMSaveAddr = SRAMAddr;
SRAMSaveLen = 0;
}
else
{
if ( (SRAMStatus & (1 << 1)) != 0 )
{
SRAM[SRAMAddr & (SRAMLength - 1)] = 0;
SRAMSaveLen++;
}
SRAMAddr++;
}
return 0;
case 0x03:
if ( SRAMPos <= 3 )
{
SRAMAddr <<= 8;
SRAMAddr |= val;
return 0;
}
else
{
byte ret = SRAM[SRAMAddr & (SRAMLength - 1)];
SRAMAddr++;
return ret;
}
case 0x0A:
if ( SRAMPos <= 3 )
{
SRAMAddr <<= 8;
SRAMAddr |= val;
SRAMSaveAddr = SRAMAddr;
SRAMSaveLen = 0;
}
else
{
if ( (SRAMStatus & (1 << 1)) != 0 )
{
SRAM[SRAMAddr & (SRAMLength - 1)] = val;
SRAMSaveLen++;
}
SRAMAddr++;
}
return 0;
case 0x0B:
if ( SRAMPos <= 3 )
{
SRAMAddr <<= 8;
SRAMAddr |= val;
return 0;
}
else if ( SRAMPos == 4 )
{
return 0;
}
else
{
byte ret = SRAM[SRAMAddr & (SRAMLength - 1)];
SRAMAddr++;
return ret;
}
case 0x9F:
return 0xFF;
case 0xD8:
if ( SRAMPos <= 3 )
{
SRAMAddr <<= 8;
SRAMAddr |= val;
SRAMSaveAddr = SRAMAddr;
SRAMSaveLen = 0;
}
if ( SRAMPos == 3 && (SRAMStatus & (1 << 1)) != 0 )
{
for ( uint i = 0; i < 0x10000; i++ )
{
SRAM[SRAMAddr & (SRAMLength - 1)] = 0;
SRAMAddr++;
}
SRAMSaveLen = 0x10000;
}
return 0;
case 0xDB:
if ( SRAMPos <= 3 )
{
SRAMAddr <<= 8;
SRAMAddr |= val;
SRAMSaveAddr = SRAMAddr;
SRAMSaveLen = 0;
}
if ( SRAMPos == 3 && (SRAMStatus & (1 << 1)) != 0 )
{
for ( uint i = 0; i < 0x100; i++ )
{
SRAM[SRAMAddr & (SRAMLength - 1)] = 0;
SRAMAddr++;
}
SRAMSaveLen = 0x100;
}
return 0;
default:
return 0xFF;
}
}
public byte ReadAuxSpiData( uint cpu )
{
if ( (AuxSpiCnt[cpu] & (1 << 15)) == 0 ) return 0;
if ( (AuxSpiCnt[cpu] & (1 << 13)) == 0 ) return 0;
if ( (AuxSpiCnt[cpu] & (1 << 7)) != 0 ) return 0;
return AuxSpiData[cpu];
}
public void WriteAuxSpiData( uint cpu, byte val )
{
if ( (AuxSpiCnt[cpu] & (1 << 15)) == 0 ) return;
if ( (AuxSpiCnt[cpu] & (1 << 13)) == 0 ) return;
if ( (AuxSpiCnt[cpu] & (1 << 7)) != 0 ) return;
bool hold = (AuxSpiCnt[cpu] & (1 << 6)) != 0;
if ( CartInserted )
{
if ( !SRAMSelected )
SaveSPISelect();
AuxSpiData[cpu] = SaveSPITransmitReceive( val );
if ( !hold )
SaveSPIRelease();
}
else
{
AuxSpiData[cpu] = 0;
}
SRAMSelected = hold;
}
}