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

Новости. Скоро пройдёт свадьба Феофилактовой и Гусева. Ждём.


  

Процедуры для работы с одним окном видеопамяти

На видеокарте обязательно расположена оперативная память, которую принято называть видеопамятью (video memory). Видеоконтроллер непрерывно выводит содержимое части видеопамяти на экран монитора, причем размер этой части зависит от установленного видеорежима. На современных видеокартах базовый объем памяти составляет не менее 1 Мбайт (1 Мбайт равен 1 048 576 байтам) и может быть расширен, по крайней мере, до 4 Мбайт при установке на видеокарту дополнительных микросхем. Напомним, что для работы в режиме VESA ивь четырех мегабайтов недостаточно. У акселераторов объем видеопамяти существенно больше (до 64 Мбайт).

Доступ к видеопамяти

Специфической особенностью семейства IBM PC является ограничение пространства доступных адресов размером 1 Мбайт.

Оно делится на сегменты, предельный размер которых составляет 64 Кбайт (1 Кбайт равен 1024 байтам). Всего в пространстве адресов помещается 16 сегментов предельного размера, 10 из них занимает оперативная память ПК.

Для доступа к видеопамяти выделяется один сегмент размером в 64 Кбайт, который чаще всего имеет адрес доооь для графических и взооь для текстовых режимов. Только при указании этих сегментов графическая или текстовая информация будет направлена в видеопамять или считана из нее, поэтому их значения ни при каких условиях не должны изменяться задачей. Размер видеосегмента значительно меньше реального объема видеопамяти. Для того чтобы задачи могли работать со всей памятью, в современных видеоконтроллерах реализован следующий механизм.

Все пространство видеопамяти делится на сегменты размером по 64 Кбайт, которые пронумерованы начиная с нуля. По принятой терминологии такие сегменты называют окнами или видеоокнами. В специальном регистре видеоконтроллера хранится номер текущего окна. При обращениях к видеопамяти контроллер добавляет его к 16-разрядному адресу, указанному задачей, и получает абсолютный адрес. Количество разрядов в абсолютном адресе зависит от предельного объема памяти, которая может быть установлена на видеокарте. Если на видеокарте может быть установлено 2 Мбайт памяти, то адрес занимает 21 разряд, если установлено 4 Мбайт — то 22 разряда и т. д.
Таким образом, полный адрес видеопамяти складывается из двух частей. Младшая часть является относительным адресом (смещением в сегменте), а старшая часть — номером текущего окна, хранящимся в одном из регистров видеоконтроллера. Задача может изменять текущее окно с помощью функции 4F05h.

Прямое обращение к BIOS. Видеокарты различаются не только адресами регистров, в которых хранится номер текущего окна, но и тем, в каких разрядах этих регистров он располагается. Поэтому при описании функции 4F05H в документации специально оговорено, что номер окна выражается в единицах приращения его значений, дословно in granularity unit. В примере 2.6 показан способ вычисления единицы приращения, она хранится в переменной GrUnit. Обычно она равна 1, только для одной видеокарты получилось другое значение, но если есть исключения, то надо следовать рекомендациям VESA и использовать переменную GrUnit.

Для установки окна с помощью функции 4F05h его номер помещается в регистр dx, а регистр bx очищается. После этого в регистр ах записывается код функции 4F05h и выполняется команда int lOh. В примере 2.7 показан способ прямого обращения к BIOS для установки окна. В нем и во всех последующих примерах текущий номер окна, выраженный в единицах GrUnit, выбирается из переменной cur_win. Она имеет размер слова и располагается в разделе данных задачи (см. пример 2.11).

Пример 2.7. Установка окна с использованием функции BIOS

mov dx, Cur_win ; запись в dx значения окна
xor bx, bx ; признак установки окна
mov ax, 4F05h ; код функции BIOS
int 10h ; обращение к BIOS

Ускорение работы с окнами. В описании стандарта VESA не рекомендуется использовать прямое обращение к BIOS для установки окна. Причина простая — при обращениях к BIOS с использованием прерываний, например int lOh, выполняется много вспомогательных действий, связанных с сохранением регистров и расшифровкой кода запроса. Специфической особенностью прерывания int 10h является то, что на обращения к нему реагируют компоненты DOS и некоторые резидентные (постоянно находящиеся в оперативной памяти) задачи, например русификатор KEYRUS. В результате количество дополнительных и ненужных в данном конкретном случае действий оказывается значительно больше количества полезных действий, выполняющих запись или чтение окна. По этой причине разработчики стандарта VESA рекомендуют использовать только процедуру BIOS, которая выполняет чтение или запись окна и состоит всего из 10—15 команд. В описании стандарта процедура называется video Memory control (VMC). Способ сохранения ее адреса показан в примере 2.6.

При вызове процедуры VMC для чтения или установки окна регистры bx и dx заполняются так же, как и при обращении к функции 4F05h. Прежде чем рассматривать конкретные примеры, мы обсудим несколько вопросов, имеющих отношения к работе с окнами.

Описание гнезда подпрограмм. Установка или изменение текущего окна производится в задачах при построении, перемещении или копировании рисунков, управлении курсором, выводе и редактировании текста, т. е. при любых манипуляциях с графическими объектами. Поэтому вызов процедуры VMC целесообразно оформить в виде подпрограмм, расположенных в теле основной задачи.

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

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

В примере 2.8 описаны три подпрограммы, предназначенные для установки значения окна путем вызова процедуры VMC. Подпрограммы оформлены как внутренние, поэтому они должны быть расположены в том же сегменте памяти, в котором находится основная программа. Обращения к ним производятся с помощью команды call, в которой указано имя (метка) подпрограммы. Входным параметром для всех трех подпрограмм является переменная Cur win, исходное значение которой изменяется при установке следующего или предшествующего окна. Так и должно быть, поскольку новое окно становится текущим. Подпрограммы не изменяют содержимое регистров общего назначения, с которыми они работают.

Подпрограммы SetWin, NxtWin и PrevWin. Ядром примера 2.8 является подпрограмма setwin (вызов call Setwin). Она помещает текущее окно в регистр dx, очищает регистр bx и вызывает процедуру VMC для установки указанного окна. Прерывание int lOh не используется, что соответствует рекомендациям стандарта VESA.

Подпрограмма Nxtwin (обращение call Nxtwin) устанавливает следующее окно. При ее выполнении текущее значение переменной Cur__win увеличивается на единицу приращения (crunit), а затем выполняется setwin.

Подпрограмма PrevWin (обращение call PrevWin) устанавливает предыдущее окно. При ее выполнении текущее значение переменной Cur_win уменьшается на единицу приращения (GrUnit), а затем вызывается setwin.

Пример 2.8. Три подпрограммы для работы с видеоокнами

  ; Установка следующего окна
NxtWin: push ax ; сохраняем содержимое ах
mov ax, GrUnit ; читаем единицу приращения окна
add Cur win, ax ; увеличиваем номер окна
pop ax ; восстанавливаем содержимое ах
; Установка окна, указанного в Cur win
SetWin: PushP,eg <ax,bx,dx> ; сохранение содержимого регистров
xor bx, bx ; признак установки окна
mov dx, Cur win ; номер устанавливаемого окна
call [VMC] ; обращение к подпрограмме BIOS
PopReg <dx,bx,ax> ; восстановление содержимого регистров
ret ; возврат из подпрограммы
; Установка предыдущего окна
PrevWin push ax ; сохранение содержимого ах
mov ax, GrUnit ; читаем единицу приращения окна
sub Cur win, ax ; уменьшаем номер окна
pop ax ; восстанавливаем содержимое ах
jmp SHORT SetWin ; переходим на установку окна

Процедура VMC расположена в "удаленном" сегменте, т. е. в пространстве адресов, не принадлежащих задаче. В таких случаях для обращения к подпрограммам используется команда call, у которой операнд является двойным словом, содержащим полный адрес (сегмент и смещение). При компиляции Макроассемблер формирует специальный код, указывающий процессору, что переход производится на удаленный адрес. В примере 2.8 операндом команды call является переменная VMC, описанная как двойное слово. Заключение имени переменной в квадратные скобки указывает на то, что адресом процедуры является не VMC, а хранящееся в ней значение, которое было установлено при выполнении команд примера 2.6.

Указание типа short в команде jmp заставит Макроассемблер сформировать короткую команду (для перехода не более чем на 128 байтов), код которой занимает два байта. pushReg и PopReg — это макросы (макровызовы). Первый эквивалентен трем командам push ax, push bx и push dx, а второй — трем командам pop dx, pop bx, pop ax. В реальной программе вы должны либо заменить макросы указанными командами, либо поместить в начале текста программы соответствующие им макроопределения, текст которых приведен в примере 2.12. Сохранение исходного содержимого регистров в стеке и восстановление при выходе делается для того, чтобы находящиеся там данные не изменялись в результате выполнения подпрограммы.

Чтение текущего окна. Еще раз вернемся к текущему окну. При корректной работе задачи с окнами значение переменной Cur_win всегда соответствует номеру, находящемуся в регистре видеоконтроллера. Если по каким-то причинам такое соответствие нарушено, то текущее значение окна можно восстановить, прочитав его из видеоконтроллера. Оформлять чтение текущего окна в виде самостоятельной процедуры не целесообразно, поскольку регулярных обращений к ней не должно быть.

Для чтения окна с помощью функции 4F05h надо выполнить следующие три команды:

mov bx, 10Oh ; признак чтения окна
mov ax, 4F05h ; код запрашиваемой функции
int 10h ; обращение к BIOS

Другой способ чтения текущего значения окна заключается в прямом обращении к процедуре BIOS, а именно:

mov bx, lOOh ; признак чтения окна
call [VMC] ; обращение к процедуре BIOS

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

Контроль ошибок

В данном разделе ничего не говорилось о контроле ошибок при установке или изменении окон видеопамяти. Это объясняется несколькими причинами. Прежде всего, признак ошибки функция 4F05h возвращает только в том случае, если содержимое регистра ьь больше единицы, т. е. если неправильно указано запрашиваемое действие. Контроль правильности указанного значения окна не производится, поскольку его не так просто осуществить.

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

В рассматриваемом случае возможен единственный способ контроля — проверка соответствия номера окна реально существующему объему видеопамяти. Но выполнять такую проверку при каждом изменении номера окна едва ли целесообразно. В крайнем случае, ее можно временно на период отладки задачи включить в подпрограмму setwin и убрать после отладки. Но лучше тщательно продумать алгоритм работы задачи и проверить правильность его воплощения.

Если вы умеете работать с отладчиками и восстанавливать по кодам команд исходный текст на языке ассемблера, то имеет смысл разобраться в том, как воплощена процедура VMC в BIOS. Это позволит вам узнать, как выполняется чтение или установка номера окна на уровне работы с портами ввода-вывода.

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