Архитектура GBA и настройка окружения разработки DevkitPro
Архитектура GBA и настройка окружения разработки DevkitPro
Добро пожаловать на курс по разработке игр для Game Boy Advance (GBA). Выбор этой платформы для изучения геймдева — отличное решение. GBA — это идеальный баланс между простотой, позволяющей понять каждый бит системы, и мощностью, достаточной для создания красивых 2D-игр. Здесь нет операционной системы, драйверов или тяжелых игровых движков. Есть только вы, ваш код и «железо».
В этой вводной статье мы разберем, как устроен GBA изнутри, почему математика здесь работает иначе и как подготовить ваш компьютер к созданию первой игры.
Сердце консоли: Процессор и архитектура
Game Boy Advance, выпущенный в 2001 году, был настоящим технологическим прорывом. Чтобы писать эффективный код, нужно понимать, на чем он исполняется.
Процессор ARM7TDMI
Центральный процессор GBA — это 32-битный RISC-процессор ARM7TDMI, работающий на частоте 16.78 МГц. Давайте расшифруем, что это значит для нас как разработчиков:
- RISC (Reduced Instruction Set Computer): Упрощенный набор команд. Каждая инструкция выполняется очень быстро, обычно за один такт.
- 32-битный: Процессор оперирует 32-битными числами. Это «родной» размер данных.
Особенность этого процессора в том, что он поддерживает два набора инструкций:
- ARM (32-бит): Мощные инструкции, дают максимальную производительность. Но код занимает больше места в памяти.
- Thumb (16-бит): Сжатый набор инструкций. Код занимает меньше места, но может работать чуть медленнее в определенных ситуациях.
В разработке под GBA мы часто используем Thumb-инструкции для основной логики, чтобы экономить драгоценное место на картридже, и переключаемся на ARM для критически важных вычислений, требующих скорости.
Память и её карта
У GBA нет жесткого диска. Вся память доступна процессору напрямую через единое адресное пространство. Однако память неоднородна и разделена на секции:
| Тип памяти | Название | Объем | Назначение |
|---|---|---|---|
| EWRAM | External Work RAM | 256 КБ | Медленная память для больших данных и переменных. |
| IWRAM | Internal Work RAM | 32 КБ | Быстрая память внутри чипа. Здесь хранят критичный код и стек. |
| VRAM | Video RAM | 96 КБ | Видеопамять. Сюда мы пишем то, что хотим увидеть на экране. |
| OAM | Object Attribute Memory | 1 КБ | Память атрибутов объектов (спрайтов). |
| ROM | Game Pak | до 32 МБ | Память картриджа (только для чтения). Здесь живет ваша игра. |
Дисплей
Экран GBA имеет разрешение 240x160 пикселей. Это может показаться малым по современным меркам, но именно это ограничение заставляет художников и программистов творить чудеса пиксель-арта. Частота обновления экрана составляет чуть меньше 60 Гц (точнее, 59.73 Гц).
Математика на GBA: Числа с фиксированной точкой
Одной из главных особенностей программирования под старые консоли является отсутствие FPU (Floating Point Unit) — специального блока процессора для работы с дробными числами (float, double).
Если вы попытаетесь использовать тип float в своем коде (например, float x = 1.5;), процессор будет эмулировать вычисления программно. Это катастрофически медленно. Обычное сложение двух float может занять в 50-100 раз больше времени, чем сложение целых чисел.
Решение? Арифметика с фиксированной точкой (Fixed Point Arithmetic).
Суть метода в том, что мы используем обычные целые числа (int), но договариваемся, что часть бит отводится под целую часть, а часть — под дробную. Например, в формате «8.8» (всего 16 бит) 8 бит — это целое, и 8 бит — дробь.
Формула перевода из реального числа в число с фиксированной точкой выглядит так:
Где:
- — полученное целочисленное значение, которое мы будем хранить в памяти GBA.
- — исходное дробное число (например, 1.5).
- — количество бит, отведенных под дробную часть (точность).
- — масштабный коэффициент (сдвиг влево).
Пример: Если мы используем 8 бит для дробной части (), то . Чтобы представить число , мы умножаем его на 256:
Процессор видит число 384, но мы знаем, что это 1.5. Сложение и вычитание таких чисел работает как обычно, а вот для умножения и деления потребуются дополнительные сдвиги битов, чтобы вернуть запятую на место.
Настройка окружения: DevkitPro
Чтобы писать код на C или C++ и превращать его в файл .gba, нам нужен кросс-компилятор. Стандартом индустрии хомбрю (homebrew — любительская разработка) является DevkitPro.
DevkitPro — это набор инструментов, включающий в себя специальную версию GCC (компилятора) для архитектуры ARM и необходимые библиотеки, главной из которых является libtonc.
Шаг 1: Установка
Процесс установки зависит от вашей ОС, но он максимально автоматизирован.
- Перейдите на официальный сайт DevkitPro.
- Скачайте установщик (графический для Windows или скрипт pacman для Mac/Linux).
- При выборе компонентов убедитесь, что отмечена группа GBA (Game Boy Advance).
Шаг 2: Выбор редактора кода
Я настоятельно рекомендую использовать Visual Studio Code. Это легкий и мощный редактор. Для удобства установите расширения:
- C/C++ (от Microsoft) — для подсветки синтаксиса и навигации.
- Makefile Tools — так как сборка проектов GBA обычно идет через Makefile.
Шаг 3: Эмулятор
Вам не обязательно каждый раз записывать игру на реальный картридж. Для разработки мы используем эмуляторы. Лучшим выбором для разработчика сейчас является mGBA. Он точен, быстр и имеет встроенные инструменты отладки (просмотр памяти, палитр, тайлов).
Ваш первый проект: Hello World
В мире GBA «Hello World» — это не вывод текста в консоль (консоли-то нет!), а закрашивание экрана в какой-либо цвет. Это доказывает, что вы получили контроль над видеопамятью.
Создайте папку проекта и файл main.c. Вот минимальный код:
// Определяем адрес видеопамяти
#define MEM_VRAM 0x06000000
// Определяем регистр управления дисплеем
#define REG_DISPCNT *(volatile unsigned int*)0x04000000
// Режим видео 3 (попиксельный) и включение фона 2
#define DCNT_MODE3 0x0003
#define DCNT_BG2 0x0400
// Определяем тип для пикселя (16 бит)
typedef unsigned short u16;
int main() {
// Настраиваем дисплей: Режим 3 + Включаем слой BG2
REG_DISPCNT = DCNT_MODE3 | DCNT_BG2;
// Получаем указатель на видеопамять
// volatile нужен, чтобы компилятор не оптимизировал запись
volatile u16* vram = (volatile u16*)MEM_VRAM;
// Рисуем точку в центре экрана
// Координаты: x=120, y=80. Ширина экрана 240.
// Формула индекса: y * ширина + x
vram[80 * 240 + 120] = 0x001F; // Красный цвет (5 бит на канал)
// Бесконечный цикл, чтобы программа не завершилась
while(1);
return 0;
}
Разбор магии
- Указатели: Мы обращаемся к памяти напрямую через адреса.
0x06000000— это начало VRAM. Записывая туда число, мы меняем цвет пикселя на экране. - Регистры ввода-вывода:
REG_DISPCNTпо адресу0x04000000— это «пульт управления» видеочипом. Записывая туда битовые флаги, мы говорим GBA: «Включи видеорежим 3». - Volatile: Ключевое слово, говорящее компилятору: «Не хитри, эта память может измениться или важна для железа, пиши туда всегда, даже если тебе кажется это лишним».
Для компиляции этого кода вам понадобится Makefile, который идет в комплекте с примерами DevkitPro. После команды make вы получите файл .gba, который можно открыть в mGBA и увидеть красную точку на черном фоне.
Заключение
Мы познакомились с архитектурой GBA, узнали про разделение памяти, важность целочисленной арифметики и написали первую программу, работающую с железом напрямую. Это ощущение полного контроля над устройством — то, ради чего стоит изучать низкоуровневую разработку игр.
В следующей статье мы углубимся в видеосистему GBA: разберем, чем тайловые режимы отличаются от растровых, и научимся выводить на экран полноценные изображения.