0109 A20:
0109 05 0001 ADD AX,01 ;Прибавить 01 к AX
010C 03 D8 ADD BX,AX ;Прибавить 01 к BX
010E D1 E1 SHL CX,1 ;Удвоить CX
0110 EB F7 JMP A20 ;Переход на A20
0112 MAIN ENDP
0112 CODESG ENDS
END MAIN
__________________________________________________________________________
Рис.7.1. Использование команды JMP.
Метку можно кодировать на одной строке с командой:
A20: ADD AX,01
или на отдельной строке:
A20:
ADD AX,01
В обоих случаях адрес A20 указывает на первый байт команды ADD.
Двоеточие в метке A20 указывает на тип метки - NEAR. Запомните: отсутствие
двоеточия в метке является частой ошибкой. В нашем примере A20
соответствует -9 байтам от команды JMP, в чем можно убедиться по
объектному коду команды - EBF7. EB представляет собой машинный код для
короткого перехода JMP, а F7 - отрицательное значение смещения (-9).
Команда JMP прибавляет F7 к командному указателю (IP), котоpый содержит
адрес команды после JMP (0112):
Дес. Шест.
Командный указатель: 274 112
Адрес в команде JMP: -9 F7 (двоичное дополнение)
--- ---
Адрес перехода: 265 109
В результате сложения получается адрес перехода - шест.109. Проверьте
по листингу программы, что относительный адрес метки действительно
соответствует шест.109. Соответственно операнд в команде JMP для перехода
вперед имеет положительное значение.
Команда JMP для перехода в пределах -128 до +127 байт имеет тип
SHORT. Ассемблер генерирует в этом случае однобайтовый операнд в пределах
от 00 до FF. Команда JMP, превосходящая эти пределы, получает тип FAR, для
которого генерируется другой машинный код и двухбайтовый операнд.
Ассемблер в первом просмотре исходной программы определяет длину каждой
команды. Однако, команда JMP может быть длиной два или три байта. Если к
моменту просмотра команды JMP ассемблер уже вычислил значение опеpанда
(при переходе назад):
A50:
...
JMP A50
то он генерирует двухбайтовую команду. Если ассемблер еще не вычислил
значение операнда (при переходе вперед)
JMP A90
...
A90:
то он не знает тип перехода NEAR или FAR, и автоматически генерирует 3-х
байтовую команду. Для того, чтобы указать ассемблеру на необходимость
генерации двухбайтовой команды, следует использовать оператор SHORT:
JMP SHORT A90
...
A90:
В качестве полезного упражнения, введите программу, проассемблируйте
ее, скомпонуйте и переведите в COM-формат. Определение данных не
требуется, поскольку непосредственные операнды генерируют все необходимые
данные. Используйте отладчик DEBUG для пошагового выполнения COM-модуля и
просмотрите несколько повторений цикла. Когда регистр AX будет содержать
08, BX и CX увеличатся до шест.24 (дес.36) и шест.80 (дес.128),
соответственно. Для выхода из отладчика используйте команду Q.
КОМАНДА LOOP
________________________________________________________________
Команда JMP в примере на рис.7.1 реализует бесконечный цикл. Но более
вероятно подпрограмма должна выполнять определенное число циклов. Команда
LOOP, которая служит для этой цели, использует начальное значение в
регистре CX. В каждом цикле команда LOOP автоматически уменьшает
содержимое регистра CX на 1. Пока значение в CX не равно нулю, управление
передается по адресу, указанному в операнде, и если в CX будет 0,
управление переходит на следующую после LOOP команду.
__________________________________________________________________________
page 60,132
TITLE EXLOOP (COM) Организация цикла командой LOOP
0000 CODESG SEGMENT PARA 'Code'
ASSUME CS:CODESG,DS:CODESG,SS:CODESG
0100 ORG 100H
0100 BEGIN PROC NEAR
0100 B8 0001 MOV AX,01 ;Инициализация AX,
0103 BB 0001 MOV BX,01 ; BX,
0106 BA 0001 MOV DX,01 ; и DX
0109 B9 000A MOV CX,10 ;Число циклов
010C A20:
010C 40 INC AX ;Прибавить 01 к AX
010D 03 D8 ADD BX,AX ;Прибавить AX к BX
010F D1 E2 SHL DX,1 ;Удвоить DX
0111 E2 F9 LOOP A20 ;Уменьшить CX и повторить
; цикл, если не нуль
0113 C3 RET ;Завершить работу
0114 BEGIN ENDP
0114 CODESG ENDS
END BEGIN
__________________________________________________________________________
Рис.7.2. Использование команды LOOP.
Программа на рис.7.2, иллюстрирующая использование команды LOOP,
выполняет действия, аналогичные примеру на рис.7.1 за исключением того,
что после десяти циклов программа завершается. Команда MOV инициализирует
регистр CX значением 10. Так как команда LOOP использует регистр CX, то в
программе для удвоения начального значения 1 вместо регистра CX
используется DX. Команда JMP A20 заменена командой LOOP и для
эффективности команда ADD AX,01 заменена командой INC AX (увеличение AX на
1).
Аналогично команде JMP, операнд команды LOOP определяет расстояние от
конца команды LOOP до адреса метки A20, которое прибавляется к содержимому
командного указателя. Для команды LOOP это расстояние должно быть в
пределах от -128 до +127 байт. Если операнд превышает эти границы, то
ассемблер выдаст сообщение "Relative jump out of range" (превышены границы
перехода).
Для проверки команды LOOP рекомендуется изменить соответствующим
образом программу, приведенную на рис.7.1, выполнить ее ассемблирование,
компоновку и преобразование в COM-файл. Для трассировки всех десяти циклов
используйте отладчик DEBUG. Когда в значение регистре CX уменьшится до
нуля, содержимое регистpов AX, BX и DX будет соответственно шест. 000B,
0042 и 0400. Для выхода из отладчика введите команду Q.
Дополнительно существует две разновидности команды LOOP - это LOOPE
(или LOOPZ) и LOOPNE (или LOOPNZ). Обе команды также уменьшают значение
регистра CX на 1. Команда LOOPE передает управление по адресу операнда,
если регистр CX имеет ненулевое значение и флаг нуля установлен (ZF=1).
Команда LOOPNE передает управление по адресу операнда, если регистр CX
имеет ненулевое значение и флаг нуля сброшен (ZF=0).
ФЛАГОВЫЙ РЕГИСТР
________________________________________________________________
Следующий материал данной главы требует более детального ознакомления
с флаговым регистром. Этот pегистр содержит 16 бит флагов, которые
управляются различными командами для индикации состояния операции. Во всех
случаях флаги сохраняют свое значение до тех пор, пока другая команда не
изменит его. Флаговый регистр содержит следующие девять используемых бит
(звездочками отмечены неиспользуемые биты):
Номер бита: 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
Флаг: * * * * O D I T S Z * A * P * C
Рассмотрим эти флаги в последовательности справа налево.
CF (Carry Flag) - флаг переноса. Содержит значение "переносов" (0 или
1) из старшего разряда при арифметических операциях и некоторых операциях
сдвига и циклического сдвига (см. гл.12).
PF (Parity Flag) - флаг четности. Проверяет младшие восемь бит
pезультатов операций над данными. Нечетное число бит приводит к установке
этого флага в 0, а четное - в 1. Не следует путать флаг четности с битом
контроля на четность.
AF (Auxiliary Carry Flag) - дополнительный флаг переноса.
Устанавливается в 1, если арифметическая операция приводит к переносу
четвертого справа бита (бит номер 3) в регистровой однобайтовой команде.
Данный флаг имеет отношение к арифметическим операциям над символами кода
ASCII и к десятичным упакованным полям.
ZF (Zero Flag) - флаг нуля. Устанавливается в качестве результата
aрифметических команд и команд сравнения. Как это ни странно, ненулевой
результат приводит к установке нулевого значения этого флага, а нулевой -
к установке единичного значения. Кажущееся несоответствие является,
однако, логически правильным, так как 0 обозначает "нет" (т.е. результат
не равен нулю), а единица обозначаeт "да" (т.е. результат равен нулю).
Команды условного перехода JE и JZ проверяют этот флаг.
SF (SIgn Flag) - знаковый флаг. Устанавливается в соответствии со
знаком результата (старшего бита) после арифметических опеpаций:
положительный результат устанавливает 0, а отрицательный - 1. Команды
условного перехода JG и JL проверяют этот флаг.
TF (Trap Flag) - флаг пошагового выполнения. Этот флаг вам уже
приходилось устанавливать, когда использовалась команда Т в отладчике
DEBUG. Если этот флаг установлен в единичное cостояние, то процессор
переходит в режим пошагового выполнения команд, т.е. в каждый момент
выполняется одна команда под пользовательским управлением.
IF (Interrupt Flag) - флаг прерывания. При нулевом состоянии этого
флага прерывания запрещены, при единичном - разрешены.
DF (DIrection Flag) - флаг направления. Используется в строковых
операциях для определения направления передачи данных. При нулевом
состоянии команда увеличивает содержимое регистров SI и DI, вызывая
передачу данных слева направо, при нулевом - уменьшает содержимое этих
регистров, вызывая передачу данных справа налево (см. гл.11).
OF (Overflow Flag) - флаг переполнения. Фиксирует арифметическое
переполнение, т.е. перенос вниз старшего (знакового) бита при знаковых
арифметических операциях.
В качестве примера: команда CMP сравнивает два операнда и
воздействует на флаги AF, CF, OF, PF, SF, ZF. Однако, нет необходимости
проверять все эти флаги по отдельности. В следующем примере проверяется
содержит ли регистр BX нулевое значение:
CMP BX,00 ;Сравнение BX с нулем
JZ B50 ;Переход на B50 если нуль
. (действия при не нуле)
.
B50: ... ;Точка перехода при BX=0
Если BX содержит нулевое значение, команда CMP устанавливает флаг
нуля ZF в единичное состояние, и возможно изменяет (или нет) другие флаги.
Команда JZ (переход, если нуль) проверяет только флаг ZF. При единичном
значении ZF, обозначающее нулевой признак, команда передает управление на
адрес, указанный в ее операнде, т.е. на метку B50.
КОМАНДЫ УСЛОВНОГО ПЕРЕХОДА
________________________________________________________________
В предыдущих примерах было показано, что команда LOOP уменьшает на
единицу содержимое регистра CX и проверяет его: если не ноль, то
управление передается по адресу, указанному в операнде. Таким образом,
передача управления зависит от конкретного состояния. Ассемблер
поддерживает большое количество команд условного перехода, которые
осуществляют передачу управления в зависимости от состояний флагового