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