Пишем эмулятор игровой консоли. Как устроена легендарная приставка Nintendo и как ее воссоздать самому

Содержание статьи

Ты наверняка сталкивался с эмуляторами игровых приставок и, возможно, даже просиживал за ними не один час. Но задавался ли ты вопросом, как это работает? На примере NES, известной в России как Dendy, я покажу, как создать собственный эмулятор. А заодно разберемся с хитрой архитектурой этой приставки, выдававшей потрясающе хорошую картинку для своего времени и своей скромной цены.

Все игровые консоли разными средствами адаптированы для запуска игр, что их и отличает от обычных компьютеров. Особенно это касается старых приставок вроде NES: в восьмидесятые годы с аппаратными ресурсами было туго, особенно если нужно было сделать недорогой домашний агрегат. Экономить приходилось буквально на всем, чем и объясняются некоторые инженерные решения.

Nintendo Entertainment System. В России таких почти ни у кого не было, поэтому все помнят ее по клонам типа DendyNintendo Entertainment System. В России таких почти ни у кого не было, поэтому все помнят ее по клонам типа Dendy

Виды эмуляции

  • Интерпретация. Интерпретатор позволяет программно эмулировать все части консоли. Этот способ самый простой и вместе с тем наименее производительный.

  • Динамическая рекомпиляция. Рекомпилятор сложен в написании, но при этом значительно превосходит интерпретатор в производительности. Такой эмулятор может рекомпилировать инструкции эмулируемой машины в машинные инструкции твоего компьютера. Проще говоря, рекомпилятор выступает в роли переводчика с одного машинного языка на другой.

WWW

Существуют эмуляторы для всех старых и даже некоторых новых приставок. Вот несколько примеров: Dolphin — эмулятор Wii и GameCube, ePSXe — PS1, PCSX2 — PS2, PPSSPP — PSP.

Среди пока что незаконченных, но быстро развивающихся эмуляторов: Cemu — эмулятор Wii U, RPCS3 — PS3, Yuzu — Switch, Xenia — эмулятор Xbox 360.

MOS 6502: регистры, режимы адресации и инструкции

NES неспроста снискала мировую популярность. Разработчики оборудования пытались создать наиболее производительные решения, применяя разного рода уловки. Разработчики игр досконально изучали особенности платформы и находили новые трюки, чтобы создать красивую картинку. Порой даже очень красивую картинку для своего времени.

Как и в случае с компьютером, основная логика программ выполняется на центральном процессоре приставки. Поэтому лучше всего начинать написание эмулятора именно с него. В NES установлен восьмибитный процессор MOS 6502 с комплексным набором инструкций (то есть как у Intel, а не как у ARM или PowerPC).

У процессора MOS 6502 шесть регистров, один из которых недоступен пользователю:

  • A — регистр, куда складываются результаты всех арифметических операций;
  • X, Y — индексные регистры;
  • SP — указатель на вершину стека;
  • P — регистр флагов, в x86 EFLAGS выполняет ту же функцию;
  • PC — счетчик команд, регистр, который указывает, какую команду выполнять следующей. Этот регистр недоступен напрямую.

Режимов адресации великое множество, и узнать о них будет полезно и за рамками этой статьи.

Название Определение Пример
Аккумуляторный Операндом инструкции является аккумулятор Арифметический сдвиг влево ASL
Предполагаемый Операнд явно указывается инструкцией Перенос значения A в X TAX
Немедленный Операнд дается в инструкции Загрузка значения в A LDA #$34
По абсолютному адресу Операндом является значение по абсолютному адресу Загрузка значения в X LDX $9010
По адресу в нулевой странице По абсолютному адресу первых 256 байт Загрузка значения в Y LDY $23
Относительный Адрес задается относительно PC Ветвление, если предыдущий операнд равен 0 BEQ $4A

INFO

Нулевая страница — первые 256 байт памяти, в которых размещаются наиболее часто используемые переменные ради более быстрого доступа к ним.

Всего у нашего процессора 256 инструкций, из которых 78 — это настоящие инструкции без учета разных режимов адресации. Сразу сократим работу: мы не будем писать обработчик для всех 256 инструкций. Напишем обработчики для всех режимов адресации и для 78 инструкций.

Начнем с кода для режима адресации нулевой страницы.

void
addr_mode_zp()
{ cpu_addr = ram_getb(reg.PC); reg.PC++;
}

В данном случае инструкция состоит из двух байт: один — это сама инструкция, второй — адрес операнда инструкции. Функция ram_getb возвращает значения байта в RAM по адресу.

А вот пример кода для инструкции STX.

void
op_stx()
{ ram_setb(cpu_addr, reg.X);
}

Функция ram_setb заменяет значение байта в RAM по адресу cpu_addr (операнд инструкции) на значение регистра X.

Таблица инструкцийТаблица инструкций

Также не стоит забывать, что MOS 6502 — мультицикличный процессор и разные инструкции могут выполняться разное время. Поэтому, чтобы выверить точное время выполнения, нужно знать, за сколько циклов выполняется инструкция.

Продолжение доступно только подписчикам

Материалы из последних выпусков можно покупать отдельно только через два месяца после публикации. Чтобы продолжить чтение, необходимо купить подписку.

Подпишись на «Хакер» по выгодной цене!

Подписка позволит тебе в течение указанного срока читать ВСЕ платные материалы сайта. Мы принимаем оплату банковскими картами, электронными деньгами и переводами со счетов мобильных операторов. Подробнее о подписке

Читать новость в источнике Xakep

0