Прошиваем эмулятор Retro-Go на Nintendo Game & Watch
3 апреля 2023
Game & Watch: Super Mario Bros — это портативная игровая консоль, выпущенная Nintendo в 2020-м году по случаю 35-и летия игр про Марио. Консоль напоминает игры Game & Watch из 80-х годов, но имеет цветной дисплей. Спустя год вышла аналогичная игровая консоль Game & Watch: The Legend of Zelda. Оба устройства имеют по три игры. Две из них — игры соответствующей серии (Марио / Зельда) под Famicom, и еще одна игра в стиле Game & Watch из 80-х. Вскоре энтузиасты научились прошивать больше трех игр. Этим мы сегодня и займемся.
Важно! Повторяйте описанные шаги на свой страх и риск. Автор данных строк, ровно как и разработчики соответствующего софта, не несут ответственности за ваш потенциально окирпиченный Game & Watch.
Закупаемся
Несмотря на то, что консоли были анонсированы несколько лет назад и якобы имели ограниченный тираж, приобрести их сегодня не составляет никакого труда. Себе я взял версию Марио:
Мне больше нравятся цвета этой версии. Устройство действительно напоминает геймпад от Famicom. Также, в Марио я хоть немного играл, в отличии от Зельды. Подставка была напечатана на 3D-принтере. Модель подставки доступна здесь.
Помимо самого G&W нам понадобится программатор STLink, а также виртуалка или ноутбук с Linux. Разработчики скриптов, которые мы будем использовать, рекомендуют Ubuntu или совместимые дистрибутивы. Поддержка MacOS не заявлена. Я использовал ноутбук с Ubuntu 22.04 LTS.
На Raspberry Pi версии ≤3 повторить описанные шаги не выйдет. Некоторые зависимости не удастся скомпилировать из-за ограниченного количества памяти.
Наконец, нам понадобится чип MX25U51245GZ4I00. Он доступен на AliExpress. Чип представляет собой 64 Мб SPI flash памяти. В моем устройстве всего лишь 1 Мб флеш-памяти (Зельда имеет 4 Мб), и много игр в нее не записать. Поэтому чип будем перепаивать.
На приведенной иллюстрации сверху показан оригинальный чип (даташит [PDF]), а снизу — тот, который будем впаивать на замену (даташит [PDF]). Они имеют разные корпуса, но совместимы по пинам. Первый чип может быть заменен на второй без модификации платы.
Ставим зависимости
На Linux-ноутбуке говорим:
cd game-and-watch
Ставим зависимости:
binutils-arm-none-eabi stlink-tools libtool pkg-config \
libusb-1.0-0-dev libhidapi-hidraw0 libftdi1 libftdi1-2
Еще нам понадобится пропатченная версия OpenOCD:
mkdir openocd-git
cd openocd
wget "https://raw.githubusercontent.com/kbeckmann/ubuntu-openocd-"\
"git-builder/master/0001-Extend-bank1-and-enable-bank2-"\
"of-STM32H7B0VBTx.patch"
git am < 0001-Extend-bank1-and-enable-bank2-of-STM32H7B0VBTx.patch
./bootstrap
./configure --prefix=/home/eax/game-and-watch/openocd-git \
--enable-stlink
make -j4
make install
Затем объявляем такую переменную окружения:
С ее помощью скрипты найдут правильную версию OpenOCD. Рекомендую сразу добавить эту строчку в ~/.bashrc
.
Бэкапимся
С обратной стороны устройства выкручиваем 4 самореза. Здесь понадобится трехгранная (Y-образная) отвертка. Внутри видим следующее:
Сердцем устройства является микроконтроллер STM32H7B0VBT6. Рядом с ним находится SPI flash, который мы уже опознали. Остальные компоненты, вроде контроллера заряда аккумулятора и регуляторов напряжения, особого интереса не представляют. С обратной стороны платы ничего нет, кроме контактных площадок для кнопок.
Отстегиваем аккумулятор. Разъем вынимается вверх, а не в сторону. Теперь наша задача — припаяться к SWD пинам. Они выведены справа от микроконтроллера:
У Зельды распиновка та же, только справа есть два дополнительных контакта. Отмеченные выводы подключаем к соответствующим пинам программатора. STLink подключаем к ноутбуку, сам G&W запитываем штатным образом, через разъем USB-C, от внешнего источника питания. Устройство должно быть включено и показывать время.
Выполняем команды:
git@github.com:ghidraninja/game-and-watch-backup.git
cd game-and-watch-backup
./1_sanity_check.sh stlink mario
Должны увидеть:
Looks good!
Далее:
В случае успеха увидим:
Validating checksum...
Looks good! Successfully backed up the (encrypted) SPI flash to ⏎
backups/flash_backup_mario.bin!
Далее:
Следуем инструкциям. В конце должны получить:
Dumping internal flash...
Verifying internal flash backup...
Device backed up successfully
На этом шаге в каталоге backup/
должно быть три .bin файла. Это очень важные файлы. Они позволят раскирпичить устройство, если во время прошивки что-то пойдет не так. Сохраните их в надежном месте.
Теперь нужно зажать боковую кнопку на G&W и выполнить:
Ожидаемый вывод:
Unlocking device... (Takes up to 30 seconds.)
Congratulations, your device has been unlocked. Just a few more steps!
- The Game & Watch will not yet be functional
- Disconnect power from the device for the changes to take full effect
- Power it again
- Run the 5_restore.sh script to restore the SPI and Internal Flash.
Устройство должно показывать черный экран. Выполняем предложенные шаги. Далее, снова удерживая боковую кнопку, говорим:
Скрипт должен вывести:
Restoring SPI flash...
Restoring internal flash...
Success, your device should be running the original firmware again!
(You should power-cycle the device now)
Следуем инструкциям. Должны снова получить работающее устройство.
Перепаиваем SPI flash
Есть больше одного способа перепаять чип. Лично я воспользовался паяльным феном. Плату нужно излечь из пластикового корпуса и заклеить каптоном (термоскотчем) все, кроме самого чипа. Ставим температуру 300 градусов и среднюю силу обдува. Прогреваем чип, снимаем его пинцетом. Удаляем остатки припоя с помощью оплетки.
Чтобы впаять новый SPI flash, нужно залудить контактные площадки и нанести побольше флюса. После этого новый чип легко впаивается тем же феном. Отклеиваем каптон, отмываем плату изопропиловым спиртом, помещаем плату в корпус.
Далее говорим:
git clone git@github.com:BrianPugh/game-and-watch-patch.git
cd game-and-watch-patch
pip3 install -r requirements.txt
make download_sdk
cp ../game-and-watch-backup/backups/flash_backup_mario.bin ./
cp ../game-and-watch-backup/backups/internal_flash_backup_mario.bin ./
Удерживая боковую кнопку на устройстве, выполняем команду:
ADAPTER=stlink flash_patched
Здесь выводится много разного текста. Главное, чтобы в конце было:
Info : 4-byte address parameter table
Info : valid SFDP detected
Info : flash1 'sfdp' id = 0x3a25c2 size = 65536 KiB
Error: FSIZE in DCR(1) doesn't match actual capacity.
** Programming Started **
Warn : Adding extra erase range, 0x900d7000 .. 0x900dffff
** Programming Finished **
Отмечу, что у меня получилось не с первого раза. Если теперь обесточить устройство и снова его включить, мы должны увидеть часы. Таким образом, был получен тот же G&W, что и раньше, только с 64 Мб флеша.
Прошиваем Retro-Go
Retro-Go — это открытый (GPL 2.0) эмулятор ретро-игр для устройств на основе ESP32. Существует порт под G&W, которым мы и воспользуемся. Точнее говоря, мы воспользуемся форком с более симпатичным интерфейсом, чем в апстриме.
Говорим:
git clone git@github.com:olderzeus/game-and-watch-retro-go.git
cd game-and-watch-retro-go
git submodule update --init --recursive
В каталог roms/
нужно положить ROM’ы с играми. В roms/nes/
идут ROM’ы для NES (a.k.a. Famicom), в roms/md/
— для Sega Mega Drive (a.k.a. Genesis), и так далее. Хороший сборник с играми для NES называется GoodNES, а для Sega Genesis — GoodGen. Заинтересованным читателям предлагается найти их самостоятельно, в качестве упражнения. Другие платформы на данный момент меня не сильно интересуют, быть может, кроме ZX Spectrum. Однако в Retro-Go он не поддерживается, ровно как и Commodore 64. Вероятно, потому что это ПЭВМ с клавиатурой, а не игровые консоли с геймпадом.
Если вы хотите, чтобы у игры была обложка, рядом с ROM’ом нужно положить файл PNG с разрешением 160x160 пикселей и 8-и битным RGB цветом. Файл должен иметь то же имя, что и ROM, с точностью до расширения. Например:
-rw-r--r-- 1 eax eax 33212 Mar 26 17:44 'Sonic and Knuckles.png'
Обложки к играм есть на Википедии. Для их редактирования подходит Gimp.
Когда ROM’ы и обложки готовы, говорим:
# Команда `make clean` не удаляет закэшированные .img/.lzma файлы,
# поэтому удаляем их самостоятельно:
find ./roms/ -type f -name "*.img" -delete -print
find ./roms/ -type f -name "*.lzma" -delete -print
make romdef
Будет выведен список игр и найденных обложек. Если он выглядит похожим на правду, собираем Retro-Go:
EXTFLASH_OFFSET=1048576 INTFLASH_BANK=2 flash
Сборка займет некотороые время и завершится с ошибкой, потому что команде не удастся прошить устройство. Теперь зажимаем боковую кнопку на G&W и повторяем последнюю команду. Должны увидеть, что G&W прошивается:
Кнопку теперь можно отпустить и пойти по своим делам. Прошивка занимает довольно много времени, особенно когда игр много.
Когда процесс завершится, выдергиваем и снова подаем питание. Должны увидеть дэфолтную прошивку с Марио. Если теперь одновременно нажать кнопки «game» и «влево», мы должны попасть в эмулятор с новыми играми.
Заключение
Если вы планируете часто загружать новые игры, то SWD можно вывести на разъем USB-C. Данный разъем используется только для питания устройства. Поэтому мы можем спокойно воспользоваться пинами D+ и D- (номера 6 и 7 из 12-и пинов разъема). Данная модификация наглядно показана в этом видео. В своем экземпляре я так и сделал. Иметь для этого микроскоп, как советует автор видео, желательно, но по моему опыту не обязательно.
Таким образом, мы получили действительно классную портативную игровую консоль. И что с ней теперь делать? Можно просто играть в любимые игры. А можно портировать перечисленные скрипты на MacOS, законтрибьютить в Retro-Go, или даже попробовать писать игры для Famicom. Как обычно, все ограничено лишь вашей фантазией.
Метки: Linux, STM32, Девайсы, Игры, Электроника.
Вы можете прислать свой комментарий мне на почту, или воспользоваться комментариями в Telegram-группе.