384 lines
7.4 KiB
C#
384 lines
7.4 KiB
C#
|
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();
|
||
|
}
|
||
|
}
|
||
|
}
|