ZX-Ревю 1992 №7-8 1991 г.

Элементарная графика в машинных кодах - организация экранной памяти.


Темы статьи: Программирование  

Организация экранной памяти.

Область оперативной памяти "Спектрума", в которой находится графическое изображение, видимое на экране в качестве включенных и выключенных точек (пикселов), называется экранной областью памяти.

Эта область занимает адреса с 4000Н по 5AFFH (16384 - 23295). Причем, она состоит из двух областей. В первой с 4000Н по 57FFH (с 16364 по 22537) расположено растровое изображение, состоящее из черных и белых неокрашенных точек (дисплейный файл). Во второй, с 5800Н по 5AFFH (с 22528 по 23295) - цветовая информация (файл атрибутов).

Размер всей экранной области - 6912 байтов. Из них 6144 байта - дисплейный файл (черно-белый) и 768 байтов - файл атрибутов (цвет).

Как получены эти числа 6144 и 728?

Вы знаете, что полный экран "Спектрума" может иметь 24 ряда по 32 символа в ряду, т. е. всего 24*32=728 знакомест. Каждое знакоместо образовано из 64-х пикселов (8 линий по 8 точек). На каждую линию достаточно одного байта (8 битов соответствуют 8 точкам) и, следовательно, для растровой графики одного знакоместа необходимы 8 байтов. Так, на 728 знакомест необходимо 728*8=6144 байта для хранения черно-белой информации.

Информация о цвете хранится более экономно. Каждому знакоместу отдан один байт, определяющий окраску всех 64 его пикселов. Три младших бита определяют цвет INK этого знакоместа, еще три бита определяют цвет PAPER и по одному биту отдано признакам BRIGHT и FLASH. Отсюда вытекает одно из самых неприятных ограничений графики "Спектрума" - в пределах одного знакоместа невозможно иметь одновременно более 2-х цветов.

А теперь давайте немного поэкспериментируем. Очистите экран - CLS. Окрасьте бордюр в голубой цвет - BORDER 5. Это нужно, чтобы точно видеть результат следующих манипуляций и дайте команды, задающие самый первый байт экранной области:

POKE 16384,255 POKE 16384,15 POKE 16384,85

После каждой команды вы увидите изменения в левом верхней углу экрана, а точнее -в первой линии первого знакоместа. На рис. 1 показана эта линия укрупненно и Вам должно быть понятно, что и почему там происходит. Вы видите, что раскладка пикселов в этой линии соответствует раскладке битов в байте 16384, отвечающем за эту линию.

7 6 5 4 3 2 1 0

X

X

X

X

X

X

X

X

128 + 64 + 32 +

16 + 8 +

4

+

2 +

1

255

X

X

X

X

8+

4

н

2 +

1

15

X

X

X

X

64

+

16

+

4

+

1

85

Рис. 1.

Теперь попробуем закрасить вторую линию в первом знакоместе. Логично предположить, что POKE в следующую ячейку памяти сделает это. Дайте POKE 16385,85. Получилось совсем не то - включилась первая линия второго знакоместа, далее третьего и так далее, до 32-го. Может быть, попробуем их пропустить и дадим POKE сразу в 33-ий адрес:

POKE (16384*32), 85

И опять ничего не получилось. Вместо второй линии в первом знакоместо включается первая линия в первом знакоместе, но во втором ряду. И так будет продолжаться, пока Вы не пройдете все 32 знакоместа в 8 рядах экрана, т.е. 32*8=256 адресов. Только дав POKE (16384 + 256), Вы получите то, что хотели. На первый взгляд, такое соответствие между точками экрана и ячейками экранной памяти выглядит достаточно нелепым и нелогичным. Но это не совсем так. Как окажется чуть ниже, это не только не усложняет жизнь, а при работе из машинного кода даже упрощает - надо только хорошо все понять.

Теперь, покопавшись в памяти, Вы наверняка вспомните, что уже много раз видели при загрузке заставок игровых программ, как экран прорисовывается постепенно, строчка за строчкой. В этот момент Вы и видели соответствие между структурой экрана и экранной памятью. Хотите повторить, пожалуйста: 10 CLS: BORDER 5 20 FOR i=16384 TO (16384+256*8) 30 POKE i, 255 40 NEXT i

Чтобы не утомлять Вас длительным ожиданием, мы сделали это только для 8 первых рядов экрана.

Научившись изображать на экране точки и тире без помощи операторов PRINT и PLOT, мы уже сделали большое дело и развязали себе руки, т.к. мы теперь умеем манипулируя с ячейками памяти делать графику, а машинный код именно и хорош, когда дело доходит до манипуляций с большими объемами памяти.

Но как насчет того, чтобы получить нормальный графический образ? Нет проблем, этот образ сначала надо где-то в памяти создать. Давайте воспользуемся готовым. Вы, конечно знаете, что в ПЗУ компьютера где-то имеется набор символов, в котором хранятся графические образы (шаблоны) всех букв и прочих знаков, вот мы возьмем оттуда образ буквы "А" и нарисуем ее на экране без PLOT или PRINT.

В адресах 23606, 23607 (5C36H) хранится 2-х байтная системная переменная CHARS, которая указывает на 256 байтов ниже, чем адрес, с которого начинается набор символов. Во-первых, давайте разберемся, почему она указывает ниже на 256 байтов, а не туда, куда надо. Все очень просто. Мы уже говорили о том, что первые 32 символа вовсе и не символы, а управляющие коды и им графические образы не нужны, все равно они не печатаются. А т.к. символы занимают по 8 байтов каждый, то на пропуск этих 32 управляющих кодов и ушло это снижение на 256 байтов. Зато теперь мы можем искать образ буквы A по ее номеру (по ее коду ASCII, который, кстати, равен 65(41Н)). 10 LET base=РЕЕК 23606 + 256*РЕЕК 23607 20 LET addr = base+8+65 25 LET screen= 16384 30 FOR i=0 TO 7 40 LET pic=PEEK (addr+i) 50 POKE (screen+256*i), pic 60 NEXT i

Мы с Вами только что нарисовали букву "А", причем именно нарисовали, а не напечатали, да к тому же работали при этом только с переброской данных из одних участков памяти в другие. Вы обратили внимание на то, что засылали мы графику в дисплейный файл в строке 50 с шагом через 256 адресов? Давайте теперь рассмотрим, как то же самое будет выглядеть в машинном коде и почему так сложно, на первый взгляд, организован дисплейный файл.

Адреса экранной памяти обычно при работе с экраном хранятся в регистровой паре HL. При этом в H хранится старший байт адреса (High - старший), а в L - младший (Low), для того, чтобы увеличить адрес на 256 и перейти к нижележащей линии в том же знакоместе, оказывается достаточно увеличить на единицу старший байт. С этой задачей изящно справляется простая команда АССЕМБЛЕРа INC H. Увеличение же на единицу младшего байта адреса (INC L) переместит Вас на соседнее знакоместо вправо в той же линии. Видите, как все просто, и преобразование вышеприведенной БЕЙСИК-программы в

машинный код выглядит (листинг 4):

ЛИСТИНГ 4.

LOOP

LD DE,(23606)

Загрузили в DE содержимое системной переменной CHARS

LD HL,0041H

Загрузили в HL код буквы А.

ADD HL,HL

Умножили его на 2.

ADD HL,HL

Умножили его на 4.

ADD HL,HL

Умножили его на 8.

ADD HL,DE

Теперь HL указывает на начало шаблона

буквы А.

ЕХ DE,HL

Освободили HL для работы с экраном.

LD HL,4000H

Загрузили в HL адрес начала экранного

файла.

LD B,08

Организуем счетчик на 8 шагов

LD A,(DE)

Переброска содержимого из

LD (HL),A

DE в экранный файл через аккумулятор.

INC H

переход к новой линии экрана.

INC DE

Переход к новой линии шаблона.

DJNZ LOOP

Окончание цикла из 8-ми шагов.

RET

возврат.

Итак, все вроде бы просто и понятно, но Вы, конечно, обратили внимание на то, что все, что мы до сих пор делали, относится только к восьми первым символьным рядам экрана, а что же дальше? Ведь их всего 24.

Здесь тоже все просто, если представить себе, что экран состоит из трех несвязанных между собой областей, каждая из которых имеет по 8 рядов. Назовем эти трети экрана сегментами. Итак, экран состоит из трех сегментов, каждый из которых состоит из восьми рядов, каждый из которых состоит из тридцати двух знакомест, каждое из которых состоит из восьми линий, каждая из которых состоит из восьми пикселов. Первый сегмент -16384 - 18431 (4000Н - 47FFH) Второй сегмент -18432 - 20479 (4800Н - 4FFFH) Третий сегмент - 20480 - 22527 (5000Н - 57FFH) Каждый сегмент занимает по 8*32*8=2048 байтов.

Если теперь развернуть регистровую пару HL в виде шестнадцати битов, то получится любопытная побитовая карта для дисплейного файла (см. рис. 2).

H L

J___L

0

1

0

X

X

X

X

X

X

X

X

X

X

X

X

X

Номер Номер Номер Номер столбца

сегмента ряда линии

0...2 0...7 0...7 0...31

Рис.2

Однажды, в 1985 году сэра К. Синклера спросили, чем он объясняет столь невероятный успех своих компьютеров по сравнению с главными конкурентами "Коммодором", "Атари", "Амстрадом" и "Би-Би-Си Микро", если известно, что графика у них лучше, музыка богаче, надежность выше и дополнительных внешних портов больше? На это он ответил: "У меня гораздо проще доступ к памяти". И этим сказано все. В частности, организация экранной памяти в "Спектруме" была не последним фактором, обеспечившим ему поддержку со стороны сотен фирм, выпускающих программное обеспечение.

Давайте рассмотрим эти преимущества.

1. В отличие от многих других разработчиков К. Синклер нашел удачное решение, объединив в едином экране и графику высокого разрешения и символьную графику.

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

2. Решение о разделении черно-белой информации высокого разрешения и цветовой информации низкого разрешения в разные файлы позволило ему в 4-5 раз уменьшить объем экранной памяти (по сравнению с некоторыми конкурентами) и выделить много места для пользователя. Практически здесь имитируется цветная графика высокого разрешения, хотя она таковой строго говоря и не является - это был гениальный ход, высоко оцененный специалистами.

3. Эти решения позволили в значительной степени сократить размеры программ ПЗУ. Действительно, по отношению возможностей ПЗУ к его размерам вряд ли найдется машина, равная "Спектруму", хотя и у этого ПЗУ, как показал дальнейший опыт, еще были огромные резервы.

Теперь посмотрим, как на практике ухватились программисты например за такой простой элемент, как сегментирование экрана на три зоны при том, что экран является одновременно и графическим и символьным.

Во-первых, множество первоклассных программ используют для своей графики только один сегмент, оставив прочее на диалог с пользователем. Ведь стоит только вдуматься, что в таких программах, как TIR-NA-NOG, DUN DARACH, MARSPORT фирмы "GARGOYLE GAMES" огромные события происходят на участке памяти размером всего лишь 2K.

Во-вторых, стал традиционным прием, при котором графика занимает вроде бы весь экран и непрофессионал даже и не замечает, что два сегмента из трех заняты красочной статической графикой, в то время как все действие разворачивается лишь на одном сегменте (может быть и менее красочном). Малый размер памяти этого сегмента позволяет достичь высокого быстродействия, плавности переметения объектов, прекрасной реакции на действия пользователя, а общий эстетический эффект непроизвольно распространяется на весь экран. Вроде бы имитация, но какая!

В третьих, очень часто экранную память неиспользуемых сегментов начинают использовать для разных вспомогательных действий, для размещения временных таблиц, буферов и т.п., втискивая в небольшие размеры оперативной памяти огромное количество информации. Вы сами, возможно видели во время работы копировщика COPY-86M, как временно ненужная информация выбрасывается на экран в виде точек и тире в двух нижних сегментах экрана. Это же происходит и при работе кнопки MAGIC BUTTON в операционной системе TR DOS. Тот же прием применяют и в игровых программах, но там Вы этого не увидите, т. к. программист заблаговременно установил в цветовых атрибутах, относящихся к этим сегментам экрана, черный цвет INK и черный цвет PAPER. За черным цветом прячут иногда даже и машинный стек процессора (например в программе NETHEREARTH), что не только экономит оперативную память, но является еще и эффективным приемом защиты программы от внешнего вторжения, и многое-многое другое.

Файл атрибутов.

Теперь, рассмотрев работу с дисплейным файлом, перейдем к файлу атрибутов и посмотрим работу следующей программы:

10 PAPER 6; INK 0: BORDER 6: CLS 20 FOR i=1 TO 22 30 PRINT "ZX-SPECTRUM" 40 NEXT i

50 FOR i=22528 TO 23295 60 POKE i,15 70 NEXT i

Посмотрите, что произойдет, когда Вы запустите эту программу. Во-первых, на экране будет напечатан текст (черным цветом по желтому фону). Во-вторых, знакоместо за знакоместом, начнется изменение его цвета (белые буквы по синему фону). Чтобы понять, почему так происходит, нам надо изучить область памяти от адреса 22528 до адреса 23295 (5800H -5AFFH), которая и называется файлом атрибутов. Содержимое ячеек памяти в этой области определяет то, каким цветом будет окрашено то или иное знакоместо.

Структура этого файла очень проста. Каждому знакоместу экрана соответствует один байт памяти, а значение этого байта и определяет цвета этого знакоместа. Это означает, что когда вы засылаете (POKE) какое-либо число в ячейку памяти этой области, Вы изменяете цвет одного из знакомест экрана. Каждый байт из файла атрибутов хранит информацию о параметрах INK, PAPER, BRIGHT и FLASH. Биты 0...2 - цвет INK (от 0 до 7) Биты 3... 5 - PAPER (от 0 до 7) Бит 6 - статус BRIGHT (0 или 1) Бит 7 - статус FLASH (0 или 1) Схематически это выглядит так:

7 6 5 4 3 2 1 0

F

B

P

P

P

I

I

I

Рис. 3

Для программирующего в машинном коде, конечно, чрезвычайно важно знать точно, какому знакоместу экрана соответствует какой байт файла атрибутов. Зная, что в каждом ряду 32 знакоместа, этот адрес вычислить нетрудно:

22528 + 32 * Y + X

Здесь Y и X - координаты знакоместа. Y - номер ряда сверху вниз, X - номер столбца слева направо. Как видите, в отличие от дисплейного файла, файл атрибутов организован вполне благоразумно: слева направо и сверху вниз.

Изменение цвета бордюра.

При работе в машинном коде здесь есть небольшая сложность, заключающаяся в том, что для изменения цвета бордюра требуется два действия, т.к. к этой цели ведут два пути. Дело в том, что тот существует текущий цвет бордюра (тот, который Вы в данный момент видите на экране) и есть установленный цвет бордюра (тот, который записан в памяти компьютера и будет установлен, как только ПЗУ компьютера перехватит управление от Вашей программы в машинных кодах, например при нажатии какой либо клавиши).

Ваша задача состоит в изменении обоих цветов и текущего и установленного, т. к. изменение только текущего будет иметь кратковременный характер, а изменение только установленного вообще никак не отразится на экране в данный момент.

Текущий цвет бордюра изменяется выдачей байта по 254-ому внешнему порту (бордюрная часть экрана является для "Спектрума" внешним устройством, подключенным к порту FEH). Это можно сделать даже из БЕЙСИКа, воспользовавшись командой OUT: OUT 254, цвет

В машинном коде эта команда выглядит удивительно похоже:

LD A, цвет OUT (FEH),A

Установленный цвет бордюра, с которым работает ПЗУ, постоянно хранится в отведенной для него ячейке памяти в области системных переменных. Ее название BORDER. Ее адрес 23624 (5C48H). Три бита этой переменной отвечают за цвет бордюра:

7 6 5 4 3 2 1 0

X

X

BRD

BRD

BRD

X

X

X

Рис. 4

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

Оба переключения одновременно можно сделать вызовом процедуры ПЗУ BORDER_A, расположенной по адресу 2297H (8855). Предварительно код цвета надо установить в аккумуляторе процессора. У нее есть и побочное воздействие. Если при вызове этой процедуры что-то содержится в системных нижних двух строках компьютера, то она обойдется с ними достаточно "гуманно". Чтобы бордюр не скрыл информацию, цвет INK этих строк будет установлен контрастным к цвету бордюра.

Владельцам 128-х машин.

"Спектрумы" со 128 килобайтной памятью имеют не одну, а две экранных области. (См. "ZX-РЕВЮ", N1, с.4; N2, с.26; М.: ИНФОРКОМ, 1991), каждая из которых может быть использована для хранения изображения, если Вы работаете в режиме 128К.

Первая экранная область, как обычно занимает адреса 4000^5AFFH, а вторая расположена в адресах С000Н - DAFF на седьмой странице оперативной памяти. Первая область называется нулевым экраном, а вторая - первым экраном. Очевидно, что только одна область из двух может быть воспроизведена на экране телевизора в данный момент.

Раскладка экрана-1 точно такая же, как и экрана-0 и мы можем считать, что разница состоит во-первых, в 15-ом байте (рис. 5), а во-вторых в том, что он расположен не на нулевой странице ОЗУ, а на седьмой.

Тот экран, который в настоящее время задействован, называется активным. Обратите внимание на интересную особенность первого (дополнительного) экрана. После того, как он был задействован, уже нет необходимости седьмой странице ОЗУ оставаться "впечатанной". Т.е. экран-1 может оставаться активным независимо от того, какие страницы ОЗУ "впечатаны" в данный момент.

Есть еще одна особенность: процедуры ПЗУ могут работать только с нулевым (основным) экраном. Они не умеют печатать и рисовать на втором экране. Ни PLOT, ни PRINT, ни DRAW, ни даже машиннокодовая команда RST 10H не работают с первым экраном. С ним не работают ни автоматический листинг, ни система редактирования, ни INPUT.

"Спектрум-128", как это ни странно, не содержит в своем ПЗУ-128 совершенно ничего, чтобы переключаться с одного экрана на другой и пользователю приходится самому писать для этого процедуру, например такую, как показано ниже, точками входа в нее являются метки SCR_0 и SCR_1, соответствующие тому, какой экран Вы хотите вызвать (листинг 5).

Примечание: Обязательный порядок всех переключений в 128-х машинах - сначала перенастраиваем BANK_M и только потом выдаем команду по порту 7FFD. Системные прерывания компьютера вызывают запуск его процедур ПЗУ, которые, заканчивая работу, выдают по порту 7FFD содержимое BANK_M. Так что, если Вы будете делать наоборот, есть высокая степень вероятности, что у Вас ничего не получится, правда, из машинного кода прерывания можно и отключать (см. "Первые шаги в машинном коде").

HL

J___L

X

1

0

X

X

X

X

X

X

X

X

X

X

X

X

X

Номер Номер Номер Номер Номер столбца

экрана сегмента ряда линии

0...1 0...2 0...7 0...7 0...31

1Е00 SCR_0 LD Е,00

1802 JR SELECT

1Е08 SCR_1 LD E,08

3А5С5В LD A,(BANK_M)

Рис. 5

ЛИСТИНГ 5.

Все биты выключены.

Переход на переключение экрана.

Включен бит-3.

Системная переменная

BANK_M (5B5CH) - служит

в 128-килобайтных машинах

E6F7 AND F7

B3 OR Е

325С5В LD (BAN^),A

01FDF7 LD BC,7FFD

ED79 OUT (0,A

C9 RET как указатель страниц ОЗУ, ПЗУ, экрана и режима (см. рис. 6). За номер экрана отвечает бит 3.

включили все биты в

аккумуляторе, кроме 3-го.

третий бит включается

или выключается в зависимости

от того, через какую

точку мы вошли в

эту процедуру.

Переключили BANK_M на

экран-1. Но он еще не

активен. Это только подготовка.

Установили в BC номер

внешнего порта, служащего для

физического переключения страниц и режимов.

Переключение экрана.

Выход

Системная переменная BANK_M (5B5CH - 23388) 7 6 5 4 3 2 1 0

Не используется-

Переключатель режимов -128 K/48 K

Номер страницы ПЗУ

Рис.6

И еще одно предостережение для тех, кто работает с RAM-диском на 128-килобайтных машинах (о RAM-диске см. "ZX-РЕВЮ", N12,^235-240; М.:ИНФОРКОМ, 1991.). Когда вы выгружаете что-либо в RAM-диск, используя для этого новую команду SAVE!, файлы сохраняются в памяти в виде стека - один над другим. Начало области - 1C000 и далее вверх до 1FFFF, потом с 3C000 по 3FFFF, c 4С000 по 4FFFF, с 6C000 по 6FFFF и, наконец, с 7С000 и вверх.

Одновременно с этим образуется второй стек. Он начинается в адресе 7EBFF и развивается вниз, В нем содержатся только имена и адреса файлов, выгруженных на RAM-диск. Короче говоря, этот стек содержит ту информацию, которую Вы получаете, воспользовавшись новой командой CAT! . Таким образом, эти два стека развиваются навстречу друг другу, встречаться они не должны. При появлении такой опасности компьютер выдаст сообщение об ошибке "4 Out of memory", стек каталога не может также опуститься ниже 7С000 - именно поэтому установлено ограничение на количество сохраняемых файлов - 562.

Итак, все сделано, чтобы эти стеки не встретились и не испортили друг друга, но ничего не сделано для того, чтобы они не затерли экран-1. Этот экран может быть испорчен как стеком файлов, так и каталожным стеком. И даже наоборот, работая с экраном-1, Вы можете испортить эти стеки. Будьте внимательны. Работая в машинном коде, использовать экран-1 можно только если Вы не очень активно используете виртуальный диск. Смело можете хранить до 216 файлов с суммарной длиной не более 64К.

Номер страницы ОЗУ Номер экрана




СОДЕРЖАНИЕ:


  Оставте Ваш отзыв:

  НИК/ИМЯ
  ПОЧТА (шифруется)
  КОД



Темы: Игры, Программное обеспечение, Пресса, Аппаратное обеспечение, Сеть, Демосцена, Люди, Программирование

Похожие статьи:
Users group - Компрессия экранных файлов: Обзор ПО. Дискография. Анализ результатов компрессии.
Раскрутка - описание игры "Talisman" - RPG с элементами аркады.
Экспертиза - разбор игры "Carrier Command".
Юмор - Машенька и медведь.
Преамбула - наконец-то удалось достать прошивку v. 4.01 для ПрофПЗУ.

В этот день...   21 ноября