Свой первый дампер для картриджей 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.

Внешне выглядит впечатляюще, но дампится достаточно просто с помощью 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.

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