Лисья Нора

Оглавление


§ Модель видеопамяти

В этом главе уже начинается рассказ о том, как запрограммировать великий Спектрум (хвала ему), чтобы он мог находить видеоадреса. Я рассмотрю 2 независимых варианта, а то есть, вычисление видеоадреса для X=0..31, Y=0..23 в текстовом режиме и X=0..255, Y=0..191 в режиме графическом.
Видеопамять у Спекки странная, конечно, но вполне постижимая. Необходимо научиться транслировать сначала Y, поскольку он самый трудный для понимания.
Общий формат 16-битного видеоадреса:
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 1 0 Y[7:6] Y[2:0] Y[5:3] X[4:0]
Здесь X и Y – это задаваемые параметры. В данном случае X может быть от 0 до 31, поскольку видеоадрес задается по 1 байту, который равен 8 точкам. А вот значение Y задается от 0 до 191 и важно следить, чтобы он не "уплыл" за 191, а то он может. Если это случится, то начнется сначала закрашивание области атрибутов, а потом вообще и данные попортить может.
Как можем заметить, распределена память очень неравномерно. Введем обозначения:
Если написать это в Си-стиле, то получится примерно следующее
word get_video_address(byte X, byte Y) {
 
return (X & 31) // Помещение X в биты 0..4
| ((Y & 7) << 8) // Y[0..2] в биты 8..10
| (((Y>>3) & 7) << 5) // Y[3..5] в биты 5..7
| (((Y>>6) & 3) << 11) // Y[6..7] в биты 11..12
| 0x4000;
}
В принципе ничего трудного, просто немного сдвиговой магии.

§ Вычисление курсора текста

Вычисление текстового курсора основывается на том же самом принципе, что и вычисление графического, но с тем отличием, что мы не будем заполнять биты 8-10 для видеоадреса, они будут равны 0. Значимыми битами останутся Y[3..7], то есть получается, что для курсора, который двигается по 8 пикселей, нижние 3 бита Y[0..2] просто опускаются. Потому новый вид будет такой:
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 1 0 Y[3..4] 0 Y[0..2] X[0..4]
7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
H L
Приведу текст программы
word get_text_cursor_address(byte X, byte Y) {
 
return (X & 31) // Помещение X в биты 0..4
| ((Y & 7) << 5) // Y[0..2] в биты 5..7
| (((Y>>3) & 3) << 11) // Y[3..4] в биты 11..12
| 0x4000;
}
Как видно из кода, допустимый диапазон Y=0-31, но, конечно же, он реально равен 0-23,
т.к. превышение диапазона будет грозить артефактами и ошибками в данных.
Пришло время транслировать программу в ассемблер Z80
; Вход: B(Y=0..23), C(X=0..31)
; Выход: HL(адрес)
get_text_cursor_address:
 
ld a, c
and 0x1F
ld l, a ; L = X & 31
ld a, b
and 0x07 ; Нужно ограничить 3 битами
rrca ; Легче дойти с [0..2] до позиции [5..7]
rrca ; Если вращать направо
rrca ; ... три раза
or l ; Объединив с 0..4 уже готовыми ранее
ld l, a ; Загрузить новый результат в L
ld a, b ; Т.к. Y[3..5] уже на месте
and 0x18 ; Его двигать даже не надо
or 0x40 ; Ставим видеоадрес $4000
ld h, a ; И загружаем результат
ret
Ассемблер конечно сложен для понимания, но эта программа не должна быть очень сложной.

§ Код вычисления позиции Y

Этот код почти полностью повторяет выше приведенный, с некоторыми поправками на то, что
Y теперь находится в диапазоне от 0 до 191.
; Вход: B(Y=0..191), C(X=0..31)
; Выход: HL(адрес)
get_graphics_address:
 
ld a, c
and 0x1F ; L[0..4] = X >> 3
ld l, a ; Y[0..2]
ld a, b
and 0x07
ld h, a ; Установка => H[0..2]
ld a, b ; Y[3..5]
and 0x38
rlca
rlca
or l
ld l, a ; Ставится в L[5..7]
ld a, b
and 0xC0
rrca
rrca
rrca
or h
or 0x40 ; H устанавливается на видеопамять
ld h, a ; Y[6..7] ставится в H[3..4]
ret
Здесь в этом коде немного непонятно сразу, но в целом он разбит на 5 частей
И видеоадрес готов!
Единственное, что я тут не рассказал, это как рассчитать точку. Но это делается очень просто. Для X[0..2], если мы берем попиксельно, ставится соответствие следующая таблица
Бит Hex Bin C X
0 = 0x01 = 00000001 = 1<<0 | 7
1 = 0x02 = 00000010 = 1<<1 | 6
2 = 0x04 = 00000100 = 1<<2 | 5
3 = 0x08 = 00001000 = 1<<3 | 4
4 = 0x10 = 00010000 = 1<<4 | 3
5 = 0x20 = 00100000 = 1<<5 | 2
6 = 0x40 = 01000000 = 1<<6 | 1
7 = 0x80 = 10000000 = 1<<7 | 0
Тут уж кому как удобнее воспринимать, но в общем-то, это довольно просто.
В данной таблице, при установке бита 0, будет отображен самый правый пиксель (координата X = 7), при установке бита 7 – самый левый (X = 0). То есть, чтобы вывести пиксель, считаем слева направо – от 7 до 0, в таблице это видно визуально.