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

        MOV      CX, LOOP_COUNT
        BEGIN_LOOP:
        ; ... тело цикла
        LOOP     BEGIN_LOOP

          Программа помещает число итераций цикла в  регистр
    CX  перед выполнением цикла. Затем выполняется тело цик-
    ла, а следом за ним команда LOOP. Она уменьшает  счетчик
    на  единицу,  что соответствует единственной, только что
    выполненной итерации цикла. Если теперь счетчик в регис-
    тре CX равен 0, программа продолжает  выполняться  после
    команды  LOOP. Если счетчик не равен 0, управление возв-
    ращается к началу цикла, чтобы совершить еще один проход
    по телу  цикла.  Тело  цикла  выполняется  столько  раз,
    сколько  было  сначала  задано  содержимым  регистра CX.
    Единственное важное  замечание:  если  программа  внутри
    цикла изменяет регистр CX, число итераций цикла не будет
    соответствовать начальному значению в регистре CX.
          Следующий пример показывает использование  команды
    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       ;  конец цикла
@e
@b
          Команды передачи  управления нужны для того,  чтобы
    передавать выполнение программы в  различные  секции  ко-
    манд. В их число входят также команды вызова подпрограмм.
    Команды вызова подпрограмм вызывают подпрограммы,  а  ко-
    манды  перехода  передают управление поименованной ячейке
    без сохранения адреса возврата. Команда условного перехо-
    да позволяет ЭВМ думать. Условные команды могут проверить
    результат предыдущих действий и изменить течение програм-
    мы на основе полученного результата.
          Хотя операнд команды перехода - такая же  ссылка  к
    памяти, как и ссылка к данным, программы используют адре-
    са перехода иначе, чем адреса данных. Поэтому для адреса-
    ции точки перехода существуют лучшие способы.
@e
@b
          Команды перехода модифицируют указатель команды IP,
    и,  возможно, регистр сегмента кодов CS. Эти регистры по-
    казывают,  какая следующая команда должна быть выполнена.
    Команда  перехода  является специальным случаем пересылки
    MOV данных в регистр или пару регистров;  и некоторые ЭВМ
    действительно  выполняют  команду  перехода  именно таким
    способом.  Однако способы загрузки пары регистров CS:IP в
    микропроцессоре  8088  во  многом отличаются от способов,
    используемых для других регистров.
          Прежде всего  мы  должны ввести некоторые определе-
    ния.  Если команда перехода изменяет только  регистр  IP,
    это  интрасегментный переход,  так как переход происходит
    внутри сегмента.  Также он называется близким, NEAR-пере-
    ходом.  Если  переход изменяет регистр CS,  это интерсег-
    ментный, или далекий FAR-переход.
          Аттрибуты NEAR  и  FAR  используются при работе ас-
    семблера.  Любая программная метка в программе  на  языке
    ассемблера имеет атрибут либо NEAR, либо FAR, так же, как
    данные имеют атрибуты BYTE или WORD. В некоторых примерах
    этой главы имеются процедуры,  которые используют атрибут
    NEAR в операторе PROC. Это означает, что метка, связанная
    с оператором PROC (имя процедуры) имеет атрибут NEAR. Ас-
    семблер использует эту информацию для того, чтобы опреде-
    лить,  какой тип команды перехода или вызова породить при
    переходе к этой метке.  Поскольку большинство процедур  -
    подпрограммы,  атрибут  NEAR или FAR оператора PROC также
    определяет тип порождаемой команды возврата.  Вызов  CALL
    FAR - процедуры сохраняет значения как регистра CS, так и
    регистра IP,  тогда как вызов NEAR-процедуры оставляет  в
    стеке только значение регистра IP. Команда возврата долж-
    на учитывать, какой тип вызова был сделан, чтобы подпрог-
    рамма могла вернуться к правильному месту.
@e
@b
          Если адрес перехода или вызова подпрограммы являет-
    ся  частью  самой команды (как данные в командах с непос-
    редственным операндом),  это - непосредственный  переход.
    Если  адрес  перехода  команды  содержится в регистре или
    ячейке памяти,  это - косвенный переход,  так как команда
    требует загрузки адреса,  извлекаемого из некоторого про-
    межуточного места хранения;  программа не  может  перейти
    прямо  в  необходимое место,  и должа идти туда косвенно.
    Если в команде указано значение  адреса,  это  абсолютный
    переход,  т.е. переход по абсолютному адресу. Команда мо-
    жет указать место перехода,  как некоторое расстояние  от
    нее  самой.  Этот метод перехода называется относительным
    переходом.
          Преимущество относительных переходов  заключается в
    том, что программа наиболее часто переходит к близлежащим
    ячейкам; команда перехода может использовать однобайтовое
    смещение.  Если смещение трактуется, как число в дополни-
    тельном коде,  то двухбайтовая команда относительного пе-
    рехода (один байт - код операции, и один байт - смещение)
    может выполнить переход на 127 байт  вперед  или  на  128
    байт  назад  внутри программы.  Микропроцессор 8088 имеет
    два типа относительных переходов: один имеет однобайтовое
    смещение, другой - двухбайтовое.
          В микропроцессоре  8088 все условные переходы имеют
    однобайтовое смещение.  Иногда это неудобно,  например  в
    случае условного перехода к ячейке,  находящейся на расс-
    тоянии в 150 байт от  текущего  места.  В  таких  случаях
    программа должна использовать пару переходов,  условный и
    безусловный.  В обычных же случаях однобайтовые  смещения
    условных  переходов  в  микропроцессоре 8088 минимизируют
    объем программы,  необходимой для реализации любой задан-
    ной функции.
          При расчете смещения относительного  перехода  мик-
    ропроцессор  8088 отсчитывает смещение от значения указа-
    теля команд,  которое получится после выполнения команды.
    Пример показывает разные случаи команд относительного пе-
    рехода.  Если точка перехода следует  непосредственно  за
    переходом, смещение равно 0. При переходе к самой команде
    перехода смещение равно -2. При двухбайтовом смещении пе-
    реход  может быть сделан в диапазоне - 32768 - 32767 байт
    от значения рагистра IP в конце команды перехода.

            PAGE    ,132
    CODE    SEGMENT
            ASSUME  CS:CODE

    ;-----  Иллюстрация значения смещения в командах
    ;       относительного перехода

    START:
            JMP     START           ; Переход на себя
    ; Короткий переход на следующую команду
            JMP     SHORT LABEL_ONE
    ; Переход вперед без SHORT (близкий)
    LABEL_ONE:
            JMP     LABEL_TWO
    ; Переход (близкий) на большее расстояние
    LABEL_TWO:
            JMP     LABEL_THREE

    ; ...   Использование ORG для демонстрации перехода
    ;       на большое расстояние

            ORG     200H
    LABEL_THREE:

    CODE    ENDS
            END
@e
@b
          Безусловный переход - это  такой  переход,  который
    передает управление всякий раз, когда он выполняется. На-
    оборот,  условный переход проверяет текущее состояние ма-
    шины,  чтобы  определить,  передавать управление или нет.
    Существует два вида команд безусловной передачи  управле-
    ния - команды переходов и вызовов.
          Все команды вызова CALL - безусловны. Различные ко-
    манды  CALL  показаны  в  примере.  Интрасегментный вызов
    CALL, или NEAR CALL, указывает новое значение регистра IP
    и сохраняет старое значение регистра IP в стеке в качест-
    ве адреса возврата.  Интерсегментный вызов CALL,  или FAR
    CALL,  организует  новые значения сегмента и смещения для
    дальнейшего выполнения программы и сохраняет  как регистр
    IP,  так  и регистр CS в стеке.  Близкий непосредственный
    вызов CALL  -  это  относительный  переход,  использующий
    двухбайтовое поле смещения.  Все остальные команды вызова
    - абсолютные переходы.  Непосредственный вызов  FAR  CALL
    требует  четырехбайтовое поле операнда для указания новых
    значений для регистров CS и IP.  Косвенные  переходы  ис-
    пользуют  байт  адресации  mod - r/m для указания операн-
    да-регистра или памяти; этот операнд содержит однословный
    операнд  в регистр IP.  Вызовы типа FAR загружают двойное
    слово из памяти в пару регистров CS:IP; первое слово заг-
    ружается в регистр IP,  а второе - в регистр CS. Если ко-
    манда указывает регистр в  качестве  операнда  косвенного
    интерсегментного вызова, результат непредсказуем; микроп-
    роцессор 8088 берет новое значение регистра CS неизвестно
    откуда.  Ни в коем случае нельзя использовать эту модифи-
    кацию команды.

            PAGE    ,132
    FAR_SEG SEGMENT
            ASSUME  CS:FAR_SEG
    FAR_LABEL       PROC    FAR
            RET
    FAR_LABEL       ENDP
    FAR_SEG ENDS

    CODE    SEGMENT
            ASSUME  CS:CODE

    INDIRECT_FAR    DD      FAR_LABEL
    INDIRECT_NEAR   DW      NEAR_LABEL
    ; Близкий (относительный) вызов
            CALL    NEAR_LABEL
    ; Далекий (абсолютный) вызов
            CALL    FAR_LABEL
    ; Косвенный близкий (абсолютный) вызов
            CALL    INDIRECT_NEAR
    ; Косвенный далекий (абсолютный) вызов
            CALL    INDIRECT_FAR

    NEAR_LABEL      PROC    NEAR
            RET
    NEAR_LABEL      ENDP
    CODE    ENDS
            END

          Командам CALL соответствуют команды  возврата  RET.
    Все возвраты - косвенные переходы, поскольку они извлека-
    ют адрес перехода из вершины стека. Интрасегментный возв-
    рат  извлекает  из  стека одно слово и помещает его в ре-
    гистр IP,  а интерсегментный возврат извлекает два слова,
    помещая слово из меньшего адреса в регистр IP, а слово из
    большего адреса в регистр CS.
          Программы могут  модифицировать  возвраты  как типа
    NEAR,  так и типа FAR, указывая параметр счетчика байтов.
    Команда возврата прибавляет его значение к указателю сте-
    ка после извлечения из него  адреса  (адресов)  возврата.
    Такая  команда  позволяет  программе удалять параметры из
    стека без использования специальных команд POP; тем самым
    подчеркивается, что стек - носитель передаваемых подпрог-
    рамме параметров. Такой стиль работы со стеком мы уже об-
    суждали  во  всех подробностях ранее в разделе "Работа со
    стеком".
          Команды безусловного  перехода JMP идентичны коман-
    дам CALL по их возможностям адресации.  Однако существует
    дополнительная команда перехода, указывающая однобайтовое
    смещение для близкого относительного перехода.  Соответс-
    твующей  ей  команды  CALL не существует,  так как вызовы
    подпрограмм,  расположенных поблизости,  происходят очень
    редко.  Команды переходов используют те же методы генера-
    ции адреса, что и команды вызова.
          Сделаем здесь  замечание  об  оптимизации  кода и о
    том,  как работает ассемблер. По мере того, как ассемблер
    делает первый переход по тексту программы и назначает ад-
    реса командам,  он должен решить,  использовать двух- или
    трехбайтовую разновидность команды JMP.  Если это переход
    назад,  т.е. на место, уже известное ассемблеру, он может
    определить правильное смещение;  тем самым ассемблер зна-
    ет,  находится ли переход в диапазоне короткого смещения.
    Однако, если переход делается вперед, на метку, о которой
    ассемблер еще не знает, он должен предположить, что метка
    находится  далее,  чем 128 байт от текущего места.  Затем
    ассемблер порождает длинную форму команды перехода.  Худ-
    ший  случай  ассемблер обязан выбирать потому,  что потом
    уже не может возвратиться назад и увеличить размер коман-
    ды. Затем ассемблер заместит трехбайтовую команду перехо-
    да двухбайтовой командой JMP и однобайтовой командой NOP,
    если  обнаружит,  что  переход делается ближе 128 байт от
    текущего места.  Так как такой переход  выполняется  нес-
    колько быстрее, время выполнения в этом случае сокращает-
    ся, но объектный код остается больше необходимого.
          Если программисту  заранее  известно,  что  переход
    вперед делается на место, лежащее в диапазоне 128 байт от
    текущего следующей строки:

                         JMP SHORT LABEL

          Аттрибут SHORT  заставляет  ассемблер  сформировать
    короткую форму SHORT команды перехода,  даже если он  еще
    не  встречал  метку.  Если же программист сделал ошибку и
    переход в действительности не может  быть  коротким,  ас-
    семблер  выдает  сообщение об ошибке.
          Пример показывает, как можно устроить таблицу пере-
    ходов с помощью команды косвенного перехода.  Этот пример
    делает выбор среди нескольких  программ,  основываясь  на
    значении  аргумента в регистре AL.  Аналогичная программа
    могла бы вызвать подпрограмму по индексу.  Это - реализа-
    ция на языке ассемблера оператора CASE, который существу-
    ет в некоторых языках высокого уровня.

            PAGE    ,132
    CODE    SEGMENT
            ASSUME  CS:CODE

    ;----------------------------------------
    ; В этом примере демонстрируется программа,
    ; осуществляющая переход в зависимости от
    ; значения регистра AL. В программе имеется
    ; таблица переходов на другие программы, а в
    ; регистре находится номер строки таблицы
    ;----------------------------------------
            SUB     BH, BH                ; BH <- 0
            MOV     BL, AL                ; Индекс в BL
            SHL     BX, 1                 ; смещение
            JMP     CS:[BX + BRANCH_TABLE]  ; переход

    BRANCH_TABLE    LABEL   WORD
            DW      ROUTINE_ONE
            DW      ROUTINE_TWO
            DW      ROUTINE_THREE
    ; ...

    ROUTINE_ONE     LABEL   NEAR
    ROUTINE_TWO     LABEL   NEAR
    ROUTINE_THREE   LABEL   NEAR

    CODE    ENDS
            END
@e
@b
          Условные переходы делятся на две группы:  проверяю-
    щие  флаги,  т.е.  флаги,  которые  проверяют  результаты
    предыдущей арифметической или логической команды,  и  уп-
    равляющие циклом, т.е. флаги, которые управляют итерация-
    ми фрагмента программы. Все условные переходы имеют одно-
    байтовое  смещение.  Если условный переход осуществляется
    на место, находящееся дальше 128 байт, нужно использовать
    другую конструкцию. Например, допустим, что программе на-
    до перейти к метке ZERO,  если установлен флаг нуля;  эта
    метка находится дальше 128 байт от текущего места.  Прог-
    рамма в этом случае выглядит примерно так:

        JNZ CONTINUE
        JMP ZERO
        CONTINUE:

          Здесь используется условный переход с противополож-
    ным  условием.  На метку ZERO управление передает команда
    безусловного перехода,  которая может использовать смеще-
    ние вплоть до 32768 байт, а в условном переходе использу-
    ется метка CONTINUE.
          Если целью является минимизация программ, этого ме-
    тода  нужно  избегать,  так  как  он  превращает  команду
    условного  перехода  в  пятибайтовую  последовательность.
    Иногда реорганизация программы приводит к тому, что место
    перехода попадает в нужный диапазон. Однако не стоит осо-
    бенно стараться минимизировать программу.  В  большинстве
    случаев не имеет особого значения,  насколько у программы
    большой объем, лишь бы он не превышал заданного. Это име-
    ло бы смысл, если бы Вы пытались сделать нечто помещающе-
    еся в модуль ПЗУ постоянного объема,  но  обычно  усилия,
    затрачиваемые  на изменения программы,  не дают ощутимого
    выигрыша.

                      Проверки кода условия

          Первая группа команд условного  перехода  проверяет
    текущее состояние регистра флагов. Затем в зависимости от
    кодов условия команда делает переход (или не делает). Ко-
    манды условного перехода не устанавливают флаги, а только
    проверяют их текущее состояние. Ранее рассмотренные ариф-
    метические  и  логические команды устанавливают флаги.  В
    последующих примерах предположим,  что команда  сравнения
    CMP уже установила флаги.
          На рис.1 показаны команды условного перехода и про-
    веряемые ими флаги. В строках рисунка перечислены команды
    условного перехода,  а в пяти колонках показано состояние
    флагов.  Буква X в любой позиции означает, что команда не
    проверяет флаг.  Цифра 0 означает,  что этот флаг  должен
    быть нулевым, чтобы условие было выполнено и переход про-
    изошел.  Цифра 1 означает, что флаг должен быть единичен,
    чтобы переход произошел. Некоторые элементы таблицы пока-
    зывают выражение,  которое должно быть истинно, чтобы пе-
    реход  произошел.  Так сделано для арифметических перехо-
    дов, и мы обсудим их далее более подробно.
          На рис.1 условные переходы разделены на три группы:
    непосредственно  проверяющие  один  из  флагов;  делающие
    арифметическое сравнение без знака; делающие арифметичес-
    кое сравнение со знаком.

      команда          ф л а г и    комментарии
    усл. перехода   OF  CY  Z  P  S

       JE/JZ        X   X   1  X  X
       JP/JPE       X   X   X  1  X
       JO           1   X   X  X  X
       JS           X   X   X  X  1
       JNE/JNZ      X   X   0  X  X
       JNP/JPO      X   X   X  0  X
       JNO          0   X   X  X  X
       JNS          X   X   X  X  0
                          а).

       JL/JNGE      a   X   X  X  b  a NEQ b
       JLE/JNG      a   X   1  X  b  z OR (a NEQ b)
       JNL/JGE      a   X   X  X  b  a = b
       JNLE/JQ      a   X   0  X  b  (NOT z) AND (a=b)
                          б).

       JB/JNAE/JC   X   1   X  X  X
       JBE/JNA      X   1   1  X  X  CY OR z
       JNB/JAE/JN   X   0   X  X  X
       JNBE/JA      X   0   0  X  X  (NOT CY) AND (NOT z)
                          в).

           Рис.1. Проверка флагов условными переходами

          На рис.1.а показана проверка отдельных флагов.  Ус-
    ловный переход может проверить каждый из этих пяти флагов
    непосредственно на 0 или 1. Проверка флага переноса пока-
    зана на рисунке в группе арифметики без  знака, поскольку
    она имеет еще и арифметический смысл. Заметим, что многие
    команды условного перехода имеют более  одной  мнемоники,
    если даже выполняется та же проверка.  Например, проверку
    флага нуля осуществляет команда JZ  (переход,  если  флаг
    равен нулю). Однако команда JE (переход, если равно) так-
    же порождает ту же команду.  Следующая последовательность
    поясняет смысл этого:

        CMP AX, BX
        JE  LABEL

          Команда CMP вычитает содержимое регистра BX из  со-
    держимого регистра AX,  устанавливая флаги в соответствии
    с результатом.  Так как результат нулевой,  если оба опе-
    ранда  равны,  флаг нуля показывает равенство.  Идентичны
    друг другу команды :

    JNZ  (переход, если  не нуль)
     =  JNE  (переход, если не равно),
    JP   (переход по четности)
     =  JPE  (переход при наличии четности),
    JNP  (переход по нечетности)
     =  JPO  (переход при отсутствии четности).

          Следующую группу   команд   условного  перехода  на
    рис.1,б составляют арифметические  сравнения  со  знаком.
    Существуют четыре условия,  которые могут быть проверены:

      JL   -  меньше
      JLE  -  меньше или равно
      JG   -  больше
      JGE  -  больше или равно

          Другие четыре мнемоники - отрицания этих четырех. В
    случае  арифметики  со знаком ассемблер использует "мень-
    ше" и "больше".  Далее мы увидим,  что для арифметики без
    знака ассемблер использует "выше" и "ниже".
          Арифметические сравнения можно понять, используя их
    вместе с командой CMP , например :

             CMP  CX, WORD_IN_MEMORY
             JNLE LABEL

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

             CMP  CX, WORD_IN_MEMORY
             JNLE LABEL

          - можно прочитать так:  "переход,  если  содержимое
    регистра CX не меньше,  чем, или равен содержимому ячейки
    памяти WORD_IN_MEMORY.  Этот прием можно использовать для
    определения  значения любой команды арифметического пере-
    хода, учитывающей знак или не учитывающей.
          Как показано на рис.1,б арифметические сравнения со
    знаком не проверяют  непосредственно  единственный  флаг.
    Фактически каждая из этих команд проверяет некоторую ком-
    бинацию переполнения,  знак, и, возможно, флаг нуля. Нап-
    ример, в команде JL требуется, чтобы флаги переполнения и
    знака имели разные значения.  Если они  имеют  одинаковое
    значение,  первый операнд не был меньше второго. Рассмот-
    рим эту операцию несколько подробнее, чтобы понять работу
    арифметических сравнений.
          Когда сравниваются два числа  со  знаком,  возможны
    четыре комбинации флагов знака и переполнения. Рассмотрим
    каждую из четырех комбинаций, чтобы определить какое сос-
    тояние операндов привело к данному результату.  Предполо-
    жим,  что в каждом случае флаги установила  команда  CMP,
    вычитавшая два операнда.

                 Знак S = 0, переполнение O = 0.

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

                          S = 1, O = 0

          В этом случае O = 0 означает,  что результат верен,
    а S = 1 1 говорит о том,  что он отрицателен. Чтобы полу-
    чить отрицательный результат,  большее число должно вычи-
    таться из меньшего, и соотношение означает "меньше".

                          S = 0, O = 1

          Здесь O = 1 показывает, что результат неверен, т.е.
    вышел  за пределы возможностей разрядной сетки.  Это зна-
    чит,  что сложение двух положительных чисел дало  отрица-
    тельный результат или наоборот. В данном случае это срав-
    нение этого сравнения идентичен случаю,  когда S = 1, O =
    0, что означает "меньше".

                          S = 1, O = 1

          Снова O = 1 говорит о том,  что знак результата не-
    верен.  Поэтому вычитание должно было  привести  к  очень
    большому положительному числу, и соотношение будет "боль-
    ше".

          В некоторых случаях также  учитывается  флаг  нуля.
    Например,  команда  JLE  выполняется,  если  условие есть
    "меньше" (знак и переполнение разные) или  "равно"  (флаг
    нуля  равен  1).  Эти три флага позволяют микропроцессору
    8088 проверить все возможные комбинации чисел  со знаком.
          Последняя часть  таблицы (рис.1,в) показывает усло-
    вия, проверяемые для арифметики без знака. Как и в случае
    арифметики со знаком, существуют четыре возможные соотно-
    шения между операндами, которые может проверить микропро-
    цессор. Для того чтобы отличить арифметику без знака, ис-
    пользуются  слова  "выше"  и   "ниже".   Вероятно,   этим
    выражается точка зрения создателей набора команд,  заклю-
    чающаяся в том,  что арифметика без знака будет использо-
    ваться в программах для вычисления адресов, а отрицатель-
    ных  адресов  не  бывает.  "Выше"  и  "ниже"   показывают
    расположение значения адресов внутри адресного пространс-
    тва, в то время как "больше" и "меньше" говорит о соотно-
    шении чисел со знаком. Здесь важно, что выполняется имен-
    но та команда,  которая  указана  в  программе  на  языке
    ассемблера,  независимо  от типов сравниваемых операндов.
    Например, программа сравнивает два числа со знаком, а ис-
    пользует команду JA (переход,  если выше). Микропроцессор
    выполняет условный переход в зависимости  от  соотношения
    двух  чисел,  считая  их числами без знака,  т.е.  именно
    программист обязан выбрать правильную условную команду.
          Микропроцессор 8088  при  сравнении  двух чисел без
    знака учитывает только два флага. Флаг переноса показыва-
    ет,  какое из чисел больше.  Сравнение устанавливает флаг
    переноса, если первый операнд ниже второго или сбрасывает
    флаг переноса,  если первый операнд либо выше, либо равен
    второму операнду,  и флаг нуля определяет,  что в  данном
    случае  верно.  Сравнения  без знака можно читать так же,
    как и сравнения со знаком. Например,

          CMP AX, BX
          JA  LABEL

          - переход  на метку LABEL происходит,  если регистр
    AX выше регистра BX. Условный переход выполняется всегда,
    если  объявленное  соотношение  существует между первым и
    вторым операндами предшествовавшей команды сравнения.
@e
@b
          Есть три команды, которые непосредственно управляют
    состоянием флага переноса :

      STC    -  устанавливает,
      CLC    -  сбрасывает,
      CMC    -  дополняет   флаг переноса.

          Этот флаг - единственный,  которому  уделено  такое
    внимание,  и  в первую очередь,  благодаря важности флага
    переноса при операциях с повышенной точностью. Флаг пере-
    носа  критичен  на промежуточных шагах любых многословных
    операций.  Возможность сбрасывать или устанавливать  флаг
    переноса  может  помочь при циклической обработке с повы-
    шенной точностью.  Флаг переноса также важен в  операциях
    сдвига,  где  он становится девятым или семнадцатым битом
    регистра во время выполнения операции.
          Два флага  состояния  микропроцессора меняют специ-
    альные работающие с ними программы. Программа может уста-
    новить  или  сбросить маску прерываний соответственно ко-
    мандами  STI  и  CLI.  Команда   STI   включает   систему
    прерываний микропроцессора 8088, позволяя ему реагировать
    на внешние  прерывания.  Команда  CLI  блокирует  систему
    внешних прерываний.
          Программа может установить или сбросить  флаг  нап-
    равления с помощью команд STD и CLD.  Команда CLD сбрасы-
    вает флаг направления,  приводя к тому, что строковые ко-
    манды  ведут  обработку  при возрастающих адресах памяти.
    Команда STD устанавливает флаг, в результате чего строко-
    вые  команды  уменьшают  адресный указатель после каждого
    выполнения.
