Команды цикла
Для организации циклов на Ассемблере вполне можно использовать команды условного перехода. Например, цикл языка Паскаль с предусловием while X<0 do S; можно реализовать в виде следующего фрагмента на Ассемблере
L:cmpX,0; Сравнить X с нулём
jge L1
; Здесь будет оператор S
jmp L
L1: . . .
Оператор цикла с постусловием repeat S1; S2;. . .Sk until X<0; можно реализовать в виде фрагмента на Ассемблере
L:; S1
; S2
. . .
; Sk
cmp X,0; Сравнить X с нулём
jge L
. . .
В этих примерах мы считаем, что тело цикла по длине не превышает примерно 120 байт (это 30-40 машинных команд). Как видим, цикл с постусловием требует для своей реализации на одну команду меньше, чем цикл с предусловием.
Как мы знаем, если число повторений выполнения тела цикла известно до начала исполнения этого цикла, то в языке Паскаль наиболее естественно было использовать цикл с параметром. Для организации цикла с параметром в Ассемблере можно использовать специальные команды цикла. Команды цикла, по сути, тоже являются командами условного перехода и, как следствие, реализуют только близкий короткий относительный переход. Команда цикла
loop L; Метка L заменится на операнд i8
использует неявный операнд – регистр CX и её выполнение может быть так описано с использованием Паскаля:
Dec(CX); {Это часть команды loop, поэтому флаги не меняются!}
if CX<>0 then goto L;
Как видим, регистр CX (который так и называется регистром счётчиком цикла – loop counter), используется этой командой именно как параметр цикла. Лучше всего эта команда цикла подходит для реализации цикла с параметром языка Паскаль вида
for CX:=N downto 1 do S;
Этот оператор можно эффективно реализовать таким фрагментом на Ассемблере:
mov CX,N
jcxz L1
L: . . .; Тело цикла –
. . .; оператор S
loop L
L1: . . .
Обратите внимание, так как цикл с параметром языка Паскаль по существу является циклом с предусловием, то до начала его выполнение проверяется исчерпание значений для параметра цикла с помощью команды условного перехода jcxz L1 , которая именно для этого и была введена в язык машины. Ещё раз напоминаем, что команды циклов не меняют флагов.
Описанная выше команда цикла выполняет тело цикла ровно N раз, где N – беззнаковое число, занесённое в регистр-счётчик цикла CX перед началом цикла. К сожалению, никакой другой регистр нельзя использовать для этой цели (т.к. это неявный параметр команды цикла). Кроме того, в приведённом выше примере реализации цикла тело этого не может быть слишком большим, иначе команда loop L не сможет передать управление на метку L.
В качестве примера использования команды цикла решим следующую задачу. Требуется ввести беззнаковое число N<=500, затем ввести N знаковых целых чисел и вывести сумму тех из них, которые принадлежат диапазону –2000..5000. Можно предложить следующее решение этой задачи.
include io.asm
; файл с макроопределениями для макрокоманд ввода-вывода
data segment
N dw?
S dw 0; Начальное значение суммы = 0
T1 db ′Введите N<=500 $′
T2 db ′Ошибка – большое N!$′
T3 db ′Вводите целые числа′,10,13,′$′
T4 db ′Ошибка – большая сумма!$′
data ends
stack segment stack
dw 64 dup (?)
stack ends
code segment
assume cs:code,ds:data,ss:stack
start:mov ax,data
mov ds,ax
mov dx, offset T1; Приглашение к вводу
Outstr
inint N
cmp N,500
jbe L1
mov dx, offset T2; Диагностика от ошибке
Err:outstr
Дата добавления: 2015-10-05; просмотров: 909;