Game Boy Advance

Встроенный эмулятор Game Boy Advance

В pureikyubu появилась вторая машина: Game Boy Advance, написанный по публичным спецификациям на железо (ARM Architecture Reference Manual для ARM7TDMI, GBATEK для периферии GBA, Pan Docs для Game Boy). Это не порт чужого кода: отдельное ядро в src/gba со своим бутромом, своим тестовым харнессом и своим фронтендом на SDL2 — под те две задачи, о которых говорит задача: быть GBA Link-партнёром и заменой Game Boy Player.

Бутром рисует логотип pureikyubu

Официальный IPL защищён авторским правом и в репозитории не распространяется. Вместо него эмулятор собирает свободную замену прямо из исходников: анимация бутрома — это эмулируемый ARM-код, который ассемблируется во время работы маленьким эмиттером из src/gba/gba_armasm.cpp. Вращающийся каркасный гиперкуб складывается в плоский куб-логотип pureikyubu, снизу выезжает надпись, после чего бутром передаёт управление картриджу так же, как это делает настоящий BIOS.

Вращающийся гиперкуб в анимации бутрома

1. Гиперкуб вращается. Каждый кадр рисует собственный растеризатор бутрома.

Гиперкуб складывается в куб-логотип

2. Проекция «схлопывается», каркас превращается в куб-логотип.

Финальный кадр бутрома: куб-логотип и надпись pureikyubu

3. Финальный кадр: куб-логотип и надпись, затем запускается картридж.

Образ бутрома можно выгрузить для проверки вместе с листингом ассемблера: gba_bench --dump-bootrom bootrom.bin.

Как запускать

GBA — это режим того же самого исполняемого файла. Картридж выбирает режим по расширению, а без картриджа бутром запускает свой SIO-драйвер — именно это и нужно режиму «GBA Link».

КомандаЧто делает
pureikyubu --gba game.gbaЗапустить картридж: сначала анимация бутрома, затем игра.
pureikyubu --gbaБез картриджа: работает SIO-драйвер бутрома.
pureikyubu game.gbaТо же, что --gba: режим определяется расширением.
pureikyubu --gba --gba-bios bios.binИспользовать настоящий BIOS (16 КБайт) вместо бутрома.
pureikyubu --gba --no-gba-bootromПропустить BIOS и запустить картридж напрямую.
pureikyubu --gba-linkИнициализировать линк-порт даже при загруженном картридже.

Окно, звук и ввод — на SDL2. Раскладка клавиатуры и геймпада, масштаб, частота дискретизации и параметры линка хранятся в build/Data/GBASettings.json; повреждённый файл отвергается с сообщением, и берутся встроенные значения по умолчанию.

Харнесс запускает картридж, который собирает сам

У ядра GBA нет зависимостей от SDL, OpenGL и ImGui, поэтому у него свой харнесс (testing/gba_bench): юнит-тесты, безоконный запуск ROM, хеши кадров, выгрузка кадров в PNG, замер скорости и проверка линка, в которой два экземпляра соединяются друг с другом. Демо-картридж на картинке выше собирается во время работы тем же эмиттером, что и бутром, — это настоящая ARM-программа в настоящем образе картриджа с настоящим заголовком, поэтому одна команда проверяет всю машину (процессор, картридж, экран, таймеры, синхронизацию по VCOUNT).

Демо-картридж рисует свою анимацию

testing/gba_bench/check.sh --demo --frames 120 --png /tmp/demo
testing/gba_bench/check.sh --bootrom --frames 300 --png /tmp/shots
testing/gba_bench/check.sh --run game.gba --frames 600 --bench

Публичные тестовые ROM

jsmolka/gba-tests — набор тестовых ROM для GBA под лицензией MIT. В репозиторий они не входят (это чужие сборки); небольшой скрипт их скачивает, после чего харнесс запускает их как обычный картридж. Это настоящая сквозная проверка, потому что результаты тесты показывают прямо на экране: наборы для памяти, ARM и Thumb сообщают «All tests passed», и именно они нашли ошибку зеркалирования VRAM, правила байтовых операций с видеопамятью и правило флага переноса при сдвиге на 0, заданном регистром.

Тестовый ROM для памяти сообщает, что все тесты пройдены

testing/gba_bench/get_test_roms.sh
testing/gba_bench/check.sh --run testing/gba_bench/roms/memory.gba --frames 200
testing/gba_bench/check.sh --run testing/gba_bench/roms/arm.gba --frames 200

Режим Game Boy

GBA умеет запускать картриджи Game Boy только потому, что внутри консоли живёт вторая, более старая машина. Она тоже реализована отдельным ядром (src/gba/gb_*.cpp): процессор LR35902, экран DMG/CGB с палитрами и банками VRAM, четыре звуковых канала и мапперы MBC1/2/3/5 с батарейным сохранением. У неё свой свободный бутром на 256 байт, в котором надпись «pureikyubu» выезжает в центр экрана.

Надпись бутрома Game Boy выезжает на экран

Что реализовано, а что нет

Реализовано

ARM7TDMI (ARM и Thumb, все семь режимов, исключения, HALT), карта памяти с open bus и задержками WAITCNT, экран (текстовые режимы 0-2, битмап-режимы 3-5, спрайты, окна, мозаика, смешивание, принудительный бланк), четыре таймера, четыре канала DMA включая тайминги для звуковых FIFO и захвата видео, клавиатура, контроллер прерываний, звук (четыре унаследованных канала и два канала прямого звука), последовательный порт в режимах normal/multiplayer/UART с эмулируемым линк-кабелем, картридж (ROM-only плюс SRAM, Flash и EEPROM, порт GPIO/RTC), вызовы BIOS в хосте и собственный бутром с SIO-драйвером.

Не реализовано (пока)

Шина JOY (геймпад GameCube на линк-порте) и собственный протокол загрузки Game Boy Player; звуковой драйвер BIOS и декомпрессор Хаффмана; сохранения состояния и перемотка; особенность EEPROM «последний байт — это AND старого и нового значения». Экран собирает строку целиком к началу HBlank, а не по точкам, и собственные задержки внутренней памяти не моделируются. Полный список отличий, включая все deliberate упрощения, зафиксированные тестами, — в testing/gba_bench/Readme.md.

Документация

Wiki: GBA

Как устроена машина: бутром, линк-порт, настройки, тесты и отличия.

Заметки по ядру

src/gba/Readme.md: состав файлов, спецификации, по которым они написаны, и как проходит кадр.

Тестовый харнесс

testing/gba_bench: что покрывают тесты и какие поведения железа сознательно упрощены.

Благодарности

Фиолетовая Game Boy Advance в иконке страницы — это фотография Evan-Amos (общественное достояние, через Wikimedia Commons); её обрезает и удаляет фон src/res/make_gba_icon.py, а сама иконка — src/res/gba_icon.png.