Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

СПРАВОЧНИК по системе программирования ТУРБО АССЕМБЛЕР 2.0


Оглавление

                           Условные переходы
-----------------------------------------------------------------

     Описанные в предыдущем разделе инструкции  переходов  -  это
только  часть  того,  что  вам потребуется для написания полезных
программ. В действительности необходима возможность писать  такие
программы,  которые могут принимать решения. Именно это можно де-
лать с помощью операций условных переходов.

     Инструкция условного  перехода может  осуществлять  или  нет
переход на целевую (указанную в ней) метку, в зависимости от сос-
тояния регистра флагов. Рассмотрим следующий пример:

             .
             .
             .
             mov   ah,1           ; функция DOS ввода с клавиату-
                                  ; ры
             int   21h            ; получить следующую нажатую
                                  ; клавишу
             cmp   al,'A'         ; была нажата буква "A"?
             je    AWasTyped      ; да, обработать ее
             mov   [TampByte], al ; нет, сохранить символ
             .
             .
             .
    AWasTyped:
             push   ax            ; сохранить символ в стеке
             .
             .
             .

     Сначала в данной программе с  помощью  функции  операционной
системы DOS  воспринимается нажатая клавиша.  Затем для сравнения
введенного символа с символом A используется инструкция  CMP. Эта
инструкция аналогична инструкции SUB,  только ее выполнение ни на
что не влияет,  поскольку назначение данной инструкции состоит  в
том,  чтобы можно было сравнить два операнда, установив флаги так
же,  как это делается в инструкции SUB. Поэтому в предыдущем при-
мере  флаг нуля устанавливается в значение 1 только в том случае,
если регистр AL содержит символ A.

     Теперь мы подошли к основному моменту. Инструкция JE  предс-
тавляет  инструкцию условного перехода, которая. осуществляет пе-
редачу управления только в том случае, если флаг нуля равен 1.  В
противном  случае выполняется инструкция, непосредственно следую-
щая за инструкцией JE (в данном случае -  инструкция  MOV).  Флаг
нуля  в  данном  примере будет установлен только в случае нажатия
клавиши A, и только в этом случае процессор 8086 перейдет  к  вы-
полнению инструкции с меткой AWasTyped, то есть инструкции PUSH.

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

     Перечень инструкций  условных переходов приводится в Таблице
5.2.

            Инструкции условных переходов             Таблица 5.2
-----------------------------------------------------------------
Название             Значение                   Проверяемые флаги
-----------------------------------------------------------------
JB/JNAE   Перейти, если меньше / перейти, если     CF = 1
          не больше или равно

JAE/JNB   Перейти, если больше или равно / пе-     CF = 0
          рейти, если не меньше

JBE/JNA   Перейти, если меньше или равно / пе-  CF = 1 или ZF = 1
          рейти, если не больше

JA/JNBE   Перейти, если больше / перейти, если    CF = 0 и ZF = 0
          не меньше или равно

JE/JZ     Перейти, если равно                       ZF = 1

JNE/JNZ   Перейти, если не равно                    ZF = 0

JL/JNGE   Перейти, если меньше чем / перейти,       SF = OF
          если не больше чем или равно

JGE/JNL   Перейти, если больше чем или равно /      SF = OF
          перейти, если не меньше чем

JLE/JNLE  Перейти, если меньше чем или равно / ZF = 1 или SF = OF
          перейти, если не больше, чем

JG/JNLE   Перейти, если больше чем / перейти,  ZF = 0 или SF = OF
          если не меньше чем или равно

JP/JPE    Перейти по четности                       PF = 1

JNP/JPO   Перейти по нечетности                     PF = 0

JS        Перейти по знаку                          SF = 1

JNS       Перейти, если знак не установлен          SF = 0

JC        Перейти при наличии переноса              CF = 1

JNC       Перейти при отсутствии переноса           CF = 0

JO        Перейти по переполнению                   OF = 1

JNO       Перейти при отсутствии переполнения       OF = 0
-----------------------------------------------------------------

      CF - флаг переноса,  SF - флаг знака,  OF - флаг переполне-
ния, ZF - флаг нуля, PF - флаг четности

     Более подробная информация об инструкциях-синонимах и  общие
сведения  об инструкциях перехода содержатся в Главе 6. Там также
подробно рассказывается о способах, с помощью которых  инструкции
процессора 8086 могут изменять регистр флагов.

     Несмотря на свою  гибкость,  инструкции  условного  перехода
имеют также серьезные ограничения, поскольку переходы в них всег-
да короткие.  Другими словами целевая метка, указанная в инструк-
ции условного перехода, должна отстоять от инструкции перехода не
более, чем на 128 байт.  Например,  Турбо Ассемблер не может  ас-
семблировать:

              .
              .
              .
 JumpTarget:
              .
              .
              .
              DB   1000 DUP (?)
              .
              .
              .
              dec   ax
              jnz   JumpTarget
              .
              .
              .

так как метка JumpTarget отстоит от инструкции JNZ более  чем  на
1000 байт. В данном случае нужно сделать следующее:

              .
              .
              .
   JumpTarget:
              .
              .
              .
              DB   1000 DUP (?)
              .
              .
              .
              dec   ax
              jnz   SkipJump
              jmp   JumpTarget
   SkipJump:
              .
              .
              .

где условный переход переход применяется для того, чтобы  опреде-
лить, нужно ли выполнить длинный безусловные переход.



                                 Циклы
-----------------------------------------------------------------

     Одним из видов конструкций в программе, которые можно  пост-
роить  с  помощью  условных переходов, являются циклы. Цикл - это
просто-напросто блок кода, завершающийся условным переходом, бла-
годаря  чему данных блок может выполняться повторно до достижения
условия завершения. Возможно, вам уже знакомы  такие  конструкции
циклов,  как  for  и while в языке Си, while и repeat в Паскале и
FOR в Бейсике.

     Для чего используются циклы? Они служат для работы с  масси-
вами, проверки состояния портов ввода-вывода до получения опреде-
ленного состояния, очистки блоков памяти, чтения строк с  клавиа-
туры  и  вывода их на экран и т.д. Циклы - это основное средство,
которое используется для выполнения повторяющихся действий.  Поэ-
тому  используются они довольно часто, настолько часто, что в на-
боре инструкций процессора 8086 предусмотрено фактически несколь-
ко инструкций циклов: LOOP, LOOPNE, LOOPE и JCXZ.

     Давайте рассмотрим сначала инструкцию LOOP. Предположим,  мы
хотим  вывести 17 символов текстовой строки TestString. Это можно
сделать следующим образом:

           .
           .
           .
           .DATA
 TestString        DB   'Это проверка! ...'
           .
           .
           .
           .CODE
           .
           .
           .
           mov   cx,17
           mov   bx,OFFSET TestString
 PrintStringLoop:
           mov   dl,[bx]              ; получить следующий
                                      ; символ
           inc   bx                   ; ссылка на следующий
                                      ; символ
           mov   ah,2                 ; функция DOS вывода на
                                      ; экран
           int   21h                  ; вызвать DOS для вывода
                                      ; символа
           dec   cx                   ; уменьшить счетчик длины
                                      ; строки
           jnz   PrintStringLoop      ; обработать следующий
                                      ; символ, если он имеется
           .
           .
           .

     Есть, однако, лучший способ. Возможно, вы помните, что ранее
мы  уже упоминали о том, что регистр CX весьма полезно бывает ис-
пользовать для организации циклов. Инструкция:

           loop   PrintStringLoop

делает то же, что и инструкции:

           dec   cx
           jnz   PrintStringLoop

однако выполняется она быстрее и занимает на  один  байт  меньше.
Всякий  раз,  когда  вам  нужно  организовать цикл, пока значение
счетчика не станет равным 0, запишите начальное значение счетчика
в регистр CX и используйте инструкцию LOOP.

     Как же строятся циклы с более сложным  условием  завершения,
чем  обратный отсчет значения счетчика? Для таких случаев предус-
мотрены инструкции LOOPE и LOOPNE.

     Инструкция LOOPE работает также, как инструкция LOOP, только
цикл  при ее выполнении будет завершаться (то есть перестанут вы-
полняться переходы),  если регистр CX примет значение 0 или  флаг
нуля будет установлен в значение 1 (нужно помнить о том, что флаг
нуля устанавливается в значение 1, если результат последней ариф-
метической операции был нулевым или два операнда в последней опе-
рации сравнения не совпадали).  Аналогично, инструкция LOOPNE за-
вершает  выполнение цикла,  если регистр CX принял значение 0 или
флаг нуля сброшен (имеет нулевое значение).

     Предположим, вы хотите повторять цикл, сохраняя коды нажатых
клавиш, пока не будет нажата клавиша ENTER или не будет накоплено
128 символов. Для выполнения такой работы  можно  написать  такую
программу (где используется инструкция LOOPNE):

          .
          .
          .
          .DATA
  KeyBuffer      DB   128 DUP (?)
          .
          .
          .
          .CODE
          .
          .
          .
          mov   cx,128
          mov   bx,OFFSET KeyBuffer
 KeyLoop:
          mov   ah,1              ; функция DOS ввода с
                                  ; клавиатуры
          int   21h               ; считать следующую
                                  ; клавишу
          mov   [bx],al           ; сохранить ее
          inc   bx                ; установить указатель
                                  ; для следующей клавиши
          cmp   al,0dh            ; это клавиша ENTER?
          loopne KeyLoop          ; если нет, то получить
                                  ; следующую клавишу, пока
                                  ; мы не достигнем максимально-
                                  ; го числа клавиш
          .
          .
          .

     Инструкция  LOOPE  известна  также,  как  инструкция  LOOPZ,
инструкция  LOOPNE  - как инструкция LOOPNZ, также как инструкции
JE эквивалентна инструкция JZ (это инструкции-синонимы).

     Имеется еще одна  инструкция  цикла.  Это  инструкция  JCXZ.
Инструкция  JCXZ  осуществляет  переход только в том случае, если
значение регистра CX равно 0. Это дает удобный  способ  проверять
регистр  CX  перед началом цикла. Например, в следующем фрагменте
программы, при обращении к которому регистр BX указывает на  блок
байт, которые  требуется  обнулить,  инструкция JCXZ используется
для пропуска тела цикла в том случае,  если регистр CX имеет зна-
чение 0:

         .
         .
         .
         jcxz   SkipLoop         ; если CX имеет значение 0, то
                                 ; ничего делать не надо
 ClearLoop:
         mov   BYTE PTR [si],0   ; установить следующий байт в
                                 ; значение 0
         inc   si                ; ссылка на следующий очищаемый
                                 ; байт
 SkipLoop:
         .
         .
         .

     Почему желательно пропустить выполнение цикла, если значение
регистра  CX  равно  0? Потому что в противном случае значение CX
будет уменьшено до величины 0FFFFh и инструкция  LOOP  осуществит
переход  на  указанную  метку. После этого цикл будет выполняться
65535 раз. Вы же хотели, чтобы значение регистра  CX,  равное  0,
указывало, что требуется обнулить 0 байт,  а не 65536. Инструкция
JCXZ позволяет вам в этом случае быстро  и  эффективно  выполнить
нужную проверку.

     Относительно инструкций циклов можно сделать пару интересных
замечаний. Во-первых, нужно помнить о том, что инструкции циклов,
как и инструкции  условных  переходов,  могут  выполнять  переход
только  на  метку,  отстоящую от инструкции цикла не более чем на
128 байт в ту или другую сторону.  Циклы,  превышающие 128  байт,
требуют  использования  условных  переходов с помощью безусловных
переходов (этот метод описан в предыдущем разделе "Условные пере-
ходы"). Во-вторых, важно понимать, что ни одна из инструкций цик-
лов не влияет на состояние флагов.  Это означает, что инструкция:

            loop   LoopTop

не эквивалентна в точности инструкциям:

            dec   cx
            jnz   LoopTop

поскольку инструкция DEC изменяет флаги переполнения, знака,  ну-
ля,  дополнительного  переноса  и  четности, а инструкция LOOP на
флаги не влияет. Кроме того, использование инструкции DEC не  эк-
вивалентно варианту:

            sub   cx,1
            jnz   LoopTop

поскольку инструкция SUB влияет на флаг  переноса,  а  инструкция
DEC -  нет.  Различия невелики,  но при программировании на языке
Ассемблера важно понимать,  какие именно флаги  устанавливают  те
или иные инструкции.




Оглавление

Оставить комментарий

Комментарий:
можно использовать BB-коды
Максимальная длина комментария - 4000 символов.
 
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог