Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
5ZTMNyz0U3.file-1.doc
Скачиваний:
6
Добавлен:
30.04.2022
Размер:
291.84 Кб
Скачать

1. ЛАБОРАТОРНАЯ РАБОТА № 3

ОРГАНИЗАЦИЯ ВЕТВЛЕНИЯ, ЦИКЛОВ

И ИНДЕКСИРОВАНИЯ

    1. 1.1. Общие методические указания по выполнению лабораторной работы

Цели работы:

- знакомство с операторами сравнения, переходов и организации циклов.

-  освоение индексирования (работы с массивами) с использованием модификации адресов.

Среда выполнения:

Интерпретатор команд DOS, ассемблер MASM, интерактивный отладчик AFD.

1.2. Теоретические сведения

1.2.1. Команды переходов

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

Переходы бывают условными и безусловными. Если переход делается только тогда, когда выполнено некоторое условие, то такой переход называется условным, а если он делается независимо от каких-либо условий, то это безусловный переход.

Безусловный переход

Безусловный переход осуществляется с помощью следующей команды:

JMP op

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

Прямой переход

В данном случае в качестве операнда указывается метка той команды, на которую надо передать управление:

JMP <метка>

Пример:

JMP L

L: MOV AX, 0

В машинной команде адрес перехода рассчитывается как разность между адресом команды, на которую надо перейти, и адресом самой команды перехода (т.е. как бы относительный адрес относительно содержимого регистра IP. При выполнении команды это смещение складывается с содержимым IP). Под смещение в команде отводится либо 1 байт (короткий переход), либо 2 байта (длинный переход). Это делается для экономии памяти. Ассемблер сам решает, какой сгенерировать.

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

JMP <регистр> или JMP <слово памяти>

Содержимое указанного в команде регистра или слова памяти рассматривается как адрес, по которому нужно делать переход (“настоящий”, а не смещение от IP).

Пример:

B DW L ; слово памяти (переменная),

; проинициализированное значением

; метки L, т.е. адресом

MOV DX, B ; в DX пересылается значение метки L

JMP DX ; goto [DX] = goto L Переход по адресу,

; записанному в регистр DX

JMP B ; goto [B] = goto L

; переход по адресу, записанному в B

………

L: MOV AX, 0

Существует проблема, с которой сталкивается ассемблер при трансляции команд безусловного перехода. Предположим, что существует команда JMP Z, где Z – некоторое имя (но не имя регистра). По самому имени Z нельзя догадаться, какой переход будет осуществлен – прямой или косвенный. Если имя Z описано до команды JMP, то проблемы нет: если именем Z помечена команда, то осуществляется переход по метке, а если имя Z описано в директиве DW, то осуществляется косвенный переход.

Прямой переход назад

Z: INC AX

JMP Z ; goto Z

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

Z DW L

JMP Z ; goto L

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

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

Прямой переход вперед

JMP Z ; goto Z

Z: INC AX

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

JMP WORD PTR Z ; goto L

Z DW L

Сравнение и условный переход

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

Команда сравнения записывается следующим образом:

CMP op1, op2

Данная команда идентична команде вычитания, но ее результат никуда не записывается. Основной результат выполнения команды CMP – установка флагов, характеризующих полученную разность, по значению которой можно понять соотношение сравниваемых величин. Рассматриваются значения флагов ZF, SF, CF, OF.

Существует достаточно большое количество команд перехода, записываемых по следующей схеме:

JXX <метка>

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

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

Группа 1. Команды, ставящиеся после команды сравнения.

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

E – equal (равно);

N – not (отрицание);

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

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

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

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

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

В таблице 1 приведены названия всех команд условного перехода, используемых после команды сравнения (через косую черту указаны названия-синонимы).

Таблица 1

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

Мнемокод

Условие перехода

Состояние флагов

для любых чисел

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

Пример использования:

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

Для чисел со знаком

Для чисел без знака

MOV AX,X

CMP AX,Y

JGE L1

MOV AX,Y

L1: MOV Z,AX

MOV AX,X

CMP AX,Y

JAE L1

MOV AX,Y

L1: MOV Z,AX

Группа 2. Команды условного перехода по значению флага.

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

В таблице 2 приведен список данных команд.

Таблица 2

Команды условного перехода по значению флагов

Мнемокод

Условие

перехода

Мнемокод

Условие

перехода

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

Пример использования:

Пусть X,Y,Z – беззнаковые байтовые переменные. Вычислить Z = X*X + Y, но если Z сумма не помещается в байт, то управление передать на метку ERROR и выдать сообщение об ошибке.

MOV AL, X

MUL AL

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

ADD AL, Z

JC ERROR ; CF=1 –> ERROR

MOV C, AL

Группа 3. Команда условного перехода по значению счетчика (регистра CX).

Команда записывается следующим образом:

JCXZ <метка>

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

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

Используется, например, для организации цикла вместе с командой LOOP (см. ниже).

Все команды условного перехода осуществляют только короткий переход (не более, чем на 128 байт – примерно 30-40 команд). Для реализации длинного условного перехода необходимо использовать конструкции вида:

CMP AX,BX

JNE L ; if AX<>BX then goto L

JMP M ; goto M

L: ……..

Данный фрагмент программы задает переход на метку M при условии равенства содержимого регистров AX и BX.

1.2.2. Команды управления циклом

С помощью команд перехода можно реализовать любые разветвления и циклы. Например, следующие операторы языка Паскаль:

а) if X>0 then S1 else S2

б) while X>0 do S

в) repeat S until X>0

где S, S1 и S2 – некоторые операторы, а X – знаковая переменная, реализуются по схемам, приведенным в таблице 3.

Таблица 3

Варианты реализации ветвлений и циклов с неизвестным числом повторений в ассемблере

if X>0 then S1 else S2

while X>0 do S

repeat S until X>0

CMP X, 0

JLE L1

JMP L2

L 1:

L2:

BEG: CMP X, 0

JLE FIN

JMP BEG

FIN: ………….

B EG:

CMP X, 0

JG BEG

Для реализации цикла с известным числом повторений можно воспользоваться командой LOOP записываемой следующим образом:

LOOP <метка>

Действие этой команды можно записать следующим образом (пользуясь операторами языка Паскаль):

CX:=CX–1 ; уменьшение счетчика повторений цикла

; на единицу (предварительно число повторений

; цикла надо записать в CX)

IF CX<>0 THEN GOTO <метка> ;

С помощью команды LOOP цикл, который необходимо повторить N раз можно записать следующим образом:

MOV CX, N ; в CX записывается число

; повторений цикла N (N>0)

L: ; начало цикла

… ; тело цикла

LOOP L

Данная команда обладает рядом особенностей:

1) В качестве счетчика цикла обязательно должен использоваться регистр CX.

2) Начальное значение для CX должно быть присвоено до цикла, причем данному регистру надо присваивать ровно столько, сколько раз должен повториться цикл.

3) Так как команда LOOP ставится в конце цикла, тело цикла выполниться хотя бы один раз. Поэтому для того, чтобы предусмотреть вариант нулевого повторения цикла, необходимо сделать обход цикла:

MOV CX, N ; N>=0

JCXZ L1 ;CX=0 -> L1

L: …

… ;

LOOP L

L1: …

Именно для осуществления подобных обходов и была введена команда условного перехода JCXZ.

1.2.3. Работа с массивами

Нумерация элементов массива

Пусть имеется массив X из 30 элементов слов.

X DW 30 DUP (?)

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

Адрес (X[i]) =X + (type X)*i

где type X – размер элемента массива в байтах (для слова type X = 2, для двойного слова type X = 4).

Модификация адресов

Для реализации обращения к разным элементам массива в одной и той же команде цикла необходимо использовать модификацию адресов.

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

MOV CX, A[BX]

Данная команда будет работать не с указанным в ней адресом A, а с исполнительным адресом, который вычисляется по формуле:

Аисп = (A + [BX]) mod 216

Таким образом, прежде чем выполнить команду, центральный процессор прибавит к адресу A текущее содержимое регистра BX, получит некоторый новый адрес и именно из ячейки с этим адресом возьмет второй операнд. Если в результате сложения получилась слишком большая сумма, то от нее берутся только последние 16 битов, на что указывает операция mod в приведенной формуле.

Замена адреса из команды на исполнительный адрес называется модификацией адреса, а регистр, участвующий в модификации, называют регистром-модификатором или просто модификатором. В качестве модификатора можно использовать только регистры BX, BP, SI или DI.

Индексирование

Пример. Пусть имеется массив

X DW 100 DUP (?) ; X[0..99]

Требуется записать в регистр AX сумму элементов массива.

Для нахождения суммы надо сначала в AX записать 0, а затем в цикле выполнить операцию AX:=AX+X[i] при i от 0 до 99. Команда, соответствующая этой операции должна быть следующей:

ADD AX, X + 2 * i

Но данная команда недопустима правилами языка ассемблер: все части команды, в том числе и адрес должны быть фиксированными. Здесь же адрес меняется вместе с изменением индекса i.

Решить проблему поможет разбиение переменного адреса X+2*I на два слагаемых – постоянное слагаемое X, которое не зависит от индекса i, и на переменное слагаемое 2*i, зависящее от индекса. Постоянное слагаемое записывается в саму команду, а переменное слагаемое заносится в регистр-модификатор (например, в SI), название которого записывается в команду.

Так как регистр-модификатор все время один и тот же, то команда будет иметь фиксированный вид, т.е. удовлетворять правилам машинного языка. С другой стороны, меняя содержимое регистра SI в другой команде, можно заставить неменяющуюся команду работать с разными адресами и, тем самым, корректно реализовать алгоритм.

При такой реализации задачи важно правильно менять содержимое регистра SI. Сначала в SI необходимо записать 0, а затем увеличивать его значение с шагом 2; в результате команда будет работать с адресами X, X+2, X+4, …, X+198.

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

MOV AX, 0 ; начальное значение суммы

MOV СX, 100 ; счетчик цикла

MOV SI, 0 ; начальное смещение по вектору

; (индекс)

L: ADD AX, X [SI] ; AX := AX + X[i]

ADD SI, 2 ; следующий индекс

LOOP L ; цикл 100 раз

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]