TURBO PASCAL

Новости

Программы   

Turbo Pascal 

Игры

Документация   

Странности

FAQ

Ссылки

Форум

Гостевая книга

Рассылка

Благодарности

Об авторе

 

 

5.2. ФУНКЦИИ ДРАЙВЕРА ОТОБРАЖАЕМОЙ ПАМЯТИ

Работа EMS— платы управляется специальным драйвером, который называется EMM (Expanded Memory Manager — администратор отображаемой памяти). Существует несколько версий EMM. В этом разделе описываются функции драйвера отображаемой памяти так, как они реализованы в EMM версии 4.0. Однако перед тем как рассматривать функции EMM, полезно обсудить некоторые подробности его работы.

Как уже говорилось, отображаемая память выделяется программе страницами по 16 Кбайт каждая. Эти страницы отображаются в окне, имеющем размеры 64 Кбайта, т.е. окно способно отобразить до четырех страниц одновременно. Условимся в дальнейшем называть страницы окна физическими, а страницы EMS— памяти логическими.

Поскольку логических страниц может быть гораздо больше физических, необходимо каким—то образом управлять процессом отображения в окне, т.е. устанавливать связи между окном и отображаемой памятью. Эта задача в EMM решается следующим образом. Для использования EMS— памяти программа должна создать так называемый дескриптор EMM. С дескриптором связывается одна или несколько (до 2048) логических

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

Для установления связи между логическими страницами дескриптора и физическими страницами окна используется специальная процедура, которая называется картированием окна. При картировании Вы должны указать номер физической страницы и номер той логической страницы, содержимое которой должно отображаться в этой физической странице окна. Нумерация как логических, так и физических страниц начинается с нуля, т.е. допустимыми являются номера 0...3 для физических и О... N— 1 для логических страниц (N — полное количество страниц, которыми владеет дескриптор).

В табл.5.1 приводится краткая характеристика функций EMM версии 4.0.

Таблица 5.1 ___________Функции драйвера отображаемой памяти_________

 

Функция

Действия

$40

Дать статус EMM

$41

Получить сегментную часть адреса отображаемого окна

$42

Получить информацию о EMS — памяти

$43

Создать дескриптор EMM и распределить память

$44

Картировать окно

$45

Уничтожить дескриптор EMM и освободить память

$46

Дать номер версии БММ

$47

Сохранить картирующий контекст

$48

Восстановить картирующий контекст (предварительно контекст должен быть сохранен с помощью функции $47)

$4В

Дать количество активных дескрипторов

$4С

Дать количество связанных с дескриптором страниц

$4D

Дать информацию о распределении памяти

$4Е

Дать/установить карту всех страниц

$4F

Дать/установить карту части страниц

$50

Картировать/освободить несколько страниц одновременно

$51

Изменить количество связанных с дескриптором страниц

$52

Получить/установить флаг сохранения страниц

$53

Установить/получить имя дескриптора

$54

Дать список имен дескрипторов или искать дескриптор по имени

$55

Картировать память и выполнить инструкцию JUMP

$56

Картировать память и выполнить инструкцию CALL

$57

Переместить/обменять блок памяти

$58

Получить полную карту EMS—окна


Для обращения к EMM используется программное прерывание с вектором $67. Чтобы вызвать нужную функцию EMM, следует поместить в регистр АН номер функции, соответствующим образом сформировать остальные регистры и вызвать прерывание $67. При выходе из преры—

вания регистр АН содержит статус возврата — код, характеризующий успешность запроса. Ненулевое значение статуса указывает на ошибку обращения (см. табл.5.2).

Таблица 5.2

 

 

Коды ошибок EMM

Код

Значение

$00

Нет ошибок, функция выполнена (во всех остальных случаях — не выполнена)

$80

Внутренняя ошибка EMM

$81

Сбой EMS—платы

$82

EMM занят обработкой предыдущего запроса

$83

Неверный дескриптор окна

$84

Запрошена неопределенная в данной версии EMM функция

$85

Нет доступных дескрипторов окон

$86

Ошибка при сохранении или восстановлении окна

$87

Запрос распределения превышает общую EMS—память

$88

Запрос распределения превышает число доступных страниц

$89

Попытка создать дескриптор с нулевым количеством страниц

$8А

Дескриптор не располагает таким числом страниц

$8В

Попытка картировать больше 4 страниц

$8С

Переполнение области сохранения картирующего контекста

$8D

Попытка повторного сохранения картирующего контекста

$8E

Попытка восстановления несохраненного контекста

$8F

Не определен параметр подфункции

$90

Неизвестный тип атрибутов

$91

Нет аппаратной подд.ержки сохраняемых страниц

$92

Источник и приемник информации одновременно находятся в EMS— памяти (предупреждение, не ошибка)

$93

Размер приемника информации слишком мал

$94

Стандартная память частично перекрывает отображаемую память

$95

Слишком большое смещение в перемещаемом блоке

$96

Размер перемещаемого блока больше 1 Мбайт

$97

Источник и приемник связаны с одним дескриптором и частично перекрываются

$98

Недопустимый тип памяти источника или приемника

$9А

Нет аппаратной подд.ержки альтернативной установки страниц

$9В

Исчерпаны все допустимые установки альтернативных регистров

$9С

Не поддерживается установка альтернативных регистров

$9D

Неправильная установка альтернативных регистров

$9Д

Назначенные каналы прямого доступа к памяти (КПДП) не поддерживаются

$9F

Указанный КПДП не поддерживается

$AO '

Дескриптор не поименован

$А1

Указанное имя дескриптора уже существует

SA2

Источник выходит за границу 1 Мбайт

$АЗ

Содержимое указанное области данных разрушено

$А4

Нет доступа к указанной функции


Дать статус EMM

Вход: АН = $40. Выход: АН — статус EMM.

Эта функция позволяет программе проконтролировать состояние только что завершившейся операции с EMS— памятью. Содержимое регистра АН кодирует состояние EMM

Получить сегмент отображаемого окна

Вход: АН = $41. Выход: J3X — сегмент окна.

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

BX+1024*N:0000,

где ВХ — сегмент окна, N — номер физической страницы (0...3). Поскольку положение окна не меняется, программа может обратиться к этой функции лишь один раз и затем использовать полученный адрес при любых операциях с отображаемой памятью.

Получить информацию о EMS-памяти

Вход: АН = $42. Выход: DX — общее число страниц (по 16 Кбайт каждая);

ВХ — количество свободных страниц.

С помощью функции $ 4 2 программа может получить, информацию об общем количестве логических страниц (регистр DX) и количестве свободных в данный момент страниц (регистр ВХ).

Создать дескриптор и распределить память

Вход: АН = $43;

ВХ — требуемое количество страниц (от 1 до 2048). Выход: DX — дескриптор EMM.

Новый дескриптор создается функцией $43. При обращении к ней в регистре ВХ указывается количество логических страниц, связываемых с дескриптором. Это количество не должно превышать значения, возвращаемого в регистре ВХ функцией $42. EMM не гарантирует, что выделенные дескриптору страницы будут располагаться в смежных физических блоках (т.е., например, соответствовать непрерывному адресному пространству дополнительной памяти, если отображаемая память эмулируется драйвером EMM386.SYS), однако он строго следит за тем, чтобы никакой другой дескриптор не использовал их. Программа должна сохранить полученный Ё регистре DX дескриптор для использования выделенной ему памяти.

Картироватъ окно

Вход: АН = $44;

AL = номер логической страницы (от 0 до 3);

ВХ = физический номер страницы (от 0 до N— 1, где

N — количество страниц, связанных с данным дескриптором);

DX = дескриптор EMM.

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

логическую страницу, в то время как содержимое остальных физических страниц останется неизменным. Замечу, что любая физическая страница может быть связана с любой логической страницей, т.е. одна и та же ло — гическая страница при необходимости может отображаться в двух, трех или даже во всех четырех страницах окна одновременно. Если какая-либо физическая страница останется не связанной ни с одной логической, EMM блокирует доступ к странице: при чтении из нее любой байт будет содержать код $FF (255) и запись по любому байту в пределах несвязанной страницы не меняет этого значения.

Уничтожить дескриптор EMM и освободить память

Вход: АН = $45;

DX — дескриптор.

Функция $45 уничтожает дескриптор и освобождает связанные с ним логические страницы. Не забывайте вызывать эту функцию в конце работы с EMS— памятью, так как в отличие от кучи отображаемая память не освобождается автоматически в момент завершения работы программы! Более того, я настоятельно рекомендую перехватить процедуру выхода (как это сделать см. в гл.2) и в новой процедуре при необходимости сделать вызов этой функции, так как программа может завершиться аварийно и выделенная дескриптору (дескрипторам) память будет потеряна для остальных программ впредь до перезагрузки ДОС. Этот прием избавит Вас от дополнительных хлопот при отладке программы.

Дать номер версии EMM

Вход: АН = $46. Выход: AL — номер версии в двоично—десятичном формате.

С помощью функции $ 4 6 программа может получить номер версии того EMM, с которым она работает в данный момент. Если Вы собираетесь писать коммерческую программу, такая проверка будет весьма кстатИг так как описываемые ниже функции $4F. . .$58 доступны Только для версии 4.0 и недоступны в ранних. После возврата из этой функции регистр AL содержит номер версии в двоично—десятичном формате: старший полубайт — первую цифру, младший — вторую. Например, для версии 4.0 в регистре содержится $40=64, а для более ранней версии 3.2 — $32'=50.

Сохранить/восстановить картирующий контекст

Вход: АН = $47 — сохранить контекст;

= $48 — восстановить контекст;

DX = дескриптор.

Функции $47 и $48 используются в ситуациях, когда нужно временно сохранить текущую карту страниц. Такие ситуации могут возникнуть, например, перед вызовом процедур, использующих Тит же самый дескриптор. Вызовы функций $47 и $48 должны быть парными. Это означает, что если Вы для одного и того же дескриптора дважды подряд попытаетесь вызвать функцию $47 без промежуточного вызова функции $48, это

приведет к возникновению ошибки $8D, а повторный вызов $48 без вызова $47 — ошибки $8Е.

Дать количество активных дескрипторов

Вход: АН == $4 в. Выход: ВХ — количество дескрипторов.

Функция $4 В возвращает в регистре ВХ количество активных в данный момент дескрипторов, а функция $4 С — количество связанных с дескриптором логических страниц (см. замечание к функции $4 С).

Дать количество связанных с дескриптором страниц

Вход: АН = $4 С;

DX = дескриптор. Выход: ВХ = количество страниц.

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

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

Uses DOS;

var

Reg: Registers;

Procedure Intr67;

{Выполняет прерывание $67 с регистрами, заданными значениями переменной Reg} begin

Intr($67,Reg) ;

if Reg.ahoO then begin

WriteLn('Ошибка ',Reg.ah);

Halt end end;

va-

Handle: Word;

begin

with Reg do

begin

^Определяем общее количество дескрипторов} ah := $4В;

Intr67;

WriteLn('Используется',bx:3,' дескрипторов');

{Определяем объем всей и доступной EMS-памяти}

ah := $42;

Intr67;

WriteLn(dx:15,' страниц EMS-памяти');

WriteLn(bx:15, ' страниц - свободно');

{Создаем новый дескриптор}

ah := $43;

Intr67;

Handle := dx;

{Определяем количество страниц, которыми он владеет}

ah := $4С;

Intr67;

WriteLn('Создан новый дескриптор, владеющий ', bx,' страницами');

{Проверяем общее количество дескрипторов}

ah := $4В;

Intr67;

WriteLn('(общее количество дескрипторов':35,bx:2,')');

{Уничтожаем новый дескриптор}

ah := $45;

dx := Handle;

Intr67;

WriteLn('Новый дескриптор уничтожен:') ;

{Указываем количество оставшихся дескрипторов}

ah := $4В;

Intr67;

Write (' осталось ',Ьх,' дескрипторов, ');

ah := $42;

Intr67;

WriteLn(bx,' свободных страниц') end end.

Дать информацию о распределении памяти

Вход: АН = $4D;

ES-.DI — адрес буфера. Выход: BX — количество активных дескрипторов.

С помощью функции $40 программа может получить информацию обо всех активных дескрипторах. Она возвращает общее количество дескрипторов в регистре BX, а информацию о каждом из них — в массиве, адрес которого передается функции в регистрах ?5 (сегмент) и DI (смещение). Для каждого дескриптора в этом массиве должно быть предусмотрено два 16—разрядных слова, в которые функция помещает сам дескриптор (в первое слово) и количество связанных с ним страниц (во второе).

Дать/установить карту всех страниц Вход: АН = $4Е;

AL = номер подфункции:

О — получить в буфере по адресу ES:DI карту страниц;

1 — установить карту страниц из буфера по адресу DS:SI;

2 — комбинация подфункций 0 и 1;

3 — дать размер буфера для подфункций О...2. BbixoA:AL — размер буфера (для подфункции 3).

Буфер ES:DI заполняется картой страниц (подфункции 0 и 2). функция $4Е используется для быстрой смены содержимого окна. Для этого следует предварительно получить текущую карту страниц с помощью подфункции 0, а затем изменить картирующий контекст. После этого быстрый возврат к прежнему контексту осуществляется с помощью подфункций 1 или 2. Подфункция 3 возвращает размер буфера ES:DI, необходимый для подфункций 0 и 2.

Дать/установить карту части страниц

Вход: АН = $4Р;

AL — номер подфункции: ' О — получить карту;

1 — установить карту;

2 — получить размер буфера для подфункции 0;

ВХ — количество страниц (для подфункции 2);

DS: SI — адрес описателя запроса (для подфункции 0) или карты страниц (для подфункции 1);

ES:DI — адрес буфера (для подфункции 0).

Функция $4F аналогична функции $4Е, но используется для сохранения/восстановления картирования не всех, а только указанных физических страниц. Подфункция 0 обеспечивает сохранение картирования. При обращении к ней регистры DS:SI должны содержать адрес описателя запроса, а регистры ES:DI — адрес буфера, куда будет помещена нужная информация. В первое 2—байтное слово описателя запроса программа помещает общее количество физических страниц, для которых запоминается картирующий контекст, а в остальные слова — сегментные части адресов тех страниц, о которых идет речь.

Как и функция $4Е, функция $4Р предназначена для обслуживания многозадачных систем.

Картировать/освободить несколько страниц одновременно

Вход: АН = $50;

AL — номер подфункции:

О — использовать номера физических страниц;

1 — использовать сегменты физических страниц;

DX — дескриптор EMM;

СХ — количество 4—байтных элементов в б_^ере запроса (по одному элементу на каждую страницу);

DS.-5J — адрес буфера запроса.

Функция $50 обеспечивает картирование сразу нескольких (до четыре^ физических страниц. При обращении к ней регистр AL должен содержат

Доступ к отображаемой памяти 1У1

указание на то, как выбираются физические страницы: если AL'=0 — по номерам, если AL=1 — по сегментам. В регистре СХ должно содержаться количество картируемых страниц, в регистре DX — дескриптор, а в DS-.SI — адрес описателя запроса. Описатель запроса содержит по два слова на каждую картируемую страницу. В первом слове указывается номер логической страницы, а во втором •'- номер (для подфункции AL^O) или сегмент (AL=1) физической страницы. Если в качестве номера логической страницы указан код $FPFF, соответствующая физическая страница перестает быть связанной с какой-либо логической: чтение из нее возвращает значение $FF (255) в любом байте и запись в нее не меняет этого значения.

Изменить количество связанных с дескриптором страниц

Вход: АН = $51;

DX = дескриптор EMM;

ВХ = новое количество страниц.

С помощью функции $51 программа может изменить количество связанных с дескриптором страниц. При обращении к ней регистр DX содержит ранее созданный дескриптор, а ВХ — новое количество логических страниц, связываемых с этим дескриптором. Если ВХ меньше того количества, которым располагает дескриптор к моменту вызова функции, освобождаются страницы со старшими номерами.

Получить/установить флаг сохранения страниц

Вход: АН = $52;

AL = номер подфункции:

О — получить флаг;

1 — установить флаг;

2 — дать признак аппаратной поддержки функций 0 и 1. Выход: AL = флаг сохранения — для подфункции 0 или признак

аппаратной поддержки для подфункции 2. Некоторые EMS— платы поддерживают так называемые сохраняемые страницы. Содержимое таких страниц не меняется при «горячей» перезагрузке ДОС, т.е. при перезагрузке без выключения питания (реализуется кнопкой RESET или клавишами Ctrl-Alt-Del). С помощью функции $52 программа может объявить сохраняемыми страницы, связанные с некоторым дескриптором. Для этого необходимо обратиться к подфункции AL=l, указав в регистре DX дескриптор, а в ВХ флаг сохранения. Если флаг равен единице, страницы становятся сохраняемыми, если нулю — не сохраняемыми. С помощью подфункции AL~=0 можно проверить флаг сохранения страниц (0 — не сохраняются, 1 — сохраняются), а подфункция 2 возвращает в AL признак аппаратной поддержки сохраняемых страниц (0 — нет пода.ержки, 1 — есть поддержка).

Установить/получить имя дескриптора Вход. АН = $53;

AL — номер подфункции:

О — получить имя;

1 — установить имя;

DX — дескриптор EMM;

ES:DI — адрес буфера для подфункции 0;

DS:SI — адрес имени для подфункции 1. Для более удобной реализации связей внутри многозадачных систем можно организовать доступ к дескрипторам по их именам. С этой целью в EMM предусмотрены функции $53 и $54. Первая позволяет установить новое имя дескриптора или получить ранее установленное имя. Вторая обеспечивает поиск дескриптора по его имени. При обращении к подфункции 0 функции $53 (получить имя) в регистре DX указывается дескриптор, а в регистрах ES:DI — адрес буфера длиной 8 байт. В этот буфер помещается связанное с дескриптором имя, соответствующее структуре

array [1..8] of Char

Если имя ранее не было определено, буфер содержит пробелы. При обращении к подфункции 1 (задать имя) в регистрах DS:S/ указывается адрес массива из восьми символов. Эти символы без какого-либо изменения помещаются во внутренний буфер EMM и в дальнейшем могут использоваться для поиска дескриптора. В качестве символов имени можно задавать любые символы ПК от #0 д® #255.

Дать список имен дескрипторов или искать дескриптор по имени

Вход: АН == $54;

AL — номер подфункции:

О — дать список имен;

1 — искать дескриптор;

2 — дать количество активных дескрипторов;

ES:DI — адрес буфера для подфункции 0;

DS.\ST — адрес имени для подфункции 1. Выход: AL — количество дескрипторов (для подфункции 2) или дескриптор (для подфункции 1).

Буфер по адресу ES:DI заполняется списком имен

(для подфункции 0).

функция $54 предназначена в основном для поиска дескриптора по его имени (подфункция 1). Однако с ее помощью можно также получить список имен (подфункция 0) и количество активных дескрипторов (подфункция 2). При обращении к подфункции 0 в ES:DI указывается адрес буфера. Каждому активному дескриптору в этом буфере должно быть выделено по 10 байт: первые два байта при выходе из функции содержат сам дескриптор (его идентификационный номер), а остальные 8 байт — связанное с ним имя.

Картировать память и выполнить инструкцию JUMP

Вход: АН = $55;

AL — номер подфункции:

О — использовать' номера физических страниц;

1 — использовать сегменты страниц;

DX — дескриптор EMM;

DS:SI — адрес буфера запроса. Функции $55 и $56 используются при размещении в отображаемой памяти исполняемых программ. При обращении к функции $55 (картиро— вать и выполнить JUMP) в регистрах DS'.DI содержится адрес описателя запроса. Описатель должен иметь длину 9 байт и соответствовать следующей структуре: первые 4 байта содержат сегмент и смещение точки, куда передается управление по инструкции JUMP FAR, следующий за ними байт указывает количество N картируемых страниц, а остальные 4 байта определяют полный адрес (т.е. сегмент и смещение) массива, описывающего новую карту страниц. Этот массив должен состоять из N пар слов и содержать номер логической страницы (первое слово каждой пары) и номер (для подфункции AL^O) или сегмент (AL=l) физической страницы (второе слово), функция $55 сначала осуществляет нужное картирование, а затем реализует инструкцию JUMP FAR.

{Сортировать память и выполнить инструкцию CALL

Вход: АН = $56;

AL — номер подфункции:

О — использовать номера физических страниц;

1 — использовать сегменты страниц;

2 — получить требуемый размер стека;

DX — дескриптор EMM;

DS:SI — адрес буфера запроса. Выход: ВХ — размер стека (для подфункции 2).

Работает приблизительно так же, как функция $55, но после картирования реализует инструкцию вызова подпрограммы CALL. При обращении к подфункциям 0 и 1 в регистрах DS:SI указывается адрес 22— байтного описателя вызова. Первые 9 байт этого описателя аналогичны описателю для функции $55. За ними следует еще один байт длины и FAR— адрес той карты страниц, которую необходимо установить перед выходом из подпрограммы. Последние 8 байт описателя зарезервированы для использования в EMM. С помощью подфункции 2 программа может получить размер области стека, используемой при вызове подфункций 0 и 1 функции $56.

Переместить/обменять блок памяти

Вход: АН = $57

AL — номер одфункции:

О — переместить блок;

1 — обменять блок;

DS:SI = адрес буфера запроса.

С помощью функции $57 программа может перемещать большие блоки данных как внутри EMS— памяти, так и между отображаемой и стандартной памятью. Максимальная длина перемещаемого блока составляет 1

Мбайт. Допускается полное или частичное перекрытие сегментов. Подфункция 0 осуществляет перемещение блока на новое место, а 1 — обмен блоков (источник помещается на место приемника и наоборот). При обращении к ним в регистрах D5;5J указывается адрес следующего описателя запроса:

MoveBlockType == record

Size : Longint; {Длина блока в байтах) SourceType-: Byte; {Тип источника: 0 - основная память,

1 - отображаемая память} SourceHand: Word; {Дескриптор EMM, если источник

находится в EMS-памяти, или О,

если в основной] SourceOffs: Word; {Смещение начала источника

внутри страницы или сегмента} SourceSegm: Word; {Сегмент или страница источника} DestinType: Byte; {Тип приемника:0 - основная память,

1 - отображаемая} DestinHand: Word; {Дескриптор EMM, если приемник

находится в EMS-памяти, или 0} DestinOffs: Word; {Смещение приемника} DestinSegm: Word; {Сегмент или страница приемника} end;

Получить полную карту EMS-окна

Вход: АН = $58;

AL — номер подфункции:

О — получить карту;

1 — получить длину карты. Выход: СХ — длина карты (для подфункции 1);

ES:DI — буфер (для подфункции 0). С помощью функции $58 программа может получить полную карту БАК—окна. При обращении к подфункции 0 регистры ES:DI содержат адрес буфера, в который будет помещена карта, а при вызове подфункции 1 драйвер помещает в регистр СХ количество 4—байтных элементов этой карты. Первое слово каждого элемента содержит сегмент физической страницы, а второе слово — номер той логической страницы, которая в данный момент отображается в этой физической. Эта карта содержит N элементов, где N — количество активных физических страниц (некоторые физические страницы могут не быть связанны с EMS— памятью).

 

Глава 5

Оглавление

На первую страницу

Rambler's Top100 Rambler's Top100
PROext: Top 1000

(с)Все права защищены

По всем интересующим вопросам прошу писать на электронный адрес

Hosted by uCoz