Графические устройства



 

Непосредственная работа с видеобуфером

Если отвлечься от вспомогательных действий, то функции 09 и OAh вычисляют адрес видеобуфера, используя номера страницы, строки и столбца, и записывают по этому адресу либо код символа (0Ah), либо код символа и атрибут (09). Эти действия достаточно просты и могут выполняться задачей без обращения к функциям BIOS. В таком случае существенно сокращается время, затрачиваемое на обмен с буфером, и появляется возможность более гибкого управления процессом вывода текста на экран. По этой причине в большинстве руководств по программированию на языке ассемблера подробно рассматриваются способы прямой работы с видеобуфером и курсором без обращения к BIOS.

Следует также подчеркнуть, что существует определенная категория задач, которые по тем или иным причинам не должны использовать поддержку DOS или BIOS. В частности, если задача работает со страницами видеопамяти, то для вывода символов нельзя использовать функции 09, 0Ah и 0Еh прерывания int 10h.

Преимущества непосредственной работы с видеопамятью по сравнению с использованием функций BIOS заключаются в следующем:

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

Вычисление адреса по координатам. Расположение текста на экране удобно задавать в виде номеров строк и столбцов. Хранить значения строки и столбца можно в словах и байтах области данных BIOS (см. пример 5.3) или в области данных задачи. Мы выберем первый вариант, поскольку в таком случае приведенные ниже примеры применимы при работе в текстовых режимах как VESA, так и IBM.

Кроме того, мы будем считать, что задача поддерживает работу со страницами видеопамяти и при преобразовании координат в адрес надо учитывать смещение страницы от начала сегмента видеопамяти.

В примере 5.11 приведена подпрограмма, вычисляющая адрес видеопамяти по текущему значению координат. Перед обращением в регистре bx указывается номер страницы, вычисленный адрес помещается в регистр di. Все нужные величины выбираются из области данных BIOS.

Пример 5.11. Вычисление адреса на указанной странице

GetAdr: Push =!.ед <ds, bx> сохранение регистров
mov ds , NulSeg очистка регистра ds
shl bx , 01 удвоение номера страницы
mov bx , [bx + 450h] Ы = столбец, bh = строка
mov ax , [44Ah] количество символов в строке
mul bh ах = размер строки номер строки
xor bh , bh очистка байта bh
add ax , bx прибавляем к ах номер столбца
shl ax , 01 удваиваем полученный результат
mov di , ax и сохраняем его в dx
mov ax , [44Ch] ах = размер страницы
pop bx восстанавливаем номер страницы
mul bl ах = смещение страницы в буфере
add di , ax вычисляем полный адрес
pop ds восстановление ds
ret возврат из подпрограммы

Напоминаем, что команды lodsb и stosw корректируют содержимое индексного регистра.

Поясним способ доступа к области данных BIOS. Она расположена в нулевом сегменте оперативной памяти. Для доступа к нулевому сегменту надо очистить один из сегментных регистров, лучше, если это регистр ds. В разделе данных задачи надо зарезервировать пустое слово с именем Nuiseg и при выполнении подпрограммы копировать его в ds.

Перед вызовом подпрограммы GetAdr значения координат должны быть указаны в слове BIOS, соответствующем нужной странице. Если задача не работает со страницами, точнее работает только с нулевой страницей, то координаты курсора хранятся в слове 450h. При этом из текста примера 5.11 надо исключить вычисление адреса слова и смещения страницы от начала сегмента видеопамяти.

Запись текста в видеопамять. Мы приведем пример подпрограммы, которая записывает-в видеопамять коды символов строки вместе с атрибутом, общим для всех символов, а затем покажем, как ее надо изменить для записи только кодов символов или только кодов атрибутов.

Замечание
Напомним, что регистр es должен содержать код видеосегмента, который в текстовых режимах равен B800h.

Текст подпрограммы показан в примере 5.12. Перед обращением к ней надо вычислить адрес видеопамяти и поместить его в регистр di, например, с помощью подпрограммы примера 5.11. Адрес начала выводимого текста указывается в регистрах ds:si, количество выводимых символов помещается в регистр сх, а код общего для всех символов атрибута — в регистр bl.

Пример 5.12. Запись символов строки с одинаковым

OutLine: push ax сохраняем содержимое ах mov ah, Ы помещаем атрибут в ah
wrt: lodsb читаем в al очередной символ
stosw пишем ах в видеобуфер
loop wrt управление повторами цикла
pop ax восстанавливаем содержимое ах
ret возврат из подпрограммы

При выполнении примера 5.12 указанный в ы атрибут копируется в регистр ah. Далее в цикле wrt каждый символ строки копируется в регистр ai и содержимое регистра ах записывается в видеопамять.

В примерах 5.13 и 5.14 показано, как изменится подпрограмма outLine, если в видеопамять записываются только коды символов или атрибуты.

Пример 5.13. Запись символов строки без атрибутов

OutSym: movsb ; копирование символа в четный байт
inc di ; пропуск нечетного байта
loop outsym ; управление повторами цикла
ret ; возврат из подпрограммы

Пример 5.14. Раскрашивание символов, находящихся в видеопамяти

OutAtr: push ax сохраняем содержимое ах
mov ai, Ы помещаем атрибут в al
wrtatr: inc di пропускаем четный байт
stosb записываем код атрибута
loop wrtatr управление повторами цикла
pop ax восстанавливаем содержимое ах
ret возврат из подпрограммы

При обращении к подпрограмме OutAtr в регистре di указывается адрес видеопамяти, в регистре bl— атрибут, а в сх — сколько раз его надо записать в видеопамять (количество раскрашиваемых символов).

Перемещение курсора

Если задача использует текстовый курсор, то для его перемещения можно использовать функцию 02 прерывания int ion, или составить свою подпрограмму. Такая подпрограмма полезна, например, в тех случаях, когда недопустимо использование поддержки BIOS.

В примере 5.15 приведена подпрограмма перемещения курсора, к которой можно обратиться по двум именам. При обращении по имени Poseur происходит обращение к описанной в примере 5.11 подпрограмме GetAdr, которая пересчитывает координаты в адрес и помещает его в регистр di. В этом случае номер страницы указывается в регистре bх, а значения координат выбираются из области данных BIOS. При обращении по имени MovCur адрес байта должен находиться в регистре di.

Замечание
Не забывайте, что курсор будет виден только в том случае, когда его рисунок расположен на активной странице.

Пример 5.15. Перемещение курсора по адресу, указанному в регистре di

PosCur: call GetAdr ; пересчет координат в адрес
MovCur: PushReg <ds,ax,bx,dx> ; сохранение используемых регистров mov ds, NulSeg ; очистка сегментного регистра
mov bx, di bx = адрес позиции в байтах
shr bx, 01 преобразование байтов в слова
mov ah, bh ah = старший байт адреса
mov al, OEh al = ног^ер регистра видеоконтроллера
mov dx, [0463h] dx = базовый адрес видеоконтроллера
out dx, ax запись старшего байта в регистр OEh
mov ah, bl ah = младший байт адреса
inc al al = номер следующего регистра
out dx, ax запись младшего байта в регистр OFh
PopReg <dx,bx,ax,ds> восстановление регистров
ret возврат из подпрограммы

В примере 5.15 основные действия выполняют команды, первая из которых имеет метку Movcur. Для записи данных в регистры нужен базовый адрес (порт) видеоконтроллера, который хранится в слове 463h области данных BIOS. Для чтения содержимого этого слова в сегментный регистр ds копируется пустое слово Nuiseg, хранящееся в разделе данных задачи.

В регистре di должен находиться адрес байта, он копируется в регистр bx и уменьшается в два раза, в результате получается адрес слова, в котором должен быть расположен рисунок курсора. Этот адрес надо записать в регистры видеоконтроллера, имеющие коды ОЕЬ и OFh (14 и 15).

Для записи адреса в регистры видеокарты выполняются следующие действия. В регистр dx записывается адрес порта видеоконтроллера из слова 463h области данных BIOS. В al помещается код регистра (OEh или OFh), в который надо записать один из байтов адреса, а сам байт помещается в регистр ah. После этого команда out записывает байт в регистр видеокарты. Сначала записывается старший байт адреса в регистр OEh, а затем младший в регистр OFh.

После выполнения описанных действий восстанавливается сохраненное в стеке содержимое регистров и происходит возврат на вызывающий модуль.
Для перемещения курсора в конец выведенного текста после выполнения подпрограмм примеров 5.12 и 5.13 вызывается подпрограмма Movcur. После выполнения указанных подпрограмм регистр di содержит нужный адрес, и дополнительное обращение к подпрограмме GetAdr не требуется.

Установка активной страницы

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

Текст подпрограммы для смены активной страницы приведен в примере 5.16. Перед ее вызовом номер активной страницы указывается в регистре эх. Содержимое этой страницы появится на экране/ Для вывода рисунка курсора на новую страницу используйте подпрограмму Poseur.

Пример 5.16. Установка активной страницы, указанной в регистре bх

SelPag: PushReg <ds, ax, bx, dx> сохранение используемых регистров
mov ds , NulSeg очистка регистра ds
mov ax , [44Ch] ах = размер страницы в байтах
mul Ы умножаем его на номер страницы
mov bx , ax сохраняем результат в bx
mov al , OCh al = номер регистра видеоконтроллера
mov dx , [463h] dx = базовый адрес видеоконтроллера
out dx , ax запись старшего байта адреса
mov ah , bl ah = младший байт адреса
inc al номер второго регистра видеокарты
out dx , ax запись младшего байта адреса
PopReg <dx,bx, ax,ds> восстановление регистров из стека
ret возврат из подпрограммы

Для установки активной страницы надо старший и младший байты адреса ее начала записать в регистры ось и ooh (12 и 13). В примере 5.16 адрес вычисляется так же, как и в примере 5.11. Размер страницы выбирается из слова 44ch области данных BIOS, помещается в регистр ах и умножается на номер страницы, указанный в регистре bx. Полученный результат сохраняется в регистре bх, а его старший и младший байты записываются в регистры 0Ch и 0Dh. Способ записи такой же, как в примере 5.15, поэтому мы не будем повторяться.

Замечание о переносимости

При разработке видеоадаптера VGA IBM стандартизировала как состав регистров видеоконтроллера, так и способы их программирования. Стандарт распространяется на все режимы работы контроллера. Со временем более совершенные графические режимы SVGA потеснили режимы VGA, но текстовые режимы остались без изменений. Все современные видеокарты соответствуют стандартам как VESA, так и VGA IBM (одно не противоречит другому). Поэтому при работе в текстовых режимах задача может самостоятельно манипулировать с регистрами видеокарты без использования функций BIOS и оставаться при этом переносимой с одного компьютера на другой.

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

 
Назад Начало Вперед