Команды LOOP, LOOPD, LOOPE, LOOPNE, LOOPNZ, LOOPZ
Команды LOOP, LOOPD, LOOPE, LOOPNE, LOOPNZ, LOOPZ используются для организации циклов. Счетчиком цикла служит регистр CX или ECX (в зависимости от разрядности). В командах циклов с условием (Z, NZ, E, NE) цикл выполняется пока заданное условие истинно.
Команды LOOP, LOOPD
Синтаксис: | LOOP op1 LOOPD op1 |
Операнды: | op1 — i8 |
Назначение: | Цикл |
Процессор: | 8086+ 80386+ |
Флаги: | Не изменяются |
Комментарий: | |
Ограничения: | Нет |
Примеры: |
mov cx,100 l1: add ax,[bx] inc bx loop l1 |
Синтаксис: | LOOPE op1 LOOPZ op1 |
Операнды: | op1 |
Назначение: | Цикл, пока равно (пока ноль) |
Процессор: | 8086+ |
Флаги: | Не изменяются |
Комментарий: | |
Ограничения: | Поскольку все модификации команды LOOP не изменяют регистр флагов, то флаг ZF должен изменяться внутри тела цикла. |
Примеры: |
mov cx,100 l1: add ax,[bx] dec bx loope l1 |
Синтаксис: | LOOPNE op1 LOOPNZ op1 |
Операнды: | op1 — i8 |
Назначение: | Цикл, пока не равно (пока не ноль) |
Процессор: | 8086+ |
Флаги: | Не изменяются |
Комментарий: | |
Ограничения: | Поскольку все модификации команды LOOP не изменяют регистр флагов, то флаг ZF должен изменяться внутри тела цикла. |
Примеры: |
mov cx,100 l1: add ax,[bx] dec bx loopne l1 |
•Промоделируем на Ассемблере простейшую задачу для 16-разрядных знаковых и беззнаковых данных:
–unsigned int c, d;
–int a, b;
•if (a=b) then Fsign = 0;
•if (a<b) then Fsign = -1;
•if (a>b) then Fsign = 1;
•if (c=d) then Fusign = 0;
•if (c<d) then Fusign = -1;
•if (c>d) then Fusign = 1;
Команды циклов LOOPx
Группа команд условного перехода LOOPх служит для организации циклов в программах. Все команды цикла используют регистр CX в качестве счетчика цикла. Простейшая из них – команда LOOP. Она уменьшает содержимое CX на 1 и передает управление на указанную метку, если содержимое CX не равно 0. Если вычитание 1 из CX привело к нулевому результату, выполняется команда, следующая за LOOP.
Синтаксис команды: LOOP короткая метка
Логика работы команды:
СХ = Counter short_label: Выполнение тела цикла СХ = СХ — 1
if (СХ != 0) goto short_label
Аналог реализации команды LOOP на Ассемблере:
MOV СХ, Counter short_label:
;Выполнение тела цикла ;
;Проверка условия ПРОДОЛЖЕНИЯ цикла DEC СХ
СМР СХ, 0 JNE short_label
Команда LOOP уменьшает содержимое регистра СХ на 1, затем передает управление метке shorMabel, если содержимое СХ не равно 0. Передача управления на метку shortjabel для базовых процессоров — только КОРОТКАЯ
[-128,0]. Поскольку условие выхода из цикла проверяется в
КОНЦЕ, при значении Counter=0 цикл все равно выполнится. Этого мало, мы еще и зациклимся. Чтобы этого избежать,
обычно ДО НАЧАЛА ЦИКЛА проверяют содержимое регистра СХ на ноль. Таким образом, стандартная последовательность команд для организации цикла СО СЧЕТЧИКОМ имеет следующий вид:
MOV CX, Counter
JCXZ ExitCicle ; если CX = 0, цикл ОБОЙТИ short_label:
; Выполнение тела цикла LOOP short_label
ExitCicle:
ПРИМЕР
Вычислить значение факториала р = n! = 1*2*3*…*n
Известно, что 0! = 1. Отрицательным значение n быть НЕ может
.Model Large,С |
| |
; определение префикса для локальных меток |
| |
|
| |
.code |
|
|
Extrn С n: Word |
| |
Extrn С p: Word |
| |
Public proizv1 |
| |
Proizv1 Proc far ; Вариант 1 |
| |
mov cx,n | ; количество повторений |
|
mov si,1 |
|
|
mov ax,si |
|
|
jcxz @@Exit ;if cx=0 then Exit |
| |
@@begin: ; | = НАЧАЛО цикла | = |
mul si | ; <dx:ax> = <ax>*si |
|
inc si |
|
; ==== Выход из цикла ==================
loop @@beg±n @@Exit: mov p,ax
ret
proizv1 endp
Public proizv2
Proizv2 Proc far ; Вариант 2
mov cx ,n ; количество повторений mov ax,1
jcxz @@Exit ;if cx=0 then Exit @@begin: ;— = НАЧАЛО цикла =====
mul cx ; <dx:ax> = <ax>*cx
; ==== Выход из цикла =========
loop @@begin @@Exit:
mov p,ax ret
proizv2 endp end
Директива locals
Директива locals позволяет нам не думать о дублировании имен меток в разных подпрограммах. Метки с префиксом @@ считаются локальными. Если компилятор встретит метку с таким же именем, он просто при компиляции присвоит ей другое имя (обычно эти метки получают в конце имени номер, который увеличивается на единицу — все очень просто!).
Команда LOOPE (LOOPZ)
•Команда LOOPE (LOOPZ) переход по счетчику и если равно
Данная команда имеет два равнозначных мнемонических имени (if Equal — если Равно или if Zero — если Ноль).
Синтаксис команды: LOOPE короткая_метка
LOOPZ короткая_метка
Логика работы команды:
СХ = Counter Short_Label: Выполнение тела цикла СХ = СХ — 1
if (СХ != 0 && ZF = 1) goto Short_Label
Все то, что говорилось для команды LOOP, справедливо и для команды LOOPE (LOOPZ), добавляется еще проверка флага ZF. Применяется данная команда в случае, если нужно досрочно выйти из цикла, как только находится ПЕРВЫЙ элемент, ОТЛИЧНЫЙ от заданной величины.
Команда LOOPNE (LOOPNZ)
•Команда LOOPNE (LOOPNZ) переход по счетчику и если НЕ равно
Данная команда тоже имеет два равнозначных мнемонических имени (if Not Equal — если НЕ равно или if Not Zero — если НЕ ноль). В отличие от предыдущей команды проверяется, сброшен ли флаг нуля ZF=0.
Как сделать цикл на ассемблере x86?
спросил
Изменено 7 лет, 1 месяц назад
Просмотрено 139 тысяч раз
Я написал код до сих пор:
.code основной Clrscr мов дч,10 ;строка 10 mov dl,20 ;столбец 20 вызвать Gotoxy ;найти курсор Промптфоринтегерс WriteString ; отображать строку ReadInt ;введите целое число Сумма массива WriteString ; отображать строку WriteInt ;отобразить целое число DisplaySum ENDP КОНЕЦ основной
Как заставить его повторять одни и те же шаги три раза, используя цикл, очищая экран после каждой итерации цикла?
- петли
- сборка
4
мов сх,3 циклический запуск: делать вещи dec cx ;Примечание: уменьшение cx и переход к результату jnz loopstart намного быстрее на Intel (и, возможно, на AMD, поскольку я не ; проверено, может быть, 12 лет) вместо использования цикла loopstart
6
Еще один метод использует инструкцию LOOP:
mov cx, 3 моя петля: ; Содержимое вашего цикла петля
Инструкция цикла автоматически уменьшает значение cx и выполняет переход только в том случае, если cx != 0. Существуют также варианты LOOPE и LOOPNE, если вы хотите сделать дополнительную проверку на преждевременное завершение цикла.
Если вы хотите изменить cx во время цикла, обязательно поместите его в стек перед содержимым цикла и извлеките его после:
мов сх, 3 моя петля: нажать сх ; Содержимое вашего цикла поп сх петля
1
Использовать регистр CX для подсчета циклов
мов сх, 3 стартовый цикл: см сх, 0 jz эндофлоп нажать сх зацикленный: Вызов ClrScr поп сх дек сх джмп стартлуп эндофлоп: ; Цикл завершен ; Делайте то, что когда-либо приходилось делать здесь
Это просто повторяется 3 раза, вызывая ClrScr
, помещая регистр CX в стек, сравнивая с 0, переходя, если установлен ZeroFlag, затем переходя к эндофлоп
. Обратите внимание, как содержимое CX помещается/извлекается из стека/из него для поддержания потока в цикле.
3
.модель маленькая .стек 100ч .код Основной процесс Мов сх, 30; //это число управляет циклом 30 означает, что цикл будет ;возбудить 30 раз Ioopfront: Мов ах, 1 Интервал 21ч лицевая петля;
этот код займет 30 символов
1
Вам нужно использовать условные команды jmp. Это не тот синтаксис, который вы используете; выглядит как MASM, но с использованием GAS вот пример кода, который я написал для вычисления gcd:
gcd_alg: subl %ecx, %eax /* а = а - с */ cmpl $0, %eax /* если a == 0 */ je gcd_done /* перейти в конец */ cmpl %ecx, %eax /* если a < c */ jl gcd_preswap /* поменять местами и начать заново */ jmp gcd_alg /* продолжайте вычитание */
В принципе, я сравниваю два регистра с помощью инструкции cmpl (сравнение длинное). Если оно меньше, инструкция JL (переход меньше) переходит к месту предварительной замены, в противном случае выполняется переход обратно к той же метке.
Что касается очистки экрана, это зависит от используемой вами системы.
1
Я искал тот же ответ и нашел эту информацию из вики полезной: Инструкции цикла
Инструкция цикла уменьшает значение ECX и переходит к адресу, указанному в arg, за исключением случаев, когда уменьшение значения ECX приводит к тому, что его значение становится равным нулю. Например:
mov ecx, 5 start_loop: ; код здесь будет выполнен 5 раз цикл start_loop
цикл не устанавливает никаких флагов.
loopx arg
Эти инструкции цикла уменьшают ECX и переходят на адрес, указанный arg, если их условие выполнено (то есть установлен определенный флаг), если только уменьшение ECX не привело к тому, что его значение стало равным нулю.
Источник: Сборка X86, поток управления
1
Зарегистрируйтесь или войдите в систему
Зарегистрируйтесь с помощью Google
Зарегистрироваться через Facebook
Зарегистрируйтесь, используя электронную почту и пароль
Опубликовать как гость
Электронная почта
Обязательно, но не отображается
Опубликовать как гость
Электронная почта
Требуется, но не отображается
Сборка- Ассемблер Asm - Зацикливание цикла CX навсегда
Задавать вопросспросил
Изменено 9 лет, 7 месяцев назад
Просмотрено 3к раз
Я использую emu8086, www. emu8086.com - и имею следующий код:
сегмент данных пять экв 5 ПТО дб 5 дуп (1,2,3,4,5) w2 дб 0 заканчивается сегмент стека дв 128 дуп(0) заканчивается сегмент кода начинать: мов топор, данные мов дс, топор мов эс, топор ;сумма xor AX, AX xor BX,BX xor СХ, СХ мов кл, пять мов си,0 сумма: добавить al,vet[si] вкл. СИ дек сх сумма цикла мов w2, ал ;конечная сумма заканчивается конец начало
проблема в том, что когда CX достигает 0, цикл суммирования должен останавливаться, а результат суммирования сохраняться в переменной w2.
по какой-то странной причине этого не происходит, программа вечно зацикливается.
в чем проблема с моим кодом? может кто-нибудь, пожалуйста, помогите мне?
- циклы
- сборка
- бесконечный цикл
Инструкция 8086 LOOP уменьшает значение CX, а затем выполняет цикл, если CX не равен нулю. В вашем коде здесь:
сумма: добавить al,vet[si] вкл. СИ дек сх сумма цикла
Сначала вы уменьшаете CX, а затем выполняете LOOP, который снова уменьшает его.