Пишем эмулятор CHIP-8. Часть 2: Ассемблер

Mar 30, 2012   #dev  #emulation 

В предыдущей статье мы рассмотрели общее устройство CHIP-8. Сегодня перейдем к описанию ассемблерных команд и их опкодов.

В этой статье список инструкций условно разбит на три колонки:

опкод команда на ассемблере описание

И используются следующие обозначения:
nnn - 12 битный адрес
kk - 8 битная константа
x - 4 битный номер регистра
y - 4 битный номер регистра
1..9, A..F - шестнадцатеричные цифры

Инструкции CHIP-8

00E0 CLS Очистить экран

00EE RET Возвратиться из подпрограммы

0nnn SYS nnn Перейти на машинный код RCA 1802 по адресу nnn. Эта инструкция была только в самой первой реализации CHIP-8. В более поздних реализациях и эмуляторах не используется. 1nnn JP nnn Перейти по адресу nnn

2nnn CALL nnn Вызов подпрограммы по адресу nnn

3xkk SE Vx, kk Пропустить следующую инструкцию, если регистр Vx = kk

4xkk SNE Vx, kk Пропустить следующую инструкцию, если регистр Vx != kk

5xy0 SE Vx, Vy Пропустить следующую инструкцию, если Vx = Vy

6xkk LD Vx, kk Загрузить в регистр Vx число kk, т.е. Vx = kk

7xkk ADD Vx, kk Установить Vx = Vx + kk

8xy0 LD Vx, Vy Установить Vx = Vy

8xy1 OR Vx, Vy Выполнить операцию дизъюнкция (логическое “ИЛИ”) над значениями регистров Vx и Vy, результат сохранить в Vx. Т.е. Vx = Vx | Vy

8xy2 AND Vx, Vy Выполнить операцию конъюнкция (логическое “И”) над значениями регистров Vx и Vy, результат сохранить в Vx. Т.е. Vx = Vx & Vy

8xy3 XOR Vx, Vy Выполнить операцию “исключающее ИЛИ” над значениями регистров Vx и Vy, результат сохранить в Vx. Т.е. Vx = Vx ^ Vy

8xy4 ADD Vx, Vy Значения Vx и Vy суммируются. Если результат больше, чем 8 бит (т.е.> 255) VF устанавливается в 1, иначе 0. Только младшие 8 бит результата сохраняются в Vx. Т.е. Vx = Vx + Vy

8xy5 SUB Vx, Vy Если Vx >= Vy, то VF устанавливается в 1, иначе 0. Затем Vy вычитается из Vx, а результат сохраняется в Vx. Т.е. Vx = Vx - Vy

8xy6 SHR Vx {, Vy} Операция сдвига вправо на 1 бит. Сдвигается регистр Vx. Т.е. Vx = Vx >> 1. До операции сдвига выполняется следующее: если младший бит (самый правый) регистра Vx равен 1, то VF = 1, иначе VF = 0

8xy7 SUBN Vx, Vy Если Vy >= Vx, то VF устанавливается в 1, иначе 0. Тогда Vx вычитается из Vy, и результат сохраняется в Vx. Т.е. Vx = Vy - Vx

8xyE SHL Vx {, Vy} Операция сдвига влево на 1 бит. Сдвигается регистр Vx. Т.е. Vx = Vx << 1. До операции сдвига выполняется следующее: если младший бит (самый правый) регистра Vx равен 1, то VF = 1, иначе VF = 0

9xy0 SNE Vx, Vy Пропустить следующую инструкцию, если Vx != Vy

Annn LD I, nnn Значение регистра I устанавливается в nnn

Bnnn JP V0, nnn Перейти по адресу nnn + значение в регистре V0.

Cxkk RND Vx, kk Устанавливается Vx = (случайное число от 0 до 255) & kk

Dxyn DRW Vx, Vy, n Нарисовать на экране спрайт. Эта инструкция считывает n байт по адресу содержащемуся в регистре I и рисует их на экране в виде спрайта c координатой Vx, Vy. Спрайты рисуются на экран по методу операции XOR, то есть если в том месте где мы рисуем спрайт уже есть нарисованные пиксели - они стираются, если их нет - рисуются. Если хоть один пиксель был стерт, то VF устанавливается в 1, иначе в 0.

Ex9E SKP Vx Пропустить следующую команду если клавиша, номер которой хранится в регистре Vx, нажата

ExA1 SKNP Vx Пропустить следующую команду если клавиша, номер которой хранится в регистре Vx, не нажата

Fx07 LD Vx, DT Скопировать значение таймера задержки в регистр Vx

Fx0A LD Vx, K Ждать нажатия любой клавиши. Как только клавиша будет нажата записать ее номер в регистр Vx и перейти к выполнению следующей инструкции.

Fx15 LD DT, Vx Установить значение таймера задержки равным значению регистра Vx

Fx18 LD ST, Vx Установить значение звукового таймера равным значению регистра Vx

Fx1E ADD I, Vx Сложить значения регистров I и Vx, результат сохранить в I. Т.е. I = I + Vx

Fx29 LD F, Vx Используется для вывода на экран символов встроенного шрифта размером 4x5 пикселей. Команда загружает в регистр I адрес спрайта, значение которого находится в Vx. Например, нам надо вывести на экран цифру 5. Для этого загружаем в Vx число 5. Потом команда LD F, Vx загрузит адрес спрайта, содержащего цифру 5, в регистр I

Fx33 LD B, Vx Сохранить значение регистра Vx в двоично-десятичном (BCD) представлении по адресам I, I+1 и I+2

Fx55 LD [I], Vx Сохранить значения регистров от V0 до Vx в памяти, начиная с адреса находящегося в I

Fx65 LD Vx, [I] Загрузить значения регистров от V0 до Vx из памяти, начиная с адреса находящегося в I

Инструкции Super CHIP

Super CHIP может использовать все вышеназванные инструкции (за исключением 0nnn), а так же добавляет следующие:

00Cn SCD n Прокрутить изображение на экране на n строк вниз

00FB SCR Прокрутить изображение на экране на 4 пикселя вправо в режиме 128x64, либо на 2 пикселя в режиме 64x32

00FC SCL Прокрутить изображение на экране на 4 пикселя влево в режиме 128x64, либо на 2 пикселя в режиме 64x32

00FD EXIT Завершить программу

00FE LOW Выключить расширенный режим экрана. Переход на разрешение 64x32

00FF HIGH Включить расширенный режим экрана. Переход на разрешение 128x64

Dxy0 DRW Vx, Vy, 0 Работает подобно инструкции Dxyn, только в расширенном режиме экрана рисует спрайты размером 16x16 пикселей, в обычном режиме 8x16

Fx30 LD HF, Vx Работает подобно команде Fx29, только загружает спрайты размером 8x10 пикселей

Fx75 LD R, Vx Сохранить регистры V0 - Vx в пользовательских флагах [RPL](http://en.wikipedia.org/wiki/RPL_(programming_language))

Fx85 LD Vx, R Загрузить регистры V0 - Vx из пользовательских флагов RPL

На самом деле как в расширенном режиме, так и в обычном, физический размер экрана одинаков. Но при разрешении экрана 64x32 каждый пиксель рисуется в два раза больше, чем при 128x64. Поэтому операции скроллинга экрана (00FB, 00FC) в расширенном режиме сдвигают 4 пикселя, а в обычном 2. То же относится и к инструкции 00Cn.

Super CHIP добавляет в память еще один шрифт. Он тоже состоит из шестнадцатеричных символов от 0 до F, размер каждого 8x10 пикселей. Если программа находится в расширенном режиме, то она должна выводить этот крупный шрифт. В обычном режиме программа выводит обычный шрифт, размером 4x5.

Сегодняшняя статья получилась довольно громоздкой и, возможно, непонятной для тех кто не знаком с ассемблером. Но не волнуйтесь если вы во всём этом не разобрались, немного позже все станет понятнее. В дальнейшем мы будем использовать информацию с этой страницы как справочник. Что бы лучше понять эмулируемую платформу в следующей статье мы напишем несколько программ для CHIP-8 и затем начнем писать наш эмулятор.