0.0 - Зміст
0.1 - Як користуватися цим документом
Створюючи цей документ я доклав всіх зусиль для полегшення читання та пошуку.
Зазвичай, поряд з шістнадцятковими значеннями пишуться рівнозначні десяткові значення в дужках. Наприклад, "0x200 (512)."
Зазвичай, якщо слово або літера похилі, це вказує на змінне значення, наприклад, якщо я пишу "Vx," де x вказує на 4-бітове значення.
1.0 - Про Chip-8
Коли я згадую, що пишу Chip-8 інтерпретатор, відповідь завжди однакова: "Що таке Chip-8?"
Chip-8 це проста, інтерпретована мова програмування, яка була вперше застосована на саморобних комп'ютерних системах кінця 1970'х і початку 1980'х. Кілька прикладів - COSMAC VIP, DREAM 6800, та ETI 660. Ці комп'ютери були спроєктовані для використання телевізора в якості дисплея, мали між 1 і 4K ОЗП, та 16-клавішну шістнадцяткову клавіатуру для вводу. Інтерпретатор займав лише 512 байтів пам'яті, а програми, які вводилися в комп'ютер в шістнадцятковому вигляді, були ще менші.
На початку 1990'х, мова Chip-8 була відроджена чоловіком на ім'я Андреас Ґюстаффсон. Він створив Chip-8 інтерпретатора для графічного калькулятора HP48, який називається Chip-48. The HP48 was lacking a way to easily make fast games at the time, and Chip-8 was the answer. Пізніше Chip-48 започаткував Super Chip-48, модифікацію Chip-48 яка надає графіку з вищою роздільною здатністю та інші графічні покращення.
Chip-48 надихнув цілий ряд Chip-8 інтерпреаторів для багатьох платформ, включно з MS-DOS, Windows 3.1, Amiga, HP48, MSX, Adam і ColecoVision. Я захопився Chip-8 після того як надибав, інтерпретатора від Поля Робсона у всесвітньому павутинні. Одразу після цього я почав писати власного Chip-8 інтерпретатора.
Цей документ є солянкою з різних джерел інформації, яких я уживав доки програмував свого інтерпретатора.
2.0 - Опис Chip-8
Цей розділ описує пам'ять, регістри, екран, клавіатуру і таймери архітектури Chip-8.
2.1 - Пам'ять
Мова Chip-8 здатна адресувати до 4кб (4,096 байтів) RAM, від адреси 0x000 (0) до 0xFFF (4095). Перші 512 байтів, від 0x000 до 0x1FF, де знаходився оригінальний інтерпретатор, не використовуються в програмах.
Більшість Chip-8 програм починаються з місця 0x200 (512), але деякі з 0x600 (1536). Програми, які починаються з 0x600, призначалися для комп'ютера ETI 660.
Мапа пам'яті:
2.2 - Регістри
Chip-8 містить 16'ть 8-бітних регістрів загального призначення, які позначаються як Vx, деx - шістнадцяткове число (від 0 до F). Також є 16-бітний регістр I. Цей регістр, головним чином, використовують для зберігання адреси пам'яті, тому лише його молодші (праві) 12 біт, зазвичай, значимі.
The VF регістр не може бути задіяний програмно, оскільки він містить прапорці для деяких інструкцій. Аби дізнатися більше - див. розділ 3.0, Інструкції.
Chip-8 також має два 8-бітних регістри особливого призначення, для таймерів затримки та звуку. Коли ці регістри містять ненульове значення, вони самостійно зменшуються з частотою 60 Гц. Аби дізнатися більше - див. розділ 2.5, Таймери та Звук.
Існують також "псевдо-регістри", до яких не можливо одержати доступ з Chip-8 програм. Програмний лічильник (англ. Program Counter, скор. PC) має бути 16-бітним та містити поточну адресу виконання. Стековий вказівник (англ. stack pointer, скор. SP) може бути 8-бітним, він вказує на найвищий стековий рівень.
Стек це масив з 16'ти 16-бітних значень, які містять адреси, куди інтерпретатор має повернутися після завершення процедури. Chip-8 дозволяє до 16 рівнів вкладеності процедур.
2.3 - Клавіатура
Комп'ютери, які початково використовувли мову Chip-8 мали 16-клавішну шістнадцяткову клавіатуру з наступною розкладкою:
Ця розкладка має бути відображена на різних конфігураціях, аби підтримувати клавіатури сучасних платформ.
2.4 - Екран
Орігінальна імплементація мови Chip-8 послуговувалася монохромним екраном з роздільною здатністю 64x32 наступного вигляду:
Деякі інші інтерпретатори, найбільш значимий з яких це ETI 660, мали також 64x48 і 64x64 режими. Наскільки мені відомо, сучасні інтерпретатори не підтримують ті режими. Більш новий Super Chip-48 інтерпретатор для програмованого калькулятора HP48, додавав ще 128x64-піксельний режим. Нині цей режим підтримується більшістю інтерпретаторів на інших платформах.
Chip-8 малює графіку на екрані за допомогою спрайтів. Спрайт це сукупність байтів, які є двійковим представленням потрібного малюнку. Спрайти Chip-8 можуть займати до 15 байтів, що відповідатиме розміру спрайта 8x15.
Програми можуть посилатися на cукупності спрайтів, які представляють шістнадцяткові цифри від 0x0 до 0xF. Ці спрайти довжиною 5 байтів, себто розміром 8x5 пікселів. Дані можуть бути збережені в пам'яті простору інтерпретатора Chip-8 (від 0x000 до 0x1FF). Нижче наведений побайтовий лістинг кажної літери, в двійковій та шістнадцятковій системах числення:
2.5 - Таймери та звук
Chip-8 має 2 таймери - затримковий таймер і звуковий таймер.
Затримковий таймер діє коли регістр затримкового таймеру (з англ. __delay timer register__, англ. скор. __DT__) не дорівнює нулеві. Цей таймер нічого не робить, окрім вичитання одиниці від значення DT з частотою 60Гц. Коли DT досягає нуля, він вимикається.
Звуковий таймер діє коли регістр звукового таймеру (з англ. sound timer, англ. скор. ST) не дорівнює нулеві. Цей таймер також зменшується з частотою 60Гц, проте, доки значення ST більше нуля, воно гуде. Коли ST досягає нуля, гудіння припиняється.
Інтерпретатор Chip-8 може гудіти лише одним тоном. Частоту цього тону визначає автор інтерпретатора.
3.0 - Набір команд Chip-8
Початкова імплементація мови Chip-8 мала 36 різних команд, які включали команди роботи з математикою, графікою та керування потоком виконання.
Розширенний набір Super Chip-48 додав ще 10 команд, до 46.
Всі команди мають довжину 2 байти та зберігають більш значимий байт першим. В пам'яті, перший байт кажної команди має бути розміщений за парною адресою. Якщо програма містить дані спрайтів, то вони мають бути вирівняні так, аби наступні команди правильно розташовувалися в пам'яті.
Цей документ не містить опису розширення системи команд Super Chip-48. Проте, вони наведені нижче.
В подальших описах команд уживаються наступні змінні:
nnn або addr - 12-бітне значення адреси, яке є молодшими 12-бітами команди
n або nibble - 4-бітне значення ніблу, яке є молодшими 4-бітами команди
x - 4-бітне значення, молодші 4 біти старшого байту команди
y - 4-бітне значення, старші 4 біти молодшого байту команди
kk або byte - 8-бітне значення сталої, молодші 8 бітів команди
3.1 - Звичайний набір команд Chip-8
0nnn - SYS addr
Перехід до машинної процедури за адресою nnn.
Уживається лише на старих комп'ютерах, для яких початково був призначений Chip-8. Нехтується сучасними інтерпретаторами.
00E0 - CLS
Очишення екрану.
00EE - RET
Повернення з процедури.
Присвоєння програмному лічильнику адреси з вершини стеку і подальще зменшення стекового вказівника на одиницю.
1nnn - JP addr
Перехід за адресою nnn.
Присвоєння програмному лічильнику значення nnn.
2nnn - CALL addr
Виклик процедури за адресою nnn.
Збільшення стекового лічильника, покладання поточного значення програмного лічильника на стекову вершину і подальще присвоєння програмному лічильнику значення nnn.
3xkk - SE Vx, byte
Пропуск наступної інструкції, якщо Vx == kk.
Порівняння значення регістру Vx зі сталою kk, і, в разі збігу, додавання двійки до програмного лічильника.
4xkk - SNE Vx, byte
Пропуск наступної інструкції, якщо Vx != kk.
Порівняння значення регістру Vx зі сталою kk, і, в разі розбіжності, додавання двійки до програмного лічильника.
5xy0 - SE Vx, Vy
Пропуск наступної інструкції, якщо Vx == Vy.
Порівняння значення регістру Vx зі значенням регістру Vy, і, в разі збігу, додавання двійки до програмного лічильника.
6xkk - LD Vx, byte
Присвоєння Vx= kk.
Присвоєння регістру Vx значення сталої kk.
7xkk - ADD Vx, byte
Присвоєння Vx = Vx + kk.
Додавання значення сталої kk до значення регістра Vx і подальше збереження результату в регістрі Vx.
8xy0 - LD Vx, Vy
Присвоєння Vx = Vy.
Присвоєння регістру Vx значення регістра Vxy.
8xy1 - OR Vx, Vy
Присвоєння Vx = Vx OR Vy.
Присвоєння регістру Vx значення результату побітового OR(АБО) між значеннями регістрів Vx і Vy. Побітове OR порівнює відповідні біти двох значень, і, якщо принаймні один з них дорівнює 1, то біт результату також дорівнюватиме 1, інакше 0.
8xy2 - AND Vx, Vy
Присвоєння Vx = Vx AND Vy.
Присвоєння регістру Vx значення результату побітового AND(І) між значеннями регістрів Vx і Vy. Побітове AND порівнює відповідні біти двох значень, і, якщо обидві біти дорівнюють 1, то біт результату також дорівнюватиме 1, інакше - 0.
8xy3 - XOR Vx, Vy
Присвоєння Vx = Vx XOR Vy.
Присвоєння регістру Vx значення результату побітового XOR (виключне АБО) між значеннями регістрів V_x_ і V_y_. XOR порівнює відповідні біти двох значень, і якщо обидві біти не збігаються, то біт результату дорівнюватиме 1, інакше - 0.
8xy4 - ADD Vx, Vy
Присвоєння Vx = Vx + Vy, присвоєння VF = переніс.
Присвоєння регістру Vx значення молодших 8 бітів результату додавання значень регістів Vxі Vy, а прапорцю VF старшого біту, себто якщо результат більший за 8 бітів ( > 255) відбувається встановлення прапорця VF, інакше - скидання.
8xy5 - SUB Vx, Vy
Присвоєння Vx = Vx - Vy, встановлення VF = NOT позика.
Віднімання значення регістрів Vy від Vx і збереження результату в регістрі Vx. Встановлення прапорця VF, якщо Vx > Vy, інакше - скидання.
8xy6 - SHR Vx {, Vy}
Присвоєння Vx = Vx SHR 1.
Встановлення прапорця VF, якщо найменш значимий біт регістра Vx дорівнює 1, інакше - скидання. з подальщим діленням Vx на 2.
8xy7 - SUBN Vx, Vy
Присвоєння Vx = Vy - Vx, присвоєння VF = NOT позика.
Встановлення прапорця VF, якщо Vy > Vx, інакше - скидання. Тоді віднімання Vx від Vy, з подальщим збереженням результату в регістр Vx.
8xyE - SHL Vx {, Vy}
Присвоєння Vx = Vx SHL 1.
Встановлення прапорця VF, якщо найстарший біт регістра Vx дорівнює 1, інакше - скидання з подальщим множенням Vx на 2.
9xy0 - SNE Vx, Vy
Пропуск наступної інструкції, якщо Vx != Vy
Порівняння значення регістру Vx зі значенням регістру Vy, і, в разі розбіжності, додавання до програмного лічильника 2.
Annn - LD I, addr
Присвоєння I = nnn.
Присвоєння регістру I значення nnn.
B_nnn_ - JP V0, addr
Перехід за адресою резутьтата додавання nnn + V0.
Присвоєння програмному лічильнику резутьтата додавання сталої *nnn* і регістра V0.
Cxkk - RND Vx, byte
Присвоєння Vx = випадковий байт AND kk.
Присвоєння регістру Vx значення результату побітового І між сталою kk та згенерованим випадковим числом в межах від 0 до 255. Див. команду 8xy2 для докладнішої інформації про команду AND.
Dxyn - DRW Vx, Vy, nibble
Промальовка n-байтового спрайту за екранними координатами (Vx, Vy), який починається за адресою пам'яті I, присвоєння VF = перетин.
Зчитування n байтів з пам'яті, починаючи з адреси збереженої в I з подальщим відображенням на екрані в якості екранних спрайтів з координатами (Vx, Vy). Спрайти XOR'яться з наявним станом екрану. Якщо хоча б один піксель при цьому гаситься, то VF <> 00, інакше - 00. Якщо спрайт розташовується за межами дисплейних координат, то він вилазе з протилежного боку екрану. Див. команду 8xy3 аби дізнатися більше про XOR, і розділ 2.4, Екран, аби дізнатися більше про екран Chip-8 та спрайти.
Ex9E - SKP Vx
Пропуск наступної інструкції, якщо код натиснутої клавши збігається зі значенням регістру Vx.
Перевірка клавіатури на збіг коду натиснутої клавіші зі значенням регістру Vx, і, в разі збігу, збільшення програмного лічильника на 2.
ExA1 - SKNP Vx
Пропуск наступної інструкції, якщо код натиснутої клавши не збігається зі значенням регістру Vx.
Перевірка клавіатури на збіг коду відтиснутої клавіші зі значенням регістру Vx, і, в разі збігу, збільшення програмного лічильника на 2.
Fx07 - LD Vx, DT
Присвоєння Vx = DT.
Присвоєння регістру Vx поточного значення затримкового таймеру.
Fx0A - LD Vx, K
Очікування натиснення клавіши і подальше збереження коду натисненої клавіші в регістрі Vx.
Припинення виконання до натиснення клавші і подальше збереження коду натисненої клавіші в регістрі Vx.
Fx15 - LD DT, Vx
Присвоєння DT = Vx.
Присвоєння затримковому таймеру значення регістра Vx.
Fx18 - LD ST, Vx
Присвоєння ST = Vx.
Присвоєння звуковому таймеру значення регістра Vx.
Fx1E - ADD I, Vx
Присвоєння I = I + Vx.
Додавання значень регістрів I та Vx і збереження результату в регістрі I.
Fx29 - LD F, Vx
Присвоєння I = розташування спрайту для числового значення в регістрі Vx.
Присвоєння регістру I розташування шістнадцяткового спрайта, який відповідає значенню регістра Vx. Див. розділ 2.4, Екран, аби дізнатися більше про шістнадцятковий шрифт Chip-8.
Fx33 - LD B, Vx
Збереження значення регістра Vx
Значення регістра Vx і розбивається на розряди, які збеігаються окремо, сотні за адресою I, десятки за адресою I+1 та одиниці за адресою I+2.
Fx55 - LD (I), Vx
Збереження значеннь регістрів від V0 до Vx у пам'яті, починаючи з адреси в I.
Копіювання значень регістрів від V0 до Vx у пам'ять, починаючи з адреси в I.
Fx65 - LD Vx, (I)
Зчитування значеннь регістрів від V0 до Vx з пам'яті, починаючи з адреси в I.
Зчитування значень з пам'яті, починаючи з адреси в I у регістри від V0 до Vx.
3.2 - Розширений набір інструкцій Super Chip-48
00Cn- SCD нібл
00FB - SCR
00FC - SCL
00FD - EXIT
00FE - LOW
00FF - HIGH
Dxy0 - DRW Vx, Vy, 0
Fx30 - LD HF, Vx
Fx75 - LD R, Vx
Fx85 - LD Vx, R
4.0 - Інтерпретатори
Нижче наведений перелік всіх інтерпретаторів мови Chip-8, які я зміг знайти у всесвітньому павутинні:
5.0 - Подяка
Цей документ писаний Томасом П. Ґріном.
Джерела:
Мої дослідження.
Особисте листування з Девідом Вінтером.
Документація долучена до Chip-8 емулятора Девіда Вінтера.
Документаця долучена до Chipper емулятора Кристияна Еґеберґа.
Джерельний код Vision-8 Марселя де Коґеля.
Документація долучена до DREAM MON емулятора від Поля Гайтера.
Веб-сторінка Поля Робсона.
Документаця долучена до емулятора Chip-48 Андреаса Ґюстафсона.