Непосредственная работа с видеобуфером
Если отвлечься от вспомогательных действий, то функции 09 и OAh вычисляют адрес видеобуфера, используя номера страницы, строки и столбца, и записывают по этому адресу либо код символа (0Ah), либо код символа и атрибут (09). Эти действия достаточно просты и могут выполняться задачей без обращения к функциям BIOS. В таком случае существенно сокращается время, затрачиваемое на обмен с буфером, и появляется возможность более гибкого управления процессом вывода текста на экран. По этой причине в большинстве руководств по программированию на языке ассемблера подробно рассматриваются способы прямой работы с видеобуфером и курсором без обращения к BIOS.
Следует также подчеркнуть, что существует определенная категория задач, которые по тем или иным причинам не должны использовать поддержку DOS или BIOS. В частности, если задача работает со страницами видеопамяти, то для вывода символов нельзя использовать функции 09, 0Ah и 0Еh прерывания int 10h.
Преимущества непосредственной работы с видеопамятью по сравнению с использованием функций BIOS заключаются в следующем:
- При выводе текста вычисляется адрес только первого символа. Все последующие адреса на 2 больше предыдущих.
- Существует возможность раскрашивания уже находящегося на экране текста. Для этого надо просто записать новые значения атрибутов в нечетные байты видеопамяти, не изменяя коды символов текста.
- Возможны ввод, вывод и редактирование текста, находящегося на любой странице видеопамяти.
Вычисление адреса по координатам
Расположение текста на экране удобно задавать в виде номеров строк и столбцов. Хранить значения строки и столбца можно в словах и байтах области данных 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 надо исключить вычисление адреса слова и смещения страницы от начала сегмента видеопамяти.