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 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 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 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 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; } } }