Assembler для начинающих


Управление циклами



Управление циклами


    Существует несколько команд условного перехода, предназначенных для
    управления циклами в программах.  Поскольку программые циклы
    используются часто, желательно эффективное управление циклом.  На
    Фиг. 4.30 показаны четыре команды, созданные для того, чтобы
    облегчить программирование циклов на языке ассемблера
    микропроцессора 8088.
 
      Так же, как строковые команды используют регистр CX в качестве
    счетчика, команды цикла LOOP используют регистр CX в качестве
    счетчика цикла. Все эти команды неявно рассматривают регистр CX как
    счетчик итераций цикла. Простейшая команда среди них - команда
    LOOP. Команда LOOP уменьшает регистр CX и передает управление на


    метку, если содержимое регистра CX не равно 0. Если вычитание
    единицы из регистра CX не привело к нулевому результату, команда
    LOOP не делает перехода, и выполняется следующая команда.
 
      Приведенный ниже программный фрагмент демонстрирует обычное
    использование команды LOOP.
 
      MOV    CX,LOOP_COUNT
      BEGIN_LOOP:
      ; ...  тело цикла
      LOOP   BEGIN_LOOP
 

          Microsoft (R) Macro Assembler Version 5.00              1/1/80 04:02:01
          Фиг. 4.30 Команды цикла                           Page  1-1
 
 
                                        PAGE    ,132
                                        TITLE   Фиг. 4.30 Команды цикла
 
           0000                   CODE    SEGMENT
                                        ASSUME  CS:CODE
 
                                  ;----------------------------------------
                                  ; В этом примере демонстрируются команды цикла.
                                  ; Команды в примере не являются законченной программой.
                                  ;----------------------------------------
 
           0000  E3 06                  JCXZ    END_OF_LOOP     ; Конец цикла, если CX равно 0
 
           0002                   BEGIN_LOOP:
 
                                  ; ....  Тело цикла
 
           0002  E2 FE                  LOOP    BEGIN_LOOP      ; Переход пока регистр CX не станет равен 0
 
                                  ; ....  Если проверяется какое-либо условие, то
           0004  E1 FC                  LOOPE   BEGIN_LOOP      ; Переход по равенству в условии и
                                                          ;  значение регистра CX не равно 0
                                  ; ....  Или
 
           0006  E0 FA                  LOOPNE  BEGIN_LOOP      ; Переход по неравенству в условиии и
                                                          ;  значение регистра CX не равно 0
 
           0008                   END_OF_LOOP:
 
           0008                   CODE    ENDS
                                        END
 
            Фиг. 4.30 Команда цикла
 
      Программа помещает число итераций цикла в регистр CX перед
    выполнением цикла. Затем выполняется тело цикла, а следом за ним
    команда LOOP. Она уменьшает счетчик на единицу, что соответствует
    единственной, только что выполненной итерации цикла. Если теперь
    счетчик в регистре CX равен 0, программа продолжает выполняться
    после команды LOOP. Если счетчик не равен 0, управление
    возвращается к началу цикла, чтобы совершить еще один проход по
    телу цикла. Тело цикла выполняется столько раз, сколько было
    сначала задано содержимым регистра CX. Единственное важное
    замечание: если программа внутри цикла изменяет регистр CX, число
    итераций цикла не будет соответствовать начальному значению в
    регистре CX.
 
      Описанный метод одинаково хорошо работает, когда число циклов
    известно во время ассемблирования (как в примере, где LOOP_COUNT -
    непосредственно заносимое значение), и когда число циклов
    определяется во время выполнения. Если вычисленное число оказалось
    равным 0, цикл выполнится 65536 раз. Когда микропроцессор 8088
    выполняет первую команду LOOP, он уменьшает CX от 0 до 0FFFFH, и
    поскольку теперь регистр CX ненулевой, повторяет цикл. Таким
    образом, загрузка нулевого значения счетчика циклов - специальный
    случай. Этот специальный случай обрабатывается командой JCXZ
    (переход, если содержимое регистра CX равно 0). Эта команда
    проверяет текущее содержимое регистра CX, и делает переход, если
    оно равно нулю. Команда не проверяет ни одного флага, и не влияет
    ни на один из них. Следующий пример аналогичен предыдущему, за
    исключением того, что он загружает регистр CX из ячейки памяти,
    содержимое которой вычисляется во время выполнения программы. По
    этой причине может оказаться, что счетчик циклов нулевой, и пример
    использует команду JCXZ, чтобы проверить, нужно ли полностью
    пропустить тело цикла.
 
         MOV         CX,LOOP_COUNT_WORD
         JCXZ    END_OF_LOOP
      BEGIN_LOOP:
         ;   ... тело цикла
         LOOP    BEGIN_LOOP
      END_OF_LOOP:
 
      В программе не нужно использовать команду JCXZ в каждом цикле с
    вычисляемым счетчиком. Если программист знает, что счетчик циклов
    никогда не будет равен нулю, проверка не нужна. Однако опыт
    показывает, что значение, которое "никогда" не должно появиться,
    обычно появляется в первую очередь, как только вы начинаете
    выполнять программу.
 
      Оставшиеся две команды цикла предоставляют еще большие
    возможностей при управлении циклами. Эти команды аналогичны
    префиксам REPE и REPNE. Если команда LOOP выходит из цикла, только
    когда в регистре CX оказывается нуль, то команда LOOPE (цикл, пока
    равно) выходит из цикла, если установлен флаг нуля, или если в
    регистре CX получился 0. Тем самым становится возможным
    двойственное завершение цикла. Программа может загрузить в регистр
    CX максимальное число итераций цикла, а затем проверять флаг нуля в
    конце каждого цикла на условие завершения. Команда LOOPNE (цикл,
    пока не равно) выполняет обратную к описанной проверку флага нуля:
    цикл здесь завершается, если регистр достиг нуля, или если
    установлен флаг нуля.
      Следующий пример показывает использование команды LOOPNE. В
    примере складываются два списка чисел, чтобы найти пару элементов,
    сумма которых точно равна 100. Так как в каждой итерации перед
    проверкой складываются два чила, команду REPNE CMPSB использовать
    нельзя.
 
      В примере предполагается, что пары регистров DS:SI и ES:DI
    инициализированы так, чтобы указывать на эти списки.
 
      MOV   CX,MAX_LOOP_COUNT ;максимальное число заходов
      BEGIN_LOOP:
      LODSB               ;чтение числа из первого списка
      ADD   AL,ES:[DI]    ;прибавить из второго списка
      INC   DI            ;указатель на следующий элемент
      CMP   AL,100              ;проверка на нужное значение
      LOOPNE      BEGIN_LOOP    ;снова, если не равно и не все
      JE    MATCH_FOUND    ;переход сюда, чтобы определить конец




Содержание раздела