horline: push dx сохранение содержимого регистра dx
mov dx, di копирование адреса в регистр dx
add dx, ex сумма текущего адреса и количества точек
jc @F -> прямая расположена в двух окнах
xor dx, dx очистка регистра dx
@@: sub ex, dx количество точек в текущем окне
rep stosb рисуем всю прямую или ее начало
or di, di адрес в пределах текущего окна ?
jne @F -> да, линия нарисована полностью
call NxtWin установка следующего окна
mov ex, dx количество не нарисованных точек
rep stosb рисуем остаток линии
@@: pop dx восстановление содержимого dx
ret возврат из подпрограммы
Линия может размещаться в текущем окне полностью или частично. Для проверки этого в примере 3.8 текущий адрес копируется в регистр dx и к нему прибавляется размер линии. Если при этом не произошло переполнение, то линия полностью помещается в текущем окне и регистр dx надо очистить. Если при сложении произошло переполнение, то команда jc @F исключает очистку регистра dx, поскольку в нем находится количество точек остатка, который будет нарисован после смены окна. Команда sub ex, dx вычитает остаток (или 0) из общего числа точек и таким способом определяет количество повторов первого микропрограммного цикла. Следующая команда rep stosb рисует часть линии, расположенную в исходном окне видеопамяти.
Затем проверяется текущий адрес видеопамяти и если он отличен от нуля, то линия нарисована полностью и происходит выход из подпрограммы. Если же текущий адрес равен нулю, то устанавливается следующее окно видеопамяти, в регистр сх копируется содержимое регистра dx и выполняется команда rep stosb, рисующая остаток прямой. После этого происходит выход из подпрограммы. Поскольку подпрограмма работает с регистром dx, то его исходное содержимое сохраняется в стеке и восстанавливается при выходе.
Уважаемые читатели, попробуйте ответить на вопрос — почему в примере 3.8 перед установкой окна проверяется текущий адрес видеопамяти (or di, di), а не размер остатка строки (содержимое регистра dx)?
Давайте посчитаем, чего мы добились. Если прямая содержит N точек и полностью помещается в текущем окне, то при ее построении по подпрограммам примера 3.6 будет выполнено 4N команд, а при построении по подпрограмме 3.8 всего 10 команд (не считая ret). Одной из них является команда rep stosb, которая записывает N байтов в видеопамять. От нее зависит время, затрачиваемое на рисование линии. Можно считать, что мы сократили это время, по крайней мере, в 4 раза по сравнению с примером 3.6 и это вполне оправдывает увеличение размера подпрограммы примера 3.8.
Дополнительные возможности ускорения. Для дальнейшего ускорения процесса рисования в микропрограммном цикле нужно записывать коды сразу двух или четырех точек.
Для записи точек парами вместо команды rep stosb надо использовать команду rep stosw, предварительно уменьшив содержимое регистра сх в два раза путем сдвига на 1 разряд вправо. Если в регистре сх находится нечетное число, то при таком сдвиге младшая единица кода попадет в С-разряд регистра флагов (признак переполнения). Следовательно, после сдвига надо проверить состояние С-разряда и записать дополнительную точку, если он установлен. Таким образом, для сокращения цикла записи в два раза в примере 3.8 каждую команду rep stosb надо заменить следующей группой команд (см. пример 3.9).