CHIP-8 — интерпретируемый язык программирования , разработанный Джозефом Вайсбекером на его микропроцессоре 1802. Первоначально он использовался на COSMAC VIP и Telmac 1800 , которые были 8-битными микрокомпьютерами, выпущенными в середине 1970-х годов.
CHIP-8 был разработан таким образом, чтобы его было легко программировать, а также чтобы он использовал меньше памяти, чем другие языки программирования, такие как BASIC . [1]
Интерпретаторы были созданы для многих устройств, таких как домашние компьютеры , микрокомпьютеры , графические калькуляторы , мобильные телефоны и игровые консоли . [2] [3]
CHIP-8 использовался на широком спектре устройств с течением времени; первое сообщество, использовавшее CHIP-8, появилось в 1970-х годах на микрокомпьютерах . Они делились расширениями и программами в информационных бюллетенях, таких как VIPER от ARESCO для пользователей COSMAC VIP или DREAMER для пользователей DREAM 6800 [4] . В информационном бюллетене VIPER в первых трех выпусках был подробно описан машинный код интерпретатора CHIP-8 для VIP. [5]
В 1990-х годах начали создаваться интерпретаторы CHIP-8 для графических калькуляторов . Известными примерами являются CHIP-48 и SCHIP для HP-48 . [6]
Приложения CHIP-8 включают в себя оригинальные игры, демоверсии , а также воссоздания популярных игр из других систем. [7] При этом некоторые приложения CHIP-8 находятся в общественном достоянии , используя лицензии, такие как лицензия Creative Commons Zero . [8] [9]
В 1970-х и 1980-х годах пользователи CHIP-8 делились программами CHIP-8, а также изменениями и расширениями интерпретатора CHIP-8, как в журнале VIPER для COSMAC VIP. Эти расширения включали CHIP-10 и Hi-Res CHIP-8, которые представили более высокое разрешение, чем стандартное 64x32, а также CHIP-8C и CHIP-8X, которые расширили возможности монохромного дисплея для поддержки ограниченного цвета, среди прочих функций. [10] Эти расширения были в основном обратно совместимы, так как они были основаны на оригинальном интерпретаторе, хотя некоторые перепрофилировали редко используемые коды операций для новых инструкций. [11]
В 1979 году Electronics Australia опубликовала серию статей о создании компьютера-комплекта, похожего на COSMAC VIP, на основе архитектуры Motorola 6800. [12] Этот компьютер, DREAM 6800, поставлялся со своей собственной версией CHIP-8. Информационный бюллетень, похожий на VIPER, под названием DREAMER [13] , использовался для обмена играми CHIP-8 для этого интерпретатора. В 1981 году Electronics Today International (ETI) опубликовала серию статей о создании компьютера ETI-660, который также был очень похож на VIP (и использовал тот же микропроцессор). ETI вела регулярные колонки ETI-660 и общие колонки CHIP-8 [14] до 1985 года.
В 1990 году Андреас Густафссон [15] создал интерпретатор CHIP-8 под названием CHIP-48 для графических калькуляторов HP-48 . Эрик Брынце позже создал другой интерпретатор на основе CHIP-48, [16] названный "SUPER-CHIP", часто сокращаемый до SCHIP или S-CHIP. SCHIP расширил язык CHIP-8 большим разрешением и несколькими дополнительными кодами операций, призванными упростить программирование. [17]
Интерпретатор, дизассемблер и расширенная техническая документация Дэвида Винтера популяризировали CHIP-8/SCHIP на других платформах. Он выложил полный список недокументированных опкодов и функций [18] и был распространен на форумах любителей. Многие интерпретаторы использовали эти работы в качестве отправной точки. [ необходима цитата ]
Однако CHIP-48 тонко изменил семантику нескольких опкодов, и SCHIP продолжил использовать эту новую семантику в дополнение к изменению других опкодов. Многие онлайн-ресурсы о CHIP-8 распространяют эту новую семантику, поэтому многие современные игры CHIP-8 несовместимы с исходным интерпретатором CHIP-8 для COSMAC VIP, даже если они специально не используют новые расширения SCHIP. [19]
Некоторые расширения берут коды операций или поведение из нескольких расширений, например, XO-CHIP, который берет часть поведения из SCHIP и CHIP-8E. [20]
CHIP-8 чаще всего реализовывался на системах 4K, таких как Cosmac VIP и Telmac 1800. Эти машины имели 4096 (0x1000) ячеек памяти, все из которых были 8 битами (байтом ) , откуда и возник термин CHIP-8. Однако сам интерпретатор CHIP-8 занимает первые 512 байт пространства памяти на этих машинах. По этой причине большинство программ, написанных для оригинальной системы, начинаются с ячейки памяти 512 (0x200) и не обращаются ни к какой памяти ниже ячейки 512 (0x200). Верхние 256 байт (0xF00-0xFFF) зарезервированы для обновления дисплея, а 96 байт ниже (0xEA0-0xEFF) были зарезервированы для стека вызовов, внутреннего использования и других переменных.
В современных реализациях CHIP-8, где интерпретатор изначально работает за пределами пространства памяти 4 КБ, нет необходимости избегать нижних 512 байт памяти (0x000-0x1FF), и данные шрифтов обычно хранятся там.
CHIP-8 имеет 16 8- битных регистров данных , называемых V0 - VF. Регистр VF дублирует флаг для некоторых инструкций; поэтому его следует избегать. В операции сложения VF является флагом переноса , а в вычитании - флагом "без заимствования". В инструкции рисования VF устанавливается при столкновении пикселей.
Адресный регистр, который называется I, имеет ширину 12 бит и используется с несколькими кодами операций , включающими операции с памятью.
Стек используется только для хранения адресов возврата при вызове подпрограмм . Оригинальная версия RCA 1802 выделяла 48 байт для 12 уровней вложенности; [ 21] современные реализации обычно имеют больше. [22] [23]
CHIP-8 имеет два таймера. Оба отсчитывают время с частотой 60 герц , пока не достигнут 0.
Ввод осуществляется с помощью шестнадцатеричной клавиатуры с 16 клавишами от 0 до F. Клавиши «8», «4», «6» и «2» обычно используются для направленного ввода. Для обнаружения ввода используются три кода операции. Один пропускает инструкцию, если нажата определенная клавиша, а другой делает то же самое, если определенная клавиша не нажата . Третий ждет нажатия клавиши, а затем сохраняет его в одном из регистров данных.
Оригинальное разрешение дисплея CHIP-8 составляет 64×32 пикселя , а цвет — монохромный . Графика отрисовывается на экране исключительно с помощью спрайтов , ширина которых составляет 8 пикселей, а высота — от 1 до 15 пикселей. Пиксели спрайтов подвергаются операции XOR с соответствующими экранными пикселями. Другими словами, установленные пиксели спрайта меняют цвет соответствующего экранного пикселя, в то время как неустановленные пиксели спрайта ничего не делают. Флаг переноса (VF) устанавливается в 1, если какие-либо экранные пиксели переворачиваются из установленного в неустановленное состояние при отрисовке спрайта, и устанавливается в 0 в противном случае. Это используется для обнаружения столкновений.
Как было описано ранее, звуковой сигнал воспроизводится, когда значение таймера звука не равно нулю.
CHIP-8 имеет 35 опкодов , все из которых имеют длину два байта и хранятся в порядке от старшего к младшему . Опкоды перечислены ниже в шестнадцатеричном формате и со следующими символами:
С 1978 года было много реализаций набора инструкций CHIP-8. Следующая спецификация основана на спецификации SUPER-CHIP от 1991 года (но без дополнительных опкодов, которые обеспечивают расширенную функциональность), поскольку это наиболее часто встречающийся набор расширений на сегодняшний день. Сноски обозначают несовместимости с исходным набором инструкций CHIP-8 от 1978 года.
Код операции | Тип | C Псевдо | Объяснение |
---|---|---|---|
0ННН | Вызов | Вызывает подпрограмму машинного кода ( RCA 1802 для COSMAC VIP) по адресу NNN. Не обязательно для большинства ПЗУ. [24] | |
00E0 | Отображать | disp_clear() | Очищает экран. [24] |
00EE | Поток | return; | Возврат из подпрограммы. [24] |
1ННН | Поток | goto NNN; | Переход к адресу NNN. [24] |
2ННН | Поток | *(0xNNN)() | Вызывает подпрограмму в NNN. [24] |
3XNN | Состояние | if (Vx == NN) | Пропускает следующую инструкцию, если VX равен NN (обычно следующая инструкция — это переход для пропуска блока кода). [24] |
4XNN | Состояние | if (Vx != NN) | Пропускает следующую инструкцию, если VX не равно NN (обычно следующая инструкция — это переход для пропуска блока кода). [24] |
5XY0 | Состояние | if (Vx == Vy) | Пропускает следующую инструкцию, если VX равно VY (обычно следующая инструкция — это переход для пропуска блока кода). [24] |
6XNN | Конст. | Vx = NN | Устанавливает VX в NN. [24] |
7XNN | Конст. | Vx += NN | Добавляет NN к VX (флаг переноса не изменяется). [24] |
8XY0 | Ассиг | Vx = Vy | Устанавливает VX на значение VY. [24] |
8XY1 | БитОп | Vx |= Vy | Устанавливает VX в VX или VY. (побитовая операция ИЛИ). [24] |
8XY2 | БитОп | Vx &= Vy | Устанавливает VX в VX и VY. (побитовая операция И). [24] |
8XY3 [а] | БитОп | Vx ^= Vy | Устанавливает VX в VX xor VY. [24] |
8XY4 | Математика | Vx += Vy | Добавляет VY к VX. VF устанавливается в 1, когда есть переполнение, и в 0, когда его нет. [24] |
8XY5 | Математика | Vx -= Vy | VY вычитается из VX. VF устанавливается в 0, если есть потеря значимости, и в 1, если нет. (т.е. VF устанавливается в 1, если VX >= VY, и в 0, если нет). [24] |
8XY6 [а] | БитОп | Vx >>= 1 | Сдвигает VX вправо на 1, затем сохраняет младший бит VX до сдвига в VF. [b] [24] |
8XY7 [а] | Математика | Vx = Vy - Vx | Устанавливает VX в VY минус VX. VF устанавливается в 0, если есть потеря целостности, и в 1, если нет. (т.е. VF устанавливается в 1, если VY >= VX). [24] |
8XYE [а] | БитОп | Vx <<= 1 | Сдвигает VX влево на 1, затем устанавливает VF в 1, если старший бит VX до этого сдвига был установлен, или в 0, если он не был установлен. [b] [24] |
9XY0 | Состояние | if (Vx != Vy) | Пропускает следующую инструкцию, если VX не равно VY. (Обычно следующая инструкция — это переход для пропуска блока кода). [24] |
АННН | МЭМ | I = NNN | Устанавливает I по адресу NNN. [24] |
БННН | Поток | PC = V0 + NNN | Переход к адресу NNN плюс V0. [24] |
CXNN | Рэнд | Vx = rand() & NN | Устанавливает VX в результат побитовой операции and над случайным числом (обычно: от 0 до 255) и NN. [24] |
ДХИН | Отображать | draw(Vx, Vy, N) | Рисует спрайт в точке с координатами (VX, VY), имеющий ширину 8 пикселей и высоту N пикселей. Каждая строка из 8 пикселей считывается как бит-кодированная, начиная с ячейки памяти I; значение I не изменяется после выполнения этой инструкции. Как описано выше, VF устанавливается в 1, если какие-либо пиксели экрана переворачиваются из установленного в неустановленное состояние при отрисовке спрайта, и в 0, если этого не происходит. [24] |
EX9E | KeyOp | if (key() == Vx) | Пропускает следующую инструкцию, если нажата клавиша, сохраненная в VX (обычно следующая инструкция — это переход для пропуска блока кода). [24] |
ЭКСА1 | KeyOp | if (key() != Vx) | Пропускает следующую инструкцию, если клавиша, сохраненная в VX, не нажата (обычно следующая инструкция — это переход для пропуска блока кода). [24] |
ФХ07 | Таймер | Vx = get_delay() | Устанавливает VX на значение таймера задержки. [24] |
FX0A | KeyOp | Vx = get_key() | Ожидается нажатие клавиши, а затем сохраняется в VX (блокирующая операция, все инструкции останавливаются до следующего нажатия клавиши). [24] |
ФХ15 | Таймер | delay_timer(Vx) | Устанавливает таймер задержки на VX. [24] |
ФХ18 | Звук | sound_timer(Vx) | Устанавливает звуковой таймер на VX. [24] |
FX1E | МЭМ | I += Vx | Добавляет VX к I. VF не затрагивается. [c] [24] |
ФХ29 | МЭМ | I = sprite_addr[Vx] | Устанавливает I в положение спрайта для персонажа в VX. Символы 0-F (в шестнадцатеричном формате) представлены шрифтом 4x5. [24] |
FX33 | БКД | set_BCD ( Vx ) * ( I + 0 ) = BCD ( 3 ); * ( I + 1 ) = BCD ( 2 ); * ( I + 2 ) = BCD ( 1 ); | Сохраняет двоично-десятичное представление VX, с цифрой сотен в памяти в ячейке I, цифрой десятков в ячейке I+1 и цифрой единиц в ячейке I+2. [24] |
ФХ55 | МЭМ | reg_dump(Vx, &I) | Сохраняет от V0 до VX (включая VX) в памяти, начиная с адреса I. Смещение от I увеличивается на 1 для каждого записанного значения, но само I остается неизменным. [d] [24] |
ФХ65 | МЭМ | reg_load(Vx, &I) | Заполняет от V0 до VX (включая VX) значениями из памяти, начиная с адреса I. Смещение от I увеличивается на 1 для каждого считанного значения, но сам I остается неизменным. [d] [24] |