CSeg1 segment
assume |
cs:Cseg1 |
. . . |
|
FarTarget |
label far |
. . . |
|
CSeg1 ends |
|
. . . |
|
CSeg2 segment |
|
assume |
cs:cseg2 |
. . .
jmp FarTarget ; переход дальнего типа
. . .
CSeg2 ends
. . .
выполняется переход дальнего типа.
Если вы хотите, чтобы метка принудительно интерпретировалась, как метка дальнего типа, можно использовать операцию far ptr. Например, во фрагменте программы
. . .
jmp far ptr NearLabel nop
NearLabel:
. . .
выполняется переход дальнего типа на метку NearLabel, хотя эта метка находится в том же сегменте кода, что и инструкция jmp.
4.8. Условные переходы
Необходима возможность писать такие программы, которые могут принимать решения. Именно это можно делать с помощью операций условных переходов.
Инструкция условного перехода может осуществлять или не осуществлять переход на целевую (указанную в ней) метку, в зависимости от состояния регистра флагов. Пример:
. . . |
|
|
mov |
ah,1 |
; функция dos ввода с клавиатуры |
int |
21h |
; получить следующую нажатую клавишу |
cmp |
al,'A' |
; была нажата буква A? |
je AWasTyped |
; да, обработать ее |
|
mov |
[TampByte], al ; нет, сохранить символ |
|
. . . |
|
|
AWasTyped:
26
push ax ; сохранить символ в стеке
. . .
Для сравнения введенного символа с символом A используется инструкция cmp. Назначение данной инструкции состоит в том, чтобы можно было сравнить два операнда, установив флаги так же, как это делается в инструкции sub. Поэтому в предыдущем примере флаг нуля устанавливается в значение 1 только в том случае, если регистр al содержит символ A.
Теперь – основное. Инструкция je представляет собой инструкцию условного перехода, которая осуществляет передачу управления только в том случае, если флаг нуля равен 1. В противном случае выполняется инструкция, непосредственно следующая за инструкцией je (в данном случае – инструкция mov). Флаг нуля в данном примере будет установлен только в случае нажатия клавиши A, и только в этом случае процессор 8086 перейдет к выполнению инструкции с меткой AWasTyped, то есть
инструкции push. |
|
Набор инструкций |
процессора 8086 предусматривает большое |
разнообразие инструкций условных переходов.
Можно осуществлять условный переход по состоянию нуля, переноса, по знаку, четности или флагу переполнения и по комбинации флагов, показывающих результаты операций чисел со знаками.
Перечень инструкций условных переходов приводится в табл. 4.2.
|
Инструкции условных переходов |
Таблица 4.2 |
|
|
|
|
|
|
Назва- |
Значение |
Проверяемые |
ние |
|
флаги |
jb/jnae |
Перейти, если меньше / |
cf = 1 |
|
перейти, если не больше или равно |
|
jae/jnb |
Перейти, если больше или равно / перейти, если не меньше |
cf = 0 |
jbe/jna |
Перейти, если меньше или равно / перейти, если не больше |
cf = 1 или zf = 1 |
ja/jnbe |
Перейти, если больше/ |
cf = 0 или zf = 0 |
|
перейти, если не меньше или равно |
|
je/jz |
Перейти, если равно |
zf = 1 |
jne/jnz |
Перейти, если не равно |
zf = 0 |
|
Окончание табл.4.2 |
|
|
|
|
Назва- |
Значение |
Проверяемые |
ние |
|
флаги |
jl/jnge |
Перейти, если меньше, чем / перейти, если не больше, чем |
sf = of |
|
или равно |
|
jge/jnl |
Перейти, если больше, чем или равно / перейти, если не |
sf = of |
|
меньше, чем |
|
jle/jnle |
Перейти, если меньше, чем или равно / перейти, если не |
zf = 1 или sf = |
|
27 |
|
|
больше, чем |
of |
jg/jnle |
Перейти, если больше, чем / перейти, если не меньше, чем |
zf = 0 или sf = |
|
или равно |
of |
jp/jpe |
Перейти по четности |
pf = 1 |
jnp/jpo |
Перейти по нечетности |
pf = 0 |
js |
Перейти по знаку |
sf = 1 |
jns |
Перейти, если знак не установлен |
sf = 0 |
jc |
Перейти при наличии переноса |
cf = 1 |
jnc |
Перейти при отсутствии переноса |
cf = 0 |
jo |
Перейти по переполнению |
of = 1 |
jno |
Перейти при отсутствии переполнения |
of = 0 |
cf – флаг переноса, sf – флаг знака, of – флаг переполнения, zf – флаг нуля, pf – флаг четности
Несмотря на свою гибкость, инструкции условного перехода имеют также серьезные ограничения, поскольку переходы в них всегда короткие. Другими словами, целевая метка, указанная в инструкции условного перехода, должна отстоять от инструкции перехода не более чем на 128 байтов. Например, ассемблер сообщит об ошибке в программе
. . .
JumpTarget:
. . .
db |
1000 dup (?) |
. . . |
|
dec |
ax |
jnz |
JumpTarget |
. . . |
|
так как метка JumpTarget отстоит от инструкции jnz более чем на 1000 байтов. В данном случае нужно сделать следующее:
. . .
JumpTarget:
. . .
db |
1000 dup (?) |
. . . |
|
dec |
ax |
jnz |
SkipJump |
jmp |
JumpTarget |
SkipJump:
. . .
Условный переход здесь применяется для того, чтобы определить, нужно ли выполнить длинный безусловный переход.
4.9. Циклы
28
Цикл – это блок кода, завершающийся условным переходом, благодаря чему данный блок может выполняться повторно до достижения условия завершения. Циклы служат для работы с массивами, проверки состояния портов ввода-вывода до получения определенного состояния, очистки блоков памяти, чтения строк с клавиатуры и вывода их на экран и т.д. Циклы – это основное средство, которое используется для выполнения повторяющихся действий. Поэтому используются они довольно часто, в наборе инструкций процессора 8086 предусмотрено несколько инструкций циклов: loop, loopne, loope и jcxz.
Инструкция loop. Предположим, нужно вывести 17 символов текстовой строки TestString. Это можно сделать следующим образом:
. . . |
|
|
.data |
|
|
TestString db |
'Это проверка! ...' |
|
. . . |
|
|
.code |
|
|
. . . |
|
|
mov |
cx,17 |
|
mov |
bx,offset TestString |
|
PrintStringLoop: |
||
mov |
dl,[bx] |
; получить следующий символ |
inc |
bx |
; ссылка на следующий символ |
mov |
ah,2 |
; функция DOS вывода на экран |
int |
21h |
; вызватьDOS для вывода символа |
dec |
cx |
; уменьшить счетчик длины строки |
jnz PrintStringLoop ; обработать следующий символ, если он имеется
. . .
4.10. Экранные операции: основные свойства
Большинcтво программ требует ввода данных с клавиатуры, диска или модема и обеспечивает вывод данных в удобном формате на экран, принтер или диск. Данные, предназначенные для вывода на экран и ввода с клавиатуры, имеют ASCII-формат.
Для выполнения ввода и вывода используется команда int (прерывание). Существуют различные требования для указания системе, какое действие (ввод или вывод) и на каком устройстве необходимо выполнить. Рассмотрим основные требования для вывода информации на экран и ввода данных с клавиатуры.
Все необходимые экранные и клавиатурные операции можно выполнить, используя команду int 10h, которая передает управление непосредственно в BIOS. Для выполнения некоторых более сложных
29
операций существует прерывание более высокого уровня int 21h, которое сначала передает управление в DOS. Например, при вводе с клавиатуры может потребоваться подсчет введенных символов, проверка на максимальное число символов и проверка на символ Enter. Преpывание DOS int 21h выполняет многие из этих дополнительных вычислений и затем автоматически передает управление в BIOS.
Материал, приведенный ниже, подходит как для монохромных (чернобелых), так и для цветных видеомониторов. В [3, 6] приведен материал для управления более совершенными экранами и для использования цвета.
4.11. Команда прерывания: int
Команда int прерывает обработку программы, передает управление в DOS или BIOS для определенного действия и затем возвращает управление в прерванную программу для продолжения обработки. Наиболее часто прерывание используется для выполнения операций ввода или вывода. Для выхода из программы на обработку прерывания и для последующего возврата команда int выполняет следующие действия:
–уменьшает указатель стека на 2 и заносит в вершину стека содержимое флагового регистра;
–очищает флаги tf и if;
–уменьшает указатель стека на 2 и заносит содержимое регистра cs в
стек;
–уменьшает указатель стека на 2 и заносит в стек значение командного указателя;
–обеспечивает выполнение необходимых действий;
–восстанавливает из стека значение регистра и возвращает управление
впрерванную программу на команду, следующую после int.
Этот процесс выполняется полностью автоматически. Необходимо лишь определить сегмент стека достаточно большим для записи в него значений регистров.
Рассмотрим два типа прерываний: команду BIOS int 10h, и команду DOS int 21h для вывода на экран и ввода с клавиатуры. В последующих примерах в зависимости от требований используются как int 10h, так и int 21h.
4.12. Установка курсора
Экран можно представить в виде двумерного пространства с адресуемыми позициями, в любую из которых может быть установлен курсор. Обычный видеомонитор имеет 25 строк, нумеруемых от 0 до 24, и 80 столбцов, нумеруемых от 0 до 79.
Таблица 4.3
30