GBA.Unity/Assets/emulator/SpiFlash.cs

110 lines
3.5 KiB
C#

using System;
using static Util;
namespace OptimeGBA
{
public enum SpiFlashState
{
Ready,
Identification,
ReceiveAddress,
Reading,
Status,
TakePrefix, // For cartridges with IR and Flash
}
public unsafe sealed class SpiFlash
{
public byte[] Data;
public SpiFlash(byte[] data) {
Data = data;
}
// Firmware flash state
public SpiFlashState FlashState;
public bool EnableWrite;
public byte IdIndex;
public uint Address;
public byte AddressByteNum = 0;
// From Nocash's original DS
byte[] Id = new byte[] { 0x20, 0x40, 0x12 };
public byte OutData;
public byte TransferTo(byte val, bool transferSize)
{
switch (FlashState)
{
case SpiFlashState.Ready:
// Console.WriteLine("SPI: Receive command! " + Hex(val, 2));
OutData = 0x00;
switch (val)
{
case 0x06:
EnableWrite = true;
break;
case 0x04:
EnableWrite = false;
break;
case 0x9F:
FlashState = SpiFlashState.Identification;
IdIndex = 0;
break;
case 0x03:
FlashState = SpiFlashState.ReceiveAddress;
Address = 0;
AddressByteNum = 0;
break;
case 0x05: // Identification
// Console.WriteLine("SPI ID");
OutData = 0x00;
break;
case 0x00:
break;
default:
throw new NotImplementedException("SPI: Unimplemented command: " + Hex(val, 2));
}
break;
case SpiFlashState.ReceiveAddress:
// Console.WriteLine("SPI: Address byte write: " + Hex(val, 2));
Address |= (uint)(val << ((2 - AddressByteNum) * 8));
AddressByteNum++;
if (AddressByteNum > 2)
{
AddressByteNum = 0;
FlashState = SpiFlashState.Reading;
// Console.WriteLine("SPI: Address written: " + Hex(Address, 6));
}
break;
case SpiFlashState.Reading:
// Console.WriteLine("SPI: Read from address: " + Hex(Address, 6));
// Nds7.Cpu.Error("SPI");
if (Address < 0x40000)
{
OutData = Data[Address];
}
else
{
OutData = 0;
}
Address += transferSize ? 2U : 1U;
Address &= 0xFFFFFF;
break;
case SpiFlashState.Identification:
OutData = Id[IdIndex];
IdIndex++;
IdIndex %= 3;
break;
}
return OutData;
}
public void Deselect()
{
FlashState = SpiFlashState.Ready;
}
}
}