using System; using System.IO; namespace MyNes.Core; internal class Eprom { private enum EpromDevice { X24C01, X24C02 } private enum EpromMode { Data, Addressing, Idle, Read, Write, Ack, NotAck, AckWait } private byte[] data; private EpromMode mode; private EpromMode nextmode; private EpromDevice device; private bool psda; private bool pscl; private int output; private int cbit; private int caddress; private int cdata; private bool isRead; private bool cSCL; private bool cSDA; public Eprom(int memorySize) { Console.WriteLine("Initializing Eprom ..."); data = new byte[memorySize]; device = ((memorySize == 256) ? EpromDevice.X24C02 : EpromDevice.X24C01); Console.WriteLine("Eprom memory size = " + memorySize); Console.WriteLine("Eprom device = " + device); } public void HardReset() { pscl = false; psda = false; mode = EpromMode.Idle; nextmode = EpromMode.Idle; cbit = 0; caddress = 0; cdata = 0; isRead = false; output = 16; } public void Write(int address, byte data) { cSCL = (data & 0x20) == 32; cSDA = (data & 0x40) == 64; if (pscl && (!cSDA & psda)) { Start(); } else if (pscl && (cSDA & !psda)) { Stop(); } else if (cSCL & !pscl) { switch (device) { case EpromDevice.X24C01: RiseX24C01((data >> 6) & 1); break; case EpromDevice.X24C02: RiseX24C02((data >> 6) & 1); break; } } else if (!cSCL & pscl) { switch (device) { case EpromDevice.X24C01: FallX24C01(); break; case EpromDevice.X24C02: FallX24C02(); break; } } pscl = cSCL; psda = cSDA; } public byte Read(int address) { return (byte)output; } private void Start() { switch (device) { case EpromDevice.X24C01: mode = EpromMode.Addressing; cbit = 0; caddress = 0; output = 16; break; case EpromDevice.X24C02: mode = EpromMode.Data; cbit = 0; output = 16; break; } } private void Stop() { mode = EpromMode.Idle; output = 16; } private void RiseX24C01(int bit) { switch (mode) { case EpromMode.Addressing: if (cbit < 7) { caddress &= ~(1 << cbit); caddress |= bit << cbit++; } else if (cbit < 8) { cbit = 8; if (bit != 0) { nextmode = EpromMode.Read; cdata = data[caddress]; } else { nextmode = EpromMode.Write; } } break; case EpromMode.Ack: output = 0; break; case EpromMode.Read: if (cbit < 8) { output = (((cdata & (1 << cbit++)) != 0) ? 16 : 0); } break; case EpromMode.Write: if (cbit < 8) { cdata &= ~(1 << cbit); cdata |= bit << cbit++; } break; case EpromMode.AckWait: if (bit == 0) { nextmode = EpromMode.Idle; } break; case EpromMode.Idle: case EpromMode.NotAck: break; } } private void RiseX24C02(int bit) { switch (mode) { case EpromMode.Data: if (cbit < 8) { cdata &= ~(1 << 7 - cbit); cdata |= bit << 7 - cbit++; } break; case EpromMode.Addressing: if (cbit < 8) { caddress &= ~(1 << 7 - cbit); caddress |= bit << 7 - cbit++; } break; case EpromMode.Read: if (cbit < 8) { output = (((cdata & (1 << 7 - cbit++)) != 0) ? 16 : 0); } break; case EpromMode.Write: if (cbit < 8) { cdata &= ~(1 << 7 - cbit); cdata |= bit << 7 - cbit++; } break; case EpromMode.NotAck: output = 16; break; case EpromMode.Ack: output = 0; break; case EpromMode.AckWait: if (bit == 0) { nextmode = EpromMode.Read; cdata = data[caddress]; } break; case EpromMode.Idle: break; } } private void FallX24C01() { switch (mode) { case EpromMode.Addressing: if (cbit == 8) { mode = EpromMode.Ack; output = 16; } break; case EpromMode.Ack: mode = nextmode; cbit = 0; output = 16; break; case EpromMode.Read: if (cbit == 8) { mode = EpromMode.AckWait; caddress = (caddress + 1) & 0x7F; } break; case EpromMode.Write: if (cbit == 8) { mode = EpromMode.Ack; nextmode = EpromMode.Idle; data[caddress] = (byte)cdata; caddress = (caddress + 1) & 0x7F; } break; case EpromMode.Idle: break; } } private void FallX24C02() { switch (mode) { case EpromMode.Data: if (cbit != 8) { break; } if ((cdata & 0xA0) == 160) { cbit = 0; mode = EpromMode.Ack; isRead = (cdata & 1) == 1; output = 16; if (isRead) { nextmode = EpromMode.Read; cdata = data[caddress]; } else { nextmode = EpromMode.Addressing; } } else { mode = EpromMode.NotAck; nextmode = EpromMode.Idle; output = 16; } break; case EpromMode.Addressing: if (cbit == 8) { cbit = 0; mode = EpromMode.Ack; nextmode = (isRead ? EpromMode.Idle : EpromMode.Write); output = 16; } break; case EpromMode.Read: if (cbit == 8) { mode = EpromMode.AckWait; caddress = (caddress + 1) & 0xFF; } break; case EpromMode.Write: if (cbit == 8) { cbit = 0; mode = EpromMode.Ack; nextmode = EpromMode.Write; data[caddress] = (byte)cdata; caddress = (caddress + 1) & 0xFF; } break; case EpromMode.NotAck: mode = EpromMode.Idle; cbit = 0; output = 16; break; case EpromMode.Ack: case EpromMode.AckWait: mode = nextmode; cbit = 0; output = 16; break; case EpromMode.Idle: break; } } public void SaveState(BinaryWriter stream) { stream.Write(data); stream.Write((int)mode); stream.Write((int)nextmode); stream.Write(psda); stream.Write(pscl); stream.Write(output); stream.Write(cbit); stream.Write(caddress); stream.Write(cdata); stream.Write(isRead); } public void LoadState(BinaryReader stream) { stream.Read(data, 0, data.Length); mode = (EpromMode)stream.ReadInt32(); nextmode = (EpromMode)stream.ReadInt32(); psda = stream.ReadBoolean(); pscl = stream.ReadBoolean(); output = stream.ReadInt32(); cbit = stream.ReadInt32(); caddress = stream.ReadInt32(); cdata = stream.ReadInt32(); isRead = stream.ReadBoolean(); } }