Иллюстрированный самоучитель по SVGA

Координаты и адреса точек

Подпрограмма Caladdr

В примере 7.3 приведен текст подпрограммы, выполняющей вычисления по этой формуле. Перед ее вызовом в регистре сх указывается номер столбца (координата х), а в регистре dx – номер строки (координата у). Вычисленный адрес помещается в регистры dx:ax, т. е. в ах находится значение окна, а в dx – адрес (смещение) в этом окне.

Пример 7.3. Универсальная подпрограмма вычисления видеоадреса.

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.

Другой вариант Caladdr

В примере 7.4 показан вариант подпрограммы caiaddr, в котором вместо умножения x*bytppnt содержимое регистра сх сдвигается на к разрядов влево. В зависимости от видеорежима, в команде сдвига букву к надо заменить цифрами 1 или 2, т. е. эта подпрограмма не универсальна.

Пример 7.4. Пересчет координат в адрес с использованием сдвига.

Caladdr: mov ax, bperline ax = размер строки в байтах
raul dx dx:ax = Y*bperline
shl ex, k k=l для Hi-Color; k=2 для True Color
add ax, ex вычисляем младшую часть адреса
adc dx, 00 учитываем возможность переноса
xchg ax, dx обмен содержимого регистров
mul byte ptr GrUnit ax = al * GrUnit
add ax, Base_win!! если используется базовое окно
ret выход из подпрограммы

В примере 7.4 сдвигается не результат умножения, а только значение координаты х (содержимое регистра сх). Это возможно потому, что значение координаты Y (содержимое регистра dx) умножается не на Horsize, а на bperline = horsize*bytppnt.

Особенность операций сдвигов заключается в том, что величина сдвига может либо находиться в регистре el (младший байт регистра сх), либо указываться непосредственно в команде, других вариантов нет. Поэтому для автоматического выбора величины сдвига в примере 7.4 вместо двух подряд расположенных команд shl ex, k и add ax, сх надо записать следующие:

mov bx, wrdppnt; bx = величина сдвига
xchg bx, ex; обмен содержимого регистров
shl bx, cl; сдвиг значения координаты X
add ax, bx; вычисляем младшую часть адреса

Напомним, что если видеокарта в режиме True color поддерживает трехбайтовый код точки, то заменять умножение сдвигами не целесообразно.

Подведем итог.
Первая из двух описанных подпрограмм универсальная, а вторая специализированная. Вопрос о том, какая из них лучше, вообще говоря, не корректен. Корректен другой вопрос – в каких случаях нужны универсальные подпрограммы, а в каких специализированные. Первые целесообразно составлять при разработке библиотечных модулей, особенно для языков высокого уровня. А если вы разрабатываете задачу, в которой большинство подпрограмм специализировано, то целесообразность включения в ее текст одной или нескольких универсальных подпрограмм весьма проблематична.

Если Вы заметили ошибку, выделите, пожалуйста, необходимый текст и нажмите CTRL + Enter, чтобы сообщить об этом редактору.