Работа с расширенной памятью
Сохранение и восстановление рабочей области экрана
В примере Б.7 основные действия выполняет строковая операция movs, у которой расположение источника задает регистр fs, а приемника – es. Следовательно, для сохранения содержимого видеопамяти в расширенной памяти в регистр fs надо записать код видеосегмента, а в es – код сегмента EMS. Для восстановления содержимого видеопамяти, сохраненного в расширенной памяти в регистре fs, указывается код сегмента EMS, а в es – код видеобуфера. Формирование нужных значений в регистрах es и fs выполняют подпрограммы, приведенные в примере Б.8. Для сохранения содержимого видеопамяти используется обращение к подпрограмме scrsave, а для восстановления – к scrrest. Входные параметры отсутствуют.
Пример Б.8. Сохранение или восстановление рабочей области экрана.
scrsave: PushReg <fs,es,vbuff,ebuff>; размещение в стеке jmp short @F обход макровызова scrrest: PushReg <fs,es,ebuff vbuff>; размещение в стеке @@: call Hidepnt удаление изображения курсора PopReg <es,fs> формируем содержимое es и fs call Movebl перемещение блока PopReg <es,fs> восстановление содержимого es и fs call Showpnt вывод курсора на экран ret возврат из подпрограммы
При вызове scrsave в стеке сохраняется исходное содержимое регистров fs, es и переменных vbuff, ebuff. При обращении к scrrest порядок записи в стек переменных ebuff, vbuff противоположный. После размещения в стеке нужных величин выполняется общая часть обеих подпрограмм.
Прежде всего надо удалить изображение курсора с экрана, иначе при сохранении оно станет частью общей картины, а при восстановлении на экране могут появиться два курсора, или при перемещении на месте курсора окажется прямоугольник другого цвета.
После этого в регистры fs и es выталкиваются из стека нужные величины, происходит обращение к подпрограмме movebi и восстанавливается исходное содержимое регистров fs и es.
Выполнение подпрограмм заканчивается восстановлением изображения курсора на экране. Напомним, что варианты подпрограмм Hidepnt и Showpnt описаны в Главе 6.
Несколько блоков в расширенной памяти
При работе с обычной памятью каждому блоку соответствует свой уникальный код сегмента. В отличие от обычной, при работе с расширенной памятью доступ ко всем зарезервированным задачей блокам осуществляется через один и тот же сегмент EMS. В таком случае по коду сегмента невозможно определить блок, к которому происходит обращение. Для этой цели можно использовать только смещение (адрес), по которому выбираются или записываются данные. Для того чтобы понять, к чему это приводит, рассмотрим простой вариант работы с двумя блоками.
Предположим, что доступны два блока, и надо переписать данные из одного в другой. Если один из блоков расположен в видео или в обычной памяти, а другой в расширенной, то размер пересылаемой порции данных ограничен адресным пространством сегмента, т. е. величиной 65 536 байтов. В этом вы могли убедиться на примере Б.7.
Если же оба блока расположены в расширенной памяти, то пространство сегмента EMS придется разделить пополам и использовать младшие адреса для работы с одним из блоков, а старшие – с другим. В результате этого в каждом блоке будет доступно пространство размером 32 768 байтов. Никаких других ограничений нет.
В таком случае перед копированием порции данных придется дважды обратиться к подпрограмме отображения страниц, описанной в примере Б.6, через точку входа mapip. Сначала отображаются две очередные логические страницы блока 1 на физические страницы 0 и 1, затем две очередные логические страницы блока 2 на физические страницы 2 и 3. Блок 1 начинается с нулевого адреса сегмента EMS, а блок 2 с адреса soooh того же сегмента. Предельный размер доступного пространства в обоих блоках составляет soooh или 32 768 байтов. После этого можно использовать любые команды для работы с отображенным пространством, например, строковую операцию movs, выполняющую перемещение данных из блока в блок.
Если особенности алгоритма требуют одновременной работы с тремя или четырьмя блоками, то доступное пространство будет ограничено размером одной страницы, т. е. величиной 16 384 байта.
Здесь уместно отметить, что в набор Advanced Functions драйвера EMM включена специальная функция, предназначенная для перемещения или обмена содержимого (перестановки) двух блоков данных размером до 1 Мбайт, ее код 57h. Блоки могут располагаться в обычной или расширенной памяти. Перед вызовом функции 57h в регистре ai указывается 0 для пересылки или 1 для перестановки блоков. Кроме того, в регистрах ds:si указывается адрес начала специальной структуры данных, содержащей размер блока и данные об источнике и приемнике. Описание этой функции вы можете найти, например, в Tech Help, нам важно было напомнить о ее существовании.
Заключение
Мы закончили описание основных видов оперативной памяти, поэтому можно подвести общий итог. При работе в среде DOS для программ доступна как основная, так и дополнительная память. Реальные размеры последней существенно больше размеров первой, поэтому при разработке задач следует отдавать предпочтение расположению больших блоков в расширенной памяти, а блоки небольшого размера размещать в обычной памяти. Кроме того, следует избегать одновременного использования нескольких блоков, расположенных в расширенной памяти, т. к. это связано с ограничением доступного пространства адресов.