Выполнение первого пункта списка является скорее данью традиции, чем необходимостью, поскольку ПК на базе Intel 386 и всех последующих моделей обязательно имеют оборудование для доступа к расширенной памяти. Для проверки можно, например, с помощью функции 40h определить статус, а с помощью функции 4бп — номер версии драйвера и убедиться, что он не меньше чем 4.0. Остальные пункты списка обязательно должны выполняться, причем в той последовательности, в которой они перечислены.
При работе с Expanded memory обязательно используются код сегмента расширенной памяти и идентификаторы выделенных блоков. В некоторых случаях могут быть нужны номера последних логических страниц в выделенных блоках и другие величины. Для их хранения в разделе данных задачи надо выделить специальные переменные, количество которых зависит от количества открытых блоков.
Если задача запрашивает у драйвера только один блок большого размера, то для работы с ним нужны следующие переменные:
EBuff dw 0 ; код сегмента для доступа к расширенной памяти
Ehndlr dw 0 ; идентификатор блока выделенного для задачи
Curpg db 0 ; номер текущей логической страницы блока
Lastpg db 0 ; номер последней логической страницы блока
Номера текущей и последней страниц нужны при работе
с большими блоками, размер которых превышает 65 536 байтов (4 страницы).
При работе с ними приходится многократно отображать его логические страницы
на физические. Если же размер блока не превышает стандартного сегмента
ОЗУ, то он отображается на физические страницы только один раз и при дальнейшей
работе номера страниц не нужны.
При работе с несколькими блоками в разделе данных задачи можно организовать
простую таблицу, состоящую из строк фиксированного размера, содержащих
характеристики каждого блока. В таком случае характеристики выбираются
из таблицы по порядковому номеру блока, и сокращается количество имен
переменных.
Резервирование блока
Предположим, что для выполнения задачи требуется непрерывное пространство расширенной памяти (блок) размером в 1 Мбайт. Для резервирования такого блока задача должна запросить у драйвера исполнение функции 43h, указав в регистре bx 64 страницы (размер страницы составляет 16 Кбайт). Если это первый запрос, обращенный к драйверу, то предварительно надо выполнить функцию 4 in для определения состояния драйвера и получения кода сегмента для доступа к памяти.
Фрагмент программы, выполняющий резервирование блока размером в 1 Мбайт, приведен в примере Б.5. Его надо включить в ту часть задачи, где выполняются подготовительные действия. Например, сразу после команд, приведенных в примерах Б.З или Б.4.
Пример Б. 5. Создание в расширенной памяти блока размером 1 Мбайт
mov ax, 4100h код функции запроса сегмента
int 67h обращение к драйверу
or ah, ah функция выполнена ?
je @F -> да
jmp emmerr -> ошибка при исполнении функции
@@: mov EBuff, bx сохраняем код сегмента
mov bx, 64 размер запрашиваемого блока
mov ax, 4300h код функции выделения памяти
int 67h обращение к драйверу
or ah, ah блок выделен ?
je @F -> да
jmp emmerr -> ошибка при выделении блока
@@: mov Ehndlr, dx сохраняем идентификатор блока
mov Curpg, 0 номер текущей страницы блока
mov Lastpg, 63 номер последней страницы блока
; Продолжение текст а программы
Выполнение примера Б.5 начинается с запроса кода сегмента для доступа к расширенной памяти. Если при возврате из драйвера регистр ah очищен, то запрос исполнен успешно, в противном случае произойдет переход на метку emmerr. для вывода аварийного сообщения.
На следующем шаге выдается запрос на выделение блока размером в 64 страницы. Если после возврата из драйвера регистр ah очищен, то блок выделен, в противном случае происходит переход на метку emmerr.
В случае успешного выделения блока формируются Curpg и Lastpg и на этом выполнение фрагмента завершено.
В примере Б.5 отсутствуют команды, обработки аварийных ситуаций. Предполагается, что первая из них имеет метку emmerr. Что делать в случае ошибки, решать вам, например, можно вывести на экран текст аварийного сообщения и завершить выполнение задачи. На стадии отладки полезно предусмотреть вывод кода ошибки, который находится в регистре ah.
Напоминаем, что после выполнения команд примера Б.5 блок только закреплен за задачей, но не доступен для записи или чтения. Для работы с его конкретными страницами их надо отобразить на физические страницы сегмента EMS. В этом заключается одно из существенных отличий доступа к блокам расширенной памяти от доступа к блокам обычной памяти.
Отображение страниц
Для отображения логической страницы блока на одну из физических страниц сегмента EMS запрашивается функция 44h. Мы рассмотрим универсальный вариант подпрограммы отображения страниц.
В зависимости от логики выполняемых в задаче действий может потребоваться отображение от одной до четырех страниц. Поэтому подпрограмма, текст которой приведен в примере Б.6, имеет две точки входа.
При вызове call mapseg отображаются четыре подряд расположенные страницы. Предварительно в регистре bx указывается номер первой логической страницы, а в регистре dx — идентификатор блока, которому принадлежат отображаемые страницы. Вариант вызова подпрограммы mapseg показан в примере Б.7 (см.