diff --git a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj
index 72b2266247..679f9b6aad 100644
--- a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj
+++ b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj
@@ -238,6 +238,7 @@
+
diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/BANDAI-FCG-1.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/BANDAI-FCG-1.cs
index 05f7759d11..cb8f41d18d 100644
--- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/BANDAI-FCG-1.cs
+++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/BANDAI-FCG-1.cs
@@ -49,6 +49,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
bool irq_enabled;
ushort irq_counter;
SEEPROM eprom;
+ DatachBarcode reader;
public override void SyncState(Serializer ser)
{
@@ -59,6 +60,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
ser.Sync("irq_enabled", ref irq_enabled);
if (eprom != null)
eprom.SyncState(ser);
+ if (reader != null)
+ reader.SyncState(ser);
SyncPRG();
}
@@ -152,7 +155,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
Cart.wram_size = 0;
regs_prg_enable = true;
regs_wram_enable = false;
+ // 24C02 is present on all boards
+ // some also have a 24C01 with SCK connected to reg ($8000-$8003).3
+ // (does that second seeprom use the same SDA and OE connections as the first? 99% yes, but not implemented)
+ eprom = new SEEPROM(true);
vram = true;
+ reader = new DatachBarcode();
break;
default:
return false;
@@ -271,6 +279,13 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
byte ret = (byte)(NES.DB & 0xef);
if (eprom != null && eprom.ReadBit(NES.DB.Bit(4)))
ret |= 0x10;
+ if (reader != null)
+ {
+ if (reader.GetOutput())
+ ret |= 0x08;
+ else
+ ret &= 0xf7;
+ }
return ret;
}
else
@@ -289,6 +304,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
IRQSignal = true;
}
}
+ if (reader != null)
+ {
+ reader.Clock();
+ }
}
diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/DatachBarcode.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/DatachBarcode.cs
new file mode 100644
index 0000000000..3d2fd486e2
--- /dev/null
+++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/DatachBarcode.cs
@@ -0,0 +1,209 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using BizHawk.Common.NumberExtensions;
+using BizHawk.Common;
+
+namespace BizHawk.Emulation.Cores.Nintendo.NES
+{
+ // mostly jacked from nestopia's NstBoardBandaiDatach.cpp
+ // very dirty, needs cleanup and such
+
+ public class DatachBarcode
+ {
+ static readonly byte[,] prefixParityType = new byte[10, 6]
+ {
+ {8,8,8,8,8,8}, {8,8,0,8,0,0},
+ {8,8,0,0,8,0}, {8,8,0,0,0,8},
+ {8,0,8,8,0,0}, {8,0,0,8,8,0},
+ {8,0,0,0,8,8}, {8,0,8,0,8,0},
+ {8,0,8,0,0,8}, {8,0,0,8,0,8}
+ };
+
+ static readonly byte[,] dataLeftOdd = new byte[10, 7]
+ {
+ {8,8,8,0,0,8,0}, {8,8,0,0,8,8,0},
+ {8,8,0,8,8,0,0}, {8,0,0,0,0,8,0},
+ {8,0,8,8,8,0,0}, {8,0,0,8,8,8,0},
+ {8,0,8,0,0,0,0}, {8,0,0,0,8,0,0},
+ {8,0,0,8,0,0,0}, {8,8,8,0,8,0,0}
+ };
+
+ static readonly byte[,] dataLeftEven = new byte[10, 7]
+ {
+ {8,0,8,8,0,0,0}, {8,0,0,8,8,0,0},
+ {8,8,0,0,8,0,0}, {8,0,8,8,8,8,0},
+ {8,8,0,0,0,8,0}, {8,0,0,0,8,8,0},
+ {8,8,8,8,0,8,0}, {8,8,0,8,8,8,0},
+ {8,8,8,0,8,8,0}, {8,8,0,8,0,0,0}
+ };
+
+ static readonly byte[,] dataRight = new byte[10, 7]
+ {
+ {0,0,0,8,8,0,8}, {0,0,8,8,0,0,8},
+ {0,0,8,0,0,8,8}, {0,8,8,8,8,0,8},
+ {0,8,0,0,0,8,8}, {0,8,8,0,0,0,8},
+ {0,8,0,8,8,8,8}, {0,8,8,8,0,8,8},
+ {0,8,8,0,8,8,8}, {0,0,0,8,0,8,8}
+ };
+
+ const int MIN_DIGITS = 8;
+ const int MAX_DIGITS = 13;
+ const int MAX_DATA_LENGTH = 0x100;
+ const byte END = 0xFF;
+ const int CC_INTERVAL = 1000;
+
+ int cycles;
+ byte output;
+ int stream_idx;
+ byte[] data = new byte[MAX_DATA_LENGTH];
+
+ public void SyncState(Serializer ser)
+ {
+ ser.BeginSection("DatachBarcode");
+ ser.Sync("cycles", ref cycles);
+ ser.Sync("output", ref output);
+ ser.Sync("stream_idx", ref stream_idx);
+ ser.Sync("data", ref data, false);
+ ser.EndSection();
+ }
+
+
+ public void Reset()
+ {
+ cycles = 0; // MAX
+ //output = 0;
+ stream_idx = 0;
+ for (int i = 0; i < data.Length; i++)
+ data[i] = END;
+ }
+
+ public bool IsTransferring()
+ {
+ return data[stream_idx] != END;
+ }
+ public static bool IsDigtsSupported(int count)
+ {
+ return count.In(MIN_DIGITS, MAX_DIGITS);
+ }
+
+ public bool Transfer(string s, int len)
+ {
+ if (s == null)
+ throw new ArgumentNullException("s");
+ if (!IsDigtsSupported(len))
+ return false;
+
+ byte[] code = new byte[16];
+
+ for (int i = 0; i < len; i++)
+ {
+ if (s[i] >= '0' && s[i] <= '9')
+ code[i] = (byte)(s[i] - '0');
+ else
+ throw new InvalidOperationException("s must be numeric only");
+ }
+
+ int out_ptr = 0;
+ for (int i = 0; i < 33; i++)
+ data[out_ptr++] = 8;
+
+ data[out_ptr++] = 0;
+ data[out_ptr++] = 8;
+ data[out_ptr++] = 0;
+
+ int sum = 0;
+
+ if (len == MAX_DIGITS)
+ {
+ for (int i = 0; i < 6; i++)
+ {
+ if (prefixParityType[code[0], i] != 0)
+ {
+ for (int j = 0; j < 7; j++)
+ data[out_ptr++] = dataLeftOdd[code[i + 1], j];
+ }
+ else
+ {
+ for (int j = 0; j < 7; j++)
+ data[out_ptr++] = dataLeftEven[code[i + 1], j];
+ }
+ }
+
+ data[out_ptr++] = 8;
+ data[out_ptr++] = 0;
+ data[out_ptr++] = 8;
+ data[out_ptr++] = 0;
+ data[out_ptr++] = 8;
+
+ for (int i = 7; i < 12; i++)
+ for (int j = 0; j < 7; j++)
+ data[out_ptr++] = dataRight[code[i], j];
+
+ for (int i = 0; i < 12; i++)
+ sum += code[i] * ((i & 1) != 0 ? 3 : 1);
+ }
+ else // len == MIN_DIGITS
+ {
+ for (int i = 0; i < 4; i++)
+ for (int j = 0; j < 7; j++)
+ data[out_ptr++] = dataLeftOdd[code[i], j];
+
+ data[out_ptr++] = 8;
+ data[out_ptr++] = 0;
+ data[out_ptr++] = 8;
+ data[out_ptr++] = 0;
+ data[out_ptr++] = 8;
+
+ for (int i = 4; i < 7; i++)
+ for (int j = 0; j < 7; j++)
+ data[out_ptr++] = dataRight[code[i], j];
+
+
+ for (int i = 0; i < 7; i++)
+ sum += code[i] * ((i & 1) != 0 ? 3 : 1);
+ }
+ sum = (10 - (sum % 10)) % 10;
+
+ for (int j = 0; j < 7; j++)
+ data[out_ptr++] = dataRight[sum, j];
+
+ data[out_ptr++] = 0;
+ data[out_ptr++] = 8;
+ data[out_ptr++] = 0;
+
+ for (int i = 0; i < 32; i++)
+ data[out_ptr++] = 8;
+
+ cycles = CC_INTERVAL;
+ output = data[stream_idx]; // ??
+ return true;
+ }
+
+ public void Clock()
+ {
+ if (cycles <= 0 || !IsTransferring())
+ return;
+ cycles--;
+ if (cycles <= 0)
+ {
+ stream_idx++;
+ output = data[stream_idx];
+ if (output == END)
+ output = 0;
+ else
+ cycles = CC_INTERVAL;
+ }
+ }
+
+ ///
+ /// d3
+ ///
+ ///
+ public bool GetOutput()
+ {
+ return output == 8;
+ }
+ }
+}