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

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

Nintendo Entertainment System. В России таких почти ни у кого не было, поэтому все помнят ее по клонам типа Dendy
Nintendo 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 — мультицикличный процессор и разные инструкции могут выполняться разное время. Поэтому, чтобы выверить точное время выполнения, нужно знать, за сколько циклов выполняется инструкция.

WWW

Полный список инструкций и режимов адресации можно найти в «Викиучебнике» и описании инструкций.

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

Вариант 1. Присоединись к сообществу «Xakep.ru», чтобы читать все материалы на сайте

Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее

Вариант 2. Открой один материал

Заинтересовала статья, но нет возможности стать членом клуба «Xakep.ru»? Тогда этот вариант для тебя! Обрати внимание: этот способ подходит только для статей, опубликованных более двух месяцев назад.


  • Подпишись на наc в Telegram!

    Только важные новости и лучшие статьи

    Подписаться

  • Подписаться
    Уведомить о
    7 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии