В отличие от расширенной памяти дополнительная память с помощью специальной аппаратуры и программного обеспечения отображается в диапазон адресов, лежащий ниже границы 1 Мбайт. Такой способ пригоден для компьютеров, использующих процессор Intel 8086, не обладающий возможностью адресации расширенной памяти.
Чтобы понять, как происходит отображение, вспомним распределение первого мегабайта оперативной памяти. Область с адресами от 00000 до 9FFFF - это стандартная память размером 640К. (Мы используем здесь физический 20-разрядный адрес). Диапазон адресов от A0000 до BFFFF используется видеоадаптерами. Наконец, 256 Кбайтов с адресами C0000 - FFFFF используется для BIOS.
Однако обычно BIOS не занимает все 256 Кбайтов адресного пространства, оставляя "окна" размером в десятки килобайтов. С помощью специальной аппаратуры можно отображать эти окна на участки дополнительной памяти, как бы "подставляя" участки памяти под адреса "окон".
В практике построения вычислительных систем на основе микропроцессоров такая техника используется уже давно. Для компьютеров IBM PC/XT/AT корпорации Lotus Development, Intel и Microsoft разработали спецификацию расширенной памяти (Expanded Memory Specification - EMS). В настоящий момент распространены версии 3.2 и 4.0 этой спецификации.
Существует альтернативная спецификация Extended Expanded Memory Specification - EEMS), отличающаяся от версии EMS 3.2 в основном наличием поддержки мультизадачных операционных систем. Эта спецификация была разработана другой группой крупных производителей компьютерного оборудования: AST Research, Ashton-Tate, Quadram. Однако эта спецификация не получила широкого распространения. Версия 4.0 EMS включила в себя все расширения спецификации EEMS.
В спецификации EMS в качестве окна для доступа к дополнительной памяти используются 64 килобайта, расположенные по адресам C0000h - EFFFFh. Это окно в спецификации называется "page frame". Окно разбивается на четыре сегмента по 16 килобайтов. Вся дополнительная память разбивается на логические страницы (logical page) размером по 16 килобайтов. Любая логическая страница может быть отображена на любой сегмент окна доступа. Таким образом, используя четыре сегмента, программа может адресоваться одновременно к любым четырем логическим страницам дополнительной памяти.
На рисунке схематически показано отображение логических страниц дополнительной памяти на сегменты 64-килобайтного окна, расположенного в области адресов ПЗУ:
Для использования дополнительной памяти в компьютер должна быть вставлена плата дополнительной памяти и в файле CONFIG.SYS подключен специальный драйвер, который обычно поставляется вместе с платой памяти. Драйвер выполняет управление дополнительной памятью и называется EMM (Expanded Memory Manager).
Операционная система MS-DOS версии 4.01 содержит драйвер XMA2EMS.SYS, реализующий функции управления дополнительной памятью. Этот драйвер должен быть подключен в файле CONFIG.SYS следующим образом:
DEVICE=XMA2EMS.SYS [FRAME=xxxx] [Pnnn=xxxx] [/X:pages]
Параметр FRAME задает базовый адрес для 64-килобайтового окна доступа в виде шестнадцатеричного сегментного адреса, например C000. Этот адрес должен находиться в диапазоне C000 - E000.
Параметр Pnnn позволяет задать базовый адрес для конкретной страницы дополнительной памяти. Здесь nnn - это номер страницы (0-255), xxxx - сегментный адрес в шестнадцатеричном формате. При использовании параметра FRAME нельзя указывать параметры P0, P1, P2, P3.
Параметр /X:pages определяет, сколько страниц дополнительной памяти будет использовано. По умолчанию используется вся дополнительная память.
Если ваш компьютер имеет процессор 80386 и расширенную память, вы можете использовать драйвер EMM386.SYS, поставляемый в составе MS-DOS версии 4.01. Этот драйвер эмулирует дополнительную память на расширенной памяти. При этом несколько снижается производительность системы.
Драйвер может быть подключен следующим образом:
DEVICE=EMM386.SYS [size] [X:mmmm-nnnn] [Mx]
Параметр size определяет количество используемой драйвером расширенной памяти в килобайтах. Значение по умолчанию - 256 Кбайт.
Параметр X:mmmm-nnnn определяет диапазон памяти, которая не должна быть использована для размещения окон доступа.
Параметр Mx задает расположение окна доступа, используемого для отображения логических страниц дополнительной памяти. Соответствие параметра x сегментному адресу окна приведено в таблице:
x Адрес окна доступа 0 C000 1 C400 2 C800 3 CC00 4 D000 5 D400 6 D800 7 DC00 8 E000
Драйвер дополнительной памяти устанавливает вектор прерывания INT 67h таким образом, что этот вектор указывает на заголовок драйвера. При изучении драйверов мы рассказывали вам о формате заголовка. Сейчас для нас важно, что со смещением 10 в заголовке располагается имя драйвера - "EMMXXXX0". Следовательно, для проверки подключения драйвера мы можем, получив адрес заголовка, сравнить восемь байтов имени устройства со строкой "EMMXXXX0". При совпадении мы можем считать, что драйвер дополнительной памяти установлен.
Для проверки установки драйвера вы можете использовать следующую функцию, выполняющую все описанные действия:
/** *.Name ems_init *.Title Функция проверяет установку драйвера EMS * *.Descr Эта функция проверяет наличие драйвера EMS * *.Proto int ems_init(void); * *.Params Не используются * *.Return 0 - драйвер EMS установлен; * 1 - драйвер EMS не установлен. * *.Sample ems_test.c **/ #include <stdio.h> #include <dos.h> #include "sysp.h" int ems_init(void) { void (_interrupt _far *EMS_driver_adr)(void); char _far *EMS_driver_name; char test_name[8]; int i; EMS_driver_adr = _dos_getvect(0x67); FP_SEG(EMS_driver_name) = FP_SEG (EMS_driver_adr); FP_OFF(EMS_driver_name) = 10; for(i=0; i<8; i++) test_name[i] = EMS_driver_name[i]; if(strncmp(test_name, "EMMXXXX0", 8) == 0) return(0); else return(1); }
Для вызова функций драйвера дополнительной памяти программа должна загрузить код функции в регистр AH, код подфункции (обычно 0) в регистр AL, и затем вызвать прерывание INT 67h.
После возврата из прерывания в регистр AH будет записано слово состояния. При успешном выполнении функции оно равно 0.
Стандартные функции - это небольшое подмножество функций EMM, необходимое для работы обычных прикладных программ (не резидентных и не драйверов). Все эти функции поддерживаются EMM версии 3.2.
На входе: AX = 4000h. На выходе: AH = байт состояния EMM.
Эта функция используется для проверки состояния драйвера EMM. Она должна использоваться только после того, как программа убедилась в наличии драйвера EMM.
Для получения состояния EMM используйте следующую функцию:
/** *.Name ems_stat *.Title Определение состояния драйвера EMS * *.Descr Эта функция возвращает байт состояния * драйвера EMS * *.Proto char ems_stat(void); * *.Params Не используются * *.Return Байт состояния драйвера EMS * *.Sample ems_test.c **/ #include <stdio.h> #include <dos.h> #include "sysp.h" char ems_stat(void) { union REGS reg; struct SREGS sreg; reg.x.ax = 0x4000; int86(0x67, ®, ®); return(reg.h.ah); }
На входе: AX = 4100h. На выходе: AH = байт состояния EMM; BX = сегмент окна для доступа к логическим страницам дополнительной памяти.
Функция позволяет получить сегмент 64-килобайтного окна, используемого драйвером EMS для доступа к логическим страницам расширенной памяти.
/** *.Name ems_fram *.Title Определение сегмента окна доступа * *.Descr Эта функция возвращает сегментный адрес * окна, которое используется для доступа к * дополнительной памяти. * *.Proto char ems_fram(unsigned *frame); * *.Params unsigned *frame - Указатель на переменную, * в которую будет записан сегментный * адрес окна доступа. * *.Return Сосотояние EMM. * *.Sample ems_test.c **/ #include <stdio.h> #include <dos.h> #include "sysp.h" char ems_fram(unsigned *frame) { union REGS reg; struct SREGS sreg; reg.x.ax = 0x4100; int86(0x67, ®, ®); *frame = reg.x.bx; return(reg.h.ah); }
На входе: AX = 4200h. На выходе: AH = байт состояния EMM; DX = общее количество 16-килобайтных страниц EMS в системе; BX = число доступных в настоящее время страниц EMS.
Эта функция позволяет вам получить информацию о наличии и доступности страниц дополнительной памяти.
/** *.Name ems_page *.Title Определение количества страниц EMS * *.Descr Эта функция предназначена для определения * общего количества страниц EMS и количества * страниц, доступных в настоящее время. * *.Proto char ems_page(unsigned *total, unsigned *free); * *.Params unsigned *total - указатель на переменную, * в которую будет записано общее количество * страниц памяти EMS; * unsigned *free - указатель на переменную, * в которую будет записано количество * доступных страниц памяти EMS; * *.Return Сосотояние EMM. * *.Sample ems_test.c **/ #include <stdio.h> #include <dos.h> #include "sysp.h" char ems_page(unsigned *total, unsigned *free) { union REGS reg; reg.x.ax = 0x4200; int86(0x67, ®, ®); *total = reg.x.dx; *free = reg.x.bx; return(reg.h.ah); }
На входе: AX = 4300h; BX = требуемое в данном пуле количество логических страниц. На выходе: AH = байт состояния EMM; DX = индекс пула EMS, он будет использоваться в операциях с пулом логических страниц.
Эта функция позволяет заказать пул логических страниц (т.е. некоторую совокупность логических страниц дополнительной памяти). Полученному пулу присваивается индекс (handle), который указывает на пул и используется во всех операциях с пулом.
/** *.Name ems_open *.Title Открытие индекса пула страниц EMS * *.Descr Эта функция открывает индекс пула страниц * EMS, делая доступными логические страницы * дополнительной памяти. * *.Proto int ems_open(int n_pages, int *handle); * *.Params int n_pages - количество требуемых логических * страниц; * int *handle - указатель на слово, в которое * будет записан индекс полученного пула. * *.Return Байт состояния драйвера EMS * *.Sample ems_test.c **/ #include <stdio.h> #include <dos.h> #include "sysp.h" int ems_open(int n_pages, int *handle) { union REGS reg; reg.x.ax = 0x4300; reg.x.bx = n_pages; int86(0x67, ®, ®); *handle = reg.x.dx; return(reg.h.ah); }
На входе: AH = 44h; AL = номер физической страницы окна доступа (от 0 до 3); BX = номер логической страницы из числа находящихся в пуле страниц (от 0 до n-1, где n - количество логических страниц в пуле); для версии EMS 4.0 задание значения 0FFFFh приводит к запрещению отображения физических страниц пула, для разрешения их отображения необходимо вызвать эту функцию еще раз, указав правильный номер страницы; DX = индекс EMM, полученный от функции 43h. На выходе: AH = байт состояния EMM.
Функция выполняет отображение (привязку) одной из логических страниц пула к одному их четырех 16-килобайтных сегментов окна просмотра, т.е. к физическим страницам.
/** *.Name ems_map *.Title Отобразить память EMS * *.Descr Эта функция отображает логические страницы * пула дополнительной памяти на физические. * *.Proto int ems_map(int phys_page, int log_page, * int handle); * *.Params int phys_pages - номер физической страницы * окна доступа (от 0 до 3), на которую необходимо * отобразить логическую страницу пула; * * int_log_page - номер логической страницы пула; * * int *handle - индекс полученного пула; * *.Return Байт состояния драйвера EMS * *.Sample ems_test.c **/ #include <stdio.h> #include <dos.h> #include "sysp.h" int ems_map(int phys_page, int log_page, int handle) { union REGS reg; reg.h.ah = 0x44; reg.h.al = phys_page; reg.x.bx = log_page; reg.x.dx = handle; int86(0x67, ®, ®); return(reg.h.ah); }
На входе: AX = 4500h; DX = индекс EMM. На выходе: AH = байт состояния EMM.
Функция освобождает все логические страницы пула. После освобождения эти страницы могут быть повторно распределены.
/** *.Name ems_clos *.Title Закрытие индекса пула страниц EMS * *.Descr Эта функция закрывает индекс пула страниц, * полученный функцией ems_open(). * *.Proto int ems_clos(int *handle); * *.Params int *handle - указатель на слово, в которое * будет записан индекс полученного пула. * *.Return Байт состояния драйвера EMS * *.Sample ems_test.c **/ #include <stdio.h> #include <dos.h> #include "sysp.h" int ems_clos(int *handle) { union REGS reg; reg.x.ax = 0x4500; reg.x.dx = *handle; int86(0x67, ®, ®); return(reg.h.ah); }
На входsе: AX = 4600h. На выходе: AH = байт состояния EMM; AL = номер версии в двоично-десятичном (BCD) формате, 32h соответствует версии 3.2.
Версия 4.0 EMM поддерживает больше функций по управлению дополнительной памятью, чем версия 3.2. Прежде чем использовать такие функции, следует определить номер используемой версии EMM с помощью функции 46h.
/** *.Name ems_ver *.Title Определение версии драйвера EMS * *.Descr Эта функция возвращает номер версии * драйвера EMS в двоично-десятичном формате. * *.Proto int ems_ver(char *ver); * *.Params char *ver - указатель на байт, в который * будет записан номер версии. * *.Return Номер версии драйвера EMS в формате BCD * *.Sample ems_test.c **/ #include <stdio.h> #include <dos.h> #include "sysp.h" int ems_ver(char *ver) { union REGS reg; reg.x.ax = 0x4600; int86(0x67, ®, ®); *ver = reg.h.al; return(reg.h.ah); }
Дополнительные функции используются резидентными программами, драйверами и мультизадачными приложениями. Кроме того, с помощью этих функций можно выполнять пересылку массивов в дополнительной и стандартной памяти, а также организовать подкачку и выполнение программных модулей в дополнительной памяти.
Обратите внимание, что использование расширенной памяти в спецификации XMS позволяет выполнять программные модули (с ограничениями) только в области HMA размером примерно 64 килобайта. Остальная расширенная память может быть использована только для хранения данных.
Специальные функции с номерами 47h - 4Eh поддерживаются EMM версии 3.2, функции с номерами 4Fh - 58h - только EMM версии 4.0.
На входе: AX = 4700h; DX = индекс EMM. На выходе: AH = байт состояния EMM.
Эта функция предназначена для использования драйверами и резидентными программами. Прежде чем работать с дополнительной памятью, такие программы должны сохранить текущий контекст отображения логических страниц. Перед возвратом управления прикладной программе контекст должен быть восстановлен с помощью функции 48h.
На входе: AX = 4800h; DX = индекс EMM. На выходе: AH = байт состояния EMM.
Функция позволяет восстановить контекст отображения логических страниц пула, сохраненный предыдущей функцией.
На входе: AX = 4B00h; DX = индекс EMM. На выходе: AH = байт состояния EMM; BX = количество логических страниц в пуле.
Функция возвращает количество логических страниц дополнительной памяти для выбранного пула.
На входе: AX = 4C00h; DX = индекс EMM. На выходе: AH = байт состояния EMM; BX = количество активных пулов дополнительной памяти.
Функция предназначена для определения количества текущих активных пулов и может вызываться перед использованием следующей функции (с номером 4Dh).
На входе: AX = 4D00h; ES:DI = адрес буфера для информации. На выходе: AH = байт состояния EMM; BX = количество активных пулов дополнительной памяти.
После вызова функции буфер заполняется как массив структур, содержащих два 16-битовых слова. Первое слово содержит индекс пула, второе - количество логических страниц в этом пуле.
На входе: AH = 4Eh; AL = код подфункции: 0 - получить содержимое всех регистров отображения в буфер ES:DI; 1 - восстановить содержимое всех регистров отображения из буфера ES:DI; 2 - получить и установить все регистры отображения в буфер ES:DI или восстановить из буфера ES:DI (т.е. комбинация подфункций 0 и 1); 3 - Определить размер требуемого буфера; ES:DI = адрес буфера для информации; На выходе: AH = байт состояния EMM; AL = для подфункции 3 - размер буфера.
Эта функция предназначена для поддержки мультизадачности. Она позволяет быстро изменять контекст дополнительной памяти при переключении с одного процесса на другой.
На входе: AH = 4Fh; AL = код подфункции: 0 - получить содержимое регистров отображения в буфер ES:DI; 1 - восстановить содержимое регистров отображения из буфера ES:DI; 2 - определить размер требуемого буфера; ES:DI = адрес буфера для информации; DS:SI = адрес массива 16-битовых слов, содержащих сегментные адреса страниц, для которых необходимо сохранить контекст отображения; самое первое слово массива - это размер массива в словах. На выходе: AH = байт состояния EMM; AL = для подфункции 2 - размер буфера.
Функция работает аналогично предыдущей, но позволяет сохранять контексты только для некоторых страниц. Это экономит время, необходимое для сохранения/восстановления.
На входе: AH = 50h; AL = код подфункции: 0 - разрешить или запретить отображение страниц, используя номера страниц; 1 - аналогично подфункции 0, но используются не номера страниц, а адреса сегментов; DS:SI = адрес массива структур, состоящий из двух слов, первое слово - номер логической страницы, второе - номер физической страницы; указание логической страницы 0FFFFh запрещает отображение страницы; CX = размер массива DS:SI в количестве структур. На выходе: AH = байт состояния EMM.
Функция позволяет за один вызов разрешить и запретить использование нескольких страниц.
На входе: AX = 5100h; BX = новый размер пула в логических страницах; DX = индекс EMM. На выходе: AH = байт состояния EMM.
С помощью этой функции программа может изменить размер уже заказанного ранее пула страниц дополнительной памяти.
На входе: AH = 52h; AL = код подфункции: 0 - получить атрибуты пула; 1 - установить атрибуты пула; 2 - определить возможность использования атрибута неразрушаемой памяти; BL = новые атрибуты; DX = индекс EMM. На выходе: AH = байт состояния EMM; AL = для подфункции 0: атрибуты пула; для подфункции 2: 0 - атрибут неразрушаемой памяти недоступен; 1 - атрибут неразрушаемой памяти доступен.
Функция дает возможность установить для некоторых пулов атрибут неразрушаемой памяти. Содержимое таких пулов не исчезает при теплой перезагрузке операционной системы (после нажатии комбинации клавиш Ctrl-Alt-Del).
На входе: AH = 53h; AL = код подфункции: 0 - получить имя пула; 1 - установить имя пула; ES:DI = адрес буфера имени пула, длина этого буфера должна быть 8 байтов; DX = индекс EMM. На выходе: AH = байт состояния EMM.
Функция предназначена для использования в мультизадачной среде. Она позволяет нескольким процессам, работающим одновременно, использовать одни и те же именованные пулы дополнительной памяти.
На входе: AH = 54h; AL = код подфункции: 0 - получить каталог пулов; 1 - найти пул по имени; 2 - определить количество открытых пулов; DS:SI = адрес буфера имени пула для подфункции 1, длина этого буфера должна быть 8 байтов; ES:DI = адрес массива 10-байтовых элементов; в первое слово элемента будет записан индекс пула, в остальные 8 - имя пула. На выходе: AH = байт состояния EMM; AL = количество элементов в массиве (подфункция 0); DX = индекс найденного пула (для подфункции 1); BX = количество открытых пулов (для подфункции 2).
Эта функция позволяет определить индекс пула по его имени или получить каталог всех именованных пулов.
На входе: AH = 55h; AL = код подфункции: 0 - использовать массив номеров физических страниц; 1 - использовать массив сегментных адресов; DS:SI = адрес структуры MapAndJump длиной 9 байтов. На выходе: AH = байт состояния EMM.
Эта функция предназначена для перекачки страниц исполняемого кода в память и последующего выполнения этого кода.
Первые четыре байта структуры MapAndJump содержат смещение и сегментный адрес, по которым должен быть выполнен переход. Следующий байт - количество элементов в таблице отображения. Последние 4 байта содержат FAR-адрес таблицы отображения, состоящей из 4-байтовых элементов. Первое слово элемента таблицы отображения - номер логической страницы, второе - номер физической страницы.
На входе: AH = 56h; AL = код подфункции: 0 - использовать массив номеров физических страниц; 1 - использовать массив сегментных адресов; 2 - получить размер стека, необходимого для использования подфункций 0 и 1; DS:SI = адрес структуры MapAndCall длиной 22 байта. На выходе: AH = байт состояния EMM; BX = требуемый размер стека (заполняется при выполнении подфункции 2).
Функция работает аналогично предыдущей, но не передает управление исполняемому коду, а вызывает его как процедуру.
Первые 9 байтов структуры MapAndCall соответствуют структуре MapAndJump. Далее идет еще один байт длины таблицы отображения и 4 байта адреса другой таблицы отображения. Вторая таблица описывает отображение страниц, которое будет установлено после вызова процедуры. Последние 8 байтов структуры зарезервированы для дальнейшего использования.
На входе: AH = 57h; AL = код подфункции: 0 - переслать область памяти; 1 - обменять область памяти; DS:SI = адрес структуры MoveInfo длиной 18 байтов. На выходе: AH = байт состояния EMM.
Функция предназначена для выполнения перемещения или обмена содержимого областей стандартной или дополнительной памяти. Возможно перекрытие исходной и результирующей областей памяти. Максимальный размер блоков, над которыми эта функция может выполнять операции - 1 мегабайт.
Структура MoveInfo содержит всю необходимую информацию о расположении блоков памяти:
Смещение Размер Описание (+0) 4 Размер блока в байтах (+4) 1 Тип исходной памяти: 0 - стандартная, 1 - EMS (+5) 2 Индекс исходной памяти: 0 для стандартной памяти, индекс пула для EMS (+7) 2 Смещение для исходной памяти (внутри сегмента или страницы) (+9) 2 Адрес исходного сегмента или номер для исходной страницы (+11) 1 Тип результирующей памяти: 0 - стандартная, 1 - EMS (+12) 2 Индекс результирующей памяти: 0 для стандартной памяти, индекс пула для EMS (+14) 2 Смещение для результирующей памяти (внутри сегмента или страницы) (+16) 2 Адрес результирующего сегмента или номер для исходной страницы
Получить массив адресов отображения
На входе: AH = 58h; AL = код подфункции: 0 - получить массив отображения; 1 - получить размер массива отображения; ES:DI = адрес буфера для массива отображения. На выходе: AH = байт состояния EMM; CX = количество элементов в массиве отображения (для подфункции 1)
Массив отображения, получаемый при помощи этой функции, состоит из 4-байтовых элементов. Первое слово элемента содержит адрес сегмента, второе - номер физической страницы, соответствующей этому адресу.
Все функции EMM возвращают код ошибки в регистре
AH:
Код |
Ошибка |
00h |
Нет ошибки, нормальное завершение |
80h |
Внутренняя ошибка драйвера EMM |
81h |
Ошибка аппаратуры EMS-памяти |
82h |
EMM занят |
83h |
Неправильный индекс пула |
84h |
Неправильный номер запрошенной функции |
85h |
Больше нет доступных индексов пулов |
86h |
Ошибка при выполнении сохранения или
восстановления контекста отображения |
87h |
Запрошено больше памяти, чем общее
количество доступной EMS-памяти |
88h |
Запрошено больше страниц, чем доступно |
89h |
Нельзя открыть индекс пустого пула |
8Ah |
Пул не содержит так много страниц |
8Bh |
Неправильное отображение, заданы номера
|
|
физических страниц, отличные от 0 - 3 |
8Ch |
Переполнена область сохранения
контекста отображения |
8Dh |
Многократное сохранение контекста для
одного пула |
8Eh |
Попытка восстановления несохраненного
контекста |
8Fh |
Неправильный номер подфункции в
регистре AL |
90h |
Неправильный тип атрибута |
91h |
Не поддерживается неразрушаемая память |
92h |
Произошло перекрытие исходной и
результирующей областей (это не ошибка, а
предупреждение) |
93h |
Область назначения, заданная индексом,
слишком мала |
94h |
Стандартная память перекрывается
дополнительной памятью |
95h |
Слишком большое смещение при пересылке
блока |
96h |
Слишком большой размер блока, больше 1
мегабайта |
97h |
Заданы одинаковые исходный и
результирующий индексы |
98h |
Задан неправильный тип памяти (смещение
4) |
A0h |
Заданному имени не соответствует ни
один пул |
A1h |
Заданное имя уже существует |
A2h |
Длина исходной области больше 1
мегабайта |
A3h |
Содержимое заданного блока данных
неверно |
A4h |
Доступ к этой функции запрещен |
Приведенная ниже программа демонстрирует использование основных функций EMM:
#include <stdio.h> #include <conio.h> #include "sysp.h" void main(void); void main(void) { unsigned frame, err; unsigned total, free; unsigned handle; char ver; // Это сообщение будет переписано сначала из // области стандартной памяти в область дополнительной, // затем обратно в область основной. static char test_msg[] = "Тестовое сообщение для " "записи в область EMS."; char buf[80]; char _far *ptr; int i; // Проверяем, установлен ли драйвер EMS. if(ems_init() != 0) { printf("\nДрайвер EMS не установлен."); exit(-1); } // Если драйвер установлен, определяем его состояние. printf("\nДрайвер EMS установлен, состояние: %02.2X.", ems_stat()); // Выводим номер версии драйвера if((err = ems_ver(&ver)) != 0) { printf("\nОшибка: %02.2X", err); exit(-1); } printf("\nВерсия EMM: %02.2X", ver); // Определяем сегмент окна доступа if((err = ems_fram(&frame)) != 0) { printf("\nОшибка: %02.2X", err); exit(-1); } printf("\nСегмент окна доступа: %04.4X", frame); // Определяем общее количество страниц и // количество доступных страниц. if((err = ems_page(&total, &free)) != 0) { printf("\nОшибка: %02.2X", err); exit(-1); } printf("\nОбщее количество страниц EMS: %d" "\nКоличество доступных страниц: %d", total, free); // Заказываем пул в дополнительной памяти. if((err = ems_open(free, &handle)) != 0) { printf("\nОшибка: %02.2X", err); exit(-1); } // Отображаем нулевую физическую страницу // на нулевую логическуб страницу пула. if((err = ems_map(0, 0, handle)) != 0) { printf("\nОшибка: %02.2X", err); exit(-1); } // Конструируем указатель на физическую страницу. ptr = FP_MAKE(frame,0); // Копируем тестовое сообщение в // дополнительную память. printf("\nКопируем в EMS: %s",test_msg); for(i=0; test_msg[i] != 0; i++) ptr[i] = test_msg[i]; // Теперь копируем это сообщение обратно // в стандартную память. for(i=0; ptr[i] != 0; i++) buf[i] = ptr[i]; buf[i] = 0; // Выводим сообщение на экран для // проверки. printf("\nСкопировано из EMS: %s",buf); // Закрываем пул. if((err = ems_clos(&handle)) != 0) { printf("\nОшибка: %02.2X", err); exit(-1); } exit(0); }