Графические устройства

         

Универсальный (цикл



Пример 7.12. Универсальный (цикл пересылки) способ построения строк

drawl ine: push dx сохранение содержимого регистра dx
xchg ax, ex обмен содержимого регистров (ах = N)
mul bytppnt dxrax = L =-N * М
xchg CX j 3X обмен содержимого регистров (сх = L)
pop dx восстановление содержимого регистра dx
drawalt : push dx сохранение содержимого регистра dx
mov dx, di копирование адреса в регистр dx
add dx, ex dx = исходный адрес + L
jc @F -> прямая расположена в двух окнах
xor dx, dx остаток в dx равен нулю
@@: sub ex, dx количество байтов в текущем окне
call moveto строим первую часть строки


mov ex, dx сх = оставшееся количество байтов
pop dx восстановление содержимого регистра dx
or di, di адрес в пределах текущего окна ?
jne d exit -> да, строка построена полностью
call NxtWin установка следующего окна
moveto: shr ex, 01 преобразуем байты в слова
jnc @F -> четное число байтов
movs byte ptr [di] , fs:[si] ; пересылка одного байта
@@: shr ex, 01 преобразуем слова в двойные слова
jnc @F -> четное число слов
movs word ptr [di], fs:[si] ; пересылка одного слова
@@: je d exit ; -> пересылать больше нечего
rep movs dword ptr [di], fs:[si] ; основной цикл пересылки
d exit: ret ; возврат из подпрограммы

Выполнение примера 7.12 начинается с вычисления количества байтов в строке. При умножении используются регистры dx и ах, поэтому содержимое dx сохраняется в стеке, а содержимое ах — за счет двухкратного использования команды xchg. Произведение находится в регистрах dx:ax. Мы будем считать, что оно меньше чем 65 536, т. е. dx содержит 0. Команда обмена xchg помешает результат в сх, одновременно восстанавливая исходное состояние ах, а из стека выталкивается исходное содержимое регистра dx.

Если количество байтов в строке известно заранее, то заново вычислять его не имеет смысла. Оно указывается в регистре сх, а для вызова подпрограммы используется вторая точка входа, имеющая имя drawait.

Команда с меткой drawait сохраняет в стеке содержимое регистра dx, затем в него копируется адрес видеопамяти, который увеличивается на размер строки в байтах. Если при сложении произойдет переполнение (установка С-разряда), то команда jc @F исключает очистку dx. В противном случае строка помещается в текущем окне и регистр dx очищается. Затем вычисляется количество выводимых точек, и подпрограмма moveto строит первую часть строки.

После построения первой части строки в регистр сх копируется содержимое dx (остаток строки). Регистр dx освободился и надо восстановить его исходное состояние. Для выбора дальнейших действий проверяется текущий адрес в регистре di, если он отличен от нуля, то построение строки завершено и выполняется команда ret. В противном случае устанавливается следующее окно видеопамяти, и подпрограмма moveto строит остаток линии. После ее выполнения завершится работа основной подпрограммы, т. к. в верхушке стека находится адрес возврата на вызывающий модуль.

В подпрограмме moveto команда rep movs dword ptr [di], f s: [si] является основной, она пересылает группу 32-разрядных слов. Однако количество байтов в строке не обязательно кратно четырем. Поэтому нужна предварительная проверка и пересылка от одного до трех "лишних" байтов, так чтобы остаток был кратен четырем.

Команда, имеющая метку moveto, сдвигает содержимое регистра сх на разряд вправо. Если оно было нечетным, то пересылается первый байт строки, в противном случае jnc @F исключает эту пересылку.

Затем содержимое сх еще раз сдвигается на разряд вправо. Если оно было нечетным, то пересылается слово (два байта строки), в противном случае jnc @F исключает эту пересылку.

В результате выполнения двух сдвигов и пересылки "лишних" байтов в строке остается целое число 32-разрядных слов, количество которых находится в регистре ex. Если оно равно нулю, то произойдет переход на команду ret, в противном случае выполняется микропрограммный цикл копирования 32-разрядных слов. После этого выполняется команда ret.

Вторая точка входа drawait введена для тех случаев, когда известен размер строки в байтах. Приведем несколько примеров таких случаев. При работе в режимах PPG количество байтов совпадает с количеством точек. Если размер строки равен ширине экрана, то ее размер в байтах указывает переменная bperiine и вычислять его нет смысла. При построении рисунка, содержащего большое количество строк, целесообразно один раз вычислить размер строки в байтах, а не повторять одни и те же вычисления при построении каждой строки. Наконец, возможны также случаи, когда количество байтов вычисляется нестандартным способом, например, зависит от определенных условий.



Содержание раздела