AxibugEmuOnline/Core/VirtualNes.Core/Mapper/EEPROM.cs

457 lines
14 KiB
C#
Raw Normal View History

namespace VirtualNes.Core
{
public class X24C01
{
public const int X24C01_IDLE = 0; // Idle
public const int X24C01_ADDRESS = 1; // Address set
public const int X24C01_READ = 2; // Read
public const int X24C01_WRITE = 3; // Write
public const int X24C01_ACK = 4; // Acknowledge
public const int X24C01_ACK_WAIT = 5; // Acknowledge wait
int now_state, next_state;
int bitcnt;
byte addr, data;
byte sda;
byte scl_old, sda_old;
ArrayRef<byte> pEEPDATA;
public X24C01()
{
now_state = X24C01_IDLE;
next_state = X24C01_IDLE;
addr = 0;
data = 0;
sda = 0xFF;
scl_old = 0;
sda_old = 0;
pEEPDATA = null;
}
public void Reset(ArrayRef<byte> ptr)
{
now_state = X24C01_IDLE;
next_state = X24C01_IDLE;
addr = 0;
data = 0;
sda = 0xFF;
scl_old = 0;
sda_old = 0;
pEEPDATA = ptr;
}
public void Write(byte scl_in, byte sda_in)
{
// Clock line
byte scl_rise = (byte)(~scl_old & scl_in);
byte scl_fall = (byte)(scl_old & ~scl_in);
// Data line
byte sda_rise = (byte)(~sda_old & sda_in);
byte sda_fall = (byte)(sda_old & ~sda_in);
byte scl_old_temp = scl_old;
byte sda_old_temp = sda_old;
scl_old = scl_in;
sda_old = sda_in;
// Start condition?
if (scl_old_temp != 0 && sda_fall != 0)
{
now_state = X24C01_ADDRESS;
bitcnt = 0;
addr = 0;
sda = 0xFF;
return;
}
// Stop condition?
if (scl_old_temp != 0 && sda_rise != 0)
{
now_state = X24C01_IDLE;
sda = 0xFF;
return;
}
// SCL ____---- RISE
if (scl_rise != 0)
{
switch (now_state)
{
case X24C01_ADDRESS:
if (bitcnt < 7)
{
// 本来はMSB->LSB
addr = (byte)(addr & (~(1 << bitcnt)));
addr = (byte)(addr | ((sda_in != 0 ? 1 : 0) << bitcnt));
}
else
{
if (sda_in != 0)
{
next_state = X24C01_READ;
data = pEEPDATA[addr & 0x7F];
}
else
{
next_state = X24C01_WRITE;
}
}
bitcnt++;
break;
case X24C01_ACK:
sda = 0; // ACK
break;
case X24C01_READ:
if (bitcnt < 8)
{
// 本来はMSB->LSB
sda = (byte)((data & (1 << bitcnt)) != 0 ? 1 : 0);
}
bitcnt++;
break;
case X24C01_WRITE:
if (bitcnt < 8)
{
// 本来はMSB->LSB
data = (byte)(data & (~(1 << bitcnt)));
data = (byte)(data | ((sda_in != 0 ? 1 : 0) << bitcnt));
}
bitcnt++;
break;
case X24C01_ACK_WAIT:
if (sda_in == 0)
{
next_state = X24C01_IDLE;
}
break;
}
}
// SCL ----____ FALL
if (scl_fall != 0)
{
switch (now_state)
{
case X24C01_ADDRESS:
if (bitcnt >= 8)
{
now_state = X24C01_ACK;
sda = 0xFF;
}
break;
case X24C01_ACK:
now_state = next_state;
bitcnt = 0;
sda = 0xFF;
break;
case X24C01_READ:
if (bitcnt >= 8)
{
now_state = X24C01_ACK_WAIT;
addr = (byte)((addr + 1) & 0x7F);
}
break;
case X24C01_WRITE:
if (bitcnt >= 8)
{
now_state = X24C01_ACK;
next_state = X24C01_IDLE;
pEEPDATA[addr & 0x7F] = data;
addr = (byte)((addr + 1) & 0x7F);
}
break;
}
}
}
public byte Read()
{
return sda;
}
public unsafe void Load(byte* p)
{
//now_state = *((INT*)&p[0]);
now_state = *(int*)p;
//next_state = *((INT*)&p[4]);
next_state = *(int*)p[4];
//bitcnt = *((INT*)&p[8]);
bitcnt = *(int*)p[8];
addr = p[12];
data = p[13];
sda = p[14];
scl_old = p[15];
sda_old = p[16];
}
public unsafe void Save(byte* p)
{
*((int*)&p[0]) = now_state;
*((int*)&p[4]) = next_state;
*((int*)&p[8]) = bitcnt;
p[12] = addr;
p[13] = data;
p[14] = sda;
p[15] = scl_old;
p[16] = sda_old;
}
}
public class X24C02
{
public const int X24C02_IDLE = 0; // Idle
public const int X24C02_DEVADDR = 1; // Device address set
public const int X24C02_ADDRESS = 2; // Address set
public const int X24C02_READ = 3; // Read
public const int X24C02_WRITE = 4; // Write
public const int X24C02_ACK = 5; // Acknowledge
public const int X24C02_NAK = 6; // Not Acknowledge
public const int X24C02_ACK_WAIT = 7; // Acknowledge wait
int now_state, next_state;
int bitcnt;
byte addr, data, rw;
byte sda;
byte scl_old, sda_old;
ArrayRef<byte> pEEPDATA;
public X24C02()
{
now_state = X24C02_IDLE;
next_state = X24C02_IDLE;
addr = 0;
data = 0;
rw = 0;
sda = 0xFF;
scl_old = 0;
sda_old = 0;
pEEPDATA = null;
}
public void Reset(ArrayRef<byte> ptr)
{
now_state = X24C02_IDLE;
next_state = X24C02_IDLE;
addr = 0;
data = 0;
rw = 0;
sda = 0xFF;
scl_old = 0;
sda_old = 0;
pEEPDATA = ptr;
}
public void Write(byte scl_in, byte sda_in)
{
// Clock line
byte scl_rise = (byte)(~scl_old & scl_in);
byte scl_fall = (byte)(scl_old & ~scl_in);
// Data line
byte sda_rise = (byte)(~sda_old & sda_in);
byte sda_fall = (byte)(sda_old & ~sda_in);
byte scl_old_temp = scl_old;
byte sda_old_temp = sda_old;
scl_old = scl_in;
sda_old = sda_in;
// Start condition?
if (scl_old_temp != 0 && sda_fall != 0)
{
now_state = X24C02_DEVADDR;
bitcnt = 0;
sda = 0xFF;
return;
}
// Stop condition?
if (scl_old_temp != 0 && sda_rise != 0)
{
now_state = X24C02_IDLE;
sda = 0xFF;
return;
}
// SCL ____---- RISE
if (scl_rise != 0)
{
switch (now_state)
{
case X24C02_DEVADDR:
if (bitcnt < 8)
{
data = (byte)(data & (~(1 << (7 - bitcnt))));
data = (byte)(data | ((sda_in != 0 ? 1 : 0) << (7 - bitcnt)));
}
bitcnt++;
break;
case X24C02_ADDRESS:
if (bitcnt < 8)
{
addr = (byte)(addr & (~(1 << (7 - bitcnt))));
addr = (byte)(addr | ((sda_in != 0 ? 1 : 0) << (7 - bitcnt)));
}
bitcnt++;
break;
case X24C02_READ:
if (bitcnt < 8)
{
sda = (byte)((data & (1 << (7 - bitcnt))) != 0 ? 1 : 0);
}
bitcnt++;
break;
case X24C02_WRITE:
if (bitcnt < 8)
{
data = (byte)(data & (~(1 << (7 - bitcnt))));
data = (byte)(data | ((sda_in != 0 ? 1 : 0) << (7 - bitcnt)));
}
bitcnt++;
break;
case X24C02_NAK:
sda = 0xFF; // NAK
break;
case X24C02_ACK:
sda = 0; // ACK
break;
case X24C02_ACK_WAIT:
if (sda_in == 0)
{
next_state = X24C02_READ;
data = pEEPDATA[addr];
}
break;
}
}
// SCL ----____ FALL
if (scl_fall != 0)
{
switch (now_state)
{
case X24C02_DEVADDR:
if (bitcnt >= 8)
{
if ((data & 0xA0) == 0xA0)
{
now_state = X24C02_ACK;
rw = (byte)(data & 0x01);
sda = 0xFF;
if (rw != 0)
{
// Now address read
next_state = X24C02_READ;
data = pEEPDATA[addr];
}
else
{
next_state = X24C02_ADDRESS;
}
bitcnt = 0;
}
else
{
now_state = X24C02_NAK;
next_state = X24C02_IDLE;
sda = 0xFF;
}
}
break;
case X24C02_ADDRESS:
if (bitcnt >= 8)
{
now_state = X24C02_ACK;
sda = 0xFF;
if (rw != 0)
{
// Readでは絶対来ないが念の為
next_state = X24C02_IDLE;
}
else
{
// to Data Write
next_state = X24C02_WRITE;
}
bitcnt = 0;
}
break;
case X24C02_READ:
if (bitcnt >= 8)
{
now_state = X24C02_ACK_WAIT;
addr = (byte)((addr + 1) & 0xFF);
}
break;
case X24C02_WRITE:
if (bitcnt >= 8)
{
pEEPDATA[addr] = data;
now_state = X24C02_ACK;
next_state = X24C02_WRITE;
addr = (byte)((addr + 1) & 0xFF);
bitcnt = 0;
}
break;
case X24C02_NAK:
now_state = X24C02_IDLE;
bitcnt = 0;
sda = 0xFF;
break;
case X24C02_ACK:
now_state = next_state;
bitcnt = 0;
sda = 0xFF;
break;
case X24C02_ACK_WAIT:
now_state = next_state;
bitcnt = 0;
sda = 0xFF;
break;
}
}
}
public byte Read()
{
return sda;
}
public unsafe void Load(byte* p)
{
//now_state = *((INT*)&p[0]);
next_state = *((int*)&p[4]);
//bitcnt = *((INT*)&p[8]);
bitcnt = *((int*)&p[8]);
addr = p[12];
data = p[13];
rw = p[14];
sda = p[15];
scl_old = p[16];
sda_old = p[17];
}
public unsafe void Save(byte* p)
{
*((int*)&p[0]) = now_state;
*((int*)&p[4]) = next_state;
*((int*)&p[8]) = bitcnt;
p[12] = addr;
p[13] = data;
p[14] = rw;
p[15] = sda;
p[16] = scl_old;
p[17] = sda_old;
}
}
}