Свой первый дампер для картриджей NES/Famicom я собрал по проекту famicom-dumper от @clusterM.

Осознанно выбрал для реализации раннюю версию, она мне больше нравится, ввиду доступности и адекватности выбора комплектующих для своей задачи. Контроллеры ATMEGA64 были в наличии, лежали лет 10, ждали своего часа.
Конечно, у ранней версии нет честного phi2, не все мапперы можно сдампить без постоянного phi2, но для подавляющего большинства этого и не требуется.
В своем форке на гитхабе (https://github.com/pavelkokorin/famicom-dumper), доделал постоянную генерацию phi2 во время idle, для некоторых мапперов многоигровок это помогло.

Моя реализация не отличается красотой, собрано на старой макетке и модулях с алиэкспресс. Главное, что работает.

Вид спереди
Вид спереди
Вид сзади
Вид сзади

Основное назначение дампера - исследование и эксперименты с мапперами (оригинальными и клонами), для этой задачи клиент-серверная архитектура ПО с компилируемыми модулями на C# подходит очень хорошо, пользоваться действительно удобно.
Есть другие проекты, например, комбайн cartreader от sanni, где вся логика внутри arduino, что для исследовательских задач менее удобно.

Дампер также умеет прошивать образы в китайские клоны flash картриджей по типу CoolBoy, дампить FDS, тестировать SRAM и прочее.

Исследование "платок" от картриджей - это то, ради чего я собирал дампер, научиться дампить многоигровки (новоделы, староделы) с неизвестными или не полностью известными типами мапперов. Большая часть мапперов, на сегодняшний день, исследована вдоль и поперек, но сложность создает большое их разнообразие, проблема идентификации маппер по косвенным признакам: номерам используемых портов, виду платы, необходимости частичного дизассемблирования дампов.

Дампер также подходит и для исследования лицензионных, но экзотических картриджей. Интересный пример -- DATACH от Bandai.

DATACH от Bandai
DATACH от Bandai

Внешне выглядит впечатляюще, но дампится достаточно просто с помощью 157 маппера, создать который по спецификации и запрограммировать новый модуль на C# не составляет труда.

// .\mappers\153.cs
// Bandai DATACH Joint ROM System

class BANDAI_LZ93D50_BARCODE : IMapper
{
    public string Name { get => "BANDAI BARCODE"; }
    public int Number { get => 157; }
    public int DefaultPrgSize { get => 256 * 1024; }
    public int DefaultChrSize { get => 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(0x8008, (byte)(bank & 0xFF));
            data.AddRange(dumper.ReadCpu(0x8000, 0x4000));
            Console.WriteLine("OK");
        }
    }
    public MirroringType GetMirroring(IFamicomDumperConnection dumper)
    {
        return MirroringType.MapperControlled;
    }
}

Запуск

D:\Develop\famicom-dumper-win-x64-self-contained\famicom-dumper>famicom-dumper.exe dump --port COM3 --mapper 157 --chr-size 0k --prg-size 256k --chr-ram-size 8k --file datach.nes
Famicom Dumper Client v3.4(c) Alexey 'Cluster' Avdyukhin / https://clusterrr.com / clusterrr@clusterrr.com
Dumper initialization... OK
Compiling mappers in D:\Develop\famicom-dumper-win-x64-self-contained\famicom-dumper\mappers...
Using 157.cs as mapper file
Using mapper: #157 (BANDAI BARCODE)
Dumping...
PRG memory size: 256KB
Reading PRG bank #0/16... OK
...
Reading PRG bank #15/16... OK
Mirroring: MapperControlled
Saving ROM as NES 2.0 file: datach.nes... OK
Done.
Запуск на эмуляторе
Запуск на эмуляторе

Или другой пример от Bandai, картридж Famicom Jump II - Saikyou no 7 Nin (Japan), со своим уникальным 153 маппером, который использовался только в нем.

// .\mappers\153.cs
// The only game "Famicom Jump II - Saikyou no 7 Nin (Japan)" uses this mapper

class BANDAI_LZ93D50_WRAM_CHRRAM_PRGROM : IMapper
{
    public string Name { get => "153 BANDAI SRAM"; }
    public int Number { get => 153; }
    public int DefaultPrgSize { get => 512 * 1024; }
    public int DefaultChrSize { get => 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}... ");

            var outerBank = (byte)((bank & 0x10) >> 4);
            dumper.WriteCpu(0x8000, outerBank);
            dumper.WriteCpu(0x8001, outerBank);
            dumper.WriteCpu(0x8002, outerBank);
            dumper.WriteCpu(0x8003, outerBank);

            dumper.WriteCpu(0x8008, (byte)(bank & 0xF));
            data.AddRange(dumper.ReadCpu(0x8000, 0x4000));
            Console.WriteLine("OK");
        }
    }
    public MirroringType GetMirroring(IFamicomDumperConnection dumper)
    {
        return MirroringType.MapperControlled;
    }
}

Запуск

Famicom Dumper Client v3.4
  (c) Alexey 'Cluster' Avdyukhin / https://clusterrr.com / clusterrr@clusterrr.com

Dumper initialization... OK
Compiling mappers in D:\Develop\famicom-dumper-win-x64-self-contained\famicom-dumper\mappers...
Using 153.cs as mapper file
Using mapper: #153 (153 BANDAI SRAM)
Dumping...
PRG memory size: 512KB
Reading PRG bank #0/32... OK
...
Reading PRG bank #31/32... OK
Mirroring: MapperControlled
Saving ROM as NES 2.0 file: Famicom Jump II Saikyou no 7-nin 153.nes... OK
Done.
Запуск на Mesen
Запуск на Mesen

Подытоживая, дампером и реализацией доволен, он полностью закрывает мои задачи. Для тех, кто подыскивает подходящий инструмент, рекомендую обратить вниманием именно на https://github.com/ClusterM/famicom-dumper, он прост в изготовлении и функционален.

Ссылки: