Проверки кода условия
Проверки кода условия
Первая группа команд условного перехода проверяет текущее состояние
регистра флагов. Затем в зависимости от кодов условия команда
делает переход (или не делает). Команды условного перехода не
устанавливают флаги, а только проверяют их текущее состояние.
Ранее рассмотренные арифметические и логические команды
устанавливают флаги. В последующих примерах предположим, что
команда сравнения CMP уже установила флаги.
На Фиг.4.29 показаны команды условного перехода и проверяемые
ими флаги. В строках рисунка перечислены команды условного
перехода, а в пяти колонках показано состояние флагов. Буква X в
любой позиции означает, что команда не проверяет флаг. Цифра 0
означает, что этот флаг должен быть сброшен, чтобы условие было
выполнено и переход произошел. Цифра 1 означает, что флаг должен
быть установлен, чтобы переход произошел. Некоторые элементы
таблицы показывают выражение, которое должно быть истинно, чтобы
переход произошел. Так сделано для арифметических переходов, и мы
обсудим их далее более подробно.
На Фиг.4.29 условные переходы разделены на три группы:
непосредственно проверяющие один из флагов; делающие арифметическое
сравнение без знака; делающие арифметическое сравнение со знаком.
На Фиг.4.29а показана проверка отдельных флагов. Условный
переход может проверить каждый из этих пяти флагов непосредственно
на 0 или 1. Проверка флага переноса показана на рисунке в группе
арифметики без знака, поскольку она имеет еще и арифметический
смысл. Заметим, что многие команды условного перехода имеют более
одной мнемоники, если даже выполняется одна и та же проверка.
Например, проверку флага нуля осуществляет команда JZ (переход,
если результат операции равен нулю). Однако команда JE (переход,
если равно) также порождает ту же команду. Следующая
последовательность поясняет смысл этого:
CMP AX, BX
JE LABEL
Команда CMP вычитает содержимое регистра BX из содержимого
регистра AX, устанавливая флаги в соответствии с результатом. Так
как результат нулевой, если оба операнда равны, флаг нуля
показывает равенство. Аналогично, команда JNZ (переход, если не
нуль) идентичен команде JNE (переход, если не равно). Команда JP
(переход по четности) - то же самое, что и команда JPE (переход при
наличии четности); команда JNP (переход по нечетности) - то же
самое, что команда JPO (переход при отсутствии четности).
Команды Флаги
условного
перехода OF CY Z P S Комментарий
-------------------------------------------------------------------
JE/JZ X X 1 X X
JP/JPE X X X 1 X
JO 1 X X X X
JS X X X X 1
JNE/JNZ X X 0 X X
JNP/JPO X X X 0 X
JNO 0 X X X X
JNS X X X X 0
(a)
JL/JNGE a X X X b a NEQ b
JLE/JNG a X 1 X b Z OR (A NEQ B)
JNL/JGE a X X X b a = b
JNLE/JG a X 0 X b (NOT Z) AND (a=b)
(b)
JB/JNAE/JC X 1 X X X
JBE/JNA X 1 1 X X CY OR Z
JNB/JAE/JN X 0 X X X
JNBE/JA X 0 0 X X (NOT CY) AND (NOT Z)
(c)
------------------------------------------------------------------
Фиг. 4.29 Проверка флагов перехода по условию. (a) Проверка флага
(b) Арифметика со знаком; (c) беззнаковая арифметика.
Следующую группу команд условного перехода на Фиг.4.29б
составляют арифметические сравнения со знаком. Существуют четыре
условия, которые могут быть проверены: меньше (JL), меньше или
равно (JLE), больше (JG), больше или равно (JGE). Другие четыре
мнемоники - отрицания этих четырех. В случае арифметики со знаком
ассемблер использует мнемонику в названии команд "меньше" (less) и
"больше" (greater). Далее мы увидим, что для арифметики без знака
ассемблер использует мнемонику "выше" (above) и "ниже" (below).
Арифметические выражения можно понять, используя их вместе с
командой CMP. Например,
CMP AX,BX
JL LABEL
Преход произойдет, если содержимое регистра AX меньше
содержимого регистра BX. Вы можете читать комбинацию команд
сравнения и условного перехода вместе, как один оператор: операнд
результата встречается первым, затем идет условный оператор, а за
ним следует исходный операнд. Другой пример:
CMP CX,WORD_IN_MEMORY
JNLE LABEL
- можно прочитать так: "переход, если содержимое регистра CX не
меньше, чем, или равен содержимому ячейки памяти WORD_IN_MEMORY.
Этот прием можно использовать для определения значения любой команды
арифметического перехода, учитывающей знак или не учитывающей.
Как показано на Фиг.4.29б арифметические сравнения со знаком
проверяют одновременно несколько флагов. Фактически каждая из этих
команд проверяет некоторую комбинацию флагов переполнения, знака,
и, возможно, флага нуля. Например, в команде JL требуется, чтобы
флаги переполнения и знака имели разные значения. Если они имеют
одинаковое значение, первый операнд не был меньше второго.
Рассмотрим эту операцию несколько подробнее, чтобы понять работу
арифметических сравнений.
Когда сравниваются два числа со знаком, возможны четыре
комбинации флагов знака и переполнения. Рассмотрим каждую из
четырех комбинаций, чтобы определить какое состояние операндов
привело к данному результату. Предположим, что в каждом случае
флаги установила команда CMP, вычитавшая два операнда.
Знак S = 0, переполнение O = 0.
Условие S=0 означает, что результат вычитания положителен.
Условие O=0 означает, что переполнения не было, т.е. результат,
представленный в дополнительном коде, правильный. Вычитание двух
чисел, дающее положительный результат, показывает, что первое число
больше второго, и поэтому имеет место соотношение "больше". Однако
вычитание двух равных чисел также дает положительный результат, так
что условие S=0, O=0 означает "больше или равно".
S=1, O=0
В этом случае O=0 означает, что результат верен, а S=1 говорит
о том, что он отрицателен. Чтобы получить отрицательный результат,
большее число должно вычитаться из меньшего, и соотношение означает
"меньше".
S = 0, O = 1
Здесь O=1 показывает, что результат неверен, т.е. вышел за
пределы возможностей разрядной сетки. Это значит, что сложение двух
положительных чисел дало отрицательный результат или наоборот. В
данном случае это сравнение показывает, что знак результата
неверен; поэтому результат этого сравнения идентичен случаю, когда
S=1, O=0, что означает "меньше".
S = 1, O = 1
Снова O=1 говорит о том, что знак результата неверен. Поэтому
вычитание должно было привести к очень большому положительному
числу, и соотношение будет "больше или равно".
В некоторых случаях также учитывается флаг нуля. Например,
команда JLE выполняется, если условие есть "меньше" (знак и
переполнение разные) или "равно" (флаг нуля равен 1). Эти три флага
позволяют микропроцессору 8088 проверить все возможные комбинации
чисел со знаком.
Последняя часть таблицы (Фиг.4.29в) показывает условия,
проверяемые для арифметики без знака. Как и в случае арифметики со
знаком, существуют четыре возможные соотношения между операндами,
которые может проверить микропроцессор. Для того чтобы отличить
команды условного перехода ориентированные на беззнаковую
арифметику от знаковой арифметики, используются слова "выше" и
"ниже" в названии команд. Вероятно, этим выражается точка зрения
создателей набора команд, заключающаяся в том, что арифметика без
знака будет использоваться в программах для вычисления адресов, а
отрицательных адресов не бывает. "Выше" и "ниже" показывают
расположение значения адресов внутри адресного пространства, в то
время как "больше" и "меньше" говорит о соотношении чисел со
знаком. Здесь важно, что выполняется именно та команда, которая
указана в программе на языке ассемблера, независимо от типов
сравниваемых операндов. Например, программа сравнивает два числа со
знаком, а использует команду JA (переход, если выше).
Микропроцессор выполняет условный переход в зависимости от
соотношения двух чисел, считая их числами без знака, т.е. именно
программист обязан выбрать правильную команду условного перехода.
Микропроцессор 8088 при сравнении двух чисел без знака
учитывает только два флага. Флаг переноса показывает, какое из
чисел больше. Сравнение устанавливает флаг переноса, если первый
операнд ниже второго или сбрасывает флаг переноса, если первый
операнд либо выше, либо равен второму операнду, и флаг нуля
определяет, что в данном случае верно.
Сравнения без знака можно читать так же, как и сравнения со
знаком. Например,
CMP AX,BX
JA LABEL
- переход на метку LABEL происходит, если регистр AX выше
регистра BX. Условный переход выполняется всегда, если объявленное
соотношение существует между первым и вторым операндами
предшествовавшей команды сравнения.