24 октября 2016, 01:42 (2981 день назад, №10326)Архитектура и программирование Philips Videopac (Magnavox Odyssey 2)
"Hardware is just software crystallized early"
- Alan Kay
Компьютер
Magnavox Odyssey 2 (Videopac) появился в 1978 году и позиционировался как игровой, однако с возможностью более серьёзного применения (для чего у него имелась встроенная плёночная клавиатура). Серьёзных приложений, учитывая назначительный объём памяти, было очень мало, так что, по факту, правильнее считать Videopac игровой приставкой.
Что касается названий, Magnavox Odyssey 2 продавался в США и выдавал NTSC видеосигнал (через RF выход). Philips Videopac G7000 (он же C52) продавался в Европе, соответственно, с PAL видео. Кроме этого различия (которое, разумеется, влияло на работоспособность части игр) компьютеры совершенно одинаковые.
Videopac был одной из первых игровых приставок, для которой игры выпускались в виде картриджей с программами. Поэтому ничего удивительного, что и технически это устройство весьма аскетично.
Процессор и память
Процессор представляет собой микроконтроллер
Intel 8048. Одно время он был довольно известен, так как ставился (в разных вариантах исполнения) во все PC XT и AT клавиатуры.
8048 имеет довольно простой набор инструкций и мало режимов адресации. Архитектура
гарвардская (в противоположность более привычной всем - фон-неймановской).
Вся память делится на три типа - программная ROM (1kb BIOS на кристалле и до 8kb ROM в картриджах), внутренняя RAM (64 байта в самом микронтроллере, 32 байта из которой зарезервирована под регистры и стек) и внешняя RAM (128 байт статического RAM, частично находящегося по тем же адресам что и видеоконтроллер).
Общий объём ОЗУ доступный программисту в итоге составляет менее 160 байт, да и то использовать его целиком - весьма сложно.
Для доступа к каждому из типов памяти существуют отдельные инструкции (MOVP, MOV, MOVX). Тактовая частота 8048 в Videopac часто указывается как 5.37 МГц, однако фактически (в смысле выполнения инструкций) она всего лишь 0.358 МГц. При этом, правда, большинство инструкций выполняется за 1-2 такта. Имеется девять регистров общего назначения - A, R0-R7.
Также на кристалле 8048 имеется таймер, два порта ввода-вывода и схема управления прерываниями. Через порты осуществляется опрос двух джойстиков и клавиатуры.
Неприятная особенность 8048 - деление памяти на страницы по 256 байт (нельзя обращаться к ячейке памяти находящейся на другой странице) и банки по 2kb (для обращения к соседнему банку необходимо переключение командами SEL RB), что приходится постоянно учитывать.
Существует отечественный аналог 8048 - 1816ВЕ48.
Видео и звук
Другим важным компонентом системы является чип Intel 8245 (он же 8244 для NTSC). Это видеоаудиоконтроллер с масочным ROM, который выпускался специально для Videopac (т.е. иных его версий или прошивок, по-видимому, не существует).
Видеоконтроллер довольно странен даже по меркам домашних компьютеров 1980-х. К примеру, в нём нет, как таковых, ни графических ни текстовых режимов. Все сущности которые он поддерживает (sprites, chars, quads, grids) представляют собой спрайты с теми или иными ограничениями. В связи с этим, такие "обыкновенные" операции как рисование точек в определённом месте экрана или заполнение экрана текстом - невозможны. Из-за этого даже нельзя определённо говорить о разрешении экрана (очень условно можно говорить о цифрах типа 228 x 262).
Фактически, этот видеоконтроллер не является универсальным и заточен под типовые (очень простые) игры. Он может формировать:
Sprites - традиционные аппаратные спрайты 8x8 пикселов. Одновременно на экране может быть 4 спрайта. Их содержимое, координаты, цвет можно менять записью в регистры видеоконтроллера. Каждый спрайт может быть любого из восьми (ярких) цветов.
Также имеется довольно странная (хотя и полезная) возможность, позволяющая сдвинуть спрайт на половину (!) пиксела, либо нечётные строки спрайта на половину пиксела относительно чётных.
Chars - символы. Буквы, цифры и некоторые знаки (всего 63), образы которых хранятся в ROM BIOS и не могут быть изменены. Одновременно на экране могут отображаться не более 12 символов. Как и спрайты, они выводятся в любое место на экране (с точностью до пиксела) но, в отличии от них, не могут накладываться друг на друга. Каждый символ может быть любого из 8 (ярких) цветов.
Адрес, откуда берётся образ символа зависит от координаты Y в которую символ выводится и кода самого символа (!). Поэтому, для вывода символов либо нужно вычислять этот адрес по хитрой формуле (особенно, если хочется получить части символов), либо пользоваться подпрограммой BIOS.
Quads - группы символов, объёдинённые по 4 штуки.
Grid - сетка 9 x 8 сегментов. Используется для отображения лабиринтов, этажей, лестниц и т.п. Есть режим, который позволяет вместо сетки отображать сплошные блоки - например, для имитации шахматной доски. Вся сетка одного цвета. Т.е. для всего grid задаётся один из восьми (тёмных) цветов.
Grid находится на заднём плане (поверх фона, который может быть любого из 8 цветов), поверх grid выводятся символы и, на переднем плане - спрайты.
Есть возможность отслеживать факт столкновения объектов между собой (по одному биту-флагу на каждый тип объёкта - без указания на конкретный).
Кроме того, видеоконтроллер позволяет, с рядом ограничений, отслеживать положение луча не только по кадру, но и по строкам. В простейшем случае это используется для рисования горизонтальных полос (земли и неба, к примеру) путём изменения цвета фона в нужные моменты.
Помимо видео, 8245 также позволяет генерировать примитивные звуки. Для этого имеется 24-разрядный циклический сдвиговый регистр, который может тактироваться одной из двух частот на выбор и переключаться в режим генерации шума. Таким образом, генерация произвольной ноты фактически невозможна, хотя с некоторыми хитростями можно получить приемлимое приближение.
Громкость на выходе общая, может быть задан один из 16 уровней.
Подпрограммы BIOS позволяют издавать несколько звуков, которые можно услышать в большинстве игр (писк, выстрел, взрыв).
Картриджи с играми представляют собой простое ПЗУ размером от 2kb (наиболее типично) до 8kb. Помимо картриджей, для Videopac существует два периферийных устройства - синтезатор речи (LPC сжатие, ПЗУ со словами) и модуль шахматного компьютера (с собственным процессором z80).
Разработка
Лучшим эмулятором является o2em, причём есть версия со встроенным отладчиком. Хотя это действительно очень приличный эмулятор, тем не менее ситуация, когда довольно простой код работает в нём, но даёт черный экран или не те цвета на реальном Videopac - довольно типична. Так же может быть полезен эмулятор 1816ВЕ48 ("SCM - Single Chip Machine by DCA Laboratory"). В качестве ассемблера лучше всего использовать AS (ASW).
Сборка и запуск выглядят так:
asw.exe -L -x %1.a48
p2bin.exe %1.p %1.bin -r 1024-3071
o2em.exe %1.bin -euro
Для проверки кода на реальном устройстве были приобретены
Mateos Videopac Multigame Cartridge и Mateos Burner/Dumper (т.е. эмулятор ПЗУ и программатор для него, с USB портом).
Также имеет смысл доработать Videopac, сделав composite либо RGB выход (в интернете много
схем). По сравнению со стандартным RF это даст более качественное изображение и более правильные и чистые цвета.
При включении компьютера (если вставлен любой рабочий картридж) на экране появляется цветная надпись "SELECT GAME" (если картриджа нет, на экране в лучшем случае мусор).
После нажатия клавиши, происходит переход по адресу 0400h - первому адресу в ПЗУ картриджа.
Типичная программа выглядит следующим образом:
; Hello World for Philips Videopac (Magnavox Odyssey 2), 8048 CPU
; by Frog ( https://github.com/petersobolev )
cpu 8048
org 400h
include "g7000.h" ; стандартные для Videopac константы
; вектора прерываний
jmp selectgame ; RESET. Инициализация VDC, внутреннего и внешнего ОЗУ. Отображение надписи "SELECT GAME" и ожидание клавиши. Затем переход по адресу 0408h, т.е. на jmp start (код клавиши в A).
jmp irq ;
jmp timer ;
jmp vsyncirq ;
jmp start ; вызывается после отработки selectgame
jmp soundirq ;
timer:
ret ; таймер не используется
start:
call gfxoff ; необходимо чтобы можно было писать в регистры VDC
mov r0,#010h ; начальный адрес в VDC отображаемого символа (одного из 12)
mov r3,#40 ; x
mov r4,#100 ; y
mov r1,#hellostr & 0ffh ; указатель на строку (должен быть на той же 255 байтной странице)
mov r2,#11 ; длина строки 11 символов
nextchar:
mov a,r1
movp a,@a ; получаем в A символ взятый по адресу хранящемуся в r1
mov r5,a
inc r1 ; увеличиваем адрес символа
mov r6,#0eh ; белый цвет
call printchar ; печатаем символ (одновременно увеличивая r0 и r3)
djnz r2,nextchar
call gfxon ; изображаем то, на что запрограммировали VDC
loop:
jmp loop ; просто ждём
; 'HELLO WORLD' (ASCII строки не поддерживаются ассемблером)
hellostr:
db 01dh, 012h, 00eh, 00eh, 017h, 00ch, 011h, 017h, 013h, 00eh, 01ah
Приложение - интро Rash
По результатам изучения Videopac, мной была написана (для конкурса на
Chaos Constructions) 256 байтная интро (
видео,
исходник).
В работе используются три вида графических примитивов (из четырёх реализованных в видеоконтроллере i8245) - grid, sprites и chars. Не используется лишь quads (представляющий собой разновидность chars).
Падающие сверху вниз человечки - не спрайты, как это может показаться, а символы (chars) размером 8x8. Впрочем, в 8245 chars и sprites - родственные понятия. Используется максимально допустимое число одновременно отображаемых chars - 12 штук. Все они берутся из стандартного знакогенератора (там есть символы человечков), что экономит как минимум 24 байта. Это немаловажный момент, поскольку архитектура i8048 и формат картриджа Videopac совсем не способствуют компактности кода. В частности, несмотря на большое число регистров (a, r0-r7), в ряде случаев можно использовать лишь некоторые (a, r0, r1), поэтому образуется довольно много "лишних" инструкций, гоняющих данные из регистра в регистр.
Фон из меняющихся оранжевых квадратов реализован через grid. Это аппаратно генерируемая сетка 9x8 (в специальном режиме "шахматного" поля), в которой по некоему алгоритму включаются те или иные сегменты. Приоритет grid всегда наименьший, поэтому человечки летят поверх неё.
Невезучий, но неунывающий котик представляет собой два спрайта (8x8 каждый). При этом данные для спрайтов во время движения периодически меняются на другие (всего два кадра)), чтобы имитировать двигающиеся лапы.
Столкновение chars и sprites фиксируется видеоконтроллером, при этом по определённому алгоритму меняется цвет спрайтов котика, а также сбрасывается или устанавливается специальный бит, сдвигающий чётные строки спрайта на полпиксела относительно нечётных.
В качестве звука столкновения используется один из звуков, доступных через подпрограмму BIOS (что экономит ещё несколько байт).
Кроме того
Помимо игр, для Videopac существовало также несколько более серьёзных приложений - программа для вывода титров в виде бегущей строки и программа для обучения программированию, о которой стоит сказать особо.
Картридж называется
"Computer Programmer" и позволяет вводить программу в машинных кодах (т.е. даже не на ассемблере) и запускать её. К картриджу прилагалась
книжка с описанием архитектуры и инструкций 8048.
Напомню, что это был вполне коммерческий продукт, рассчитанный на покупателей игровой (!) приставки.
На
видео можно посмотреть, как это работает.
Ссылки
Здесь можно посмотреть мои работы под разные ретро-платформы, а
здесь их исходники на github.
Автор статьи - Пётр Соболев (frog). Октябрь 2016 г.
p.s. Спасибо tnt23 за переделку видеовыхода Videopac с RF на композит.