Smlbmp : pusha сохранение "всех" регистров
PushReg <fs,gs,Cur wi n>; сохранение fs, gs, Cur win
mov ax, horsize ax = horsize
sub ax, iwidth ax = horsize — iwidth
mul bytppnt ax = (horsize — iwidth) * bytppnt, dx = 0
mov dx , ax dx = ax, для коррекции адреса строки
mov ex , si ex = si, размер образа рисунка
mov SwpOffs, 0 начало считываемых данных
call readf чтение образа рисунка
jnc ok -> чтение без ошибок
; Здесь должны выполнят! эСЯ действия в случае ошибки при чтении
ok: mov fs, SwpSeg fs = сегмент буфера обмена
mov gs, GenSeg ! ! gs = сегмент таблицы цветов
mov ex, iheight сх = количество строк в рисунке
invout : push ex сохраняем счетчик повторов
Выполнение примера А.9 начинается с сохранения в стеке содержимого регистров общего назначения, сегментных регистров fs, gs и переменной cur_win. Следующие четыре команды вычисляют константу для коррекции адресов строк видеопамяти по способу, описанному в примере 7.13.
Для чтения образа файла в регистр сх помещается его размер, очищается переменная Swpoffs и происходит обращение к подпрограмме readf. Если чтение прошло без ошибок, то команда jnc ok обойдет строку, состоящую только из комментария. Что делать при ошибках чтения, решать вам.
В подпрограммах построения строк (drawiine) регистр fs используется при чтении кодов точек из оперативной памяти, а регистр gs — при работе с таблицей цветов. Поэтому перед началом основного цикла в них записываются коды соответствующих сегментов.
Цикл построения рисунка имеет метку invout. Работа с адресами в нем организована так, что при каждом повторе регистр di содержит адрес очередной строки видеопамяти, а регистр si — адрес последней обработанной строки образа рисунка (при первом входе это размер рисунка в байтах).
Перед вызовом подпрограммы drawiine содержимое si уменьшается на размер строки в файле (fwidth) и указывает начало очередной строки. При выполнении подпрограммы drawiine регистр si увеличится на iwidth. Поэтому после возврата из drawiine значение si увеличивается на rmndr (количество лишних байтов) и уменьшается на fwidth. В результате регистр si будет содержать адрес начала последней обработанной строки.
Адрес начала следующей строки видеопамяти, как обычно, увеличивается на константу переадресации, которая хранится в регистре dx. Если при сложении (add di, dx) происходит переполнение, то устанавливается следующее окно видеопамяти.
Команда loop invout повторяет выполнение цикла нужное количество раз, после чего восстанавливаются сохраненные в стеке величины, исходное окно видеопамяти и происходит возврат на вызывающий модуль.
По сравнению с обычным циклом построения рисунка (см. пример 7.23) в данном случае добавились три команды, корректирующие значение регистра si. При желании их количество можно сократить до двух. Подумайте, как это сделать, но не забывайте, что fwidth - rmndr не обязательно равно iwidth. Вспомните, как вычислялись эти величины.
Замечание 1
Замечание 1
Напомним, что имя подпрограммы построения строки не обязательно указывать в явном виде. Команду call drawline можно изменить на call bx, а перед обращением формировать в регистре bх адрес подпрограммы построения строки (см. раздел в данном приложении).