Команды управления циклом
С помощью команд перехода можно реализовать любые разветвления и циклы. Изучите таблицу 4, в которой представлены способы реализации ветвлений и циклов в языках Pascal и ассемблер.
Таблица 4.4
Реализация ветвлений и циклов в языках Pascal и ассемблер.
Тип цикла | Язык Pascal | Язык Ассемблер |
Ветвление | If X > 0 then begin Блок S1 end else begin Блок S2 end; | CMP X, 0 JLE L2 Блок S1 JMP Fin L2: Блок S1 Final: |
Цикл со счетчиком | For X:=1 to N do begin Блок S end; | MOV CX, N L: Блок S DEC CMP CX, 0 JNE L Final: |
Цикл с передусловием | While X > 0 do begin Блок S end; | Begin: CMP X, 0 JLE Fin Блок S JMP Begin Final: |
Цикл с постусловием | Repeat Блок S until X > 0 | Begin: Блок S CMP X, 0 JG Begin |
Для организации циклов с заранее известным числом повторений, в систему команд микропроцессора Intel 8086 включены специальные команды управления циклом: LOOP, LOOPE/LOOPZ и LOOPNE/LOOPNZ.Состояние флагов после выполнения команды этих команд не меняется.
4.4.1. Управление циклом по счетчику: LOOP <метка>
С помощью команды LOOP цикл может быть записан следующим образом:
MOV | CX, N | ; N>0 | |
L: | … | ||
… | |||
… | |||
LOOP | L |
Особенности команды LOOP.
ü В качестве счетчика цикла обязательно использовался регистр СХ, при другом регистре команду применять нельзя.
ü Начальное значение для СХ должно быть присвоено до цикла, причем этому регистру надо присваивать ровно столько, сколько раз должен повторяться цикл.
ü Так как команда LOOP ставится в конце цикла, тело цикла хотя бы раз обязательно выполнится. Поэтому для случая СХ = 0 такая схема цикла не подходит. Если возможен вариант, что число повторений может быть и нулевым, то при СХ = 0 надо сделать обход цикла с помощью команды условного перехода JCXZ:
MOV | CX, N | ; N>0 | |
JCXZ | L1 | ; CX = 0 а L1 | |
L: | … | ||
… | |||
… | |||
LOOP | L | ||
L1: | … |
Команда LOOP реализует только короткий переход, поэтому расстояние от нее до начала цикла (метки L) не должно превышать 127-128 байтов (примерно 30-40 команд). Если цикл содержит больше команд, тогда команду LOOP использовать нельзя и надо реализовывать цикл по-иному.
4.4.2. Цикл по счетчику и пока равно (пока ноль):
LOOPE <метка> или LOOPZ <метка>
Эта команда совмещает в себе изменение счетчика цикла (регистра СХ) и условный переход (короткий), когда счетчик еще не нулевой и когда предыдущая команда выработала флаг нуля, равный 1. Она используется для организации цикла с известным числом повторений, из которого возможен досрочный выход. До начала цикла в регистр СХ записывается число повторений.
По какой причине произошел выход из цикла (по ZF=0 или СХ=0), надо проверять после цикла. Проверить необходимо флаг ZF (по команде JE/JZ или JNE/JNZ), а не регистр СХ, т. к. условие ZF = 0 («не равно») может появиться как раз на последнем шаге цикла, когда и регистр СХ стал нулевым.
Чаще всего команда LOOPE используется для поиска первого элемента некоторой последовательности, отличного от заданной величины.
4.4.3. Цикл по счетчику и пока не равно:
LOOPNE <метка> или LOOPNZ <метка>
Эта команда аналогична команде LOOPE/LOOPZ, но выход из цикла осуществляет при СХ = 0 или ZF = 1. Команда LOOPNE обычно используется для поиска в некоторой последовательности первого элемента, имеющего заданную величину.
Examle 4.3.Фрагмент программы организации цикла, выводящий сообщение N раз.
; описание данных
.data
mes1 db ‘Шаг цикла выполнен’, 10, 13, ‘$’
mes2 db ‘Цикл завершен’, 10, 13, ‘$’
N EQU 5
; фрагмент кода программы
.code ;
…
MOV CX, N ; количество итерации равен пяти
cycl:
MOV DX, OFFSET mes1 ; вывод сообщения
MOV AH, 09h ;
INT 21h ;
LOOP cycl; CX = CX – 1, если CX > 0, то переход на метку, иначе к следующей команде.
MOV DX, OFFSET mes2 ; сообщение, что цикл завершен
MOV AH, 09h ;
INT 21h ;
MOV AH, 4Ch ;
INT 21h ;
…;
Examle 4.4.Фрагмент программы организации цикла, для поиска числа в массиве.
; описание данных
.data
mes1 db ‘Число найдено’, 10, 13, ‘$’
mes2 db ‘Число не найдено’, 10, 13, ‘$’
array db 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
; фрагмент кода программы
.code ;
MAIN:
…
MOV CX, 10 ; количество итерации равен пяти
MOV SI, OFFSET array ; инициализация начало массива
MOV BL, 3 ; искомое число
DEC SI ; Декремент адреса в регистре SI
cycl:
INC SI ; Инкремент адреса в регистре SI, установка на начало массива
CMP [SI], BL
LOOPNE cycl; CX = CX – 1, если CX > 0 и ZF = 0, то переход на метку, иначе к следующей команде.
JE ravno
JNE neravno
JMP exit
ravno:
MOV DX, OFFSET mes3 ;
MOV AH, 09h ;
INT 21h
JMP exit;
neravno:
MOV DX, OFFSET mes4 ;
MOV AH, 09h ;
INT 21h
exit:
Examle 4.5.Дан массив из десяти слов, содержащих целые числа. Найти максимальное значение элементов массива.
Фрагмент программы.
MAX | DW | ? | ||
MASS | DW | 10h, 20h, 30h, 5h, 40h, 15h, 20h, 70h, 35h, 34h | ||
… | ||||
LEA | BX, MASS | |||
MOV | CX, 10 | ; установить счетчик | ||
MOV | AX, [BX] | ;первый элемент массива в аккумулятор | ||
BEG: | CMP | [BX], AX | ;сравнить текущий элемент массива с максимальным | |
JL | NO | ;он меньше | ||
MOV | AX,[BX] | ;он больше | ||
NO: | ADD | BX, 2 | ;следующий элемент массива | |
LOOP | BEG | ; | ||
MOV | MAX,AX | ; | ||
… | ||||
Examle 4.6.Пусть N - байтовая переменная со значением от 0 до 8 . В регистр АХ записать факториал этого числа. (8! = 40320 < 2 16).
Для решения этой задачи надо вначале положить АХ := 1, а затем N раз выполнить умножение AX := AX*i, меняя i от 1 до 8. При этом следует учитывать, что при N = 0 цикл не должен выполняться.
MOV | AX,1 | ; AX:=0! | |
MOV | CL, N | ||
MOV | СН, 0 | ; CX := N как слово (счетчик цикла) | |
JCXZ | Fl | ; при N = 0 обойти цикл | |
MOV | SI, 1 | ; i := l | |
F: | MUL | SI | ; (DX, AX) := AX*i (DX = 0) * |
INC | SI | ||
LOOP | F | ||
F1: | … |
Examle 4.7.Записать в регистр BL наименьшее число из отрезка [2, К], на которое не делится число N (К и N - байтовые переменные, 2 <= K < N), или записать 0, если такого числа нет.
Для решения будем последовательно делить N на числа 2, 3, ..., К и сравнивать остатки от деления с 0 - до тех пор, пока не найдется ненулевой остаток либо не будут исчерпаны все числа отрезка.