Команды сравнения и условного перехода

Если переход осуществляется только при выполнении некоторого условия и не осуществляется в противном случае, то такой переход называется условным. Условный переход обычно реализуется в два шага: сначала сравниваются некоторые величины, в результате чего соответствующим образом формируются флаги (ZF, SF и т. д.), а затем выполняется собственно условный переход в зависимости от значений флагов. Поэтому мы сейчас рассмотрим и команду сравнения, и команды условного перехода.

Сравнение (compare): CMP op1,op2

Эта команда эквивалентна команде SUB op1,op2 за одним исключением: вычисленная разность op1-op2 никуда не записывается. Поэтому единственный и главный эффект от команды сравнения - это установка флагов, характеризующих полученную разность, или, что то же самое, характеризующих сравниваемые величины ор1 и ор2. Как формируются флаги при вычитании, мы уже рассматривали (см. лаб. 5), поэтому повторяться не будем.

Что же касается команд условного перехода, то их в ПК достаточно много, но в Ассемблере они все записываются единообразно:

Jxx <метка>

где операнд указывает метку той команды программы, на которую надо сделать переход в случае выполнения некоторого условия, а мнемокод начинается буквой J (от jump), за которой следует одна или несколько букв, в сокращенном виде описывающих это условие.

Все команды условного перехода можно разделить на три группы.

В первую группу входят команды, которые ставятся после команды сравнения. В их мнемокодах с помощью определенных букв описывается тот исход сравнения, при котором надо делать переход. Это такие буквы:

Е - equal (равно)

N - not (не, отрицание)

G - greater (больше) - для чисел со знаком

L - less (меньше) - для чисел со знаком

А - above (выше, больше) - для чисел без знака

В - below (ниже, меньше) - для чисел без знака

Как видно, для условий "меньше" и "больше" введены две системы обозначений. Это связано с тем, что после сравнения чисел со знаком и сравнения чисел без знака надо реагировать на разные значения флагов.

Отметим, что одна и та же команда условного перехода может иметь несколько названий-синонимов. Это объясняется тем, что одно и то же условие перехода может быть сформулировано по-разному. Например, условие "меньше" - это в то же время и условие "не верно, что больше или равно", поэтому переход по меньше для знаковых чисел обозначается и как JL, и как JNGE. Какое из этих названий-синонимов использовать - это личное дело автора программы.

Мнемокод Содержательное условие для перехода после СМР ор1,ор2 Состояние флагов для перехода
для любых чисел
JE op1 = op2 ZF=1
JNE op1 <> op2 ZF=0
для чисел со знаком
JL/JNGE op1 < op2 SF<>OF
JLE/JNG op1 <= op2 SF<>OF или ZF=1
JG/JNLE op1 > op2 SF=OF и ZF=0
JGE/JNL op1 <= op2 SF=OF
для чисел со знаком
JB/JNAE op1 < op2 CF=1
JBE/JNA op1 <= op2 CF=1 или ZF=1
JA/JNBE op1 > op2 CF=0 и ZF=0
JAE/JNB op1 <= op2 CF=0

(Объясним, к примеру, почему в команде условного перехода "по меньше" для знаковых чисел (JL) проверяется соотношение OF<>SF. Если в команде СМР op1,op2 сравниваемые числа трактуются как знаковые, тогда возможны две комбинации флагов, соответствующие условию op1<op2. Во-первых, если при вычитании op1-op2 не было переполнения мантиссы (OF=0), тогда флаг SF фиксирует настоящий знак разности op1-op2 и потому SF=1 означает, что op1-op2<0, т. е. op1<op2. Во-вторых, если при вычитании произошло переполнение мантиссы (OF=1), тогда результатом команды будет число с противоположным знаком, чем у настоящей разности, и поскольку флаг SF фиксирует не знак настоящей разности, а знак результата команды, то условие SF=0 означает, что у искаженного результата знак положителен, а значит, у настоящей разности знак отрицателен, т. е. op1<op2. Итак, условию op1<op2 соответствует либо OF=0 и SF=1, либо OF=1 и SF=0, что можно записать более коротко: OF<>SF. Именно это условие и указано в таблице для команды JL.)

Пример. Пусть X, Y и Z - переменные размером в слово. Требуется записать в Z максимальное из чисел X и Y.

Решение этой задачи различно для чисел со знаком (см. слева) и для чисел без знака (см. справа), т. к. приходится использовать разные команды условного перехода:

;числа со знаком ;числа без знака

MOV АХ,Х MOV АХ,Х

СМР AX,Y ;х=у? СМР AX,Y

JGE М ;х>=у а M JAE M

MOV AX,Y MOV AX,Y

M: MOV Z,AX M: MOV Z,AX

Во вторую группу команд условного перехода входят те, которые ставятся после команд, отличных от команды сравнения, и которые реагируют на то или иное значение какого-нибудь определенного флага. В мнемокодах этих команд указывается первая буква проверяемого флага, если переход должен быть выполнен при значении 1 у флага, либо эта буква указывается с буквой N (not), если переход надо сделать при нулевом значении флага:

 

Мнемокод Условие перехода Мнемокод Условие перехода
JZ ZF=1 JNZ ZF=0
JS SF=1 JNS SF=0
JC CF=1 JNC CF=0
JO OF=1 JNO OF=0
JP PF=1 JNP PF=0

(Замечание. Легко заметить, что следующие пары мнемокодов эквиваленты: JE и JZ, JNE и JNZ, JB и JC, JNB и JNC.)

Пример. Пусть А, В и С - беззнаковые байтовые переменные. Требуется вычислить С=А*А+В, но если ответ превосходит размер байта, тогда надо передать управление на метку ERROR.

Возможное решение этой задачи:

MOV AL,A

MUL AL

JC ERROR ;A*A > 255 (CF=1) а ERROR

ADD AL,B

JC ERROR ;перенос (CF=1) а ERROR

MOV C,AL

И, наконец, в третью группу входит только одна команда условного перехода, проверяющая не флаги, а значение регистра СХ:

JCXZ <метка>

Действие команды JCXZ (jump if CX is zero) можно описать так:

if CX=0 then goto <метка>

Примеры на использование этой команды будут приведены позже.

Отметим общую особенность команд условного перехода: все они осуществляют только короткий переход, т. е. с их помощью можно передать упраштение не далее чем на 127-128 байтов вперед или назад. Это примерно 30-40 команд (в среднем одна команда ПК занимает 3-4 байта). Дело в том, что в ПК все машинные команды условного перехода имеют вид КОП i8 и реализуют короткий относительный переход: IP:=IP+i8, а команд с операндом в слово (i16) нет. Это объясняется тем, что в большинстве случаев как раз и нужны такие короткие переходы, а с другой стороны, для команд длинных условных переходов в ПК попросту не хватило кодов операций.

Естественно, возникает вопрос: а как в этих условиях осуществлять длинные условные переходы, на расстояние более 127 байтов от команды перехода? Здесь надо привлекать команду длинного безусловного перехода. Например, при "далекой" метке М оператор

if AX=BX then goto M

следует реализовывать так:

if AX<>BX then goto L; {короткий переход}

goto M; {длинный переход}

L: ...

На ЯА это записывается следующим образом:

CMP AX,BX

JNE L

JMP M

L: ...

Получается очень коряво, но иного варианта нет.

Отметим, что использовать в командах условного перехода оператор SHORT не надо, т. к. все эти переходы и так короткие.