CFA LogoCFA Logo Computer
Новости Статьи Магазин Драйвера Контакты
Новости
RSS канал новостей
В конце марта компания ASRock анонсировала фирменную линейку графических ускорителей Phantom Gaming. ...
Компания Huawei продолжает заниматься расширением фирменной линейки смартфонов Y Series. Очередное ...
Компания Antec в своем очередном пресс-релизе анонсировала поставки фирменной серии блоков питания ...
Компания Thermalright отчиталась о готовности нового высокопроизводительного процессорного кулера ...
Компания Biostar сообщает в официальном пресс-релизе о готовности флагманской материнской платы ...
Самое интересное
Программаторы 25 SPI FLASH Адаптеры Optibay HDD Caddy Драйвера nVidia GeForce Драйвера AMD Radeon HD Игры на DVD Сравнение видеокарт Сравнение процессоров

АРХИВ СТАТЕЙ ЖУРНАЛА «МОЙ КОМПЬЮТЕР» ЗА 2003 ГОД

Мысли о Паскале

Владислав ДЕМЬЯНИШИН nitromanit@mail.ru

Продолжение, начало см. в МК №46, 51-52, 4, 6-7, 10, 12-13, 16-18, 22, 24, 29, 34, 41, 46, 4, 6, 17, 21, 23, 28, 30, 32, 39, 42, 45 (165, 170-171, 175, 177-178, 181, 183-184, 187-189, 193, 195, 200, 205, 212, 217, 227, 229, 240, 244, 246, 251, 253, 255, 262, 265, 268).

Спрашивали? Отвечаю…

640 Кб для Паскаля не предел

В предыдущих статьях я упоминал о том, что Паскаль-программе может быть доступна вся свободная оперативная память, доступная операционной системе. Как известно, Turbo Pascal предназначен для проектирования программ, работающих под MS-DOS, которой может быть доступно не более 640 Кб оперативной памяти. Но порой такого объема памяти может не хватить прожорливой программе.

Сегодня я расскажу об extended-памяти, которая впервые появилась в компьютерах на базе процессора Intel 80286. В компьютерах на базе процессоров Intel 80386 и выше всегда есть extended-память (eXtended Memory Specification — спецификация дополнительной памяти XMS, это вся оперативная память свыше границы первого мегабайта) и обычно нет аппаратной expanded-памяти (EMS), хотя ее можно эмулировать с помощью драйверов EMM386, QEMM и т.п.

Существует всем известный XMS-драйвер himem.sys, обеспечивающий работу программ, использующих extended-память. Настроить работу этого драйвера можно через config.sys.

В данной статье я расскажу, как составить модуль — назовем его xms.pas, — который бы содержал все необходимые функции для выделения больших непрерывных блоков памяти, размер которых ограничен размерами extended-памяти — 64 Мб или менее. Предположим, что у нас в машине 128 Мб ОЗУ, тогда при работе под MS-DOS можно будет рассчитывать не более чем на 64 Мб XMS. При работе в сеансе MS-DOS под Windows можно будет использовать преимущество виртуальной памяти и запрашивать блоки XMS суммарным объемом намного больше 128 Мб.

В моем модуле XMS описано много полезных функций для работы с большими блоками extended-памяти (EMB — Extended Memory Block), но в данной статье я постараюсь лаконично осветить лишь самые необходимые.

Для начала следует установить директиву компиляции {$G+}, которая включает генерацию машинных инструкций для процессора INTEL80286. Затем опишем структуру TLinePtr для хранения 32-битного адреса (во всех возможных вариациях) и комбинированный тип TXMSPtr для хранения информации о выделенном блоке. При этом нулевое значение поля Allocated будет означать пустой и не инициализированный указатель на EMB, а единичное значение будет указывать на то, что указатель инициализирован для EMB с идентификатором в поле Handle и линейным адресом в поле LPtr, и что по завершении программы этот блок следует освободить. В данной структуре для поля Allocated выбран тип Word, хотя можно было применить и Boolean. Это сделано для того, чтобы размер структуры TXMSPtr был четным, да к тому же кратен двум.

Далее следует объявление экспортируемых процедур и функций модуля.

В блоке реализации объявим структуру для внутреннего использования TEMBCopyRec, которую необходимо заполнять для копирования данных из одной памяти в другую. Например, для копирования данных из DOS-памяти в XMS-память, следует занести нуль в поле SrcHandle, а в поле SrcPtr занести указатель на буфер DOS-памяти, в поле DstHandle поместить идентификатор EMB-блока XMS-памяти, а в поле DstPtr указать смещение в байтах относительно начала EMB-блока. Для реверсной, то есть обратной пересылки данных из XMS-памяти в DOS-память следует поместить в поле SrcHandle идентификатор EMB и в поле SrcPtr указать смещение в байтах относительно начала EMB, а в поле DstHandle поместить нуль и в поле DstPtr дать указатель на буфер DOS-памяти. Размер пересылки данных заносится в поле Counter, причем это значение должно быть четно, иначе пересылка нечетного количества байт — например, 201 байта — не состоится.

Теперь объявим переменную XMM для хранения адреса драйвера и переменную EMBCopy для осуществления всех операций по копированию данных из одной памяти в другую.

Теперь рассмотрим две функции, которые имеют лишь косвенное отношение к работе с XMS, но при этом будут полезны.

Код функции TestX86 реализует «официальный» метод фирмы Intel по распознаванию типа процессора, и в качестве результата возвращает 0, если в машине установлен процессор i8086, либо 1, если в компьютере i80286, либо 2 для i80386 соответственно. Не буду вдаваться в подробности данного метода — ассемблерные магические пассы вроде нижеследующего кода следует принять как должное.

Вторая функция позволяет определить, в каком режиме находится центральный процессор. Результат False будет свидетельствовать о работе процессора в режиме реальных адресов (реальный режим), а True — о том, что процессор находится в виртуальном режиме процессора 8086 (V86, то есть подвиде защищенного режима).

Вот теперь мы подобрались к функциям, которые касаются непосредственно работы с XMS.

Процедура GetXMMAddr для внутреннего использования позволяет получить адрес диспетчера функций драйвера XMS (HIMEM.SYS). Для этого в регистр AX заносится код функции $43 и код подфункции $10 и вызывается программное прерывание $2F, после чего в регистровой паре ES:BX (сегмент в ES, смещение в BX) будет получен адрес драйвера для дальнего вызова.

Работу с драйвером следует начинать с вызова функции InitXMS, которая вовсе не инициализирует драйвер, а просто проверяет наличие драйвера XMS в памяти и пытается получить его адрес в переменную XMM. Если драйвер загружен, то функция возвращает True, иначе False. Для обнаружения драйвера в регистр AX заносится код функции $43 и код подфункции $00 и вызывается прерывание $2F. Если в регистре AL возвращено значение $80, значит, драйвер присутствует, и наоборот.

Вот теперь можно непосредственно заняться работой с XMS.

Для начала проведем ревизию свободной памяти. Для этого поместим номер функции 8 драйвера в AH, и вызовем диспетчер функций драйвера. В регистре AX будет возвращен размер максимального свободного EMB в килобайтах, а в регистре DX суммарный объем свободной XMS в килобайтах. Размер максимального свободного EMB можно получить функцией MaxXMSAvail, так как для удобства в ней игнорируется значение регистра DX.

Для получения суммарного объема свободной XMS при помощи функции MemXMSAvail вызываем ту же функцию драйвера, но в качестве результата возвращаем значение регистра DX.

Следующие функции тоже для внутреннего использования. Первая из них, GetEMB, позволяет выделить EMB размером Size килобайт. Для этого в регистр DX заносим размер, в AH номер функции 9 драйвера. При возникновении ошибки в регистре AX будет возвращен нуль, а в регистре BL код ошибки. При успешном выделении EMB в регистре AX будет ненулевое значение, а в DX — идентификатор выделенного EMB. В итоге функция GetEMB при удачном выделении EMB возвращает нуль, иначе код ошибки — например, ошибка с кодом $0A0 означает, что не хватает XMS для выделения EMB затребованного размера.

Процедура FreeEMB освобождает EMB, для чего в AH помещаем номер функции $0A, а в DX — идентификатор освобождаемого EMB.

Возможная ошибка игнорируется.

Ну и конечно, зачем нам нужен блок памяти, если в него нельзя пересылать и читать из него данные? Ответом на этот вопрос послужит функция CopyEMB. В регистре AH номер функции —$0B; регистровая же пара DS:SI должна содержать указатель на структуру типа TEMBCopyRec. Поэтому для удобства я объявил переменную EMBCopy в сегменте данных, чтобы не пришлось изменять содержимое регистра DS в блоке реализации данной функции. Если в регистре AX возвращено нулевое значение, значит, произошла ошибка, и ее код находится в регистре BL. Иначе в AX найдем ненулевое значение.

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

Иногда возникает необходимость работать напрямую с линейным адресом EMB, например, в режиме реальных адресов. Для получения линейного 32-битного адреса выделенного EMB служит функция GetLinePointer. В AH загружаем номер $0C функции блокирования EMB, а в DX ее идентификатор. В регистровой паре DX:BX будет возвращен линейный адрес. Если в регистре AX возвращено нулевое значение, значит, произошла ошибка, ее код находится в регистре BL. Иначе в AX — ненулевое значение. При удаче функция GetLinePointer возвращает нуль, иначе код ошибки.

Ну и последнее — внутренняя процедура по разблокированию EMB.

В регистр AH загружается номер функции $0D, а в DX — идентификатор разблокируемого EMB.

Литература:

Диалоговая справочная система Norton Guide.

Д-р Джон М. Гудмэн. Управление памятью для всех — К.: Диалектика, 1996. — 520 с.

(Продолжение следует)

Рекомендуем ещё прочитать:






Данную страницу никто не комментировал. Вы можете стать первым.

Ваше имя:
Ваша почта:

RSS
Комментарий:
Введите символы или вычислите пример: *
captcha
Обновить





Хостинг на серверах в Украине, США и Германии. © sector.biz.ua 2006-2015 design by Vadim Popov