Программирование графики

Работа с ГЗУ в Корвете полностью отличается от работы с ОЗУ. Авторы придумали и воплотили довольно неплохой, хотя и не слишком интуитивный, графический ускоритель. Благодаря ему однотипные операции над пикселями требуют в несколько раз меньше инструкций процессора.

## Кратко об устройстве ГЗУ

Физически ГЗУ выглядит как три блока 8-разрядной памяти по 64К каждый, каждый такой блок называется плоскостью или слоем. Плоскости разделены на четыре страницы по 16К (512x256 = 16K):

```
              стр.0    стр.1    стр.2    стр.3
Плоскость 1: aaaaaaaa bbbbbbbb cccccccc dddddddd
Плоскость 2: aaaaaaaa bbbbbbbb cccccccc dddddddd
Плоскость 3: aaaaaaaa bbbbbbbb cccccccc dddddddd
             ^                                 ^
          0x0000                            0xFFFF

```

Плоскости очень условно можно назвать R, G и B: если установить бит во всех трех блоках, то на экране появится белая точка.

Любая страница ГЗУ]может быть отображена на экране и/или подключена к адресному пространству процессора для операций записи/чтения. Практически это можно использовать как backbuffer, когда картинка формируется в "теневой" видеопамяти, а по готовности выводится на экран: так анимация выглядит более плавной. Но можно работать и непосредственно с отображаемой областью: у режимов нет никаких накладных расходов.

## Переключение страниц ГЗУ

За переключение страниц отвечает регистр PAGREG с нижним адресом 0x3A. Так как регистры отображены на ОЗУ, то запись в регистр это просто запись в ячейку памяти. Константы управления страницами:

```
    VPAGE0  EQU  00000000B  ; Выбор 0 страницы отображения
    VPAGE1  EQU  00000001B  ; Выбор 1 страницы отображения
    VPAGE2  EQU  00000010B  ; Выбор 2 страницы отображения
    VPAGE3  EQU  00000011B  ; Выбор 3 страницы отображения

    RWPAG0  EQU  00000000B  ; Выбор 0 страницы чтения/записи
    RWPAG1  EQU  01000000B  ; Выбор 1 страницы чтения/записи
    RWPAG2  EQU  10000000B  ; Выбор 2 страницы чтения/записи
    RWPAG3  EQU  11000000B  ; Выбор 3 страницы чтения/записи

```

## Управление цветами

В Корвете можно переназначать цвета, для чего служит регистр LUT - таблица трансляции 4-битных графических пикселей в 4-битный цвет. Важная особенность в том, что этот регистр доступен для перепрограммирования.

Путь пикселя от памяти до монитора поверхностно выглядит так:
1. Электронная схема запрашивает четыре бита из ГЗУ и АЦЗУ:

```
    b1 = Плоскость0 / Байт 11 / Бит0
    b2 = Плоскость1 / Байт 11 / Бит0
    b3 = Плоскость2 / Байт 11 / Бит0
    b4 = БитмапАЦЗУ / Байт 11 / Бит0

```

2. Эти четыре бита подаются на микросхему LUT:

RGBI = LUT(b1, b2, b3, b4)
3. Внутри LUT хранится таблица соответствия (Look-Up Table). Например, такая:

```
    b1 b2 b3 b4		R G B I
     0  0  0  0         0 0 0 0   черный
     0  0  0  1         1 1 1 0   белый текст
     1  1  1  0         1 1 1 0   белый графический пиксель
     0  0  1  0		1 0 1 0   фиолетовый графический пиксель
     0  0  1  1         0 1 0 0   наложение пикселя на текст -> зеленый

```

4. Значение RGBI из LUT поступает на RGB-монитор

### Программирование LUT

Для переназначения цветов в LUT надо сформировать управляющее слово и записать его в ячейку с нижним адресом 0xFB.

```
Формат управляющего слова:
    D0…D3	комбинация пикселей (0000...1111)
    D4…D7	сигналы BGRI для монитора (0000...1111)

Например,
    00000000B   если нет пикселей - черный цвет на экране
    00011110B   текст - белый цвет

```

## Запись в ГЗУ

Из-за графического ускорителя, запись в ГЗУ выглядит не так, как в других компьютерах:

* сперва необходимо решить, в каком режиме будет запись: в цветовом или послойном
* сконфигурировать цветовой регистр NCREG
* сформировать "маску": это байт, где единицами отмечены точки, которые будут изменены в ГЗУ
* записать маску в ГЗУ

Звучит странно, но на практике довольно просто.

### Послойный доступ к ГЗУ

Задача: выключить в точках xy(112,136) и xy(119,136) биты во всех трех плоскостях.

"Сконфигурировать NCREG" это, как всегда, записать в ячейку памяти с нижним адресом 0xBF нужное управляющее слово. Пошаговая подготовка управляющего слова:

* Чтобы включить послойный режим, в старший бит NCREG надо записать 0:

**0**1111111B
* Решить, в какие слои ГЗУ будет произведена запись. По задаче - во три слоя:

0111**000**1B
* Какое значение бита надо записать? По задаче - выключить биты, поэтому ноль:

0111000**0**B
* Управляющее слово готово, это число **0x71**.

Теперь сформировать маску. Вычисляем адрес в ГЗУ, где находятся точки, по формуле addr = x/8 + y\*(512/8) :

* xy(112,136) => 112/8 + 136\*(512/8) = 14 + 8704 = 8718
* xy(119,136) => 119/8 + 136\*(512/8) = 14 + 8704 = 8718

Обе точки находятся в одной 8-битной ячейке ГЗУ, только первая точка - старший бит, а вторая - младший. Чтобы сделать маску, надо взять нулевой байт 00000000B и поставить единицы там, где в ГЗУ должны быть внесены изменения: **1**000000**1**B

Осталось выполнить задание - погасить точки:

```
POKE NCREG, 0x71       ; послойный режим; все три слоя; выключить пиксель
POKE GZU+8718, 0x81    ; применить команду выше к битам 0 и 7 (0x81 -> 10000001B)

```

Состояние всех трех слоев ГЗУ по адресу 8718 до операции записи маски:

```
Слой0: 10110010
Слой1: 00011111
Слой2: 11111111

```

Состояние слоев после операции записи:

```
Слой0: 00110010
Слой1: 00011110
Слой2: 01111110

```