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);
     }
 }
Example #3
0
    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);
    }
Example #4
0
    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");
        }
    }
 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");
 }
 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");
 }
    /*
     * Main method name must be "Run". You can specify those parameters in any order:
     *
     *  IFamicomDumperConnection dumper - dumper object used to access dumper
     *  string filename                 - filename specified by --file argument
     *  IMapper mapper                  - mapper object compiled from mapper script specified by --mapper argument
     *  int prgSize                     - PRG size specified by --prg-size argument (parsed)
     *  int chrSize                     - CHR size specified by --chr-size argument (parsed)
     *  string unifName                 - string specified by --unif-name argument
     *  string unifAuthor               - string specified by --unif-author argument
     *  bool battery                    - true if --battery argument is specified
     *  string[] args                   - additional command line arguments
     *
     * You can specify additional arguments this way: >famicom-dumper script --csfile DemoScript.cs - argument1 argument2 argument3
     *
     * Always define default value if parameter is optional.
     * The only exception is the "mapper" parameter, the "NROM" mapper will be used by default.
     * Also "args" will be a zero-length array if additional arguments are not specified
     *
     */
    void Run(IFamicomDumperConnection dumper, string[] args, IMapper mapper, int prgSize = 128 * 1024, int chrSize = -1)
    {
        if (mapper.Number >= 0)
        {
            Console.WriteLine($"Using mapper: #{mapper.Number} ({mapper.Name})");
        }
        else
        {
            Console.WriteLine($"Using mapper: {mapper.Name}");
        }

        if (chrSize < 0)
        {
            // Oh no, CHR size is not specified! Lets use mapper's default
            chrSize = mapper.DefaultChrSize;
        }

        Console.WriteLine($"PRG size: {prgSize}");
        Console.WriteLine($"CHR size: {chrSize}");

        if (args.Any())
        {
            Console.WriteLine("Additional command line arguments: " + string.Join(", ", args));
        }

        // You can use other methods
        Reset(dumper);
    }
Example #8
0
 public void EnablePrgRam(IFamicomDumperConnection dumper)
 {
     dumper.WriteCpu(0x5102, 0x02); // PRG-RAM protection
     dumper.WriteCpu(0x5103, 0x01); // PRG-RAM protection
     dumper.WriteCpu(0x5100, 3);    // bank mode #3, four 8KB banks
     dumper.WriteCpu(0x5113, 7);    // PRG-RAM bank #7
 }
Example #9
0
 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");
 }
Example #10
0
        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");
            }
        }
Example #11
0
 public void EnablePrgRam(IFamicomDumperConnection dumper)
 {
     dumper.Reset();
     dumper.WriteCpu(0xA001, 0x00);
     dumper.WriteCpu(0x6003, 0x80);
     dumper.WriteCpu(0xA001, 0x80);
 }
 public static void ResetFlash(IFamicomDumperConnection dumper)
 {
     // Exit command set entry if any
     dumper.WriteCpu(0x8000, 0x90);
     dumper.WriteCpu(0x8000, 0x00);
     // Reset
     dumper.WriteCpu(0x8000, 0xF0);
 }
Example #13
0
    // 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;
            }
        }
    }
Example #14
0
        void WriteMMC1(IFamicomDumperConnection dumper, ushort address, byte data)
        {
            var buffer = new byte[5];

            for (var i = 0; i < 5; i++)
            {
                buffer[i] = (byte)(data >> i);
            }
            dumper.WriteCpu(address, buffer);
        }
Example #15
0
        public void DumpChr(IFamicomDumperConnection dumper, List <byte> data, int size)
        {
            var banks = size / 0x400;

            for (var bank = 0; bank < banks; bank++)
            {
                Console.Write("Reading CHR bank #{0}... ", bank);
                dumper.WriteCpu(0x8000, (byte)bank);
                data.AddRange(dumper.ReadPpu(0x0000, 0x0400));
                Console.WriteLine("OK");
            }
        }
 public static void FullTest(IFamicomDumperConnection dumper, int count, int chrSize)
 {
     while (count != 0)
     {
         TestPrgRam(dumper, 1);
         TestChrRam(dumper, 1, chrSize);
         if (count > 0)
         {
             count--;
         }
     }
 }
Example #17
0
    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");
        }
    }
Example #18
0
        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");
            }
        }
Example #19
0
    public void DumpChr(IFamicomDumperConnection dumper, List <byte> data, int size)
    {
        var banks = size / 0x2000;

        for (var bank = 0; bank < banks; bank++)
        {
            Console.Write($"Reading CHR bank #{bank}/{banks}... ");
            dumper.WriteCpu((ushort)(0x8000 | (bank << 1)), 0);
            data.AddRange(dumper.ReadPpu(0x0000, 0x2000));
            Console.WriteLine("OK");
        }
    }
Example #20
0
    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");
        }
    }
Example #21
0
    public void DumpChr(IFamicomDumperConnection dumper, List <byte> data, int size)
    {
        var banks = size / 0x1000;

        for (var bank = 0; bank < banks; bank++)
        {
            Console.Write($"Reading CHR bank #{bank}/{banks}... ");
            dumper.WriteCpu(0xB000, (byte)bank); // CHR ROM $FD/0000 bank select
            dumper.WriteCpu(0xC000, (byte)bank); // CHR ROM $FE/0000 bank select
            data.AddRange(dumper.ReadPpu(0x0000, 0x1000));
            Console.WriteLine("OK");
        }
    }
Example #22
0
        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");
            }
        }
Example #23
0
    public void DumpChr(IFamicomDumperConnection dumper, List<byte> data, int size)
    {
        var banks = size / 0x400;

        for (var bank = 0; bank < banks; bank++)
        {
            Console.Write($"Reading CHR bank #{bank}/{banks}... ");
            dumper.WriteCpu(0xB000, (byte)(bank & 0x0F)); // CHR Select 0 low
            dumper.WriteCpu(0xB002 | 0xB040, (byte)(bank >> 4)); // CHR Select 0 low
            data.AddRange(dumper.ReadPpu(0x0000, 0x0400));
            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");
            }
        }
Example #25
0
    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--;
        }
    }
Example #26
0
        public void DumpChr(IFamicomDumperConnection dumper, List <byte> data, int size)
        {
            var banks = size / 0x2000;

            dumper.WriteCpu(0x2000, 0); // 8x8 sprites mode
            dumper.WriteCpu(0x5101, 0); // bank mode #0, one 8KB bank
            for (var bank = 0; bank < banks; bank++)
            {
                Console.Write("Reading CHR bank #{0}... ", bank);
                dumper.WriteCpu(0x5127, (byte)bank);
                data.AddRange(dumper.ReadPpu(0x0000, 0x2000));
                Console.WriteLine("OK");
            }
        }
    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);
        }
    }
Example #28
0
    public void DumpChr(IFamicomDumperConnection dumper, List <byte> data, int size)
    {
        dumper.WriteCpu(0x8000, 0x80);
        WriteMMC1(dumper, 0x8000, 0b11100);

        var banks = size / 0x1000;

        for (var bank = 0; bank < banks; bank++)
        {
            Console.Write($"Reading CHR bank #{bank}/{banks}... ");
            WriteMMC1(dumper, 0xA000, (byte)bank);
            data.AddRange(dumper.ReadPpu(0x0000, 0x1000));
            Console.WriteLine("OK");
        }
    }
Example #29
0
    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");
    }
Example #30
0
        public void DumpChr(IFamicomDumperConnection dumper, List <byte> data, int size)
        {
            dumper.WriteCpu(0x8000, 0x80);
            WriteMMC1(dumper, 0x8000, 0x0C);

            var banks = size / 0x1000;

            for (var 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");
            }
        }