Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ЭВМ практические.docx
Скачиваний:
101
Добавлен:
11.04.2015
Размер:
275.2 Кб
Скачать

Косвенный переход

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

JMP r16 или JMP m16

В этих командах берется содержимое указанного регистра или слова памяти, оно рассматривается как адрес некоторой команды программы и именно по этому адресу делается переход. Причем этот адрес рассматривается как "настоящий", а не отсчитанный от команды перехода.

Примеры ([х] - содержимое ячейки или регистра х):

A DW L

...

JMP А ; goto [A] = goto L

MOV DX,A ; DX=L

JMP DX ; goto [DX] = goto L

L: ...

Косвенные переходы используются в тех случаях, когда адрес перехода становится известным только во время счета программы.

Возьмем команду JMP Z, где Z - некоторое имя (но не имя регистра). Что это такое - прямой переход по метке Z или косвенный переход по адресу из ячейки Z? Если имя Z описано до этой команды, то здесь проблемы нет: если именем Z помечена команда (рис. а), то это переход по метке, а если имя Z описано в директиве DW (рис. б), то это косвенный переход.

Z: INC AX Z DW L JMP Z ; goto ?

… … …

JMP Z ;goto Z JMP Z ;goto L Z …

a) б) в)

Но если Z - ссылка вперед, т. е. это имя описывается позже (рис. в), тогда ассемблер не будет знать, какой здесь переход. Чтобы снять эту неоднозначность, принято следующее соглашение: в подобной ситуации ассемблер всегда считает, что Z - метка, и потому всегда формирует команду прямого перехода по этой метке (причем команду длинного перехода). Если же затем обнаружится, что Z - не метка, то будет зафиксирована ошибка.

Так вот, если нас это правило не устраивает, если нам нужен косвенный переход, то мы обязаны сообщить об этом ассемблеру. Для этого используется оператор PTR: вместо просто имени Z надо записать конструкцию WORD PTR Z, которой мы сообщаем ассемблеру, чтобы он рассматривал Z как имя переменной размером в слово, чтобы он формировал машинную команду косвенного перехода.

Итак, при переходах вперед имеем следующие случаи:

JMP Z ;goto Z JMP Z ;ошибка JMP WORD PRT Z ;goto L

… … …

Z: Z DW L Z DW L

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

Если переход осуществляется только при выполнении некоторого условия и не осуществляется в противном случае, то такой переход называется условным. Условный переход обычно реализуется в два шага: сначала сравниваются некоторые величины, в результате чего соответствующим образом формируются флаги (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 не надо, т. к. все эти переходы и так короткие.