Архитектура и программирование Fairchild Channel F
«Channel F homebrew would be like programming sprites via hardware jumpers...»
/ chadtower, atariage forum /
Игровая приставка Fairchild Channel F, также известная как VES, появилась в ноябре 1976 года. В отличие от своих предшественников типа Ping-Pong, Tennis (в том же ряду — советский «Видеоспорт»), у неё было очень существенное отличие — наличие микропроцессора и картриджей с программами. До этого игры в приставках реализовывались на жёсткой логике — программа, в современном понимании, там отсутствовала.
Fairchild Channel F выпускалась вплоть до 1983 года. За это время было продано более четверти миллиона этих приставок и выпущено около 30-40 игр, некоторые из которых — уже в 2000-х годах.
Говоря о первенстве в плане использования микропроцессора стоит отметить, что RCA Studio II, о которой я рассказывал в прошлой статье, опоздала всего на пару месяцев, но оказалась существенно слабее Channel F, ввиду чего и провалилась по продажам. Впрочем, появление, менее чем через год, Atari VCS — вытеснило с рынка и Channel F.
Развития Fairchild_Channel_F, как такового, не было. В System II и нескольких клонах, типа Saba Videoplay 2 (1979), отличия состояли преимущественно в корпусе, джойстиках (кстати, все они понимали кроме обычных положений ещё и поворот ручки) и количестве микросхем. Архитектурно всё было практически идентично.
Что же собой представляет Channel F?
ПРОЦЕССОР
Процессор, в традициях эпохи, производился той же компанией Fairchild, что и сама приставка и называется F8. Это 8-разрядный процессор 1974 года выпуска, работающий на частоте 1.8МГц (одна инструкция занимает от 1 до 6 тактов).
Микропроцессором его можно назвать, однако, лишь с натяжкой, поскольку состоит этот процессор из двух чипов — вычислительного устройства 3850CPU, содержащего АЛУ, аккумулятор, 64 байта SRAM, логику необходимую для выполнения инструкций, два порта (шины адреса нет!) и 3851PSU (Programmable Storage Unit), который содержит 1кб ПЗУ (используется для BIOS), указатель команд, схемы адресации памяти, прерываний, таймер (прерывания и таймер конкретно в Channel F не используются).
Позднее появился чип F3859, который объединял CPU и PSU на одном кристалле и Mostek 3870 — чуть усовершенствованная версия, выпускавшаяся вплоть до 1990-х. Впрочем, это уже отдельная история. Интересно, что иногда F8 называют микроконтроллером (в частности, из-за наличия таймера и портов) и упоминают как предка семейства Intel MCS-48 (8048).
Помимо Channel F, процессор F8 использовался также в компьютере VideoBrain и в шахматном компьютере CompuChess. В целом удивительно, что об этом процессоре очень мало информации. За исключением пары описаний от Fairchild и исходников нескольких игр и примеров конкретно для Channel F — больше ничего толком и нет. Такое впечатление, что этот процессор больше нигде не использовали, что кажется невероятным (учитывая, что его продвинутые версии выпускались довольно долго). Предположу, что все остальные устройства, где он применялся — были военного назначения.
Теперь немного об особенностях процессора. Наводят на размышления набор и функции его регистров. Думаю, это одна из самых замороченных из существовавших в то время архитектур (наверное современные могут потягаться, но сравнение будет некорректным, т.к. они рассчитаны на компиляторы. С F8 же работали живые люди).
Регистров в процессоре много. Помимо 8-разрядного аккумулятора A и регистра флагов W (I,O,Z,C,S), имеется ещё «scratchpad» — 64 восьмиразрядные ячейки с различными функциями.
Первые девять ячеек используются как регистры общего назначения R0-R8 в командах типа 'lr a, 7" (загрузить содержимое регистра R7 в аккумулятор). Обратите внимание, что буква R не указывается — пишется лишь номер регистра. Что именно имеется ввиду, число или номер — должно быть ясно из контекста. Скажем, в случае с инструкцией lr чисел просто не может быть. А если это, допустим, «li 7» (загрузить константу в аккумулятор), то там это точно число, а не регистр.
Ячейки 9, 10-11 (H), 12-13 (K), 14-15 (Q) предназначены для сохранения других регистров в разных, типа вызова подпрограмм, ситуациях.
Регистры R16-R63 доступны только через специальный индексный регистр ISAR (Indirect Scratchpad Address Register), как шесть восьмибайтных буферов, которые образуются из ячеек 16-23, 24-31, 32-39, 40-47, 48-55, 56-63.
Шестиразрядный ISAR разделён на две части по 3 разряда. При увеличении или уменьшении ISAR на единицу, затрагиваются только младшие 3 разряда — т.е. адресация осуществляется в пределах одного из шести упомянутых восьмибайтных буферов (конец буфера при этом можно отследить специальной инструкций условного перехода br7).
В данном случае «d» в инструкции «lr d,a» — это не название регистра, а признак того, что ISAR надо будет уменьшить («i» — увеличивать, «s» — оставлять неизменным).
Есть и другой способ косвенной адресации — через регистр DC0 (Data Counter):
Если нужно переносить данные из одной области памяти в другую, то дополнительно используется команда xdc, которая меняет местами содержимое регистров DC0 и DC1. Т.е. читаем из адреса на который указывает DC0, потом делаем xdc и пишем по адресу, в который указывает теперь уже DC1. Потом снова xdc, и т.д. Т.е. DC1 — это некий теневой регистр для хранения копии DC0. Напрямую к нему обращаться (кроме как командной xdc) — нельзя.
Приведённые примеры иллюстрируют лишь часть возможностей в плане адресации, на самом деле их больше.
Также в F8 имеются четыре порта — 0,1,4,5, в которые можно писать командой out и читать командой in. В Channel F порты используются для вывода графики, звука и чтения состояния джойстика.
На прочих инструкциях типа арифметики, переходов и прочего особо останавливаться не буду — они достаточно стандартны. Отмечу лишь, что выбор регистров над которыми можно производить действия очень ограничен, поэтому код быстро разрастается из-за необходимости постоянно перемещать значения туда-сюда.
Отсутствует вычитание (есть только сложение). Инструкции уменьшения (ds) и увеличения (inc) на единицу — несимметричны. ds работает только с регистрами r0-r8, inc — только с аккумулятором.
Безусловный переход портит аккумулятор.
Пример обычного цикла:
ПОДПРОГРАММЫ
Поскольку в F8 нет аппаратного стека, имеются сложности с вложенными вызовами подпрограмм. Обычный вызов и возврат выглядит так:
Здесь PC0 — это обычный указатель команд. PC1 — так называемый «регистр стека». К стеку он отношения не имеет, просто в него сохраняется PC0 при вызове подпрограммы.
Если из sub вызывается ещё одна подпрограмма, адрес возврата затирается и нужно усложнять (сохранять первый адрес возврата в регистр K):
Если же нужен ещё и третий уровень вложенности, то всё становится совсем грустно (в BIOS для этого есть даже две специальных подпрограммы — pushk и popk).
Общая рекомендация — стараться заменять вызовы подпрограмм макросами. Конечно, если нет жёстких ограничений на размер кода.
Аппаратного стека в F8 нет. При необходимости он реализуется программно — через ISAR и буферы.
Запись в ОЗУ не очень актуальна (за неимением такового), но выглядит так:
ПАМЯТЬ
Хотя это прозвучит несколько странно, но ОЗУ в Fairchild Channel F нет. Имеющиеся два килобайта видеопамяти (MK4027) не отображаются в адресное пространство, да и вообще — недоступны для чтения, запись в них осуществляется через порты. Регистры же микропроцессора, хоть их аж целых 64, за ОЗУ считать вряд ли корректно.
Исполняемая программа хранится в сменных ROM картриджах, чаще всего имеющих ёмкость 2кб (некоторые современные игры используют 3к, 4к и 5к картриджи). Кроме того есть, встроенное в микросхему процессора, ПЗУ BIOS объемом 1кб, содержащее простую игру типа Tennis, пару-тройку полезных подпрограмм и образы нескольких символов.
В адресном пространстве BIOS расположен с $0000 по $07ff, ПЗУ картриджа — с $0800.
ГРАФИКА
Графические возможности Channel F весьма примитивны, поскольку видеоконтроллера в виде отдельного чипа там просто нет — всё реализовано на обычной логике типа сдвиговых регистров, вентилей и операционных усилителей. Довольно необычно, что в разных источниках упоминается разное разрешение, причём вариантов — множество. Дело в том, что имеющиеся 2 килобайта видеопамяти подрузамевают разрешение 128 x 64, но в реальности это далеко не так. Во-первых, многое зависит от того, какая область формируемого изображения на данном конкретном телевизоре видна (из-за чего первые 4 столбца официально вообще не используются). Во-вторых, последние несколько столбцов используются под палитру. В третьих, часть памяти не используется вообще.
В итоге — фактическое разрешение можно примерно оценить как 95 x 58 пикселов при 8 цветах (что, впрочем, сильно лучше, чем RCA Studio II с её черно-белыми 64x32).
Большинство приставок выпущено в NTSC варианте, однако PAL тоже существуют. Практических различий, как пишут, нет (количество строк то же самое).
По существу, такое простое железо позволяет лишь рисовать на экране точки. Хотя общее количество отображаемых цветов — 8, однако в пределах одной строки могут быть отображены лишь четыре (можно условно назвать это палитрой). Палитра устанавливается индивидуально для каждой строки, причём хранится в довольно странном месте — в столбцах 125 и 126 каждой из строк (которые в любом случае находятся за пределами видимой области). Изменение палитры производится, соответственно, рисованием пикселов в этих двух столбцах.
(жёлтым выделены область видеопамяти, которая фактически видна на экране и область, где устанавливается палитра)
Как уже отмечалось выше, записать данные в VRAM можно лишь одним способом — через порты. При этом указывается цвет, столбец, строка:
X записывается в порт 4, Y в порт 5, цвет в порт 1, после чего записью константы в порт 0 осуществляется передача данных:
Задержка требуется, чтобы всё успело записаться, иначе следующая точка может не нарисоваться. В официальной версии к столбцу и строке ещё добавляется 4 (для простоты опущено)
Заполнить весь экран точками (в цикле) занимает таким образом порядка секунды. Важно отметить, что к чрезвычайно медленному обновлению экрана добавляется ещё и то, что нет способа подождать обратного хода луча по кадру. Соответственно, даже небольшая перерисовка неизбежно сопровождается мерцанием.
Теперь о палитре. Строго говоря, для каждой строки есть два режима — чёрно-белый (когда фон чёрный, а передний план — только белый, какой бы пиксел не нарисовали) и цветной.
В цветном режиме цветов переднего плана всегда три — красный, зелёный, голубой (rgb). Плюс один из трёх цветов фона — серый, светло-синий, светло-зелёный.
Для установки палитры в столбцы 125 и 126 нужно записать следующие значения:
В типовых играх обычно поступают так: сначала задают некий общий фон, для чего можно воспользоваться готовой процедурой BIOS:
Затем, при необходимости, делают полосу с чёрно-белой палитрой (к примеру, для вывода счёта игры белыми цифрами на чёрном фоне)
И далее уже ставят пикселы одного из трёх цветов (если фон серый, соответственно — r,g,b). В итоге, цветов-то конечно 8, но поставить в конкретное место точку произвольного цвета так вот запросто — нельзя. Вот набор картинок, которые дают некоторое представление о цветах и их сочетаниях.
Собственно, на этом вся графика, как таковая, заканчивается — всё, что хочется делать, делается рисованием пикселов, причём вручную. Из полезных подпрограмм, в BIOS есть вывод символов. Однако, из соображений экономии места, в ПЗУ имеются лишь изображения цифр и отдельных знаков, размером 5x8 точек:
Тем не менее, процедура их вывода полезна и может быть использована следующим образом:
В вышеприведённом варианте старшие два разряда в регистре r0 определяют цвет (10 — red, 11 — green, 01 — blue, 00 — transparent), остальные — порядковый номер символа ( 0 1 2 3 4 5 6 7 8 9 G? T SPACE M X BLOCK: — center|| left|| ` ), начиная с нуля. В регистры r1 и r2 помещаются, соответственно, столбец и строка.
Более практичный вариант, чтобы не думать о разрядах:
Чтобы немного прочувствовать платформу, я написал для конкурса tiny intro на Chaos Constructions'2019 256-байтное интро. Ничего особенного, но обратите внимание, для чего там использовано построчное изменение палитры. Ползущая горизонтальная полоска как бы подсвечивает строчку, которая под ней находится, временно заменяя весь фон на чёрный, а все пикселы на белые. Поскольку для этого не надо перезаписывать сами пикселы (и не надо их потом за собой восстанавливать), можно делать такую «подсветку» очень быстрой и без мерцаний.
Второй момент — буквы «CC». Поскольку букв «C» нет в BIOS, использовано наложение друг на друга букв GG и цифры 1, чтобы получить инверсные «CC».
ЗВУК
Со звуком всё плохо. Официально есть три звука — 120Гц, 500 Гц и 1 КГц. Фактически, получить что-то кроме щелчков и сдавленного писка — проблематично. Вдобавок, говорят что между PAL и NTSC машинами, равно как и между старыми и новыми версиями звук ещё и отличается. Впрочем, для типовых игр — вполне достаточно. Включается и выключается звук через порты:
Народ развлекался даже проигрыванием музыки. Лучшие образцы отдалённо напоминают PC-Speaker. Правда, практического смысла всё равно нет — все ресурсы процессора уходят на музыку, ничего особо уже не порисуешь.
СРЕДСТВА РАЗРАБОТКИ
В настоящее время существует готовая подборка необходимого софта под названием «Development Pack».
Туда входит ассемблер DASM, дизассемблер, эмулятор MESS (с отладчиком). Всё это без проблем работает как минимум под Windows 7.
Параметры для ассемблирования и запуска:
dasm.exe test.asm -f3 -otest.bin
messd channelf -cartridge %cartPath%\test.bin -w -effect sharp -r 640x480 -ka
Эмулятор вполне неплох, хотя отладчик там чрезвычайно странный. Новую версию MAME/MESS мне настроить сходу не удалось (заметил, что настроить MAME под непопулярную платформу, которую он, якобы, поддерживает — каждый раз нетривиальная задача).
В эмуляторе предполагается, что разрешение видимой области соответствует minx=5,minY=5, maxX=105,maxY=61
Поскольку нет никакого удовольствия что-то писать под эмулятор, не опробовав результат вживую, пришлось решать проблему с эмулятором ПЗУ. По моей просьбе @tnt23 сделал специальный картридж (Александр Новожилов напечатал к нему корпус), в который вставляется EEPROM 28C16A. Из-за особенностей адресации F8, пришлось ещё покупать на eBay древнюю микросхему Fairchild 3853. В итоге, появилась возможность, запрограммировав EEPROM, смотреть, как выглядит код на живой машинке.
Кроме того, tnt23 приделал к Channel F S-Video выход (штатно её можно было подключить лишь к телевизору через антенный вход), что сильно улучшило качество изображения и цветопередачу.
Рассказ про Fairchild Channel F:
РЕСУРСЫ
/ chadtower, atariage forum /
Игровая приставка Fairchild Channel F, также известная как VES, появилась в ноябре 1976 года. В отличие от своих предшественников типа Ping-Pong, Tennis (в том же ряду — советский «Видеоспорт»), у неё было очень существенное отличие — наличие микропроцессора и картриджей с программами. До этого игры в приставках реализовывались на жёсткой логике — программа, в современном понимании, там отсутствовала.
Fairchild Channel F выпускалась вплоть до 1983 года. За это время было продано более четверти миллиона этих приставок и выпущено около 30-40 игр, некоторые из которых — уже в 2000-х годах.
Говоря о первенстве в плане использования микропроцессора стоит отметить, что RCA Studio II, о которой я рассказывал в прошлой статье, опоздала всего на пару месяцев, но оказалась существенно слабее Channel F, ввиду чего и провалилась по продажам. Впрочем, появление, менее чем через год, Atari VCS — вытеснило с рынка и Channel F.
Развития Fairchild_Channel_F, как такового, не было. В System II и нескольких клонах, типа Saba Videoplay 2 (1979), отличия состояли преимущественно в корпусе, джойстиках (кстати, все они понимали кроме обычных положений ещё и поворот ручки) и количестве микросхем. Архитектурно всё было практически идентично.
Что же собой представляет Channel F?
ПРОЦЕССОР
Процессор, в традициях эпохи, производился той же компанией Fairchild, что и сама приставка и называется F8. Это 8-разрядный процессор 1974 года выпуска, работающий на частоте 1.8МГц (одна инструкция занимает от 1 до 6 тактов).
Микропроцессором его можно назвать, однако, лишь с натяжкой, поскольку состоит этот процессор из двух чипов — вычислительного устройства 3850CPU, содержащего АЛУ, аккумулятор, 64 байта SRAM, логику необходимую для выполнения инструкций, два порта (шины адреса нет!) и 3851PSU (Programmable Storage Unit), который содержит 1кб ПЗУ (используется для BIOS), указатель команд, схемы адресации памяти, прерываний, таймер (прерывания и таймер конкретно в Channel F не используются).
Позднее появился чип F3859, который объединял CPU и PSU на одном кристалле и Mostek 3870 — чуть усовершенствованная версия, выпускавшаяся вплоть до 1990-х. Впрочем, это уже отдельная история. Интересно, что иногда F8 называют микроконтроллером (в частности, из-за наличия таймера и портов) и упоминают как предка семейства Intel MCS-48 (8048).
Помимо Channel F, процессор F8 использовался также в компьютере VideoBrain и в шахматном компьютере CompuChess. В целом удивительно, что об этом процессоре очень мало информации. За исключением пары описаний от Fairchild и исходников нескольких игр и примеров конкретно для Channel F — больше ничего толком и нет. Такое впечатление, что этот процессор больше нигде не использовали, что кажется невероятным (учитывая, что его продвинутые версии выпускались довольно долго). Предположу, что все остальные устройства, где он применялся — были военного назначения.
Теперь немного об особенностях процессора. Наводят на размышления набор и функции его регистров. Думаю, это одна из самых замороченных из существовавших в то время архитектур (наверное современные могут потягаться, но сравнение будет некорректным, т.к. они рассчитаны на компиляторы. С F8 же работали живые люди).
Регистров в процессоре много. Помимо 8-разрядного аккумулятора A и регистра флагов W (I,O,Z,C,S), имеется ещё «scratchpad» — 64 восьмиразрядные ячейки с различными функциями.
Первые девять ячеек используются как регистры общего назначения R0-R8 в командах типа 'lr a, 7" (загрузить содержимое регистра R7 в аккумулятор). Обратите внимание, что буква R не указывается — пишется лишь номер регистра. Что именно имеется ввиду, число или номер — должно быть ясно из контекста. Скажем, в случае с инструкцией lr чисел просто не может быть. А если это, допустим, «li 7» (загрузить константу в аккумулятор), то там это точно число, а не регистр.
Ячейки 9, 10-11 (H), 12-13 (K), 14-15 (Q) предназначены для сохранения других регистров в разных, типа вызова подпрограмм, ситуациях.
Регистры R16-R63 доступны только через специальный индексный регистр ISAR (Indirect Scratchpad Address Register), как шесть восьмибайтных буферов, которые образуются из ячеек 16-23, 24-31, 32-39, 40-47, 48-55, 56-63.
Шестиразрядный ISAR разделён на две части по 3 разряда. При увеличении или уменьшении ISAR на единицу, затрагиваются только младшие 3 разряда — т.е. адресация осуществляется в пределах одного из шести упомянутых восьмибайтных буферов (конец буфера при этом можно отследить специальной инструкций условного перехода br7).
clr ; 0 -> A ; set ISAR to full address Ox27 (octal 27) lisu 2 ; buffer N2 lisl 7 ; index within buffer N2 loop: lr d,a ; A-> buffer N2[index], than decrement ISAR (27, 26, 25, ... ) br7 loop ; go further if low part of ISAR contains 7 (end of buffer N2). if not, go loop again
В данном случае «d» в инструкции «lr d,a» — это не название регистра, а признак того, что ISAR надо будет уменьшить («i» — увеличивать, «s» — оставлять неизменным).
Есть и другой способ косвенной адресации — через регистр DC0 (Data Counter):
dci data_addr ; data_addr -> DC0 lm ; [data_addr] -> A, DC0 + 1 -> DC0 ... data_addr: db 0,1,2,3,...
Если нужно переносить данные из одной области памяти в другую, то дополнительно используется команда xdc, которая меняет местами содержимое регистров DC0 и DC1. Т.е. читаем из адреса на который указывает DC0, потом делаем xdc и пишем по адресу, в который указывает теперь уже DC1. Потом снова xdc, и т.д. Т.е. DC1 — это некий теневой регистр для хранения копии DC0. Напрямую к нему обращаться (кроме как командной xdc) — нельзя.
Приведённые примеры иллюстрируют лишь часть возможностей в плане адресации, на самом деле их больше.
Также в F8 имеются четыре порта — 0,1,4,5, в которые можно писать командой out и читать командой in. В Channel F порты используются для вывода графики, звука и чтения состояния джойстика.
На прочих инструкциях типа арифметики, переходов и прочего особо останавливаться не буду — они достаточно стандартны. Отмечу лишь, что выбор регистров над которыми можно производить действия очень ограничен, поэтому код быстро разрастается из-за необходимости постоянно перемещать значения туда-сюда.
Отсутствует вычитание (есть только сложение). Инструкции уменьшения (ds) и увеличения (inc) на единицу — несимметричны. ds работает только с регистрами r0-r8, inc — только с аккумулятором.
Безусловный переход портит аккумулятор.
Пример обычного цикла:
li 25 ; (r4) number of iterations lr 4,a next: ds 4 ; r4-- bnz next ; until r4 == 0
ПОДПРОГРАММЫ
Поскольку в F8 нет аппаратного стека, имеются сложности с вложенными вызовами подпрограмм. Обычный вызов и возврат выглядит так:
; ...code pi sub ; Pushes address of next instruction to PC1 ; address of sub is stored in PC0 (jump to subroutine) ; ...code continues sub: ; ... often used code pop ; Move return address from PC1 to PC0
Здесь PC0 — это обычный указатель команд. PC1 — так называемый «регистр стека». К стеку он отношения не имеет, просто в него сохраняется PC0 при вызове подпрограммы.
Если из sub вызывается ещё одна подпрограмма, адрес возврата затирается и нужно усложнять (сохранять первый адрес возврата в регистр K):
prog: ; ...do something... pi sub1 ; Address of next instruction stored in PC1 ; sub1 is stored in PC0 (jump to subroutine) ; ...do more... sub1: lr k,p ; Copy PC1 to K, original jump address to K ; ...do something... pi sub2 ; Pushes address of next instruction to PC1 ; sub1 is stored in PC0 (jump to subroutine) ; ...do more... pk ; Store address of next instruction in PC1 ; Copy value in K to PC0 (jump back to main) sub2: ; ...do something... pop ; Move return address from PC1 to PC0
Если же нужен ещё и третий уровень вложенности, то всё становится совсем грустно (в BIOS для этого есть даже две специальных подпрограммы — pushk и popk).
Общая рекомендация — стараться заменять вызовы подпрограмм макросами. Конечно, если нет жёстких ограничений на размер кода.
Аппаратного стека в F8 нет. При необходимости он реализуется программно — через ISAR и буферы.
Запись в ОЗУ не очень актуальна (за неимением такового), но выглядит так:
li $FF ; set value dci $3800 ; set target address st ; write
ПАМЯТЬ
Хотя это прозвучит несколько странно, но ОЗУ в Fairchild Channel F нет. Имеющиеся два килобайта видеопамяти (MK4027) не отображаются в адресное пространство, да и вообще — недоступны для чтения, запись в них осуществляется через порты. Регистры же микропроцессора, хоть их аж целых 64, за ОЗУ считать вряд ли корректно.
Исполняемая программа хранится в сменных ROM картриджах, чаще всего имеющих ёмкость 2кб (некоторые современные игры используют 3к, 4к и 5к картриджи). Кроме того есть, встроенное в микросхему процессора, ПЗУ BIOS объемом 1кб, содержащее простую игру типа Tennis, пару-тройку полезных подпрограмм и образы нескольких символов.
В адресном пространстве BIOS расположен с $0000 по $07ff, ПЗУ картриджа — с $0800.
ГРАФИКА
Графические возможности Channel F весьма примитивны, поскольку видеоконтроллера в виде отдельного чипа там просто нет — всё реализовано на обычной логике типа сдвиговых регистров, вентилей и операционных усилителей. Довольно необычно, что в разных источниках упоминается разное разрешение, причём вариантов — множество. Дело в том, что имеющиеся 2 килобайта видеопамяти подрузамевают разрешение 128 x 64, но в реальности это далеко не так. Во-первых, многое зависит от того, какая область формируемого изображения на данном конкретном телевизоре видна (из-за чего первые 4 столбца официально вообще не используются). Во-вторых, последние несколько столбцов используются под палитру. В третьих, часть памяти не используется вообще.
В итоге — фактическое разрешение можно примерно оценить как 95 x 58 пикселов при 8 цветах (что, впрочем, сильно лучше, чем RCA Studio II с её черно-белыми 64x32).
Большинство приставок выпущено в NTSC варианте, однако PAL тоже существуют. Практических различий, как пишут, нет (количество строк то же самое).
По существу, такое простое железо позволяет лишь рисовать на экране точки. Хотя общее количество отображаемых цветов — 8, однако в пределах одной строки могут быть отображены лишь четыре (можно условно назвать это палитрой). Палитра устанавливается индивидуально для каждой строки, причём хранится в довольно странном месте — в столбцах 125 и 126 каждой из строк (которые в любом случае находятся за пределами видимой области). Изменение палитры производится, соответственно, рисованием пикселов в этих двух столбцах.
(жёлтым выделены область видеопамяти, которая фактически видна на экране и область, где устанавливается палитра)
Как уже отмечалось выше, записать данные в VRAM можно лишь одним способом — через порты. При этом указывается цвет, столбец, строка:
X записывается в порт 4, Y в порт 5, цвет в порт 1, после чего записью константы в порт 0 осуществляется передача данных:
; set color (2 bit per pixel) li $00 ; color ($00 = green, $40 = red, $80 = blue, $C0 = background) outs 1 li 104 ; X com outs 4 ; set the row li 61 ; Y com outs 5 ; transfer data to VRAM li $60 outs 0 li $50 outs 0 ; wait for update lis 6 delay: ai $ff bnz delay
Задержка требуется, чтобы всё успело записаться, иначе следующая точка может не нарисоваться. В официальной версии к столбцу и строке ещё добавляется 4 (для простоты опущено)
Заполнить весь экран точками (в цикле) занимает таким образом порядка секунды. Важно отметить, что к чрезвычайно медленному обновлению экрана добавляется ещё и то, что нет способа подождать обратного хода луча по кадру. Соответственно, даже небольшая перерисовка неизбежно сопровождается мерцанием.
Теперь о палитре. Строго говоря, для каждой строки есть два режима — чёрно-белый (когда фон чёрный, а передний план — только белый, какой бы пиксел не нарисовали) и цветной.
В цветном режиме цветов переднего плана всегда три — красный, зелёный, голубой (rgb). Плюс один из трёх цветов фона — серый, светло-синий, светло-зелёный.
Для установки палитры в столбцы 125 и 126 нужно записать следующие значения:
x=125 x=126 palette --------------------------------------------------------------------- 00 00 COLOR: rgb, light green bg 00 ff COLOR: rgb, light blue bg ff 00 COLOR: rgb, gray bg ff ff B/W: www, black bg
В типовых играх обычно поступают так: сначала задают некий общий фон, для чего можно воспользоваться готовой процедурой BIOS:
li $c6 ; $21 - b/w palette, fill with black. $c6 - color palette, fill with gray lr 3, A pi clrscrn ; clrscrn BIOS call
Затем, при необходимости, делают полосу с чёрно-белой палитрой (к примеру, для вывода счёта игры белыми цифрами на чёрном фоне)
И далее уже ставят пикселы одного из трёх цветов (если фон серый, соответственно — r,g,b). В итоге, цветов-то конечно 8, но поставить в конкретное место точку произвольного цвета так вот запросто — нельзя. Вот набор картинок, которые дают некоторое представление о цветах и их сочетаниях.
Собственно, на этом вся графика, как таковая, заканчивается — всё, что хочется делать, делается рисованием пикселов, причём вручную. Из полезных подпрограмм, в BIOS есть вывод символов. Однако, из соображений экономии места, в ПЗУ имеются лишь изображения цифр и отдельных знаков, размером 5x8 точек:
Тем не менее, процедура их вывода полезна и может быть использована следующим образом:
li 25 ; column lr 1,a li 25 ; row lr 2,a li %11000000 ; e.g. $c0 - green "0" lr 0,a ; a -> r0 pi drawchar ; call subroutine
В вышеприведённом варианте старшие два разряда в регистре r0 определяют цвет (10 — red, 11 — green, 01 — blue, 00 — transparent), остальные — порядковый номер символа ( 0 1 2 3 4 5 6 7 8 9 G? T SPACE M X BLOCK: — center|| left|| ` ), начиная с нуля. В регистры r1 и r2 помещаются, соответственно, столбец и строка.
Более практичный вариант, чтобы не думать о разрядах:
li 20 ; x lr 1,a ; a -> r1 li 10 ; y lr 2,a ; a -> r2 li $40 ; char color in bits 6,7: $80 (%10000000) - red, $c0 (%11000000) - green, $40 (%01000000) - blue, $00 (%00000000) - transparent oi 1 ; index of char ( e.g. 3 for "3" ) lr 0,a ; combined color + char index -> r0 pi drawchar ; call subroutine
Чтобы немного прочувствовать платформу, я написал для конкурса tiny intro на Chaos Constructions'2019 256-байтное интро. Ничего особенного, но обратите внимание, для чего там использовано построчное изменение палитры. Ползущая горизонтальная полоска как бы подсвечивает строчку, которая под ней находится, временно заменяя весь фон на чёрный, а все пикселы на белые. Поскольку для этого не надо перезаписывать сами пикселы (и не надо их потом за собой восстанавливать), можно делать такую «подсветку» очень быстрой и без мерцаний.
Второй момент — буквы «CC». Поскольку букв «C» нет в BIOS, использовано наложение друг на друга букв GG и цифры 1, чтобы получить инверсные «CC».
ЗВУК
Со звуком всё плохо. Официально есть три звука — 120Гц, 500 Гц и 1 КГц. Фактически, получить что-то кроме щелчков и сдавленного писка — проблематично. Вдобавок, говорят что между PAL и NTSC машинами, равно как и между старыми и новыми версиями звук ещё и отличается. Впрочем, для типовых игр — вполне достаточно. Включается и выключается звук через порты:
li %01000000 ; 1khz beep $40 outs 5 li %10000000 ; 500hz beep $80 outs 5 li %11000000 ; 120hz beep $c0 outs 5 ; some pause clr outs 5 ; turn off sound
Народ развлекался даже проигрыванием музыки. Лучшие образцы отдалённо напоминают PC-Speaker. Правда, практического смысла всё равно нет — все ресурсы процессора уходят на музыку, ничего особо уже не порисуешь.
СРЕДСТВА РАЗРАБОТКИ
В настоящее время существует готовая подборка необходимого софта под названием «Development Pack».
Туда входит ассемблер DASM, дизассемблер, эмулятор MESS (с отладчиком). Всё это без проблем работает как минимум под Windows 7.
Параметры для ассемблирования и запуска:
dasm.exe test.asm -f3 -otest.bin
messd channelf -cartridge %cartPath%\test.bin -w -effect sharp -r 640x480 -ka
Эмулятор вполне неплох, хотя отладчик там чрезвычайно странный. Новую версию MAME/MESS мне настроить сходу не удалось (заметил, что настроить MAME под непопулярную платформу, которую он, якобы, поддерживает — каждый раз нетривиальная задача).
В эмуляторе предполагается, что разрешение видимой области соответствует minx=5,minY=5, maxX=105,maxY=61
Поскольку нет никакого удовольствия что-то писать под эмулятор, не опробовав результат вживую, пришлось решать проблему с эмулятором ПЗУ. По моей просьбе @tnt23 сделал специальный картридж (Александр Новожилов напечатал к нему корпус), в который вставляется EEPROM 28C16A. Из-за особенностей адресации F8, пришлось ещё покупать на eBay древнюю микросхему Fairchild 3853. В итоге, появилась возможность, запрограммировав EEPROM, смотреть, как выглядит код на живой машинке.
Кроме того, tnt23 приделал к Channel F S-Video выход (штатно её можно было подключить лишь к телевизору через антенный вход), что сильно улучшило качество изображения и цветопередачу.
Рассказ про Fairchild Channel F:
РЕСУРСЫ
- VES Wiki
- Схема [1], [2]
- История F8
- Программирование F8
- Патент (как всё работает)
- Music player / converter from XM [1], [2]
- Картинки
- Intro со скроллингом
20 комментариев
Видео, кстати, с час назад досмотрел. Насчёт этих вот непоняток с адресациями я испытывал похоже такие же ощущения как и вы когда читал доки по Intel 4004 — прям реально вроде вот оно всё написано, но тоже доступ через пень-колоду, и даже 3 или 4 разных видов банков с разной адресацией и вырвиглазным страничным доступом который точно так же «вроде уже показалось что начал понимать», но снова натыкаешься на какую то хрень которую не можешь приладить к только что прочитанному и якобы «осмысленному». :) Дааа.
Где я могу об этом прочесть? Можно URL на документацию? Страницу, конкретное место текста?
Это неверно. Внешняя память технологически появилась позже регистровой, но интерес представляет история термина «регистр». Помимо прямого смыслового значения: записывать, отмечать, вносить (т.е. регистрировать) дело тут может оказаться поинтереснее! Гипотезы такие. 1. «регистром» называется электронная схема, триггер. 2. Регистр это кассовый аппарат, втч счетный (букв. — счетчик). 3. Блок механического калькулятора/счетчика называется «регистром». 4. Регистры ЭВМ зачастую предоставляли оператору возможность механически вносить данные. Склоняюсь к прямому смысловому значению, но как оно исторически пока информации нет.
Страница 7 глава Magnetic Core Storage:
При этом надо заметить, что в этой системе была еще память на магнитном барабане (magnetic drum storage) с заметно меньшей скоростью, может быть поэтому так выделено (потому что знаю несколько документаций тех лет других машин где термин регистра используется только в современном смысле), но в любом случае «программа исполняемая из регистров» в современном понимании — чушь, а исполнялась там программа из core storage. Имхо в те времена смысл был несколько размыт, а в случае с F8 такая память тоже была более быстродействующая несмотря на индексный многокомандный доступ чем большая внешняя.
Вообще (отступая в сторону) я в таких случая проверяю у англоговорящих исходный смысл термина по сайту etymonline.com. Учитывая что есть слова registrant, registry, registration — для англоговорящих это слово, по видимому, несет устойчивый смысл «запись», «нечто записанное». В смысле записи какого-то списка, нечто записанное на бумаге или внесённое. Поэтому регистры в самом общем смысле «записи» или ячейки (памяти)...
Но. Несмотря на это в каждой области существует устойчивый набор терминов и устоявшееся значение. Так что не стоит обобщать без явной на то необходимости. Напротив, стоит разделять понятия.
Интересный нюанс. На той же страница 6, конец параграфа вверху читаем о Core Memory: «Information is not retained when the power is off». Вообще, память на маг.серд. хранит информацию постоянно, до считывания, а у них на это не рассчитано.
Копнул из любопытства в чуть более древнуюю штуку — UNIVAC I: www.bitsavers.org/pdf/univac/univac1/UNIVAC1_Operating_Manual_1954.pdf — документация от 1954 года. Опять таки память чётко отличается от регистров.
Есть чуть более поздняя дока от 59 года www.bitsavers.org/pdf/univac/univac1/UNIVAC1_Programming_1959.pdf где прям проговаривается, что регистры это такие же ячейки как ячейки памяти, но их мало, они в тельняшках и быстро работают. Однако есть некоторые забавные отличия от того как бы (имхо) описывали некоторые вещи сейчас.
Но прежде тут уместно вспомнить откуда взялся еще один термин — word/слово. А взялся от судя по всему как раз из UNIVAC (в вики вроде бы это же и написано), т.к. ячейка памяти в нём хранила 12 разрядов в каждом из которых хранились буквы, цифры или символы из алфавитно-цифрового набора на 63 знака и вместе эти 12 разрядов и составляли то что документация называет буквально словом по очевидной причине — там можно хранить слова до 12 знаков. Заодно они могут выступать как 12-разрядные числа при условии что в разрядах представлены только цифры.
Ну так вот — в системе UNIVAC I есть два регистра I и O (input/output) размером по 60 слов каждый. Т.е. не каждое из 60 слов называется регистром, а весь массив как целое. Сомневаюсь что в наше время такие буфера ввода-вывода (на магнитную плёнку) вообще называли бы регистрами, а не собственно буфером памяти.
В общем наверное чтобы понять где когда и кто чётко стал разграничивать надо кучу литературы перелопатить.
Регистры это вид памяти, ячейки памяти, да. Как иначе? Возникает ощущение, что у тебя трудности с базовой терминологией, не понимая общих (обобщенных) терминов ты полагаешь что это ФИЗИЧЕСКИ одни и те же вещи.
Загугли что такое «омонимы».
По моему мнению, ячейки памяти (в смысле ячейки ОЗУ) по смыслу не считались регистрами (в смысле регистрами процессора). В тексте применен термин «registers», означающий по смыслу также «ячейки памяти», «записи». Чего ты, видимо, не знал, не понял и не учел.
Второй мой тезис такой — в генеральном смысле регистр (в смысле регистр процессора) является ячейкой памяти (но не ОЗУ) и это действительно, может утверждаться в общем смысле.
Я тебе это пояснил, на что ты мне снова выдаёшь:
Подозреваю что с пониманием текста про UNIVAC1 у тебя происходит то же самое. Уточни страницу по внутренней нумерации, абзац, текст. Гляну. А главное, еще раз выскажи свои тезисы, что ты утверждаешь/не утверждаешь, хочешь понять.
В общем спорим ни о чём, тут и спора то не должно быть.
Что касается UNIVAC — это один из первых компьютеров общего назначения вообще и видно что в нём регистры памяти противопоставляются несмотря на то что всё сделано на электронно-лучевых-трубках и первое же место где слово register встречается во второй документации говорит что registers are identical to memory, но присутствуют в единичных экземплярах и как бы находятся между памятью и вычислительным устройством — и тут приводится аналогия с табло калькулятора. В общем у тех кто писал документацию к UNIVAC уже есть сложившаяся терминология в этом смысле и по видимому так просто корней не найти, т.к. скорее всего это были кулуарные штуки конкретных коллективов людей работавших в оборонке под грифом секретно до того.
Тьфу, смешались люди-кони, «электронно-лучевых-трубках» читать как «электронных лампах».
Интересно, залез сейчас взглянуть на документацию еще какого-нибудь из предтеч. И выбрал в этот раз Manchester Mark I — его «родитель» Manchester Baby был вообще первым компьютером с программой хранимой в ОЗУ. Этот компьютер был некоммерческим, поэтому документации какой то официальной долгое время не было и почитать можно было только статьи в разные журналы и издания. Например:
curation.cs.manchester.ac.uk/computer50/www.computer50.org/kgill/mark1/natureart.html
curation.cs.manchester.ac.uk/computer50/www.computer50.org/kgill/mark1/natureart51.html
curation.cs.manchester.ac.uk/computer50/www.computer50.org/kgill/mark1/conf.html
curation.cs.manchester.ac.uk/computer50/www.computer50.org/kgill/mark1/ssem.html
Так вот — несмотря на то что в этих статьях подробно описываются такие вещи как память, аккумулятор и счётчик инструкций — слово register не используется вообще.
К 1951 году коммерческая жилка всё-таки врывается в цех и выпускается коммерческий вариант (с поднятыми характеристиками) Manchester Mark I с названием Ferranti Mark I.
Для него конечно же уже появляется официальная документация по программированию за авторством самого Алана Тюринга (!) которую можно почитать тут: curation.cs.manchester.ac.uk/computer50/www.computer50.org/kgill/mark1/RobertTau/turing.pdf
Так вот — если там тоже дать на поиск слово «register» то оно найдётся два раза, но не в тексте инструкции, а в предисловии которое написано много много позже. Сам Алан Тюринг нигде не использует слово «регистр». Надо заметить, правда, что как ОЗУ так и аккумулятор там хранились на электронно-лучевых трубках (именно ЭЛТ!) и поэтому к ним чаще всего применяется эпитет «tubes». Такое ощущение, что британцы слово «регистр» переняли у американцев когда то позднее.
Желательно привести «точные координаты» утверждений, как я просил. Страницу (по нумерации источника), абзац, текст. Связано это с тем что я не могу вычитывать все документы в поиске утверждаемого, весьма лимитировано время...
Но если прям интересно, то тут (документация по UNIVAC I от 59 года): www.bitsavers.org/pdf/univac/univac1/UNIVAC1_Programming_1959.pdf
Это страница 16 со слов: «The arithmetic registers are identical to memory cells except...»
Давно уже натыкался на статью от 20 сентября 1975 года про тестирование новенького и только что спущенного со стапелей микропроцессора 6502 (англ.): www.swtpc.com/mholley/Microprocessors/EDN_Sep_20_1975_6502.pdf
Текст под фото: «Рис. 2 — Изначальный макет (нашего) журнала для „оживления“ микропроцессора MOS Technology 6502 показывает насколько просты машины второго с половиной поколения в плане разводки проводов для пользователя. Эта макетная плата была разложена (в течении недели) чтобы приблизиться к топологии, которую журнал использует для общих замеров микропроцессоров. И хотя мы обнаружили немало шума (главным образом вместе с синхроимпульсами) на всех наших довольно длинных и разбросанных проводах, но 6502 отработал без ошибок.»
Так вот — эта разводка это они буквально тестировали как работает процессор подключив к нему просто щупы и анализируя активность на шине данных, т.к. даже толком RAM к нему подключить не могли. 10 байт программы в ППЗУ залили и смотрели как она ножками «шевелит». :)
Fairchild F8 там, кстати, тоже упомянут как «сильный соперник».
Так вот в начале статьи с восхищением рассказывается, что с появлением MOS 6502 на рынке становится возможным всего за 50 долларов (~240 долларов в сегодняшних ценах) становится возможным создать полностью рабочую мю-систему с 200 байтами ROM, 100 байтами RAM и даже, возможно (!) четырьмя портами ввода-вывода!