Запуск DOOM на процессоре собственной разработки

Запуск DOOM на процессоре собственной разработки

Прокомментировать Просмотры: 8

Культовый шутер Doom, представленный студией id Software в 1993 году, навсегда изменил облик игровой индустрии. Сегодня игра стала мерилом технического прогресса: фраза «запустить Doom на чём угодно» давно стала девизом энтузиастов, которые переносят классику на самые неожиданные устройства — от бытовой техники до колоний бактерий.

Две недели назад мы совершили невозможное: запустили Doom на собственном процессоре, спроектированном «с нуля». Видео с этим достижением мгновенно стало виральным, собрав миллионы просмотров. Мы проделали огромный путь: от разработки архитектуры CPU на уровне логических вентилей и создания периферийных контроллеров до портирования исходного кода игры и реализации всего этого комплекса на базе FPGA в режиме реального времени. Ранее наша система справлялась лишь с примитивными задачами вроде Pong или фракталов Мандельброта, но теперь она способна запускать полноценные коммерческие игры, хотя реализация этого проекта оказалась крайне тернистой.

Амбициозные цели

Начав с конвейерной архитектуры, мы стремились к покорению новых высот. Однако, оставив позади 50-летние игры, мы столкнулись с жесткими ограничениями: нехваткой памяти и низкой производительностью. Вся доступная BRAM-память нашей FPGA составляла менее мегабайта, в то время как лишь один файл данных shareware-версии Doom (doom1.wad) весит 14 МБ. Кроме того, на нашей базовой архитектуре игра едва функционировала, превращаясь в бесконечное слайд-шоу.

Решение требовало разделения усилий. Лиам занялся внедрением механизмов исполнения с изменением последовательности (out-of-order execution) для повышения параллелизма, а я взял на себя задачу интеграции внешней памяти DDR3 — задачу обманчиво простую на бумаге, но сложную в реализации.

Работа с памятью

Изначально наш процессор полагался на внутреннюю BRAM с предсказуемой задержкой в один такт. Это позволяло избежать простоев конвейера. Внешняя DDR3-память работает по иным правилам: она медленнее, обладает переменной латентностью и широкой шиной данных. Чтобы не допустить падения производительности CPU до катастрофических значений, нам потребовалось внедрить систему кэширования. Грамотно реализованный кэш позволяет удерживать наиболее востребованные данные в быстрой BRAM, минимизируя обращения к «тяжелой» DDR3.

Архитектурные решения

Наш процессор построен по классической пятиступенчатой схеме: выборка (Fetch), декодирование (Decode), считывание регистров (Read), исполнение (Execute) и запись (Writeback). Каждая стадия абстрагирована через единый интерфейс.

Основные узлы конвейера

Стадия Fetch теперь опирается на кэш команд (ICache) и самостоятельно управляет задержками при перенаправлении потока выполнения. В условиях работы с DDR3 это стало сложнее, так как запросы к памяти могут быть отправлены до момента осознания необходимости перехода, что потребовало от нас механизмов отмены неактуальных операций.

Этап Decode выполняет трансформацию 32-битных инструкций в управляющие пакеты, понятные исполнительным блокам.

Блок Read претерпел серьезные изменения: чтение теперь также конвейеризировано. Для предотвращения конфликтов данных (RAW — Read-After-Write) мы внедрили Register Usage Map (RUM). Эта 32-битная карта состояния регистров позволяет процессору динамически решать, когда следует приостановить выполнение, что значительно надежнее прежних попыток предсказания состояний.

Стадия Execute управляет логикой вычислений, передавая команды в АЛУ или модули доступа к памяти. В случае ветвления конвейер очищается, а при работе с памятью процессор уходит в режим ожидания ответа от кэша.

Подсистема памяти

Поскольку процессор требует данные в каждом такте, а DDR3 выдает их порциями с высокой задержкой, мы разделили кэши на командный (ICache) и данных (DCache). Каждый из них имеет архитектуру прямого отображения с 2048 линиями. Метка (tag) гарантирует корректность данных, а сигналы валидности и модификации (dirty bit) обеспечивают целостность при записи.

Управление конфликтами

Для разрешения одновременных обращений двух кэшей к единственному контроллеру DDR3 был создан блок арбитража. Он выстраивает запросы в очередь и отдает приоритет DCache, что предотвращает взаимные блокировки системы.

Интеграция с реальным «железом»

Переход от симуляции к реальному FPGA потребовал использования IP-блока Xilinx MIG для работы с DDR3. Из-за проблем с таймингами и ограничениями текущей платы мы перешли на конфигурацию с 64-битной шиной. Стабильность работы между различными тактовыми доменами обеспечили FIFO-буферы и методы CDC (Clock Domain Crossing).

Периферия и ввод-вывод

Для взаимодействия с внешним миром мы реализовали MMIO. Контроллер VGA был расширен до поддержки 12-битной палитры и вывода через HDMI. UART-порт с FIFO-буфером взял на себя роль отладочного канала, а вместо USB-хоста, с которым возникли аппаратные сложности, мы организовали передачу нажатий клавиатуры через серийный интерфейс с ноутбука.

Портирование Doom

Адаптация игры проходила с помощью проекта doomgeneric. Процесс сопровождался борьбой с багами: от проблем с printf до нестабильности при обработке прерываний. Выяснилось, что ряд ошибок был вызван неверными предположениями игры об обнулении оперативной памяти при старте — пришлось внедрить принудительную инициализацию DDR3 в коде загрузчика.

Впервые что-то отрендерилось
Первые успешные кадры рендеринга

Стартовая производительность составила всего 0,7 FPS, что заставило нас перейти к этапу глубокой оптимизации.

Путь к играбельной частоте кадров

Повышение тактовой частоты до 125 МГц дало незначительный прирост. Основные успехи пришли с оптимизацией конвейера (устранение дублирующих запросов ICache) и переходом на архитектуру RV32I-ZMMUL. Прямая запись данных в BRAM контроллера VGA и сокращение латентности кэша до одного такта подняли FPS до 6,7.

Финальным рывком стала компиляторная оптимизация (флаг O2). После устранения бага с пропущенным квалификатором volatile для MMIO-регистров таймера, игра наконец «взлетела», показав стабильные 15-20 FPS.

Заключение

Этот проект стал для нас настоящей школой инженерного мастерства. Мы прошли путь от примитивной логики до сложной системы с кэшированием, арбитражем памяти и оптимизацией ПО. Вирусный успех нашего видео лишь подтверждает: сообщество ценит смелые эксперименты. В планах — дальнейшее развитие архитектуры, внедрение полноценного out-of-order исполнения и, возможно, будущий портинг Quake 2 на более мощной аппаратной базе.


 

Источник

Поделиться:

Похожие статьи

Поиск по играм, новостям и статьям…

Введите не менее двух символов

Введите не менее двух символов