Как известно, проект PentEvo задумывался как реализация прототипа ATM3 и, соответственно, повторял конфигурацию предшественников ATM-Turbo и Turbo 2+. И, в первую очередь, это коснулось расширенного графического режима. В ATM расширенный графический режим один и представляет собой 320x200 точек каждая своим цветом. Одновременно могло отображаться 16 цветов фиксированной палитры состоящей из 64х доступных цветов. Это ограничение (64 цвета) так же было перенесено в современную архитектуру — PentEvo(ZX Evolution) на базе плис ALTERA.
Для этой цели с чипа EP1K50Q208(АLTERA) было выделено по две ноги на каждый канал RGB (красный, зелёный и синий), что позволило реализовать 64-х цветную палитру, состоящую из 6bit (%00111111). Каждый канал(RGB) может принимать четыре бинарных значения: %00, %01, %10, %11 и, соответственно, иметь 4 градации яркости:
В левой части таблицы (dec/hex) приведены приблизительные эквиваленты цветов на PC в диапазоне от 0 до 255.
Таким образом, из 6 бит мы получаем комбинацию 64 цветов в виде такой палитры:
Не смотря на ограничения в 6 bit, в конфигурации от TS-Labs реализован видео-ШИМ, при котором стало возможно одновременное отображение до 15625 оттенков (по 25 градаций на каждый из основных цветов). К уже имеющимся 2 битам на цветовой канал добавились ещё три бита ШИМ, и палитра стала состоять из 15 бит. На каждый из основных цветов выделено 5 бит в палитре. Валидные значения: 0-24 (%00000 – %11000 или #00 – #18).
В результате преобразования мы получаем такую таблицу:
Первая колонка (от 0 до 24) – это 25 цветов 15-битной палитры, вторая колонка – это 2 бита базового цвета (без ШИМ), третья — старший бит ШИМ, четвёртая 2 младших бита ШИМ. Далее три цветовых колонки и завершает таблицу колонка с примерным аналогичным значением цвета на PC (от 0 до 255).
Для чего так разделены биты и сгруппированы цвета (зелёная колонка, желтая и красная)? Дело всё в том, что, как уже было сказано выше, из-за ограничения в 2 бита на канал видео-ЦАП PentEvo может отобразить только 4 градации яркости (0%, ⅓, ⅔ и 100%). С помощью ШИМ достигается большее количество оттенков путем создания мелкой текстуры из соседних градаций. (Размер суб-пикселя текстуры равен 1/8 размера спектрумского пикселя.) Это неплохо отображается на CRT-дисплеях (трубках), но на LCD, из-за оцифровки видеосигнала, происходит интерференция между суб-пикселями текстуры и частотой видео-АЦП; суб-пиксели превращаются в жирные линии.
В зелёной колонке приведены основные цвета видео-ЦАП без текстуры (единственные, которые отображаются на LCD нормально), в жёлтой – цвета с текстурой в виде шахматки, которые на CRT отображаются как сплошные, в красной – цвета, которым соответствуют текстуры, которые даже на CRT слегка заметны, как мелкая сетка.
Однако не всё так плохо, можно рисовать графику базовыми цветами (зелёная колонка), делать сглаживание (antialiasing) с помощью цветов из жёлтой колонки и, если уже будет совсем не хватать цветовых переходов, — воспользоваться группой цветов из красной колонки.
Теперь, когда с палитрой цветов более-менее всё ясно, можно перейти к графическим режимам. В прошивке от TS-Labs их несколько.
Независимо задаются:
- видео-режим (ZX, 16 цветов и 256 цветов, текстовый),
- графическое разрешение экрана: 256x192, 320x200, 320x240 и 360x288.
Для переключения графических режимов, загрузки палитры, а так же для управления конфигурацией используется системный порт — #xxAF. Рассмотрим несколько значений:
#00AF(175) — VConfig. Видеорежим. Биты 0-1 – режим графики, биты 6-7 – размер рамки (разрешение).
#01AF(431) — VPage. Видеостраница. Диапазон 0-255. Для режима 16 цветов должна быть кратна 8, для режима 256 цветов – кратна 16.
#02AF(687) и #03AF(943) — XOffsL и XOffsH. Младшая (8 бит) и старшая (1 бит) часть смещения изображения по горизонтали.
#04AF(1199) и #05AF(1455) — YOffsL и YOffsH. Младшая и старшая часть смещения изображения по вертикали.
#0FAF(4015) — Border. Цвет бордера.
#15AF(5551) — FMAddr. Выбор адреса и включение маппинга внутренней памяти альтеры (палитра и спрайтовые регистры) в адресное пространство Z80 для записи.
Начнём с загрузки палитры. Для этого необходимо разрешить маппинг палитрового ОЗУ, включив 4-й бит порта FMAddr. При этом, биты 0-3 задают адрес маппинга (например: 0 – #0000, 8 – #8000, 15 – #F000 и т.д.). После включения маппинга с выбранного адреса станет доступно окно для загрузки палитры. Далее с помощью обычного LDIR перебрасываем 512 байт палитры. После пересылки данных необходимо закрыть окно маппинга, сбросив 4-й бит порта FMAddr. Рассмотрим пример:
- Code: Select all
FMAddr EQU #15AF
LOAD_PAL LD A,%00010000 ; Включаем маппинг по адресу #0000
LD BC,FMAddr
OUT (C),A
LD HL,ZXPAL ; Перебрасываем данные (32 байта)
LD DE,#0000
LD BC,#0020
LDIR
XOR A ; Отключаем маппинг
LD BC,FMAddr
OUT (C),A
RET
ZXPAL dw #0000,#0010,#4000,#4010,#0200,#0210,#4200,#4210
dw #0000,#0018,#6000,#6018,#0300,#0318,#6300,#6318
В данном примере заданы лишь первые 16 цветов (32 байта) стандартной ZX Spectrum палитры. Рассмотрим структуру более подробно в таблице:
Как видно из таблицы, на описание одно цвета отводится 15 бит (или 2 байта). 16-й бит не используется, далее идут два бита (RR) красного канала (основной цвет) и три бита (rrr) красного канала ШИМ. Далее структура повторяется соответственно для зелёного и синего каналов.
UPD: Небольшое дополнение. При включении режима 16 цветов, необходимо с помощью PalSel (#07af) выбрать какую группу из 16 палитр (256/16=16) следует использовать. Для этого отведены биты 0-3 PalSel. (Биты 4-7 используются для выбора группы палитр в тайловых плоскостях, здесь не рассматриваются.) Например, если мы хотим использовать ячейки палитрового ОЗУ с 0й по 15й, то в порт PalSel необходимо записать 0. Если ячейки 16-31 — то 1 и.тд.
Для режима ZX по умолчанию используются ячейки #F0-#FF (значение бит 0-3 PalSel - 15), и набор ZX цветов в них записывается биосом. Пример:
- Code: Select all
LD A,%00000000 ; T1PAL[7:6] T0PAL[7:6] GPAL[7:4] Palette selection for 4 bit modes
LD BC,PalSel ; GPAL 0-15 colors
OUT (C),A
Теперь, когда мы разобрались с загрузкой палитры, давайте посмотрим на структуру экрана в различных графических режимах.
Для того, что бы включить интересующий нас графический режим, необходимо через порт VPage(#01AF) задать страницу видеопамяти, и затем, через VConfig(#00AF) задать интересующий нас видеорежим.
Данные для VConfig имеют следующую структуру:
биты 6-7 задают размер пиксельного окна:
- Code: Select all
%00 – 256x192
%01 – 320x200
%10 – 320x240
%11 – 360x288
Биты 0-1 задают режим графики:
- Code: Select all
%00 – ZX (Стандартный режим ZX Spectrum)
%01 – 16 цветов (4 бита на 1 пиксель)
%10 – 256 цветов (1 байт на 1 пиксель)
%11 – текстовый режим (в данном описании не рассматривается)
Рассмотрим пример:
- Code: Select all
LD BC,VPage ; Указываем системе, что видеопамять начинается с #10
LD A,#10 ; Номер страницы
OUT (C),A
LD BC,VConfig ; Включаем видеорежим: %11-360x288, %10-256 цветов
LD A,%11000010
OUT (C),A
После «активации» данного видеорежима всё содержимое памяти, начиная со страницы #10, будет считаться видеопамятью, и мы получим замечательный цветной мусор на экране:
Видеопамять представляет собой битмап размеров 512x512 пикселей. Битами 6-7 порта #00AF мы задаём размер видимого окна, а регистрами оффсетов – положение окна на битмапе. Оффсеты зациклены по обеим осям. Изменяя значения оффсетов, мы двигаем окно монитора по битмапу, достигая эффекта скроллирования графического поля. При любом размере окна за границами видимости всегда остается часть битмапа, что позволяет незаметно перерисовывать графику, например, при движении игровой карты.
После RESET значения оффсетов равны 0, 0.
Рассмотрим пример, в котором каждое прерывание экран циклично смещается на 1 точку вправо:
- Code: Select all
VPage EQU #01AF
VConfig EQU #00AF
XOffsL EQU #02AF
XOffsH EQU #03AF
LD BC,VPage ; Указываем системе, что видеопамять начинается с #20
LD A,#20 ; Номер страницы
OUT (C),A
LD BC,VConfig ; Включаем видеорежим: %11-360x288, %10-256 цветов
LD A,%11000010
OUT (C),A
EI
LD HL,#0200 ; Задаём начальное смещение 512 pix
Loop HALT
LD BC,XOffsL ; Устанавливаем младший байт
OUT (C),L
LD BC,XOffsH ; Устанавливаем старший байт
OUT (C),H
DEC HL ; Уменьшаем позицию
LD A,H
OR L
JR Z,Loop-3 ; Если дошли до 0 инициализируем значение заново
JR Loop
Изображение скроллируется по кругу, поэтому пока отображается видимая часть на скрытой части можно достроить новый пейзаж или вывести текст. Так же (циклично) изображение скроллируется по вертикали, только для этого необходимо изменять значения YOffsL и YOffsH.
Значения битов 1-7 старшего байта оффсета игнорируются.
Для описания одной точки в 256-цветном режиме отводится 8 бит(1 байт) поэтому 1 страница (16Кб) описывает блок 512x32 точки. В свою очередь для описания точек в 16-цветном режиме отводится 4 бита, то есть 1 байт уже описывает 2 точки. Поэтому 1 страница хранит информацию блока 512x64 точки. Это наглядно видно в приведённой выше таблице, для 256-цветного режима используется 16 страниц по 16Кб = 256Кб, для режима в 16 цветов используется 8 банок по 16Кб = 128Кб.
Теперь рассмотрим пример, как поставить точку в координатах 0, 0. Для этого мы включим 256-цветный режим, разрешение 320x240, очистим часть экрана и разместим байт #02 (2й цвет в палитре - красный) по адресу #С000. Для очистки экрана нам понадобится ещё один порт RAMPage3 (#13AF), с помощью которого мы подключим интересующую страницу памяти в окно с адреса #С000. Так же есть ещё три порта RAMPage0 (#10AF), RAMPage1 (#11AF) и RAMPage2 (#12AF) с помощью которых задаются номера страниц в окнах #0000-#3FFF, #4000-#7FFF и #8000-#BFFF соответственно.
- Code: Select all
VPage EQU #01AF
VPage EQU #01AF
VConfig EQU #00AF
RAMPage3 EQU #13AF
LD BC,RAMPage3 ; Подключаем страницу #20 с адреса #С000
LD A,#20
OUT (C),A
LD HL,#С000 ; Очищаем часть видеопамяти
LD DE,#С001
LD BC,#3fff
XOR A
LD (HL),A
LDIR
LD BC,VPage ; Включаем видеопамять со страницы #20
LD A,#20
OUT (C),A
LD BC,VConfig ; Включаем видеорежим: %10-320x240, %10-256 цветов
LD A,%10000010
OUT (C),A
LD A,#02 ; Указываем цвет пикселя = номер цвета в палитре (2=красный)
LD HL,#C000
LD (HL),A
JR $
Немного модифицировав, получим пример для режима в 16 цветов:
- Code: Select all
LD BC,VConfig ; Включаем видеорежим: %10-320x240, %01-16 цветов
LD A,%10000001
OUT (C),A
LD A,#21 ; Указываем цвета пикселей (2=красный, 1=синий в палитре)
LD HL,#C000 ; биты 4-7 – левый пиксель, биты 0-3 - правый
LD (HL),A
В заключении упомяну ещё один порт Border (#0FAF). В отличие от стандартного порта #FE (254), здесь задается номер цветовой ячейки палитры, в цвет которой будет окрашен бордюр. Аппаратно, при записи в порт #FE происходит запись порта #0FAF значениями из диапазона #F0-F7, где 0-7 – значения битов 0-2 порта #FE при записи.
Стандартная палитра для режима ZX хранится в ячейках палитрового ОЗУ #F0-F7 для цветов с BRIGHT=0 и в #F8-FF для цветов с BRIGHT=1.
UPD: Для того, что бы не было сложностей с попаданием в такты, применение новых значений для портов (VConfig, VPage, GXOffsL, GXOffsH, GYOffsL, GYOffsH, PalSel) задержано до начала новой (следующей) тв-строки.
p.s. в атачменте исходники и готовые файлы $c.
p.p.s. отдельное спасибо TS-Labs за исправления и дополнения материала.