public static void ReadCrc(FamicomDumperConnection dumper) { Console.Write("Reset... "); dumper.Reset(); Console.WriteLine("OK"); dumper.WriteCpu(0x5007, 0x04); // enable PRG write dumper.WriteCpu(0x5002, 0xFE); // mask = 32K var flashSize = CommonHelper.GetFlashSizePrintInfo(dumper); int prgBanks = flashSize / 0x8000; var readStartTime = DateTime.Now; var lastSectorTime = DateTime.Now; var timeTotal = new TimeSpan(); UInt16 crc = 0; for (int bank = 0; bank < /*16*/ prgBanks; bank++) { byte r0 = (byte)(bank >> 7); byte r1 = (byte)(bank << 1); dumper.WriteCpu(0x5000, r0); dumper.WriteCpu(0x5001, r1); var data = new byte[0x8000]; int pos = bank * 0x8000; if (pos % (128 * 1024) == 0) { timeTotal = new TimeSpan((DateTime.Now - lastSectorTime).Ticks * (prgBanks - bank) / 4); timeTotal = timeTotal.Add(DateTime.Now - readStartTime); lastSectorTime = DateTime.Now; } var timePassed = DateTime.Now - readStartTime; Console.Write("Reading CRC {0}/{1} ({2}%, {3:D2}:{4:D2}:{5:D2}/{6:D2}:{7:D2}:{8:D2})... ", bank + 1, prgBanks, (int)(100 * bank / prgBanks), timePassed.Hours, timePassed.Minutes, timePassed.Seconds, timeTotal.Hours, timeTotal.Minutes, timeTotal.Seconds); var crcr = dumper.ReadCpuCrc(0x8000, 0x8000); Console.WriteLine("CRC = {0:X4}", crcr); crc ^= crcr; } Console.WriteLine("Total CRC = {0:X4}", crc); }
public static void Write(FamicomDumperConnection dumper, string fileName, IEnumerable <int> badSectors, bool silent, bool needCheck = false, bool writePBBs = false) { byte[] PRG; if (Path.GetExtension(fileName).ToLower() == ".bin") { PRG = File.ReadAllBytes(fileName); } else { try { var nesFile = new NesFile(fileName); PRG = nesFile.PRG; } catch { var nesFile = new UnifFile(fileName); PRG = nesFile.Fields["PRG0"]; } } int prgBanks = PRG.Length / 0x4000; Console.Write("Reset... "); dumper.Reset(); Console.WriteLine("OK"); int flashSize = CommonHelper.GetFlashSize(dumper); if (PRG.Length > flashSize) { throw new Exception("This ROM is too big for this cartridge"); } PPBErase(dumper); var writeStartTime = DateTime.Now; var lastSectorTime = DateTime.Now; var timeTotal = new TimeSpan(); int errorCount = 0; for (int bank = 0; bank < prgBanks; bank++) { if (badSectors.Contains(bank / 8)) { bank += 8; // bad sector :( } try { byte r0 = (byte)(((bank >> 3) & 0x07) // 5, 4, 3 bits | (((bank >> 9) & 0x03) << 4) // 10, 9 bits | (1 << 6)); // resets 4th mask bit byte r1 = (byte)((((bank >> 7) & 0x03) << 2) // 8, 7 | (((bank >> 6) & 1) << 4) // 6 | (1 << 7)); // resets 5th mask bit byte r2 = 0; byte r3 = (byte)((1 << 4) // NROM mode | ((bank & 7) << 1)); // 2, 1, 0 bits dumper.WriteCpu(0x6000, new byte[] { r0 }); dumper.WriteCpu(0x6001, new byte[] { r1 }); dumper.WriteCpu(0x6002, new byte[] { r2 }); dumper.WriteCpu(0x6003, new byte[] { r3 }); var data = new byte[0x4000]; int pos = bank * 0x4000; if (pos % (128 * 1024) == 0) { timeTotal = new TimeSpan((DateTime.Now - lastSectorTime).Ticks * (prgBanks - bank) / 8); timeTotal = timeTotal.Add(DateTime.Now - writeStartTime); lastSectorTime = DateTime.Now; Console.Write("Erasing sector... "); dumper.ErasePrgFlash(FamicomDumperConnection.FlashAccessType.Direct); Console.WriteLine("OK"); } Array.Copy(PRG, pos, data, 0, data.Length); var timePassed = DateTime.Now - writeStartTime; Console.Write("Writing {0}/{1} ({2}%, {3:D2}:{4:D2}:{5:D2}/{6:D2}:{7:D2}:{8:D2})... ", bank + 1, prgBanks, (int)(100 * bank / prgBanks), timePassed.Hours, timePassed.Minutes, timePassed.Seconds, timeTotal.Hours, timeTotal.Minutes, timeTotal.Seconds); dumper.WritePrgFlash(0x0000, data, FamicomDumperConnection.FlashAccessType.Direct, true); Console.WriteLine("OK"); if ((bank % 8 == 7) || (bank == prgBanks - 1)) { PPBWrite(dumper, (uint)bank / 8); } } catch (Exception ex) { errorCount++; if (errorCount >= 3) { throw ex; } if (!silent) { Program.errorSound.PlaySync(); } Console.WriteLine("Error: " + ex.Message); bank = (bank & ~7) - 1; Console.WriteLine("Lets try again"); Console.Write("Reset... "); dumper.Reset(); Console.WriteLine("OK"); continue; } } if (errorCount > 0) { Console.WriteLine("Warning! Error count: {0}", errorCount); } if (needCheck) { Console.WriteLine("Starting check process"); Console.Write("Reset... "); dumper.Reset(); Console.WriteLine("OK"); var readStartTime = DateTime.Now; lastSectorTime = DateTime.Now; timeTotal = new TimeSpan(); for (int bank = 0; bank < prgBanks; bank++) { byte r0 = (byte)(((bank >> 3) & 0x07) // 5, 4, 3 bits | (((bank >> 9) & 0x03) << 4) // 10, 9 bits | (1 << 6)); // resets 4th mask bit byte r1 = (byte)((((bank >> 7) & 0x03) << 2) // 8, 7 | (((bank >> 6) & 1) << 4) // 6 | (1 << 7)); // resets 5th mask bit byte r2 = 0; byte r3 = (byte)((1 << 4) // NROM mode | ((bank & 7) << 1)); // 2, 1, 0 bits dumper.WriteCpu(0x6000, new byte[] { r0 }); dumper.WriteCpu(0x6001, new byte[] { r1 }); dumper.WriteCpu(0x6002, new byte[] { r2 }); dumper.WriteCpu(0x6003, new byte[] { r3 }); var data = new byte[0x4000]; int pos = bank * 0x4000; if (pos % (128 * 1024) == 0) { timeTotal = new TimeSpan((DateTime.Now - lastSectorTime).Ticks * (prgBanks - bank) / 8); timeTotal = timeTotal.Add(DateTime.Now - readStartTime); lastSectorTime = DateTime.Now; } Array.Copy(PRG, pos, data, 0, data.Length); UInt16 crc = 0; foreach (var a in data) { crc ^= a; for (int i = 0; i < 8; ++i) { if ((crc & 1) != 0) { crc = (UInt16)((crc >> 1) ^ 0xA001); } else { crc = (UInt16)(crc >> 1); } } } var timePassed = DateTime.Now - readStartTime; Console.Write("Reading CRC {0}/{1} ({2}%, {3:D2}:{4:D2}:{5:D2}/{6:D2}:{7:D2}:{8:D2})... ", bank + 1, prgBanks, (int)(100 * bank / prgBanks), timePassed.Hours, timePassed.Minutes, timePassed.Seconds, timeTotal.Hours, timeTotal.Minutes, timeTotal.Seconds); var crcr = dumper.ReadCpuCrc(0x8000, 0x4000); if (crcr != crc) { throw new Exception(string.Format("Check failed: {0:X4} != {1:X4}", crcr, crc)); } else { Console.WriteLine("OK (CRC = {0:X4})", crcr); } } if (errorCount > 0) { Console.WriteLine("Warning! Error count: {0}", errorCount); return; } } }