ПОИСК
Категории книг
ОПРОС
Вопрос: Какой язык программирования вы предпочитаете
С/C++
Delphi
Visual Basic
Perl
Java
PHP
ASP
Другой
ЭТО ПОЛЕЗНО!
ОБРАТНАЯ СВЯЗЬ

/ Главная / Программирование / Иллюстрированный самоучитель по SVGA
Иллюстрированный самоучитель по SVGA

     

Работа с расширенной памятью

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

Способ пересылки большого блока

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

Размер рабочего пространства видеопамяти зависит от установленного видеорежима, он вычисляется умножением размера строки в байтах на количество строк на экране (bperiine versize). Для временного хранения произведения нужна переменная, состоящая из двух слов (но не одно двойное слово), назовем ее bisize. В первом слове будет храниться старшая часть произведения, а во втором слове — младшая. Старшая часть указывает количество полных окон видеопамяти, а младшая часть — количество байтов в последнем окне, оно может быть равно нулю.

Если в результате умножения в первом слове bisize окажется число N, а во втором bisize+2 число м, то размер отображаемой части видеопамяти составляет N* 6553б + м байтов, т. е. надо переслать N полных сегментов и еше м байтов. Поэтому перед пересылкой очередного фрагмента данных необходимо уточнять его размер.

Кроме того, перед пересылкой каждого фрагмента производится отображение очередной группы логических страниц блока, выделенного в расширенной памяти на физические с помощью подпрограммы mapseg, приведенной в примере Б.6 Для исключения лишних проверок можно каждый раз отображать по 4 страницы. В процессе отображения mapseg изменяет номера логических страниц (содержимое регистра bx), поэтому при работе с ней достаточно задать номер исходной страницы и в дальнейшем просто не изменять текущее содержимое регистра bx.

Для упрощения и ускорения пересылки нужен микропрограммный цикл на основе строковой операции movs, работающей с двойными словами.

Подпрограмма пересыки блока

Программная реализация пересылки показана в примере Б.7. Перед вызовом подпрограммы в регистрах es и fs указываются коды видеобуфера и сегмента EMS, в примере Б.8 показано, как это делается.

Предполагается, что в разделе данных задачи описана переменная bisize, а в расширенной памяти зарезервирован блок, размер которого не меньше размера отображаемой части видеопамяти.

Пример Б.7. Пересылка содержимого рабочей области экрана

movebl: push Cur_win pusha
mov ax, BaseWin
mov Cur_win, ax
call Setwin
mov ax, bperline
mul versize
mov bisize, dx
mov blsize+2, ax
xor bx, bx
mov dx, Ehndlr
xor di, di
xor si, si
сохраняем текущее окно видеопамяти
сохраняем "все" регистры
ах = BaseWin (или ах = 0)
Cur_win = BaseWin
установка нулевого окна видеопамяти
ах = размер строки в байтах
dx:ax = bperline * versize
bisize = число полных окон
bisize +2 = размер последнего окна
bx = исходная логическая страница
dx = идентификатор файла
di = 0 исходный адрес
si = 0 исходный адрес
mloop: mov ex, 4000h 0,25 размера стандартного сегмента
dec blsize уменьшаем количество сегментов
jns sc I -> пересылка полного окна
mov ex, blsize+2 ex = размер последнего окна
shr ex, 02 уменьшаем его в 4 раза
je sc__2 -> окно пустое, пересылка окончена
sc I: call mapseg отображаем очередные 4 страницы
rep movs dword ptr [di], fs:[si]; цикл пересылки
call Nxtwin следующее окно видеопамяти
cmp blsize, -1 пересылка завершена ?
jne mloop -> нет, продолжаем пересылку
sc_2: pop Cur_win исходное значение видеоокна
рора восстановление "всех" регистров
call Setwin восстановление исходного окна
ret возврат из подпрограммы

Выполнение примера Б. 7 начинается с сохранения исходного окна видеопамяти, содержимого всех регистров и установки базового окна. Если переменная Basewin в задаче не используется, то надо просто установить нулевое окно. Затем вычисляется размер отображаемой области видеопамяти, и результат сохраняется в словах bisize и bisize+2. В регистр bx помещается номер нулевой логической странице, а в dx — идентификатор блока. Содержимое этих двух регистров использует только подпрограмма mapseg. Подготовка оканчивается очисткой содержимого индексных регистров si и di.

Основной цикл имеет метку mloop. Его первые шесть команд определяют размер фрагмента пересылаемых данных. Он составляет 16 384 двойных слова, если окно заполнено полностью, или равен значению слова bisize+2, уменьшенному в 4 раза, если окно заполнено частично.

Команда, имеющая метку sc_i, отображает очередные четыре страницы блока на сегмент EMS. Затем микропрограммный цикл пересылает очередной фрагмент данных. Он выполняет основную работу, все остальные команды примера Б. 7 являются вспомогательными.

После пересылки очередного фрагмента проверяется содержимое bisize, и работа подпрограммы продолжается до тех пор, пока его значение не окажется равным "-1". В этом случае из стека выталкиваются значения переменной Cur_win и сохраненных регистров, восстанавливается исходное окно видеопамяти и происходит возврат на вызывающий модуль.

Сохранение и восстановление рабочей области экрана

В примере Б. 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 для программ доступна как основная, так и дополнительная память. Реальные размеры последней существенно больше размеров первой, поэтому при разработке задач следует отдавать предпочтение расположению больших блоков в расширенной памяти, а блоки небольшого размера размещать в обычной памяти. Кроме того, следует избегать одновременного использования нескольких блоков, расположенных в расширенной памяти, т. к. это связано с ограничением доступного пространства адресов.

     


Компьютерные книги © 2006-2013
computers.plib.ru