public void DumpPrg(IFamicomDumperConnection dumper, List <byte> data, int size) { Console.Write("Reading random PRG... "); byte[] lastBank = dumper.ReadCpu(0x8000, 0x8000); Console.WriteLine("OK"); var banks = size / 0x8000; for (var bank = 0; bank < banks; bank++) { Console.Write("Reading PRG bank #{0}... ", bank); // Avoiding bus conflicts bool noBusConflict = false; for (int i = 0; i < lastBank.Length; i++) { if (lastBank[i] == bank) { dumper.WriteCpu((ushort)(0x8000 + i), (byte)bank); noBusConflict = true; break; } } if (!noBusConflict) // Whatever... { dumper.WriteCpu((ushort)0x8000, (byte)bank); } lastBank = dumper.ReadCpu(0x8000, 0x8000); data.AddRange(lastBank); Console.WriteLine("OK"); } }
public void DumpPrg(IFamicomDumperConnection dumper, List <byte> data, int size) { var banks = (byte)(size / 0x4000); Console.Write("Reading last PRG bank... "); var lastBank = dumper.ReadCpu(0xC000, 0x4000); Console.WriteLine("OK"); for (int bank = 0; bank < banks - 1; bank++) { Console.Write($"Reading PRG bank #{bank}/{banks}... "); // Avoiding bus conflicts var noBusConflict = false; for (var i = 0; i < lastBank.Length; i++) { if (lastBank[i] == bank) { dumper.WriteCpu((ushort)(0xC000 + i), (byte)bank); noBusConflict = true; break; } } if (!noBusConflict) // Whatever... { dumper.WriteCpu(0x8000, (byte)bank); } data.AddRange(dumper.ReadCpu(0x8000, 0x4000)); Console.WriteLine("OK"); } data.AddRange(lastBank); }
void Run(IFamicomDumperConnection dumper) { try { // Just simple test that RAM adapter is connected bool ramAdapterPresent = true; dumper.WriteCpu(0x4023, 0x01); // enable disk registers dumper.WriteCpu(0x4026, 0x00); dumper.WriteCpu(0x4025, 0b00100110); // reset dumper.WriteCpu(0x0000, 0xFF); // to prevent open bus read var ext = dumper.ReadCpu(0x4033); if (ext != 0x00) { ramAdapterPresent = false; } dumper.WriteCpu(0x4026, 0xFF); dumper.WriteCpu(0x0000, 0x00); // to prevent open bus read ext = dumper.ReadCpu(0x4033); if ((ext & 0x7F) != 0x7F) { ramAdapterPresent = false; } if (!ramAdapterPresent) { throw new IOException("Famicom Disk System RAM adapter IO error, is it connected?"); } dumper.WriteCpu(0x4025, 0b00100110); // reset dumper.WriteCpu(0x4025, 0b00100101); // enable motor without data transfer Thread.Sleep(100); // Check battery health ext = dumper.ReadCpu(0x4033); if ((ext & 0x80) == 0) { throw new IOException("Battery voltage is low or power supply is not connected"); } Console.WriteLine("Measuring FDS drive speed, make sure that disk card is inserted and wait. Press any key to stop."); var cancellationTokenSource = new CancellationTokenSource(); var task = SpeedMeasureLoop(dumper, cancellationTokenSource.Token); Console.ReadKey(); cancellationTokenSource.Cancel(); task.GetAwaiter().GetResult(); } finally { // Stop dumper.WriteCpu(0x4025, 0b00100110); } }
public static void PPBClear(IFamicomDumperConnection dumper) { LockBitsCheckPrint(dumper); PPBLockBitCheckPrint(dumper); Console.Write($"Erasing all PBBs... "); // PPB Command Set Entry dumper.WriteCpu(0x8AAA, 0xAA); dumper.WriteCpu(0x8555, 0x55); dumper.WriteCpu(0x8AAA, 0xC0); // All PPB Erase dumper.WriteCpu(0x8000, 0x80); dumper.WriteCpu(0x8000, 0x30); // Check try { DateTime startTime = DateTime.Now; while (true) { byte b = dumper.ReadCpu(0x8000); if (b == 0x01) { break; } if ((DateTime.Now - startTime).TotalMilliseconds >= 1500) { throw new IOException("PPB clear failed"); } } } finally { ResetFlash(dumper); } Console.WriteLine("OK"); }
async Task SpeedMeasureLoop(IFamicomDumperConnection dumper, CancellationToken cancellationToken = default) { DateTime?lastCycleTime = null; while (true) { // Reset dumper.WriteCpu(0x4025, 0b00100110); // reset dumper.WriteCpu(0x4025, 0b00100101); // enable motor without data transfer // Wait for ready state while ((dumper.ReadCpu(0x4032) & 2) != 0) { if (cancellationToken.IsCancellationRequested) { return; } await Task.Delay(1); } // Calculate and print cycle duration if (lastCycleTime != null) { Console.WriteLine($"Full cycle time: {(int)(DateTime.Now - lastCycleTime.Value).TotalMilliseconds} ms"); } // Remember cycle start time lastCycleTime = DateTime.Now; } }
public static void LockBitsCheckPrint(IFamicomDumperConnection dumper) { try { // Lock Register Set Entry dumper.WriteCpu(0x8AAA, 0xAA); dumper.WriteCpu(0x8555, 0x55); dumper.WriteCpu(0x8AAA, 0x40); var lockRegister = dumper.ReadCpu(0x8000); if ((lockRegister & 1) == 0) { Console.WriteLine("WARNING: Secured Silicon Sector Protection Bit is set!"); } if ((lockRegister & 2) == 0) { Console.WriteLine("WARNING: Persistent Protection Mode Lock Bit is set!"); } if ((lockRegister & 4) == 0) { Console.WriteLine("WARNING: Password Protection Mode Lock Bit is set!"); } } finally { ResetFlash(dumper); } }
public static void PPBSet(IFamicomDumperConnection dumper) { Console.Write("Writing PPB for sector... "); // PPB Command Set Entry dumper.WriteCpu(0x8AAA, 0xAA); dumper.WriteCpu(0x8555, 0x55); dumper.WriteCpu(0x8AAA, 0xC0); // PPB Program dumper.WriteCpu(0x8000, 0xA0); dumper.WriteCpu(0x8000, 0x00); // Check try { DateTime startTime = DateTime.Now; while (true) { byte b = dumper.ReadCpu(0x8000); if (b == 0x00) { break; } if ((DateTime.Now - startTime).TotalMilliseconds >= 1500) { throw new IOException("PPB write failed"); } } } finally { ResetFlash(dumper); } Console.WriteLine("OK"); }
public void DumpPrg(IFamicomDumperConnection dumper, List <byte> data, int size) { Console.Write("Reading PRG... "); prg = dumper.ReadCpu(0x8000, size); data.AddRange(prg); Console.WriteLine("OK"); }
public void DumpPrg(IFamicomDumperConnection dumper, List <byte> data, int size) { dumper.Reset(); version = DetectVersion(dumper); UInt16 coolboyReg = (UInt16)(version == 2 ? 0x5000 : 0x6000); int banks = size / 0x4000; for (var bank = 0; bank < banks; bank++) { var r0 = (byte)(((bank >> 3) & 0x07) // 5, 4, 3 bits | (((bank >> 9) & 0x03) << 4) // 10, 9 bits | (1 << 6)); // resets 4th mask bit var r1 = (byte)((((bank >> 7) & 0x03) << 2) // 8, 7 | (((bank >> 6) & 1) << 4) // 6 | (1 << 7)); // resets 5th mask bit var r2 = (byte)0; var r3 = (byte)((1 << 4) // NROM mode | ((bank & 7) << 1)); // 2, 1, 0 bits dumper.WriteCpu(coolboyReg, r0, r1, r2, r3); Console.Write($"Reading PRG bank #{bank}/{banks}... "); data.AddRange(dumper.ReadCpu(0x8000, 0x4000)); Console.WriteLine("OK"); } }
// But method signature must be like this. Also you can make this method static. void Run(IFamicomDumperConnection dumper, string[] args) { // You can parse additional command line arguments if need // Specify arguments this way: >FamicomDumper.exe script --csfile DemoScript.cs - argument1 argument2 argument3 if (args.Any()) { Console.WriteLine("Command line arguments: " + string.Join(", ", args)); } Console.WriteLine("Please insert MMC3 cartridge and press enter"); Console.ReadLine(); Console.WriteLine("Let's check - how many PRG banks on this MMC3 cartridge"); byte[] firstBank = null; for (var bank = 0; ; bank = bank == 0 ? 1 : bank * 2) { if (bank > 256) { throw new InvalidDataException("Bank number out of range, did you actually insert the MMC3 cartridge?"); } Console.Write($"Reading PRG bank #{bank}... "); dumper.WriteCpu(0x8000, 6, (byte)bank); var data = dumper.ReadCpu(0x8000, 0x2000); Console.WriteLine("OK"); if (bank == 0) { firstBank = data; } else if (Enumerable.SequenceEqual(data, firstBank)) { Console.WriteLine($"There are {bank} PRG banks on this cartridge, {bank * 0x2000 / 1024} KBytes in total"); break; } } Console.WriteLine("Let's check - how many CHR banks on this MMC3 cartridge"); for (var bank = 0; ; bank = bank == 0 ? 1 : bank * 2) { if (bank > 256) { throw new InvalidDataException("Bank number out of range, did you actually insert the MMC3 cartridge?"); } Console.Write($"Reading CHR bank #{bank}... "); dumper.WriteCpu(0x8000, 2, (byte)bank); var data = dumper.ReadPpu(0x1000, 0x0400); Console.WriteLine("OK"); if (bank == 0) { firstBank = data; } else if (Enumerable.SequenceEqual(data, firstBank)) { Console.WriteLine($"There are {bank} CHR banks on this cartridge, {bank * 0x0400 / 1024} KBytes in total"); break; } } }
public void DumpPrg(IFamicomDumperConnection dumper, List <byte> data, int size) { var banks = size / 0x2000; dumper.WriteCpu(0x6000, 0); for (var bank = 0; bank < banks - 2; bank += 2) { Console.Write("Reading PRG banks #{0} and #{1}... ", bank, bank + 1); dumper.WriteCpu(ScrumbleAddress(0x8000), ScrumbleValues(6)); dumper.WriteCpu(ScrumbleAddress(0x8001), (byte)bank); dumper.WriteCpu(ScrumbleAddress(0x8000), ScrumbleValues(7)); dumper.WriteCpu(ScrumbleAddress(0x8001), (byte)(bank | 1)); data.AddRange(dumper.ReadCpu(0x8000, 0x4000)); Console.WriteLine("OK"); } Console.Write("Reading last PRG banks #{0} and #{1}... ", banks - 2, banks - 1); data.AddRange(dumper.ReadCpu(0xC000, 0x4000)); Console.WriteLine("OK"); }
public void DumpPrg(IFamicomDumperConnection dumper, List <byte> data, int size) { var banks = size / 0x2000; if (banks > 256) { throw new ArgumentOutOfRangeException("size", "PRG size is too big"); } for (var bank = 0; bank < banks - 2; bank += 2) { Console.Write("Reading PRG banks #{0} and #{1}... ", bank, bank + 1); dumper.WriteCpu(0x8000, new byte[] { 6, (byte)bank }); dumper.WriteCpu(0x8000, new byte[] { 7, (byte)(bank | 1) }); data.AddRange(dumper.ReadCpu(0x8000, 0x4000)); Console.WriteLine("OK"); } Console.Write("Reading last PRG banks #{0} and #{1}... ", banks - 2, banks - 1); data.AddRange(dumper.ReadCpu(0xC000, 0x4000)); Console.WriteLine("OK"); }
public void DumpPrg(IFamicomDumperConnection dumper, List <byte> data, int size) { dumper.WriteCpu(0x8000, 0x80); WriteMMC1(dumper, 0x8000, 0x0C); var banks = size / 0x4000; for (var bank = 0; bank < banks - 1; bank++) { Console.Write("Reading PRG bank #{0}... ", bank); WriteMMC1(dumper, 0xE000, (byte)bank); data.AddRange(dumper.ReadCpu(0x8000, 0x4000)); Console.WriteLine("OK"); } if (banks > 0) { Console.Write("Reading last PRG bank #{0}... ", banks - 1); data.AddRange(dumper.ReadCpu(0xC000, 0x4000)); Console.WriteLine("OK"); } }
public void DumpPrg(IFamicomDumperConnection dumper, List <byte> data, int size) { var banks = size / 0x4000; for (var bank = 0; bank < banks; bank++) { Console.Write($"Reading PRG bank #{bank}/{banks}... "); dumper.WriteCpu(0x8000, (byte)bank); data.AddRange(dumper.ReadCpu(0x8000, 0x4000)); Console.WriteLine("OK"); } }
public void DumpPrg(IFamicomDumperConnection dumper, List <byte> data, int size) { var banks = size / 0x4000; for (var bank = 0; bank < banks; bank++) { Console.Write("Reading PRG bank #{0}... ", bank); dumper.WriteCpu((ushort)(0x8000 | (bank << 1)), 0); data.AddRange(dumper.ReadCpu(0xC000, 0x4000)); Console.WriteLine("OK"); } }
public void DumpPrg(IFamicomDumperConnection dumper, List <byte> data, int size) { var banks = size / 0x2000; dumper.WriteCpu(0x5100, 3); // bank mode #3, four 8KB banks for (var bank = 0; bank < banks; bank++) { Console.Write("Reading PRG bank #{0}... ", bank); dumper.WriteCpu(0x5114, (byte)(bank | 0x80)); data.AddRange(dumper.ReadCpu(0x8000, 0x2000)); Console.WriteLine("OK"); } }
public void DumpPrg(IFamicomDumperConnection dumper, List <byte> data, int size) { var banks = size / 0x2000; for (var bank = 0; bank < banks; bank++) { Console.Write("Reading PRG bank #{0}... ", bank); dumper.WriteCpu(0x8000, 9); // Bank $9 - CPU $8000-$9FFF dumper.WriteCpu(0xA000, (byte)bank); data.AddRange(dumper.ReadCpu(0x8000, 0x2000)); Console.WriteLine("OK"); } }
public void DumpPrg(IFamicomDumperConnection dumper, List<byte> data, int size) { var banks = size / 0x2000; dumper.WriteCpu(0x9004 | 0x9080, 0); // disable swap mode for (var bank = 0; bank < banks; bank++) { Console.Write($"Reading PRG bank #{bank}/{banks}... "); dumper.WriteCpu(0x8000, (byte)bank); // PRG Select 0 data.AddRange(dumper.ReadCpu(0x8000, 0x2000)); Console.WriteLine("OK"); } }
void Run(IFamicomDumperConnection dumper, IMapper mapper, string[] args) { int count = -1; if (args.Any()) { count = int.Parse(args.First()); } if (mapper != null) { if (mapper.Number >= 0) { Console.WriteLine($"Using mapper: #{mapper.Number} ({mapper.Name})"); } else { Console.WriteLine($"Using mapper: {mapper.Name}"); } mapper.EnablePrgRam(dumper); } var rnd = new Random(); while (count != 0) { var data = new byte[0x2000]; rnd.NextBytes(data); Console.Write("Writing PRG RAM... "); dumper.WriteCpu(0x6000, data); Console.Write("Reading PRG RAM... "); var rdata = dumper.ReadCpu(0x6000, 0x2000); bool ok = true; for (int b = 0; b < 0x2000; b++) { if (data[b] != rdata[b]) { Console.WriteLine($"Mismatch at {b:X4}: {rdata[b]:X2} != {data[b]:X2}"); ok = false; } } if (!ok) { File.WriteAllBytes("prgramgood.bin", data); Console.WriteLine("prgramgood.bin writed"); File.WriteAllBytes("prgrambad.bin", rdata); Console.WriteLine("prgrambad.bin writed"); throw new InvalidDataException("Failed!"); } Console.WriteLine("OK!"); count--; } }
public void DumpPrg(IFamicomDumperConnection dumper, List <byte> data, int size) { var banks = size / 0x2000; dumper.WriteCpu(0x6000, 0); for (var bank = 0; bank < banks; bank++) { Console.Write($"Reading PRG banks #{bank}/{banks}... "); dumper.WriteCpu(ScrumbleAddress(0x8000), ScrumbleValues(6)); dumper.WriteCpu(ScrumbleAddress(0x8001), (byte)bank); data.AddRange(dumper.ReadCpu(0x8000, 0x2000)); Console.WriteLine("OK"); } Console.WriteLine("OK"); }
public void DumpPrg(IFamicomDumperConnection dumper, List <byte> data, int size) { var outbanks = size / (256 * 1024); for (byte outbank = 0; outbank < outbanks; outbank += 1) { dumper.Reset(); dumper.WriteCpu(0xA001, 0x80); // RAM protect dumper.WriteCpu((ushort)(0x6828 | (outbank << 1)), 0x00); dumper.WriteCpu(0xA001, 0); // disable W-RAM const int banks = 32; for (var bank = 0; bank < banks - 2; bank += 2) { Console.Write("Reading PRG banks #{2}|{0} and #{2}|{1}... ", bank, bank + 1, outbank); dumper.WriteCpu(0x8000, new byte[] { 6, (byte)bank }); dumper.WriteCpu(0x8000, new byte[] { 7, (byte)(bank | 1) }); data.AddRange(dumper.ReadCpu(0x8000, 0x4000)); Console.WriteLine("OK"); } Console.Write("Reading last PRG banks #{2}|{0} and #{2}|{1}... ", banks - 2, banks - 1, outbank); data.AddRange(dumper.ReadCpu(0xC000, 0x4000)); Console.WriteLine("OK"); } }
public static byte PPBRead(IFamicomDumperConnection dumper) { try { // PPB Command Set Entry dumper.WriteCpu(0x8AAA, 0xAA); dumper.WriteCpu(0x8555, 0x55); dumper.WriteCpu(0x8AAA, 0xC0); // PPB Status Read return(dumper.ReadCpu(0x8000)); } finally { ResetFlash(dumper); } }
void Run(IFamicomDumperConnection dumper, IMapper mapper) { if (mapper != null) { if (mapper.Number >= 0) { Console.WriteLine($"Using mapper: #{mapper.Number} ({mapper.Name})"); } else { Console.WriteLine($"Using mapper: {mapper.Name}"); } mapper.EnablePrgRam(dumper); } var rnd = new Random(); var data = new byte[0x2000]; rnd.NextBytes(data); Console.Write("Writing PRG RAM... "); dumper.WriteCpu(0x6000, data); Console.WriteLine("OK"); Console.WriteLine("Replug cartridge and press any key"); Console.ReadKey(); Console.WriteLine(); Console.Write("Reading PRG RAM... "); var rdata = dumper.ReadCpu(0x6000, 0x2000); bool ok = true; for (int b = 0; b < 0x2000; b++) { if (data[b] != rdata[b]) { Console.WriteLine($"Mismatch at {b:X4}: {rdata[b]:X2} != {data[b]:X2}"); ok = false; } } if (!ok) { File.WriteAllBytes("prgramgood.bin", data); Console.WriteLine("prgramgood.bin writed"); File.WriteAllBytes("prgrambad.bin", rdata); Console.WriteLine("prgrambad.bin writed"); throw new InvalidDataException("Failed!"); } Console.WriteLine("OK!"); Console.WriteLine("Battery is OK!"); }
public void DumpPrg(IFamicomDumperConnection dumper, List <byte> data, int size) { var banks = size / 0x2000; if (banks > 256) { throw new ArgumentOutOfRangeException("size", "PRG size is too big"); } for (var bank = 0; bank < banks; bank++) { Console.Write($"Reading PRG banks #{bank}/{banks}... "); dumper.WriteCpu(0x8000, 6, (byte)bank); data.AddRange(dumper.ReadCpu(0x8000, 0x2000)); Console.WriteLine("OK"); } Console.WriteLine("OK"); }
public static void TestPrgRam(IFamicomDumperConnection dumper, int count) { Console.Write("Reset... "); dumper.Reset(); Console.WriteLine("OK"); dumper.WriteCpu(0x5007, 0x01); // enable PRG RAM var rnd = new Random(); while (count != 0) { var data = new byte[][] { new byte[0x2000], new byte[0x2000], new byte[0x2000], new byte[0x2000] }; for (byte bank = 0; bank < 4; bank++) { Console.WriteLine($"Writing PRG RAM, bank #{bank}/{4}... "); rnd.NextBytes(data[bank]); dumper.WriteCpu(0x5005, bank); dumper.WriteCpu(0x6000, data[bank]); } for (byte bank = 0; bank < 4; bank++) { Console.Write($"Reading PRG RAM, bank #{bank}/{4}... "); dumper.WriteCpu(0x5005, bank); var rdata = dumper.ReadCpu(0x6000, 0x2000); bool ok = true; for (int b = 0; b < 0x2000; b++) { if (data[bank][b] != rdata[b]) { Console.WriteLine($"Mismatch at {b:X4}: {rdata[b]:X2} != {data[bank][b]:X2}"); ok = false; } } if (!ok) { File.WriteAllBytes("prgramgood.bin", data[bank]); Console.WriteLine("prgramgood.bin writed"); File.WriteAllBytes("prgrambad.bin", rdata); Console.WriteLine("prgrambad.bin writed"); throw new InvalidDataException("Test failed"); } Console.WriteLine("OK"); } count--; } }
public static CFIInfo GetCFIInfo(IFamicomDumperConnection dumper) { try { dumper.WriteCpu(0x8AAA, 0x98); // CFI mode var cfiRaw = dumper.ReadCpu(0x8000, 0x100); if (cfiRaw[0x20] != 0x51 || cfiRaw[0x22] != 0x52 || cfiRaw[0x24] != 0x59) { throw new IOException("Can't enter CFI mode. Invalid flash memory? Broken cartridge? Is it inserted?"); } var cfi = new CFIInfo(cfiRaw, CFIInfo.ParseMode.Every2Bytes); return(cfi); } finally { dumper.WriteCpu(0x8000, 0xF0); } }
public static void PPBLockBitCheckPrint(IFamicomDumperConnection dumper) { try { // PPB Lock Command Set Entry dumper.WriteCpu(0x8AAA, 0xAA); dumper.WriteCpu(0x8555, 0x55); dumper.WriteCpu(0x8AAA, 0x50); var ppbLockStatus = dumper.ReadCpu(0x8000); if (ppbLockStatus == 0) { Console.WriteLine("WARNING: PPB Lock Bit is set!"); } } finally { ResetFlash(dumper); } }
// But method signature must be like this. Also you can make this method static. void Run(IFamicomDumperConnection dumper) { Console.WriteLine("Please insert MMC3 cartridge and press any key"); Console.ReadKey(); Console.WriteLine("Let's check - how many PRG banks on this MMC3 cartridge"); byte[] firstBank = null; for (var bank = 0; ; bank = bank == 0 ? 1 : bank * 2) { Console.Write("Reading PRG bank #{0}... ", bank); dumper.WriteCpu(0x8000, new byte[] { 6, (byte)bank }); var data = dumper.ReadCpu(0x8000, 0x2000); Console.WriteLine("OK"); if (bank == 0) { firstBank = data; } else if (Enumerable.SequenceEqual(data, firstBank)) { Console.WriteLine("There are {0} PRG banks on this cartridge, {1} KBytes in total", bank, bank * 0x2000 / 1024); break; } } Console.WriteLine("Let's check - how many CHR banks on this MMC3 cartridge"); for (var bank = 0; ; bank = bank == 0 ? 1 : bank * 2) { Console.Write("Reading CHR bank #{0}... ", bank); dumper.WriteCpu(0x8000, new byte[] { 2, (byte)bank }); var data = dumper.ReadPpu(0x1000, 0x0400); Console.WriteLine("OK"); if (bank == 0) { firstBank = data; } else if (Enumerable.SequenceEqual(data, firstBank)) { Console.WriteLine("There are {0} CHR banks on this cartridge, {1} KBytes in total", bank, bank * 0x0400 / 1024); break; } } }
public void DumpPrg(IFamicomDumperConnection dumper, List <byte> data, int size) { var banks = size / 0x8000; Console.Write("Reset... "); dumper.Reset(); Console.WriteLine("OK"); dumper.WriteCpu(0x5002, 0xFE); // mask = 32K for (int bank = 0; bank < banks; bank++) { var r0 = (byte)(bank >> 7); var r1 = (byte)(bank << 1); dumper.WriteCpu(0x5000, r0); dumper.WriteCpu(0x5001, r1); Console.Write($"Reading PRG bank #{bank}/{banks}... "); data.AddRange(dumper.ReadCpu(0x8000, 0x8000)); Console.WriteLine("OK"); } }
public void DumpChr(IFamicomDumperConnection dumper, List <byte> data, int size) { if (prg == null) { prg = dumper.ReadCpu(0x8000, DefaultPrgSize); } var banks = size / 0x2000; for (var bank = 0; bank < banks; bank++) { Console.Write($"Reading CHR bank #{bank}/{banks}... "); // Avoiding bus conflicts for (var i = 0; i < prg.Length; i++) { if (prg[i] == bank) { dumper.WriteCpu((ushort)(0x8000 + i), (byte)bank); break; } } data.AddRange(dumper.ReadPpu(0x0000, 0x2000)); Console.WriteLine("OK"); } }