Хабрахабр

От «Цветорасширителя для ZX-Spectrum» до ZX-Poly

Статья описывала идею решения одной из главных проблем платформы ZX-Spectrum — конфликта атрибутов (attribute clash). "Цветорасширитель для ZX-Spectrum" — так называлась статья, опубликованная в эхе fido7.zx.spectrum 3 августа 1997 года. Публикация вызвала в то время определенный интерес, про технические детали и историю вопроса я и хотел бы рассказать.

ZX-Poly logo

Не буду залезать глубоко в технические подробности и просто структурно опишу идею и решение.

Нетехническая часть истории, можно пропустить

История разработки началась ранней весной 1994го года, когда страна все еще переживала "изменения в призыве", которые привели к массовому закрытию отсрочек и призыву студентов ПТУ и техникумов. Мне повезло - я был на последнем курсе Ленинградского радиотехнического техникума и таким государство согласилось дать кратковременную отсрочку на ускоренное получение диплома с заменой дипломного проектирования на экзамен по всем предметам. В армию ушел 1-го марта 1994го года уже дипломированным техником-радиотехником. В вооруженных силах в это время был небывалый наплыв таких же специалистов средне-технического звена, правда это немного рушило осенне-весеннюю призывную систему в головах “дедушек” у которых уже была сформирована четкая градация в наименованиях, они этот нестандартный призыв окрестили “гоблинским”. Среди “загремевших” хватало людей увлекавшихся ZX-Spectrum и в моем подразделении таким был Александр Гумин (он писал игры на ZX-Spectrum под лейблом ANCCAN вместе с Денисом Маркеловым и стал известен своей адаптацией Mortal Kombat для этой платформы в 1997м году), было с кем поговорить о программировании и “железе”. Ближе к середине апреля 1994го года, по окончании "курса молодого бойца", мы с Александром, были переведены в стройбатовскую учебную часть, расположенную в пригороде Санкт-Петербурга - поселке Стрельна. Там нам предстояло несколько месяцев осваивать нелегкую специальность кабельщика-спайщика. Жизнь в этой части текла неторопливо и учеба чередовалась с нарядами, что в основном напрягало руки, но давало мозгу время для размышлений. Так, в один из нарядов по кухне, моя пол и размышляя о ZX-Spectrum и его возможностях, мне пришла в голову идея - как победить "конфликт атрибутов". Я обдумывал эту идею до конца службы и всё больше убеждался, что "может сработать". К сожалению мысль о жизнеспособности самой платформы, к которой я собирался применять эту идею, посещала меня реже. Впрочем, в России, ZX-Spectrum наиболее ярко вспыхнул на небосводе как раз примерно с 1991го по 1996й. Некоторые российские производители его клонов поднялись настолько, что спонсировали передачи на ТВ (например компания БиЭм какое то время спонсировала передачу “Джунгли зовут”). Но во время службы были другие проблемы, так что я решил отложить все вопросы связанные с коммерцией до своего увольнения в запас. Периодически и без раскрытия деталей, интересовался у разных специалистов на тему технической возможности и обоснованности подхода. Саму идею держал в глубоком секрете и не поделился ею даже с Александром Гуминым, только расплывчато указав ему, что нашел очень простое решение как увеличить количество цветов с сохранением обратной совместимости. Выйдя на “гражданку” в 1997м году и устроившись работать инженером-программистом второй категории в питерской компании “Информационные Технологии и Модели”, я начал помаленьку интересоваться вопросом коммерциализации решения. У меня почему-то была уверенность, что стоит только заикнуться о найденном решении, как все начнут рвать с руками и потоком польются деньги. Я начал обзванивать известных, на тот момент в области "спектрумостроения", производителей и коммерсантов, таких как Сергей Зонов, Вячеслав Скутин (Nemo) и прочих. Сергей Зонов сказал мне просто, что "поезд уже ушел" и никакого коммерческого смысла в этой затее больше нет. Вячеслав Скутин, будучи ортодоксальным спектрумистом, воспринимал в штыки любую идею, в которой пытались что-то поменять в платформе и это был тоже совершенно мертвый вариант. Я решил, что разговоров мало и надо сделать хоть что-то и лучше всего начать с эмулятора, что-бы получить промо-материалы и экспериментальные данные. В 1998м, взяв за основу один из существующих на тот момент open-source эмуляторов ZX-Spectrum написанных на Pascal, я сделал примитивный эмулятор работающих параллельно четырех компьютеров. Под него частично адаптировал игру After The War 2, раскрасив некоторые её спрайты. Система заработала и помимо наслаждения от работающей идеи, я получил в свое распоряжение скриншоты, подтверждающие идею расцветки существующих игр. В 1998м году, я посетил компанию “Петерс”, которая разрабатывала в тот момент свою новую платформу Sprinter. Проделал попытку заинтересовать их директора Николая Носкова. Они сильно вложились в новую разработку и, по закону подлости, супер-гибкая архитектура Sprinter, способная эмулировать практически любую однопроцессорную платформу на Z80, не могла вытянуть четыре процессора. Однако посещение этой компании было очень полезным, так как познакомился с автором платформы Sprinter Иваном Макарченко и узнал про новые возможности в сфере разработок на ПЛИС. Вскорости "жахнул" кризис 1998го года и появилась наивная надежда на то, что интерес к ZX-Spectrum может возродиться. В начале 1999го года у нас (с моим компаньоном на тот момент - Андреем Савичевым) даже были планы по созданию “Национального Фонда Спектрума” и на эту тему прошло одно собрание в новом офисе всё той же компании “Петерс”. Но в одну реку дважды не входят и конечно ничего не вышло. Уже в 1999м году, все идеи на тему аппаратной реализации платформы были отброшены (над этой разработкой мы работали вместе с Сергеем Егоровым, но дальше схем не ушло). До 2007го года, я практически не занимался платформой, но появилось время и решил переписать эмулятор и проработать детали платформы, проверив подходы пускай и "виртуально".

В монохромном режиме это требует всего 6144 байт, что примерно 10% от общего поля памяти (против 50% на БК-0010). Стандартный видеорежим ZX-Spectrum, отображает 256 на 192 пикселя. Палитра состоит из восьми цветов и двух оттенков. Цветовая информация хранится в дополнительных 768 байтах, расположенных сразу за данными пикселей. Цвет засвеченного и сброшенного пикселей определяется сразу для блока 8 на 8 пикселей, а оттенок определяется сразу и для цвета засвеченного и сброшенного пикселей.

Малейшая несогласованность в графике приводит к конфликту атрибутов. Смотрится красочно и относительно небольшой объем данных пересылается очень быстро, но требует неимоверных усилий и искусства от художников и программистов при разработке цветных игр и заставок. Большинство разработчиков, отлично делали свое дело и на фоне БК-0010, с её всего четырьмя цветами (но для каждой точки!), спектрумовская квази-цветность смотрелась очень выигрышно и свежо.

пример ZX-Spectrum атрибутов

Программисты быстро нашли способ получать многоцветность при помощи очень быстрой смены отображаемых видео-страниц и динамической смены цвета атрибутов. С развитием платформы до ZX-Spectrum 128, была добавлена возможность аппаратного переключения между двумя страницами видео-памяти.

За счет этого удавалось даже программно поднимать разрешение экрана (что отлично показано например в деме "Dead Morose", где одновременно бежит текст с разрешением в 256, 512 и 768 точек по горизонтали).

Какого-то неиспользованного источника резервов вычислительных мощностей в системе не было. Но любые программные решения, требующие увеличения потока видеоинформации, приводили к росту потребления процессора, что в случае динамических игр весьма критично. На процессоре в ZX-Spectrum висит всё и небольшую разгрузку ему дает, разве что, музыкальный процессор в области звуковых эффектов.

Полученные данные из собственной видео-памяти каждого процессора должны были интегрироваться, формируя YRGB значение для каждого пикселя. Моя идея состояла в том, что можно добавить еще три процессора, перекинув на каждый из них обработку своего цветового компонента. Параллельная обработка информации должна обеспечивать отсутствие проседания производительности. Стандартные цветовые атрибуты при этом игнорируются.

Схема формирования цвета в ZX-Poly 256x192

Да и по ТРИЗ это просто переход от моно-системы к поли-системе. Не могу сказать, что был оригинален в идее, так как на неё меня сподвигло прочтение переводной книги “Компьютер обретает разум” (изд-во "Мир", 1990), где описывалась некая графическая платформа Pixar разработанная в "Lucasfilm".

участок страницы из книги "Компьютер обретает разум"

(в частности на этот "подводный камень" натолкнулась платформа Sprinter). Очень болезненный вопрос для любой разработки — а кто будет писать программы? По моим расчетам получалось, что большинство существующих игровых программ могли достаточно спокойно пережить адаптацию своих видео-данных без изменений в исполняемом коде. В моем случае, вопрос с программным обеспечением автоматически решался через то, что очень нечасто уже существующие программы проверяли какие именно данные они записывали в видеопамять и просто работали с ними "как почтальон с запечатанным письмом". Адаптация таких программ потребовала бы исследования и переделки исполняемого кода. Конечно отсекались игры имеющие паковку графики или внутренние оптимизации в её выводе на экран. Разработка специализированного ПЗУ и вовсе не требовалась.

Думаю, что эта концепция применима к любой старой бытовой платформе (например АГАТ, Радио86РК, БК-0010 и т.п.), где отсутствует выделенный видео-акселератор и процессор напрямую работает с видеопамятью, формируя картинку.

Но то, что легко имитировать на эмуляторе, на реальном железе повторить очень непросто. В первой версии эмулятора, я просто сделал синхронно работающие четыре ZX-Spectrum 48. Схожее решение Spec256 вводит для этого специализированный виртуальный 64 битный SIMD Z80, которого не существует в природе. Достаточно сложно обеспечить загрузку данных в четыре вычислительных модуля и сделать синхронный старт с одного и того же адреса. В рамках более реалистичного (и более сложного) решения этой задачи и была сформирована платформа ZX-Poly.

Процессорные модули

Каждый модуль имеет свои видимые извне адресуемые системные IO порты. ZX-Poly это вычислительная платформа на базе ZX-Spectrum 128 содержащая четыре процессорных модуля. Процессорные модули хоть и разделяют системные управляющие сигналы (RESET, NMI, CLK и INT), но работают независимо.

Блок схема

Доступ по записи в системные порты модуля разрешен только модулю с таким же или более высоким рангом, ограничений на чтение нет. Присутствует некая ранжируемость зависящая от индекса модуля — чем меньше индекс, тем выше ранг, соответственно "модуль 0" это master в системе. Это было сделано, так как присутствовали мысли о разработке специализированной ОС.

Ранжированность модулей

Очень важная деталь — все используемые процессорные устройства, должны быть одного производителя (и было бы неплохо — одной производственной серии), так как малейшая разница в их внутренней организации или оптимизация, может нарушить согласованность работы системы.

Сразу после старта системы, запускается только master-модуль (CPU0), остальные модули находятся в режиме WAIT, поэтому для пользователя всё проходит малозаметно.

В IO пространстве, ZX-Poly добавляет следующие порты доступные на запись и чтение:

  • главный конфигурационный порт $3D00
  • модуль 0 — $00FF, $10FF, $20FF, $30FF
  • модуль 1 — $01FF, $11FF, $21FF, $31FF
  • модуль 2 — $02FF, $12FF, $22FF, $32FF
  • модуль 3 — $03FF, $13FF, $23FF, $33FF

В него может писать только модуль-master, но на чтение он доступен всем модулям и каждому возвращается его собственная специализированная информация. Основной конфигурационный порт ZX-Poly — $3D00. Так же, небольшие изменения претерпел конфигурационный порт базовой платформы $7FFD, у которого задействованы неиспользованные в оригинале биты. В частности модуль может узнать свой индекс, замаппирована ли его память на IO порты главного модуля, смещение своей памяти в куче и т.п.

Память

Если организация и работа с ПЗУ практически не претерпела изменений, то ОЗУ превратилось в общую "кучу" размерностью 512 Кб, в которой каждый процессор работает с выделенным 128 Кб окном (это 8 страниц по 16 Кб в ZX-Spectrum 128). Как и в оригинальной архитектуре ZX-Spectrum 128, присутствуют ПЗУ и ОЗУ. ПЗУ может быть отключено и на его место будет подключена страница ОЗУ RAM0 (это позволяет сделать "полноцветную" версию базовой ОС, например интерпретатор бейсика). Смещение окна можно изменять с шагом в 64 Кб и можно спроецировать все процессорные модули на работу с полностью или частично перекрывающимся участком памяти в "куче". После аппаратного RESET, все модули получают автоматические смещения на непересекающиеся окна памяти в "куче".

Т.е. Процессорный модуль master (CPU0), имеет возможность маппировать адресные пространства других модулей (CPU1-3) в область своих IO портов. При чтении из ячеек памяти маппированного модуля, возможна генерирация INT. он может писать в порт, меняя состояние ячейки памяти у заданного модуля, причем при этом возможна генерация NMI сигнала на маппированный модуль. Это было сделано для возможности эмуляции виртуальных устройств при помощи модулей 1-3.

Видео-контроллер

Всего платформой поддерживаются пять видео-режимов. Основная "вишенка" это конечно видео-контроллер, ради него всё и затевалось.

Видео-режимы ZX-Spectrum 128 (mode 0,1,2,3)

Выводится текущая видео-страницу выбранного процессорного модуля с атрибутной раскраской. Эти видео-режимы ничем не примечательны и совершенно не отличаются от стандартного видеорежима ZX-Spectrum 128. выводится видео-страница master-модуля (CPU0). Сразу после старта системы, активирован mode 0, т.е.

ATW2 в стандартном ZX режиме

ZX-Poly 256x192 (mode 4)

Пиксель-бит каждого модуля комбинируется с пиксельными данными из других модулей и сформированные четыре бита, используются для формирования цвето-яркостного YRGB сигнала. Данный видео-режим вообще не использует каких либо данных из области атрибутов.

Каждый модуль отвечает за свой компонент:

  • модуль 0 (master) за Green (зеленый).
  • модуль 1 за Red (красный)
  • модуль 2 за Blue (синий)
  • модуль 3 за яркость

расцвеченная версия

Если в таком режиме запустить неадаптированную игру, то она будет просто черно-белая.
неадаптированная игра

ZX-Poly 256x192 с маскированием по INK+PAPER (mode 6)

В некоторых программах ZX-Spectrum, графические элементы скрываются при помощи идентичных значений INK и PAPER в атрибутах, особенно это практикуется в играх-скроллерах. Как и предыдущий, предоставляет 16 цветов для каждой точки, но имеется одна "хитрость". Поэтому анализируется состояние INK и PAPER из атрибута считанного из видео-памяти master-модуля (CPU0) и если они идентичны, то все точки засвечиваются цветом взятым из INK/PAPER (конечно с учетом яркости). Если убрать такую возможность, то графические элементы начинают скапливаться на экране, ломая картинку.

ZX-Poly 256x192 с маскированием по FLASH+INK+PAPER (mode 7)

У считываемых атрибутов master-модуля (CPU0), анализируется бит FLASH и если он выставлен (что в динамических играх достаточно редко на игровом поле), то блок 8 на 8 пикселей выводится в режиме mode 6 (с маскированием при идентичных INK и PAPER). Режим — комбинация mode 4 и mode 6. Бит FLASH не отрабатывается в его прямой роли и включенного режима мерцания не будет.
Этот режим очень удобен для избежания перекрашивания игровых информационных панелей и некоторых внутриигровых эффектов (например когда разработчики игры делают вспышку на игровом поле через атрибуты). Если FLASH сброшен, то блок выводится как на обычном ZX-Spectrum.

Animated adapted Flying Shark

ZX-Poly 512x384 с атрибутами (mode 5)

Видео-данные пикселей каждого модуля раскрашиваются атрибутом из видео-памяти данного модуля и пройдя раскраску, выводятся на экран в шахматном порядке, из-за чего один блок знакоместа получается 16 на 16 точек. Атрибуты используются практически так же, как в оригинальной платформе, без каких либо изменений (даже бит FLASH).

формирование шахматки

Правда эксперименты с той же игрой «Буратино», показали, что на ярких играх с крупными деталями, эффект будет слабо заметен. Этот режим позволяет увеличить разрешение приложений вдвое, без изменений в исполняемом коде. Думаю, что этот режим хорош для игр с маленькими игровыми объектами в знакоместо. Поскольку это своего рода виртуальные пиксели, то игры об этом ничего не знают и минимально-возможное перемещение игровых элементов идет на уровне двух виртуальных пикселей.

пример игры "Буратино"

Гораздо лучший эффект в этом видео-режиме был получен на текстовых приложениях, например на текстовом редакторе ZX-Word, где только обработан фонт без изменений в исполняемом коде.

адаптированный ZX-Word

Многозадачность

Систему нельзя назвать полноценной SIMD, так как каждый процессор обрабатывает инструкции из своего блока памяти, просто используется возможность "подсовывать" одинаковые инструкции. Несмотря на то, что процессоры в системе используют один и тот же источник управляющих сигналов, они работают независимо. Если один из процессоров встретит в памяти отличающуюся команду, то "его пути разойдутся" с остальными и в случае адаптированной игры — картинка расслоится.

Пример рассинхронизации

Для упрощения, были добавлены механизмы примитивной синхронизации. Потенциально можно расчитывать пути выполнения потактово и добиваться как расхождения, так и схождения потоков выполнения, но это очень сложно и наверное интересно только "демосценерам".

Механизмы синхронизации

Локальный RESET

Это позволяет выполнить команду JP ADDR переведя все модули синхронно на одну и туже ячейку памяти. Этот механизм позволяет одновременно послать сигнал RESET на все процессорные модули, но первые три байта будут каждым модулем считаны из своих внутренних портов.

Стоп-адрес

В порты модуля можно записать определенный адрес, при выполнении команды на котором (определяется по сигналу M1), на процессоре модуля будет установлен локальный сигнал WAIT, который будет активен до момента смены этого адреса в портах или прохождения общесистемного или локального RESET. Это механизм для всех модулей кроме master-модуля (CPU0). Есть возможность считывать последний исполненный модулем адрес, но достаточно условно, так как 16 битный адрес пакуется в байт.

В его рамках были написаны подсистемы процессора Z80 (с потактовой эмуляцией и покрытием команд юнит-тестами) и FDD контроллера К1818ВГ93. В 2007м на JavaSE была написана новая версия эмулятора. 8+. Для работы приложения требуется JDK 1.

Окно эмулятора

Так же он может использоваться как эмулятор обычного ZX-Spectrum 128, для этого надо включить режим Options->ZX 128 Mode, при этом подсистема ZX-Poly в эмуляторе блокируется для повышения совместимости. Эмулятор был разработан для проверки совместимости платформы с существующим программным обеспечением ZX-Spectrum и портами устройств и в целом он показал, что 80% запущенных программ работают, не конфликтуя с нововведениями.

Но его можно загрузить через интернет, выбрав в меню File->Options В комплекте с эмулятором поставляется только тест-ПЗУ, поскольку официальное ПЗУ ZX-Spectrum — объект авторского права.

ZX-Poly test ROM

Требуется соблюдать осторожность при наличии оптимизаций в исполняемом коде вывода спрайтов, так как это может приводить к рассинхронизации процессорных модулей. Если игры не используют какие-то паковки спрайтов, то расцвечивание происходит достаточно просто.

Его код для TAP и TR-DOS представлен в проекте. Был разработан загрузчик, для подгрузки данных в модули с диска и одновременного синхронного старта.

Пример работы загрузчика

Вместе с эмулятором была разработана небольшая (тоже написанная на Java) утилита для раскраски приложений.

ZX-Poly корректор спрайтов

Весь проект опубликован на GitHub под лицензией GNU GPLv3.

Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть