示例#1
0
        public void DumpPrg(FamicomDumperConnection dumper, List <byte> data, int size)
        {
            byte banks = (byte)(size / 0x2000);

            for (byte bank = 0; bank < banks - 2; bank += 2)
            {
                Console.Write("Reading PRG banks #{0} and #{1}... ", bank, bank + 1);
                dumper.WriteCpu(0x8000, new byte[] { 6, 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");
        }
示例#2
0
 public static void PasswordUnlock(FamicomDumperConnection dumper, byte[] password)
 {
     try
     {
         if (password.Length != 8)
         {
             throw new InvalidDataException("Invalid password length");
         }
         Console.Write("Unlocking password... ");
         // Password Protection Set Entry
         dumper.WriteCpu(0x8AAA, 0xAA);
         dumper.WriteCpu(0x8555, 0x55);
         dumper.WriteCpu(0x8AAA, 0x60);
         // Password unlock
         dumper.WriteCpu(0x8000, 0x25);
         dumper.WriteCpu(0x8000, 0x03);
         for (byte i = 0; i < password.Length; i++)
         {
             dumper.WriteCpu((ushort)(0x8000 + i), password[i]);
         }
         dumper.WriteCpu(0x8000, 0x29);
         Console.WriteLine("OK");
     }
     finally
     {
         ResetFlash(dumper);
     }
 }
        public void DumpChr(FamicomDumperConnection dumper, List <byte> data, int size)
        {
            byte outbanks = (byte)(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

                int banks = 256;
                if (banks > 256)
                {
                    throw new Exception("CHR size is too big");
                }
                for (int bank = 0; bank < banks; bank += 4)
                {
                    Console.Write("Reading CHR banks #{4}|{0}, #{4}|{1}, #{4}|{2}, #{4}|{3}... ", bank, bank + 1, bank + 2, bank + 3, outbank);
                    dumper.WriteCpu(0x8000, new byte[] { 2, (byte)bank });
                    dumper.WriteCpu(0x8000, new byte[] { 3, (byte)(bank | 1) });
                    dumper.WriteCpu(0x8000, new byte[] { 4, (byte)(bank | 2) });
                    dumper.WriteCpu(0x8000, new byte[] { 5, (byte)(bank | 3) });
                    data.AddRange(dumper.ReadPpu(0x1000, 0x1000));
                    Console.WriteLine("OK");
                }
            }
        }
示例#4
0
 void WriteMMC1(FamicomDumperConnection dumper, UInt16 address, byte data)
 {
     byte[] buffer = new byte[5];
     for (int i = 0; i < 5; i++)
     {
         buffer[i] = (byte)(data >> i);
     }
     dumper.WriteCpu(address, buffer);
 }
示例#5
0
 public static CFIInfo GetCFIInfo(FamicomDumperConnection 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);
     }
 }
示例#6
0
 public static void PPBLockBitCheckPrint(FamicomDumperConnection 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);
     }
 }
示例#7
0
        public void DumpChr(FamicomDumperConnection dumper, List <byte> data, int size)
        {
            int banks = size / 0x400;

            if (banks > 256)
            {
                throw new Exception("CHR size is too big");
            }
            for (int bank = 0; bank < banks; bank += 4)
            {
                Console.Write("Reading CHR banks #{0}, #{1}, #{2}, #{3}... ", bank, bank + 1, bank + 2, bank + 3);
                dumper.WriteCpu(0x8000, new byte[] { 2, (byte)bank });
                dumper.WriteCpu(0x8000, new byte[] { 3, (byte)(bank | 1) });
                dumper.WriteCpu(0x8000, new byte[] { 4, (byte)(bank | 2) });
                dumper.WriteCpu(0x8000, new byte[] { 5, (byte)(bank | 3) });
                data.AddRange(dumper.ReadPpu(0x1000, 0x1000));
                Console.WriteLine("OK");
            }
        }
示例#8
0
        public static void TestPrgRam(FamicomDumperConnection dumper, int count = -1)
        {
            Program.Reset(dumper);
            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 IOException("Test failed");
                    }
                    Console.WriteLine("OK");
                }
                count--;
            }
        }
示例#9
0
        public void DumpPrg(FamicomDumperConnection dumper, List <byte> data, int size)
        {
            int prgBanks = size / 0x8000;

            Console.Write("Reset... ");
            dumper.Reset();
            Console.WriteLine("OK");
            dumper.WriteCpu(0x5002, 0xFE); // mask = 8K
            for (int bank = 0; bank < prgBanks; bank++)
            {
                byte r0 = (byte)(bank >> 7);
                byte r1 = (byte)(bank << 1);
                dumper.WriteCpu(0x5000, r0);
                dumper.WriteCpu(0x5001, r1);

                Console.Write("Reading PRG bank #{0}/{1}... ", bank, prgBanks);
                data.AddRange(dumper.ReadCpu(0x8000, 0x8000));
                Console.WriteLine("OK");
            }
            Console.WriteLine("Done!");
        }
示例#10
0
        public void DumpPrg(FamicomDumperConnection dumper, List <byte> data, int size)
        {
            dumper.WriteCpu((ushort)(0x5000), (byte)0x00);
            dumper.WriteCpu((ushort)(0x5001), (byte)0x10);
            dumper.WriteCpu((ushort)(0x5002), (byte)0x10);
            dumper.WriteCpu((ushort)(0x5006), (byte)0x07);
            dumper.WriteCpu((ushort)(0x5007), (byte)0x03);
            byte banks = (byte)(size / 0x8000);

            for (int bank = 0; bank < banks; bank++)
            {
                Console.Write("Reading PRG bank #{0}... ", bank);
                // TODO: избежать конфликтов шины
                // Avoiding bus conflicts

                /*
                 * for (int i = 0; i < lastBank.Length; i++)
                 * {
                 *  if (lastBank[i] == bank)
                 *  {
                 *      break;
                 *  }
                 * }
                 */
                dumper.WriteCpu((ushort)(0x8000), (byte)bank);
                data.AddRange(dumper.ReadCpu(0x8000, 0x8000));
                Console.WriteLine("OK");
            }
        }
示例#11
0
        private static void CheckRAMAdapter(FamicomDumperConnection dumper)
        {
            // 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("RAM adapter IO error, is it connected?");
            }
        }
        public void DumpPrg(FamicomDumperConnection dumper, List <byte> data, int size)
        {
            dumper.Reset();
            int outbanks = size / (128 * 1024);

            int outbankSize = 512;

            for (int outbank = 0; outbank < outbanks; outbank += outbankSize / 128)
            {
                byte r0 = (byte)((outbank & 0x07) | ((outbank & 0xc0) >> 2));
                byte r1 = (byte)(((outbank & 0x30) >> 2) | ((outbank << 1) & 0x10));
                byte r2 = 0;
                byte r3 = 0;
                dumper.WriteCpu(0x6000, new byte[] { r0 });
                dumper.WriteCpu(0x6001, new byte[] { r1 });
                dumper.WriteCpu(0x6002, new byte[] { r2 });
                dumper.WriteCpu(0x6003, new byte[] { r3 });

                int banks = outbankSize * 1024 / 0x2000;
                for (int 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");
            }
        }
示例#13
0
        public static void ReadCrc(FamicomDumperConnection dumper)
        {
            Program.Reset(dumper);
            dumper.WriteCpu(0x5007, 0x04); // enable PRG write
            dumper.WriteCpu(0x5002, 0xFE); // mask = 32K
            var cfi = FlashHelper.GetCFIInfo(dumper);

            Console.WriteLine($"Device size: {cfi.DeviceSize / 1024 / 1024} MByte / {cfi.DeviceSize / 1024 / 1024 * 8} Mbit");
            uint banks = cfi.DeviceSize / BANK_SIZE;

            var    readStartTime  = DateTime.Now;
            var    lastSectorTime = DateTime.Now;
            var    timeEstimated  = new TimeSpan();
            ushort crc            = 0;

            for (int bank = 0; bank < banks; bank++)
            {
                byte r0 = (byte)(bank >> 7);
                byte r1 = (byte)(bank << 1);
                dumper.WriteCpu(0x5000, r0);
                dumper.WriteCpu(0x5001, r1);

                int pos = bank * BANK_SIZE;
                if (pos % (128 * 1024) == 0)
                {
                    timeEstimated  = new TimeSpan((DateTime.Now - lastSectorTime).Ticks * (banks - bank) / 4);
                    timeEstimated  = timeEstimated.Add(DateTime.Now - readStartTime);
                    lastSectorTime = DateTime.Now;
                }
                var timePassed = DateTime.Now - readStartTime;
                Console.Write($"Reading CRC of bank #{bank}/{banks} ({100 * bank / banks}%, {timePassed.Hours:D2}:{timePassed.Minutes:D2}:{timePassed.Seconds:D2}/{timeEstimated.Hours:D2}:{timeEstimated.Minutes:D2}:{timeEstimated.Seconds:D2})... ");
                var crcr = dumper.ReadCpuCrc(0x8000, BANK_SIZE);
                Console.WriteLine($"CRC = {crcr:X4}");
                crc ^= crcr;
            }
            Console.WriteLine($"Total CRC = {crc:X4}");
        }
        public void DumpPrg(FamicomDumperConnection dumper, List <byte> data, int size)
        {
            byte outbanks = (byte)(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
                byte banks = 32;               //(byte)(size / 0x2000);
                for (byte 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, 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");
            }
        }
示例#15
0
        public void DumpChr(FamicomDumperConnection dumper, List <byte> data, int size)
        {
            dumper.WriteCpu(0x8000, 0x80);
            WriteMMC1(dumper, 0x8000, 0x0C);

            byte banks = (byte)(size / 0x1000);

            for (int bank = 0; bank < banks; bank += 2)
            {
                Console.Write("Reading CHR banks #{0} and #{1}... ", bank, bank + 1);
                WriteMMC1(dumper, 0xA000, (byte)bank);
                data.AddRange(dumper.ReadPpu(0x0000, 0x2000));
                Console.WriteLine("OK");
            }
        }
示例#16
0
        static void TestBattery(FamicomDumperConnection dumper, string mapperName)
        {
            var mapper = GetMapper(mapperName);

            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);
            Reset(dumper);
            Console.WriteLine("Replug cartridge and press any key");
            Console.ReadKey();
            Console.WriteLine();
            mapper.EnablePrgRam(dumper);
            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)
            {
                Console.WriteLine("OK!");
            }
            else
            {
                throw new VerificationException("Failed!");
            }
        }
示例#17
0
        public static void PPBClear(FamicomDumperConnection dumper, ushort coolboyReg)
        {
            // Sector 0
            int  bank = 0;
            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(coolboyReg, r0, r1, r2, r3);

            FlashHelper.PPBClear(dumper);
        }
示例#18
0
        static void WriteEeprom(FamicomDumperConnection dumper, string fileName)
        {
            var nesFile = new NesFile(fileName);
            var prg     = new byte[0x8000];
            int s       = 0;

            while (s < prg.Length)
            {
                var n = Math.Min(nesFile.PRG.Count(), prg.Length - s);
                Array.Copy(nesFile.PRG.ToArray(), s % nesFile.PRG.Count(), prg, s, n);
                s += n;
            }
            var chr = new byte[0x2000];

            s = 0;
            while (s < chr.Length)
            {
                var n = Math.Min(nesFile.CHR.Count(), chr.Length - s);
                Array.Copy(nesFile.CHR.ToArray(), s % nesFile.CHR.Count(), chr, s, n);
                s += n;
            }

            dumper.Timeout = 1000;
            var buff = new byte[64];

            Console.Write("Writing PRG EEPROM");
            for (UInt16 a = 0; a < prg.Length; a += 64)
            {
                Array.Copy(prg, a, buff, 0, buff.Length);
                dumper.WriteCpu((UInt16)(0x8000 + a), buff);
                Thread.Sleep(3);
                Console.Write(".");
            }
            Console.WriteLine(" OK");
            Console.Write("Writing CHR EEPROM");
            for (UInt16 a = 0; a < chr.Length; a += 64)
            {
                Array.Copy(chr, a, buff, 0, buff.Length);
                dumper.WritePpu(a, buff);
                Thread.Sleep(3);
                Console.Write(".");
            }
            Console.WriteLine(" OK");
        }
示例#19
0
        static void TestPrgRam(FamicomDumperConnection dumper, string mapperName, int count = -1)
        {
            var mapper = GetMapper(mapperName);

            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 VerificationException("Failed!");
                }
                Console.WriteLine("OK!");
                count--;
            }
        }
示例#20
0
        static void WritePrgRam(FamicomDumperConnection dumper, string fileName, string mapperName)
        {
            var mapper = GetMapper(mapperName);

            if (mapper.Number >= 0)
            {
                Console.WriteLine($"Using mapper: #{mapper.Number} ({mapper.Name})");
            }
            else
            {
                Console.WriteLine($"Using mapper: {mapper.Name}");
            }
            mapper.EnablePrgRam(dumper);
            Console.Write("Writing PRG RAM... ");
            var prgram = File.ReadAllBytes(fileName);

            dumper.WriteCpu(0x6000, prgram);
            Console.WriteLine("OK");
            dumper.ReadCpu(0x0, 1); // to avoid corruption
            Reset(dumper);
        }
示例#21
0
        public void DumpPrg(FamicomDumperConnection dumper, List <byte> data, int size)
        {
            dumper.WriteCpu(0x8000, 0x80);
            WriteMMC1(dumper, 0x8000, 0x0C);

            byte banks = (byte)(size / 0x4000);

            for (byte bank = 0; bank < banks - 1; bank++)
            {
                Console.Write("Reading PRG bank #{0}... ", bank);
                WriteMMC1(dumper, 0xE000, 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");
            }
        }
示例#22
0
        public static byte DetectVersion(FamicomDumperConnection dumper)
        {
            byte version;

            Console.Write("Detecting COOLBOY version... ");
            // 0th CHR bank using both methods
            dumper.WriteCpu(0x5000, 0, 0, 0, 0x10);
            dumper.WriteCpu(0x6000, 0, 0, 0, 0x10);
            // Writing 0
            dumper.WritePpu(0x0000, 0);
            // First CHR bank using both methods
            dumper.WriteCpu(0x5000, 0, 0, 1, 0x10);
            dumper.WriteCpu(0x6000, 0, 0, 1, 0x10);
            // Writing 1
            dumper.WritePpu(0x0000, 1);
            // 0th bank using first method
            dumper.WriteCpu(0x6000, 0, 0, 0, 0x10);
            byte v6000 = dumper.ReadPpu(0x0000);

            // return
            dumper.WriteCpu(0x6000, 0, 0, 1, 0x10);
            // 0th bank using second method
            dumper.WriteCpu(0x5000, 0, 0, 0, 0x10);
            byte v5000 = dumper.ReadPpu(0x0000);

            if (v6000 == 0 && v5000 == 1)
            {
                version = 1;
            }
            else if (v6000 == 1 && v5000 == 0)
            {
                version = 2;
            }
            else
            {
                throw new IOException("Can't detect COOLBOY version");
            }
            Console.WriteLine($"Version: {version}");
            return(version);
        }
示例#23
0
        public static void PrintFlashInfo(FamicomDumperConnection dumper)
        {
            Program.Reset(dumper);
            var  version    = DetectVersion(dumper);
            var  CoolboyReg = (UInt16)(version == 2 ? 0x5000 : 0x6000);
            int  bank       = 0;
            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(CoolboyReg, r0, r1, r2, r3);
            var cfi = FlashHelper.GetCFIInfo(dumper);

            FlashHelper.PrintCFIInfo(cfi);
            FlashHelper.LockBitsCheckPrint(dumper);
            FlashHelper.PPBLockBitCheckPrint(dumper);
        }
示例#24
0
        public void DumpChr(FamicomDumperConnection dumper, List <byte> data, int size)
        {
            if (prg == null)
            {
                prg = dumper.ReadCpu(0x8000, DefaultPrgSize);
            }
            byte banks = (byte)(size / 0x2000);

            for (int bank = 0; bank < banks; bank++)
            {
                Console.Write("Dumping CHR bank #{0}... ", bank);
                for (int i = 0; i < prg.Length; i++)
                {
                    if (prg[i] == bank)
                    {
                        dumper.WriteCpu((ushort)(0x8000 + i), (byte)bank);
                        break;
                    }
                }
                byte[] d = dumper.ReadPpu(0x0000, 0x2000);
                data.AddRange(d);
                Console.WriteLine("OK");
            }
        }
示例#25
0
        public static void FindBads(FamicomDumperConnection dumper, bool silent)
        {
            Program.Reset(dumper);
            dumper.WriteCpu(0x5007, 0x04); // enable PRG write
            dumper.WriteCpu(0x5002, 0xFE); // mask = 32K
            try
            {
                PPBClear(dumper);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error: {ex.Message}. Lets try anyway.");
            }
            dumper.WriteCpu(0x5000, 0);
            dumper.WriteCpu(0x5001, 0);
            var cfi = FlashHelper.GetCFIInfo(dumper);

            Console.WriteLine($"Device size: {cfi.DeviceSize / 1024 / 1024} MByte / {cfi.DeviceSize / 1024 / 1024 * 8} Mbit");
            uint banks = cfi.DeviceSize / BANK_SIZE;

            FlashHelper.LockBitsCheckPrint(dumper);

            Console.Write("Erasing sector #0... ");
            dumper.EraseCpuFlashSector();
            Console.WriteLine("OK");
            var data = new byte[BANK_SIZE];

            new Random().NextBytes(data);
            Console.Write("Writing sector #0 for test... ");
            dumper.WriteCpuFlash(0x0000, data);
            Console.WriteLine("OK");
            Console.Write("Reading sector #0 for test... ");
            var datar = dumper.ReadCpu(0x8000, BANK_SIZE);

            for (int i = 0; i < data.Length; i++)
            {
                if (data[i] != datar[i])
                {
                    throw new VerificationException("Check failed");
                }
            }
            Console.WriteLine("OK");

            var writeStartTime = DateTime.Now;
            var lastSectorTime = DateTime.Now;
            var timeEstimated  = new TimeSpan();
            var badSectors     = new List <int>();

            for (int bank = 0; bank < banks; bank += 4)
            {
                byte r0 = (byte)(bank >> 7);
                byte r1 = (byte)(bank << 1);
                dumper.WriteCpu(0x5000, r0);
                dumper.WriteCpu(0x5001, r1);

                timeEstimated  = new TimeSpan((DateTime.Now - lastSectorTime).Ticks * (banks - bank) / 4);
                timeEstimated  = timeEstimated.Add(DateTime.Now - writeStartTime);
                lastSectorTime = DateTime.Now;
                var timePassed = DateTime.Now - writeStartTime;
                Console.Write($"Erasing sector #{bank / 4}/{banks / 4} ({100 * bank / banks}%, {timePassed.Hours:D2}:{timePassed.Minutes:D2}:{timePassed.Seconds:D2}/{timeEstimated.Hours:D2}:{timeEstimated.Minutes:D2}:{timeEstimated.Seconds:D2})... ");
                try
                {
                    dumper.EraseCpuFlashSector();
                    Console.WriteLine("OK");
                }
                catch
                {
                    Console.WriteLine("ERROR!");
                    if (!silent)
                    {
                        Program.PlayErrorSound();
                    }
                    Console.Write("Trying again... ");
                    Program.Reset(dumper);
                    dumper.WriteCpu(0x5007, 0x04); // enable PRG write
                    dumper.WriteCpu(0x5002, 0xFE); // mask = 32K
                    dumper.WriteCpu(0x5000, r0);
                    dumper.WriteCpu(0x5001, r1);
                    try
                    {
                        dumper.EraseCpuFlashSector();
                        Console.WriteLine("OK");
                    }
                    catch
                    {
                        Console.WriteLine($"ERROR! Sector #{bank / 4} is bad.");
                        if (!silent)
                        {
                            Program.PlayErrorSound();
                        }
                        badSectors.Add(bank / 4);
                    }
                }
            }
            if (badSectors.Count > 0)
            {
                foreach (var bad in badSectors)
                {
                    Console.WriteLine($"Bad sector: {bad}");
                }
                throw new IOException("Bad sectors found");
            }
            else
            {
                Console.WriteLine("There is no bad sectors");
            }
        }
示例#26
0
        public static void Write(FamicomDumperConnection dumper, string fileName, IEnumerable <int> badSectors, bool silent, bool needCheck = false, bool writePBBs = false, bool ignoreBadSectors = false)
        {
            byte[] PRG;
            if (Path.GetExtension(fileName).ToLower() == ".bin")
            {
                PRG = File.ReadAllBytes(fileName);
            }
            else
            {
                try
                {
                    var nesFile = new NesFile(fileName);
                    PRG = nesFile.PRG.ToArray();
                }
                catch
                {
                    var nesFile = new UnifFile(fileName);
                    PRG = nesFile.Fields["PRG0"];
                }
            }

            int banks = PRG.Length / BANK_SIZE;

            Program.Reset(dumper);
            dumper.WriteCpu(0x5007, 0x04); // enable PRG write
            dumper.WriteCpu(0x5002, 0xFE); // mask = 32K
            dumper.WriteCpu(0x5000, 0);
            dumper.WriteCpu(0x5001, 0);
            FlashHelper.ResetFlash(dumper);
            var cfi = FlashHelper.GetCFIInfo(dumper);

            Console.WriteLine($"Device size: {cfi.DeviceSize / 1024 / 1024} MByte / {cfi.DeviceSize / 1024 / 1024 * 8} Mbit");
            Console.WriteLine($"Maximum number of bytes in multi-byte program: {cfi.MaximumNumberOfBytesInMultiProgram}");
            if (dumper.ProtocolVersion >= 3)
            {
                dumper.SetMaximumNumberOfBytesInMultiProgram(cfi.MaximumNumberOfBytesInMultiProgram);
            }
            FlashHelper.LockBitsCheckPrint(dumper);
            if (PRG.Length > cfi.DeviceSize)
            {
                throw new ArgumentOutOfRangeException("PRG.Length", "This ROM is too big for this cartridge");
            }
            try
            {
                PPBClear(dumper);
            }
            catch (Exception ex)
            {
                if (!silent)
                {
                    Program.PlayErrorSound();
                }
                Console.WriteLine($"ERROR! {ex.Message}. Lets continue anyway.");
            }

            var writeStartTime    = DateTime.Now;
            var lastSectorTime    = DateTime.Now;
            var timeEstimated     = new TimeSpan();
            int totalErrorCount   = 0;
            int currentErrorCount = 0;
            var newBadSectorsList = new List <int>();

            for (int bank = 0; bank < banks; bank++)
            {
                while (badSectors.Contains(bank / 4) || newBadSectorsList.Contains(bank / 4))
                {
                    bank += 4;                                                                           // bad sector :(
                }
                try
                {
                    byte r0 = (byte)(bank >> 7);
                    byte r1 = (byte)(bank << 1);
                    dumper.WriteCpu(0x5000, r0);
                    dumper.WriteCpu(0x5001, r1);

                    var data = new byte[BANK_SIZE];
                    int pos  = bank * BANK_SIZE;
                    if (pos % (128 * 1024) == 0)
                    {
                        timeEstimated  = new TimeSpan((DateTime.Now - lastSectorTime).Ticks * (banks - bank) / 4);
                        timeEstimated  = timeEstimated.Add(DateTime.Now - writeStartTime);
                        lastSectorTime = DateTime.Now;
                        Console.Write($"Erasing sector #{bank / 4}... ");
                        dumper.EraseCpuFlashSector();
                        Console.WriteLine("OK");
                    }
                    Array.Copy(PRG, pos, data, 0, data.Length);
                    var timePassed = DateTime.Now - writeStartTime;
                    Console.Write($"Writing bank #{bank}/{banks} ({100 * bank / banks}%, {timePassed.Hours:D2}:{timePassed.Minutes:D2}:{timePassed.Seconds:D2}/{timeEstimated.Hours:D2}:{timeEstimated.Minutes:D2}:{timeEstimated.Seconds:D2})... ");
                    dumper.WriteCpuFlash(0x0000, data);
                    Console.WriteLine("OK");
                    if ((bank % 4 == 3) || (bank == banks - 1)) // After last bank in sector
                    {
                        if (writePBBs)
                        {
                            FlashHelper.PPBSet(dumper);
                        }
                        currentErrorCount = 0;
                    }
                }
                catch (Exception ex)
                {
                    totalErrorCount++;
                    currentErrorCount++;
                    Console.WriteLine($"ERROR {ex.GetType()}: {ex.Message}");
                    if (!silent)
                    {
                        Program.PlayErrorSound();
                    }
                    if (currentErrorCount >= 5)
                    {
                        if (!ignoreBadSectors)
                        {
                            throw ex;
                        }
                        else
                        {
                            newBadSectorsList.Add(bank / 4);
                            currentErrorCount = 0;
                            Console.WriteLine($"Lets skip sector #{bank / 4}");
                        }
                    }
                    else
                    {
                        Console.WriteLine("Lets try again");
                    }
                    bank = (bank & ~3) - 1;
                    Program.Reset(dumper);
                    dumper.WriteCpu(0x5007, 0x04); // enable PRG write
                    dumper.WriteCpu(0x5002, 0xFE); // mask = 32K
                    FlashHelper.ResetFlash(dumper);
                    continue;
                }
            }
            if (totalErrorCount > 0)
            {
                Console.WriteLine($"Write error count: {totalErrorCount}");
            }
            if (newBadSectorsList.Any())
            {
                Console.WriteLine($"Can't write sectors: {string.Join(", ", newBadSectorsList.OrderBy(s => s))}");
            }

            var wrongCrcSectorsList = new List <int>();

            if (needCheck)
            {
                Console.WriteLine("Starting verification process");
                Program.Reset(dumper);

                var readStartTime = DateTime.Now;
                lastSectorTime = DateTime.Now;
                timeEstimated  = new TimeSpan();
                dumper.WriteCpu(0x5002, 0xFE); // mask = 32K
                for (int bank = 0; bank < banks; bank++)
                {
                    while (badSectors.Contains(bank / 4))
                    {
                        bank += 4;                                   // bad sector :(
                    }
                    byte r0 = (byte)(bank >> 7);
                    byte r1 = (byte)(bank << 1);
                    dumper.WriteCpu(0x5000, r0);
                    dumper.WriteCpu(0x5001, r1);

                    var data = new byte[BANK_SIZE];
                    int pos  = bank * BANK_SIZE;
                    if (pos % (128 * 1024) == 0)
                    {
                        timeEstimated  = new TimeSpan((DateTime.Now - lastSectorTime).Ticks * (banks - bank) / 4);
                        timeEstimated  = timeEstimated.Add(DateTime.Now - readStartTime);
                        lastSectorTime = DateTime.Now;
                    }
                    Array.Copy(PRG, pos, data, 0, data.Length);
                    ushort crc = 0;
                    foreach (var a in data)
                    {
                        crc ^= a;
                        for (int i = 0; i < 8; ++i)
                        {
                            if ((crc & 1) != 0)
                            {
                                crc = (ushort)((crc >> 1) ^ 0xA001);
                            }
                            else
                            {
                                crc = (ushort)(crc >> 1);
                            }
                        }
                    }
                    var timePassed = DateTime.Now - readStartTime;
                    Console.Write($"Reading CRC of bank #{bank}/{banks} ({100 * bank / banks}%, {timePassed.Hours:D2}:{timePassed.Minutes:D2}:{timePassed.Seconds:D2}/{timeEstimated.Hours:D2}:{timeEstimated.Minutes:D2}:{timeEstimated.Seconds:D2})... ");
                    var crcr = dumper.ReadCpuCrc(0x8000, BANK_SIZE);
                    if (crcr != crc)
                    {
                        Console.WriteLine($"Verification failed: {crcr:X4} != {crc:X4}");
                        if (!silent)
                        {
                            Program.PlayErrorSound();
                        }
                        wrongCrcSectorsList.Add(bank / 4);
                    }
                    else
                    {
                        Console.WriteLine($"OK (CRC = {crcr:X4})");
                    }
                }
                if (totalErrorCount > 0)
                {
                    Console.WriteLine($"Write error count: {totalErrorCount}");
                }
                if (newBadSectorsList.Any())
                {
                    Console.WriteLine($"Can't write sectors: {string.Join(", ", newBadSectorsList.OrderBy(s => s))}");
                }
                if (wrongCrcSectorsList.Any())
                {
                    Console.WriteLine($"Sectors with wrong CRC: {string.Join(", ", wrongCrcSectorsList.Distinct().OrderBy(s => s))}");
                }
            }

            if (newBadSectorsList.Any() || wrongCrcSectorsList.Any())
            {
                throw new IOException("Cartridge is not writed correctly");
            }
        }
 public void EnablePrgRam(FamicomDumperConnection dumper)
 {
     dumper.WriteCpu(0xA001, 0x80);
 }
示例#28
0
 public void EnablePrgRam(FamicomDumperConnection dumper)
 {
     dumper.Reset();
     dumper.WriteCpu(0x5007, 0x01); // enable SRAM
     dumper.WriteCpu(0x5005, 0x02); // select bank
 }
示例#29
0
        public static void TestChrRam(FamicomDumperConnection dumper, int count = -1, int chrSize = -1)
        {
            if (chrSize < 0)
            {
                chrSize = 256 * 1024;
            }
            Console.WriteLine($"Testing CHR RAM, size: {chrSize / 1024}KB");
            Program.Reset(dumper);
            dumper.WriteCpu(0x5007, 0x2); // enable CHR writing
            var rnd  = new Random();
            var data = new byte[0x2000];

            rnd.NextBytes(data);
            Console.WriteLine("Single bank test.");
            Console.Write("Writing CHR RAM... ");
            dumper.WritePpu(0x0000, data);
            Console.Write("Reading CHR RAM... ");
            var  rdata = dumper.ReadPpu(0x0000, 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("chrramgood.bin", data);
                Console.WriteLine("chrramgood.bin writed");
                File.WriteAllBytes("chrrambad.bin", rdata);
                Console.WriteLine("chrrambad.bin writed");
                throw new IOException("Test failed");
            }
            Console.WriteLine("OK");

            Console.WriteLine("Multibank test.");
            data = new byte[chrSize];
            for (; count != 0; count--)
            {
                dumper.WriteCpu(0x5007, 0x2); // enable CHR writing
                rnd.NextBytes(data);
                for (byte bank = 0; bank < data.Length / 0x2000; bank++)
                {
                    Console.WriteLine($"Writing CHR RAM bank #{bank}/{data.Length / 0x2000}...");
                    dumper.WriteCpu(0x5003, (byte)(bank & 0b00011111));        // select bank, low 5 bits
                    dumper.WriteCpu(0x5005, (byte)((bank & 0b00100000) << 2)); // select bank, 6th bit
                    var d = new byte[0x2000];
                    Array.Copy(data, bank * 0x2000, d, 0, 0x2000);
                    dumper.WritePpu(0x0000, d);
                }
                for (byte bank = 0; bank < data.Length / 0x2000; bank++)
                {
                    Console.Write($"Reading CHR RAM bank #{bank}/{data.Length / 0x2000}... ");
                    dumper.WriteCpu(0x5003, (byte)(bank & 0b00011111));        // select bank, low 5 bits
                    dumper.WriteCpu(0x5005, (byte)((bank & 0b00100000) << 2)); // select bank, 6th bit
                    rdata = dumper.ReadPpu(0x0000, 0x2000);
                    ok    = true;
                    for (int b = 0; b < 0x2000; b++)
                    {
                        if (data[b + bank * 0x2000] != rdata[b])
                        {
                            Console.WriteLine($"Mismatch at {b:X4}: {rdata[b]:X2} != {data[b + bank * 0x2000]:X2}");
                            ok = false;
                        }
                    }
                    if (!ok)
                    {
                        File.WriteAllBytes("chrramgoodf.bin", data);
                        Console.WriteLine("chrramgoodf.bin writed");
                        File.WriteAllBytes("chrrambad.bin", rdata);
                        Console.WriteLine("chrrambad.bin writed");
                        throw new IOException("Test failed");
                    }
                    Console.WriteLine("OK");
                }
            }
        }
示例#30
0
 public LuaMapper()
 {
     script = new Script();
     script.Globals["ReadPrg"] = script.Globals["ReadCpu"] = (Func <UInt16, int, List <byte> >) delegate(UInt16 address, int length)
     {
         if (Verbose)
         {
             Console.WriteLine("Reading {0} bytes from CPU:${1:X4}", length, address);
         }
         var result = new List <byte>();
         result.AddRange(dumper.ReadCpu(address, length));
         return(result);
     };
     script.Globals["WritePrg"] = script.Globals["WriteCpu"] = (Action <UInt16, List <byte> >) delegate(UInt16 address, List <byte> data)
     {
         if (Verbose)
         {
             var a = address;
             foreach (var v in data)
             {
                 Console.WriteLine("CPU write ${0:X2} => ${1:X4}", v, a);
                 a++;
             }
         }
         dumper.WriteCpu(address, data.ToArray());
     };
     script.Globals["AddPrg"] = script.Globals["AddPrgResult"] = (Action <List <byte> >) delegate(List <byte> r)
     {
         resultPrg.AddRange(r);
     };
     script.Globals["ReadAddPrg"] = script.Globals["ReadAddCpu"] = (Action <UInt16, int>) delegate(UInt16 address, int length)
     {
         if (Verbose)
         {
             Console.WriteLine("Reading {0} bytes from CPU:${1:X4}", length, address);
         }
         resultPrg.AddRange(dumper.ReadCpu(address, length));
     };
     script.Globals["ReadChr"] = script.Globals["ReadPpu"] = (Func <UInt16, int, List <byte> >) delegate(UInt16 address, int length)
     {
         if (Verbose)
         {
             Console.WriteLine("Reading {0} bytes from PPU:${1:X4}", length, address);
         }
         var result = new List <byte>();
         result.AddRange(dumper.ReadPpu(address, length));
         return(result);
     };
     script.Globals["WriteChr"] = script.Globals["WritePpu"] = (Action <UInt16, List <byte> >) delegate(UInt16 address, List <byte> data)
     {
         if (Verbose)
         {
             var a = address;
             foreach (var v in data)
             {
                 Console.WriteLine("PPU write ${0:X2} => ${1:X4}", v, a);
                 a++;
             }
         }
         dumper.WritePpu(address, data.ToArray());
     };
     script.Globals["ReadAddChr"] = script.Globals["ReadAddPpu"] = (Action <UInt16, int>) delegate(UInt16 address, int length)
     {
         if (Verbose)
         {
             Console.WriteLine("Reading {0} bytes from PPU:${1:$X4}", length, address);
         }
         resultChr.AddRange(dumper.ReadPpu(address, length));
     };
     script.Globals["AddChr"] = script.Globals["AddChrResult"] = (Action <List <byte> >) delegate(List <byte> r)
     {
         resultChr.AddRange(r);
     };
     script.Globals["Reset"] = (Action) delegate
     {
         if (Verbose)
         {
             Console.Write("Reset... ");
         }
         dumper.Reset();
         if (Verbose)
         {
             Console.WriteLine("OK");
         }
     };
     script.Globals["WriteFile"] = (Action <string, List <byte> >) delegate(string filename, List <byte> data)
     {
         if (Verbose)
         {
             Console.Write("Writing data to \"{0}\"... ", Path.GetFileName(filename));
         }
         File.WriteAllBytes(filename, data.ToArray());
         if (Verbose)
         {
             Console.WriteLine("OK");
         }
     };
     script.Globals["WriteNes"] = (WriteNesDelegate) delegate(string filename, List <byte> prgData, List <byte> chrData, byte mapper, bool vertical)
     {
         if (Verbose)
         {
             Console.Write("Writing data to NES file \"{0}\" (mapper={1}, mirroring={2})... ", Path.GetFileName(filename), mapper, vertical ? "vertical" : "horizontal");
         }
         var nesFile = new NesFile();
         nesFile.PRG       = prgData.ToArray();
         nesFile.CHR       = chrData.ToArray();
         nesFile.Mapper    = 0;
         nesFile.Mirroring = vertical ? NesFile.MirroringType.Vertical : NesFile.MirroringType.Horizontal;
         nesFile.Save(filename);
         if (Verbose)
         {
             Console.WriteLine("OK");
         }
     };
     script.Globals["Error"] = (Action <string>) delegate(string message)
     {
         throw new Exception(message);
     };
 }