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