Daladdr: mov ax, bperline ax = размер строки в байтах
mul dx dx:ax = Y*bperline
push dx сохраняем старшую часть результата
xchg ax, ex обмен содержимого регистров
mul bytppnt ах = X*bytppnt, dx = 0
add ax, ex вычисляем младшую часть адреса
mov dx, ax и сохраняем ее в регистре dx
pop ax ах = старшая часть Y*bperline
adc ax, 00 учитываем возможность переноса
mul byte ptr GrUnit ах = al * GrUnit
add ax, Base win ! ! если используется базовое окно
ret выход из подпрограммы
Текст примера 7.3 не нуждается в подробных пояснениях, обращаем ваше внимание только на следующие особенности. Содержимое регистра dx (старшую часть произведения y*bperiine) надо сохранить в стеке потому, что оно будет испорчено при втором умножении. После второго умножения и вычисления младшей части адреса старшая часть выталкивается из стека в регистр ах. К ней прибавляется единица переноса, которая могла возникнуть, если при выполнении команды add ax, сх произошло переполнение и был установлен С-разряд регистра флагов (признак Carry). Команды пересылки и выталкивания из стека не изменяют состояние С-разряда. Поэтому если он был установлен, то adc ax, 00 прибавит единицу к содержимому регистра ах.
Можно изменить текст примера 7.3 так, чтобы вычисленный адрес возвращался в регистре di, значение окна присваивалось переменной cur_win и выполнялась установка окна (call setwin). В результате получится вариант подпрограммы Caiiwin, описанной в примере 3.4, применимый в любых видеорежимах VESA.