diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/FDS/RamAdapter.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/FDS/RamAdapter.cs
index 09f0527ffa..bdff080ca3 100644
--- a/BizHawk.Emulation/Consoles/Nintendo/NES/FDS/RamAdapter.cs
+++ b/BizHawk.Emulation/Consoles/Nintendo/NES/FDS/RamAdapter.cs
@@ -15,10 +15,16 @@ namespace BizHawk.Emulation.Consoles.Nintendo
{
for (int i = 0; i < pregap - 1; i++)
dest.WriteByte(0);
+ ushort crc = 0;
dest.WriteByte(0x80); // end of gap marker
- dest.Write(data, 0, data.Length);
- dest.WriteByte(0xff); // CRC (todo)
- dest.WriteByte(0xff);
+ crc = CCITT_8(crc, 0x80);
+ for (int i = 0; i < data.Length; i++)
+ {
+ dest.WriteByte(data[i]);
+ crc = CCITT_8(crc, data[i]);
+ }
+ dest.WriteByte((byte)(crc & 0xff));
+ dest.WriteByte((byte)(crc >> 8));
}
static byte[] FixFDSSide(byte[] inputdisk)
@@ -81,6 +87,25 @@ namespace BizHawk.Emulation.Consoles.Nintendo
return tmp;
}
+ static ushort CCITT(ushort crc, int bit)
+ {
+ int bitc = crc & 1;
+ crc >>= 1;
+ if ((bitc ^ bit) != 0)
+ crc ^= 0x8408;
+ return crc;
+ }
+
+ static ushort CCITT_8(ushort crc, byte b)
+ {
+ for (int i = 0; i < 8; i++)
+ {
+ int bit = (b >> i) & 1;
+ crc = CCITT(crc, bit);
+ }
+ return crc;
+ }
+
/// currently loaded disk side (ca 65k bytes)
byte[] disk = null;
@@ -189,6 +214,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo
{
bytetransferflag = false;
writereglatch = value;
+ //Console.WriteLine("!!4024:{0:x2}", value);
}
byte cached4025;
@@ -198,6 +224,8 @@ namespace BizHawk.Emulation.Consoles.Nintendo
/// true if 4025.1 is set to true
bool transferreset = false;
+ ushort crc = 0;
+
// control reg
public void Write4025(byte value)
{
@@ -223,6 +251,8 @@ namespace BizHawk.Emulation.Consoles.Nintendo
bytetransferflag = true;
// irq?
Console.WriteLine("FDS: Startwrite @{0} Reload {1:x2}", diskpos, writereglatch);
+ crc = 0;
+ writecomputecrc = true;
}
}
@@ -230,6 +260,9 @@ namespace BizHawk.Emulation.Consoles.Nintendo
irq = false; // ??
cached4025 = value;
+ if ((cached4025 & 4) == 0)
+ if ((cached4025 & 0x10) != 0)
+ Console.WriteLine("FDS: Starting CRC");
}
// some bits come from outside RamAdapter
@@ -238,7 +271,8 @@ namespace BizHawk.Emulation.Consoles.Nintendo
byte ret = 0;
if (bytetransferflag)
ret |= 0x02;
- // bit 4 always 0: CRC not implemented
+ if (crc != 0)
+ ret |= 0x10;
if (diskpos == disksize)
ret |= 0x40; // end of disk
if (disk != null && !writeprotect)
@@ -346,8 +380,10 @@ namespace BizHawk.Emulation.Consoles.Nintendo
bool lookingforendofgap = false;
- /// number of CRC bytes read/written
- //int numcrc;
+ ///
+ /// true if data being written to disk is currently being computed in CRC
+ ///
+ bool writecomputecrc; // this has to be latched because the "flush CRC" call comes in the middle of a byte, of course
void Read()
{
@@ -363,6 +399,9 @@ namespace BizHawk.Emulation.Consoles.Nintendo
lookingforendofgap = false;//cached4025 &= unchecked((byte)~0x40); // stop looking for end of gap
readregpos = 0;
+ crc = 0;
+ // the first '1' is included in the CRC
+ crc = CCITT(crc, 1);
//bytetransferflag = true;
//if ((cached4025 & 0x80) != 0)
// irq = true;
@@ -371,29 +410,27 @@ namespace BizHawk.Emulation.Consoles.Nintendo
}
else // reading actual data
{
+ crc = CCITT(crc, bit);
readreg &= (byte)~(1 << readregpos);
readreg |= (byte)(bit << readregpos);
readregpos++;
if (readregpos == 8)
{
readregpos = 0;
- //if ((cached4025 & 0x10) == 0) // not in CRC
- //{
- bytetransferflag = true;
- if ((cached4025 & 0x80) != 0)
- irq = true;
- lastreaddiskpos = diskpos;
- Console.WriteLine("{0:x2} {1} @{2}", readreg, (cached4025 & 0x80) != 0 ? "RAISE" : " ", diskpos);
- readreglatch = readreg;
- //}
- //else // when in CRC, don't send results back to user
- //{
- if ((cached4025 & 0x10) != 0)
- {
- Console.WriteLine("FDS: crc byte {0:x2} @{1}", readreg, diskpos);
- cached4025 &= unchecked((byte)~0x10); // clear CRC reading
- }
- //}
+
+ bytetransferflag = true;
+ if ((cached4025 & 0x80) != 0)
+ irq = true;
+ lastreaddiskpos = diskpos;
+ //Console.WriteLine("{0:x2} {1} @{2}", readreg, (cached4025 & 0x80) != 0 ? "RAISE" : " ", diskpos);
+ readreglatch = readreg;
+
+ if ((cached4025 & 0x10) != 0)
+ {
+ Console.WriteLine("FDS: crc byte {0:x2} @{1}", readreg, diskpos);
+ cached4025 &= unchecked((byte)~0x10); // clear CRC reading. no real effect other than to silence debug??
+ Console.WriteLine("FDS: Final CRC {0:x4}", crc);
+ }
}
}
}
@@ -417,6 +454,9 @@ namespace BizHawk.Emulation.Consoles.Nintendo
else
{
bittowrite = (writereg & (1 << writeregpos)) != 0;
+ //if ((cached4025 & 0x10) == 0)
+ if (writecomputecrc)
+ crc = CCITT(crc, bittowrite ? 1 : 0);
writeregpos++;
if (writeregpos == 8)
{
@@ -427,15 +467,25 @@ namespace BizHawk.Emulation.Consoles.Nintendo
irq = true;
Console.WriteLine("FDS: Write @{0} Reload {1:x2}", diskpos + 1, writereglatch);
-
- // it seems that after a successful CRC, the writereg is reset to 0 value. this is needed?
- // TODO: actually write the CRC (2 bytes)
if ((cached4025 & 0x10) != 0)
{
Console.WriteLine("FDS: write clear CRC", readreg, diskpos);
- cached4025 &= unchecked((byte)~0x10); // clear CRC reading
- //writereg = 0; // don't do this
- writereglatch = 0; //??
+
+ if (crc == 0)
+ {
+ cached4025 &= unchecked((byte)~0x10); // clear CRC reading
+ Console.WriteLine("FDS: write CRC commit finished");
+ // it seems that after a successful CRC, the writereglatch is reset to 0 value. this is needed?
+ writereglatch = 0;
+ }
+
+ Console.WriteLine("{0:x4}", crc);
+ writereg = (byte)crc;
+ Console.WriteLine("{0:x2}", writereg);
+ crc >>= 8;
+ Console.WriteLine("{0:x4}", crc);
+ // loaded the first CRC byte to write, so stop computing CRC on data
+ writecomputecrc = false;
}
}