← На главную

Энтузиасты запустили DOOM на собственном CPU с нуля — 15-20 FPS

21.07.2026 03:54 · hackernews

Два энтузиаста запустили DOOM на собственном процессоре, который они собрали с нуля — на уровне логических вентилей. Задача была сложнее, чем кажется. У их предыдущей версии CPU, работавшей только на FPGA-памяти BRAM (меньше мегабайта), не хватало ни объёма, ни скорости. Файл doom1.wad занимает 14 мегабайт, а без кэша DDR3 превратила бы процессор в черепаху.

Они спроектировали стандартный 5-ступенчатый конвейер (Fetch, Decode, Read, Execute, Writeback), но полностью переписали работу с памятью. DDR3 медленная — отдаёт 2 слова за 30–60 тактов, против 1 такта у BRAM. Спасли два независимых кэша: ICache для инструкций и DCache для данных. Каждый — 2048 строк по 4 слова, прямая адресация. Чтобы оба кэша не дрались за единственный чип памяти, добавили арбитр, который всегда пропускает вперёд DCache — он дальше по конвейеру и может заблокировать всю систему.

С железом тоже намучились. Интерфейс DDR3 требует жёстких таймингов — использовали Xilinx MIG, но он работает в своей тактовой зоне. Пришлось городить синхронизаторы, FIFO и CDC-переходники, а изначальную плату с 128-битной шиной пришлось заменить на чужую (одолжили у друга) с 64-битной. Периферию подключили через MMIO: VGA-контроллер (12 бит цвета через HDMI), аппаратный таймер, UART для отладки. Клавиатуру завести через USB не вышло — порт на плате не давал питание. Пришлось эмулировать ввод с ноутбука через UART-приёмник.

Портирование DOOM через библиотеку doomgeneric упростило задачу, но отладка превратилась в ад. Программа падала либо из-за ошибок в коде, либо из-за глюков самого CPU. Часть багов сидела ещё в первом однотактном процессоре — их просто раньше не замечали. Главная проблема вскрылась, когда симуляцию заставили инициализировать DDR3 случайными значениями: DOOM полагал, что вся память обнулена, а на реальном чипе там мусор. После правок линковки игра запустилась в «железе»... с частотой 0.7 FPS.

Чтобы сделать DOOM играбельным, ускорили тактовую частоту со 100 до 125 МГц, переписали неэффективный Fetch (раньше он делал два запроса к ICache подряд) и добавили инструкции умножения (получился RV32I-ZMMUL). Итоговый рывок — 6.7 FPS. Последним рычагом стала компиляция с O2. Она валила программу, пока не выяснилось, что указатель на таймер был не помечен как volatile — оптимизатор выкидывал его как мёртвый код. После исправления DOOM полетел на 15–20 FPS. В планах — внеочередное выполнение инструкций, собственный GPU, а затем и порт Quake 2. И, конечно, 30 FPS на DOOM.

Читать оригинал →