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

         

Адресация через базу и смещение



Адресация через базу и смещение


    Поскольку  вычисление для  операнда  адреса,  состоящего из  базы и
    индекса, встречается довольно часто,  среди способов адресации 8088
    есть  такие, что  позволяют автоматически  производить идексирующее
    сложение.  Вместо  выполнения   всех  вычислений,  программа  может
    определить только величину 2*I и поместить ее в регистр BX. Команда
 
      INC    [OPND + BX]
 
    вычисляет исполнительный адрес через сложение адреса базы  OPND  со
    значением  индекса в BX. Этой командой достигается тот же самый ре-
    зультат что и в предыдущем случае, но меньшим числом команд.  Обра-
    тите внимание, что в этой команде ассемблеру не требуется подсказка
    WORD  PTR,    потому что ассемблер уже знает, что OPND является пере-
    менной типа WORD. Оператор PTR требуется только в тех случаях, ког-
    да ассемблер не может определить тип операнда.
      Любой из  четырех адресных регистров  может быть использован  в
    качестве индекса  при базе. Фиг.  3.2 показывает возможные    способы
    адресации через  базу и индекс. Вы    видите, что ассемблер допускает
    несколько способов  записи операции адресации.  В группе, состоящей


    из      пяти команд  на Фиг.  3.2,  во      всех командах  адрес базы  OPND
    складывается с указанным рядом индексным регистром.
      Надо  отметить,  что  в  команде,  содержащей  базисный  адрес,
    регистр  не обязательно  должен содержать  именно значение индекса.
    Действительно, поскольку BX  называется базисным регистром, кажется
    разумным воспользоваться противоположной  конфигурацией. В качестве
    примера  предположим,  что      программа  использует  множество разных
    векторов с одинаковой длиной  и размером элементов. Такую структуру
    может  иметь,   например,  классный  журнал,   в  котором  векторам
    соответствуют   наборы   оценок   за   каждую  контрольную    работу.
    Программа, вычисляющая оценку пятого ученика в классе по I-й работе
    будет  иметь  уже  известное  значение  индекса  (5) а базу (вектор
    данной  контрольной   работы)  -  вычисляемую   в  ходе  выполнения
    программы.
      Индексный регистр может содержать как адрес базы вектора, так и
    значение  индекса  в  векторе.  Поскольку  константное  значение  в
    команде может  оказаться и базой  и индексом (или  вовсе чем-нибудь
    известным только программисту), то это значение называют смещением.
    Оно соответствует  расстояню или смещению  от адреса в  регистре до
    исполнительного адреса, по которому происходит обращение.




Байт MOD RM



Байт MOD R-M


    Как  же адресная  информация передается  микропроцессору в машинном
    языке?  8088  использует  почти  для  всех  операций адресации байт
    MOD-R/M  (байт  режима  адресации  и  регистра/модификатора - прим.
    перев.).  Фиг.3.4  показывает  формат  этого  байта  команды.  Байт
    MOD-R/M следует  за байтом кода операции  и определяет один операнд
    памяти команды 8088. Этот байт может вместо ячейки памяти указывать
    и регистр.    Такое  единство  структуры  позволяет  реализовать  все
    возможности адресации операндов.
        ЪДДДДДДДВДДДДДДДДДДДВДДДДДДДДДДДї
        і     і         і       і
        АДДДБДДДБДДДБДДДБДДДБДДДБДДДБДДДЩ
          Режим   Заданная    Регистр-
                команда модификатор
 
      Режим       Смещение
     -------------------------------------------------
      00     DISP=0, нет байтов смещения
      01     -128<DISP<127, однобайтовое смещение
      10     -32768<DISP<32767, двухбайтовое смещение
      11     В поле r/m - регистр, а не адрес
 
      Фиг. 3.4 Байт режима адресации и регистра-модификатора
 
      Первые два  бита байта MOD-R/M определяют  выбранный способ ад-
    ресации.  Эти  два  бита  определяют  число  байт смещения, которые
    следуют за    байтом MOD-R/M - ни  одного, один или два.  Последние 3
    бита байта MOD-R/M определяют вид  адреса - одну из восьми комбина-
    ций базисных и индексных регистров. Это поле называется полем R/M -
    полем регистра/модификатора. Это те самые  3 бита из колноки R/M на
    Фиг.3.3, где показаны возможные  комбинации при адресации. Значение
    оставшихся 3-х  бит в середине байта  MOD-R/M зависят от конкретной
    команды.  Для  команды  с  двумя  операндами,  вроде  ADD, это поле
    указывает регистр, являющийся вторым операндом. Для команды с одним
    операндом,    как INC,  эти три  бита обычно      составляют часть самого
    кода операции. 8088  не знает, что имеет дело  с командой INC, пока
    не расшифрует средние три бита байта MOD-R/M.
      Этот же байт используется еще  в паре специальных случаев. Если
    в команде определен  регистр, а не    адрес памяти, то  в поле режима
    помещается код  11B, чтобы сообщить  микропроцессору, что поле  R/M
    содержит  код регистра,  а не  адрес памяти.  Наконец, вы  возможно
    заметили, что в механизме работы  с байтом MOD-R/M не предусмотрена
    прямая  адресация. 8088  рассматривает как  прямую адресацию случай
    типа  [BP +  СМЕЩЕНИЕ] при      нулевом смещении.  В этом  случае поле
    смещения имеет длину два байта,  и в вычислении адреса не участвует
    ни один регистр. Из-за этого особого случая доступ к ячейке памяти,
    на      которую  указывает  регистр   BP,  в  машинном  коде  требуется
    однобайтовое поле смещения с нулевым значением. Использование в той
    же      ситуации регистров  BX, SI  и DI  не требует  байта смещения. В
    следующем пункте будет показано  еще одно различие между адресацией
    через регистры BP и BX.





База + индекс + смещение



База + индекс + смещение


    Программа  может  также  комбинировать  вычисляемый  адрес    базы  с
    вычисляемым  индексом.  Как  показано  на  Фиг.3.2, программа может
    использовать режим адресации с  двумя разными адресными регистрами.
    Для формирования исполнительного адреса  в команде могут сочетаться
    любой из  регистров базы (BX и  BP) с любым из  индексных регистров
    (SI  и  DI).  В  программе      может      быть  также  указано  смещение,
    добавляемое  к  сумме  значений  этих  двух  регистров. Этот способ
    адресации  обладает  максимальной     гибкостью,  так  как  позволяет
    вычислять во  время выполнения программы и  адрес базы, и индексное
    значение.  Такая возможность  не  всегда  требуется, но  доступна в
    любой момент.
      Пример с классным журналом демонстрирует случай, когда програм-
    ма может вычислять и адрес базы,  и индекс вектора. Для того, чтобы
    определить отметку  I-го ученика за  J-ю контрольную, потребовалось
    бы установить адрес базы на J-й  вектор и индексировать его по I-му
    элементу.
      На   Рисунок 3.3   приведена   сводка   восьми  различных  способов
    адресации,    возможных  в  микропроцессоре  8088.  В  команде  могут
    использоваться любые из четырех  адресных регистров и смещение либо
    комбинация    базисного регистра  и индексного  вместе со  смещением.
    Смысл колонки, обозначенной R/M, будет объяснен позже.
 
      R/M       Адрес операнда
      -----------------------------
      000   [BX + SI + СМЕЩЕНИЕ]
      001   [BX + DI + СМЕЩЕНИЕ]
      010   [BP + SI + СМЕЩЕНИЕ]
      011   [BP + DI + СМЕЩЕНИЕ]
      100   [SI + СМЕЩЕНИЕ]
      101   [DI + СМЕЩЕНИЕ]
      110   [BP + СМЕЩЕНИЕ]
      111   [BX + СМЕЩЕНИЕ]
      ----------------------------- Фиг. 3.3 Способы адресации 8088
 
      В наборе команд 8088  поле смещения для адресации оптимизирова-
    но таким образом, чтобы минимизировать кличество треуемых байт. Ко-
    манда может не содержать поле  смещения, когда смещение равно нулю.
    Если смещение  находится в диапазоне  от -127 до  127, то для  него
    достаточно    одного байта.  Когда же  для его  обозначения требуется
    полное 16-битовое поле адреса, то  поле смещения будет занимать два
    байта. Таким  образом, поле смещения  может по необходимости  иметь
    длину 0, 1    или 2 байта. Когда оно имеет  длину один байт, двоичное
    число перед форимроваием адереса получает распостранение знака. Это
    означает, что процессор перед выполнением сложения помещает старший
    бит смещения  в старшие 8  бит 16-битового значения.  Это позволяет
    представлять  отрицательные смещения  в одном  байте. Самое  лучшее
    здесь  то, что  ассемблер сам  определяет нужную  длину и  выбирает
    правильную и наиболее короткую команду для выполнения этой работы.
      Но  не      смотря      даже  на  все  эти возможности адресации, набор
    команд  8088 допускает  только по  одному операнду      памяти в  одной
    команде.  Двухоперандная  команда  ADD  позволяет  складывать  либо
    регистр с ячейкой памяти, либо два регистра. В одной команде нельзя
    сложить  две ячейки  памяти. Это  и означает,  что команда содержит
    только один адрес памяти.




Дополнительный флаг переноса



Дополнительный флаг переноса


    Возможно,     вам    никогда    не   придется      пользоваться    флагом
    дополнительного  переноса (AUX),  по крайней  мере непосредственно.
    Изучив команды условных переходов микропроцессора 8088, вы увидите,
    что  прямое  тестирование  этого  флага  невозможно. Микропроцессор
    имеет флаг дополнительного переноса  AUX для очень конкретной цели:
    он      позволяет  микропроцессору  выполнять  десятичные  вычисления в
    двоичной кодировке (Binary-coded-decimal arithmetic - BCD - арифметика).
       BCD - арифметика отличается от  той, которую мы обсудили в гл.2.
    Она  основана на  десятичной системе  счисления. При  осуществлении
    десятичной арифметики  в двоичной кодировке  любая дасятичная цифра
    представляется четырьмя битами  (полубайтом). Каждый полубайт может
    представлять  значения  от      0  до  9;  значения  от  0AH  до 0FH не
    используются.  Это  означает,  что    один  байт  может  представлять
    десятичные числа от 0 до 99.
      На  первый  взгляд  такой  способ  хранения числовой информации
    кажется  расточительным,  двоичная    кодировка  десятичныч  чисел не
    использует 6 из 16 возможных состояний каждого полубайта. Однако во
    многих   случаях  применения   микропроцессора  этот   способ  дает
    непосредственное    представление     вводимых    оператором  чисел.
    Большинство людей более подготовлено к работе с десятичными, а не с
    двоичными  или шестнадцатеричными  числами. Как  только потребности
    ввода-вывода  могут  перевесить  аспекты  хранения      и  вычислений в
    приложениях, так удобнее становится  выстраивать информацию в виде,
    легко  преобразуемом  к  формату  ввода-вывода.  Двоичная кодировка
    десятичных    чисел дает  такую возможность.      BCD -  арифметика также
    решает   возникающую   в   некоторых   двоичных  системах  проблему
    представления  чисел. При  использовании чисел  с плавающей  точкой
    иногда возникает  проблема округления, потому  что двоичная система
    счисления     не  полностью     соответствует  десятичной   системе.  В
    некоторых случаях последняя цифра  в результате простого вычисления
    может  оказаться неверной.      Иногда это  называют проблемой      "потери
    пенни",  так   как  эти  случаи   наиболее  заметны  в   финансовых
    приложениях. BCD - представление  чисел дает альтернативу для таких
    вычислений.
      Набор команд  микропроцессора 8088 не  имеет специальных команд
    сложения и вычитания для BCD-арифметики. Здесь используется обычное
    сложение  и  вычитание,  применяемые  как  и  при  обычном двоичном
    представлении.  Результат сложения  двух    BCD-чисел   на    обычном
    математическом процессоре может  оказаться неправельным BCD-числом;
    Для  устранения этого  микропроцессор 8088  имеет несколько команд,
    которые  преобразуют  результат  к    правильной  двоичной  кодировке
    десятичного числа. Для  корректного проведения этого преобразования
    процессор  должен знать,  был ли  перенос из  младшего полубайта  в
    старший во    время сложения. Пример на  Фиг. 3.13 показывает, почему
 
               38
            +  29
              ----
               61       Фиг. 3.13 Десятичное сложение
 
    это  необходимо. Десятичная  сумма 38  + 29  равна 67.  Но двоичная
    сумма  38H    +  29H      равна  61H.  Если  числа  38  и 29 представляют
    BCD-значения, то после операции сложения программа должна выполнить
    коррекцию.    Команда  десятичной   коррекции  для     сложения  (DAA)
    преобразует число в форму BCD.  В нашем случае число представлено в
    десятичной форме, т.е. оба полубайта  находятся в диапазоне от 0 до
    9, однако результат неверен. В данном случае сложение устанавливает
    флаг дополнительного  переноса, который показаывает,  что произошел
    перенос из младшей  цифры (8 + 9). Этот  флаг сообщает команде DAA,
    чтобы она прибавила к результату 6, давая правильный результат 67.
      Микропроцессор    также использует  флаг дополнительного переноса
    при коррекции  десятичной арифметики вслед за  вычитанием с помощью
    команды  десятичной коррекции  для вычитания  DAS. Существуют также
    две  другие команды,  которые используют  флаг AUX      для определения
    правильности  действий.  Эти   команды,  символьная  коррекция  для
    вычитания AAS и символьная коррекция для сложения AAA, выполняют ту
    же      BCD-коррекцию, что  и команды  DAA  и  DAS. Команды  AAA и  AAS
    используются в программах для  работы с таким представлением чисел,
    при  котором  каждая  десятичная  цифра  занимает  один  байт.  Это
    представление,  еще более  расточающее память,  чем BCD,  допускает
    очень удобную перекодировку из  кода ASCII в числовое представление
    и обратно. Числа от  0 до 9 представляются в  коде ASCII значениями
    от      30H  до  39H,  и  преобразование  в  этот  код и обратно просто
    означает   сложение   или вычитание   30H.   В   следующей  главе
    рассматривается   использование  команд   десятичной  и  сомвольной
    коррекции.




Физическая адресация



Физическая адресация


    Все,  что до сих пор говорилось об адресации, относится к генерации
    так называемого смещения (offset) адреса. Смещение имеет 16-битовое
    значение. 8088 сегментирует память таким образом, что можно адресо-
    ваться к памяти большей чем 64K. В этом пункте бует показан  способ
    сегментауии 8088.
      Поскольку размер слова в микропроцессоре 8088 равен 16 бит, для
    него естественно  генерировать адреса в  16 бит длиной.  Это делает
    доступными для  прямой адрессации 2**16  элементов или 65  535 байт
    памяти.   Однако   для   некоторых    программ   64K   ячеек  памяти
    недостаточно.   Поэтому  фирма   INTEL  сконструировала   8088  для
    адресации 2**20 байт или одного мегабайта памяти.
      Для  получения 20-битовой адресации требуется еще четыре бита к
    имеющимся 16-ти. Добавочные 4 бита адресной информации  берутся  из
    сегментных регистров. Сегментные регистры сами имеют размер 16 бит.
    8088  комбинирует  16-битовый  адрес  смещения и 16-битовый регистр
    сегмета как показано на Фиг.3.5. Процессор дополняет сегментный ре-
    гистр 4-мя нулевыми битами, что составляет вместе полное 20-битовое
    значение.  К расширенному значению сегмента процессор добавляет ад-
    рес сммещения, определяемый через вычисление адреса. 20-битовый ре-
    зультат является указателем на исполнительный адрес.
 
                 ЪДДДДДДДДДї
                 і Сегмент і  0000
                 АДДДДДДДДДЩ
                    ЪДДДДДДДДДДДї
                  +   і Смещение  і
                    АДДДДДДДДДДДЩ
                   ----------------
                  ЪДДДДДДДДДДДДДДДДї
                  і20-битовый адресі
                  АДДДДДДДДДДДДДДДДЩ
 
            Фиг.3.5 Вычисление адреса с сегментом и смещением
 
      Каждая обращающаяся к памяти  команда может сформировать только
    16-битовый адрес  операнда. В действительности  процессор применяет
    этот  адрес внутри  определенного сегмента.  Фиг. 3.6 иллюстриирует
    такой способ применения сегментации.
 
            ЕДДДДДДДДДДДДДДДДДДґ ДДДДДВДДДДСегментный регистр
             іі            і    і
             іі            і  смещение
             іі            і    і
     Сегмент   іГДДДДДДДДДДДДДДДДДДЕ ДДДДДБДДДДАдресуемая область
       64К  ГДДДДДДДДДДДДДДДДДДґ
             іі            і
             іі            і
             іі            і
            ЕДДДДДДДДДДДДДДДДДДґ
            і              і
           Фиг.3.6 Сегментация.
 
      Начальный адрес  сегмента всегда имеет    нули в младших    четырех
    битах.  Адрес с  этим  свойством  имеет каждая  шестнадцатая ячейка
    памяти. Конструируя расположение данных  в своей программе помните,
    что сегмент всегда должен  приходиться на такую 16-битовую границу.
    Эти границы называются также границами параграфов.




Флаг четности



Флаг четности


    Флаг четности (PF) показывает,  является ли число едениц результата
    последеней операции четным. Четность - это способ контроля значений
    данных. Бит  четности - это  дополнительный бит, который  проверяет
    значения других бит. Программа может использовать флаг четности для
    определения,  в  какое  значение  следует  установить бит четности.
    Четность  используется в  оперативной  памяти  IBM PC  для контроля
    сохраненных  в  ней  данных.  Такой  контроль  четности выполняется
    непосредственно  аппаратными средствами  и не  влияет на  бит флага
    четности.
      Флаг  четности устанавливается      в "1",  если результат операции
    имеет четное  число едениц и переустанавливается  в "0", если число
    едениц  результата нечетно.  В обычных  арифметических и логических
    операциях знак четности использкется мало.




Флаг направления



Флаг направления


    Последним флагом в регистре флагов является флаг направления DF.
    Набор команд микропроцессора 8088 содержит несколько команд
    обработки строк, которые работают с большими блоками данных. Эти
    команды обработывают блоки данных побайтно или по одному слову
    памяти за раз. Индексные регистры указывают на блоки данных. После
    обработки байта или слова процессор изменяет индексный регистр так,
    чтобы он указывал на следующий элемент блока.
 
      Строковые операции используют флаг направления для определения
    направления продвижения по блоку данных. Если флаг направления
    сброшен в 0, команды обработки строк увеличивают значение
    индексного регистра, а если флаг направления установлен в 1, то они
    уменьшают это значение. Флаг направления позволяет одному набору
    строковых команд обслуживать оба направления в зависимости от
    установки флага. В некоторых случаях желательно пересылать строку с
    увеличением адресов, а в других лучше всего использовать уменьшение
    адреса.
 
      В качестве примера предположим, что в программе используется
    команда пересылки строк для пересылки блока данных на новое место.
    Если программа пересылает блок, с большего адреса памяти на
    меньший, она сбрасывает флаг направления, чтобы увеличивать
    значения индексных регистров после каждой пересылки; если же
    пересылка производится на больший адрес памяти, флаг направления
    устанавливается в 1, показывая уменьшение индексных регистров. В
    случае большинства пересылок не имеет значения, как именно
    установлен этот флаг. Но если конечное положение блока перекрывает
    его начальное положение, а флаг направления уствновлен неверно, то
    информация в блоке будет во время пересылки испорчена.
 
      Рисунок 3.16 иллюстрирует пример пересылки блоков. Исходный
    блок данных имеет длину 200H байт и расположен от 300H до 4FFH.
    Нужно переслать его на новое место, расположив от 400H до 5FFH;
    исходное и результирующее поля перекрываются.

                       300 ГДДДДДДДДДДДЕДДД Указатель    300 ГДДДДДДДДДДДґ
                         і         і        источника    і         і
                         і         і          SI               і         і
                         і         і                     і         і
              Источник   400 ГДДДДДДДДДДДЕДДД Указатель    400 ГДДДДДДДДДДДґ
                         і         і        назначения         і         і
                         і         і          DI               і         і
                         і         і                     і         і
     Назначение        500 ГДДДДДДДДДДДґ               500 ГДДДДДДДДДДДґ<-- Указатель
                         і         і                     і         і    источника
                         і         і                     і         і
                         і         і                     і         і
                       600 ГДДДДДДДДДДДґ               600 ГДДДДДДДДДДДґ<-- Указатель
 
            Фиг. 3.16 Флаг направления
 
      В примере на Фиг.3.16(а) указатели источника и результата
    установлены на начала соответствующих блоков: указатель источника
    на 300H, а указатель результата на 400H. Флаг направления в примере
    сброшен, так, чтобы указатели увеличивались после каждой пересылки.
    Как показано на рисунке, после пересылки с помощью строковой
    операции 100H байт, указатель источника переместится на блок
    результата, а эта область блока уже заполнена данными после
    пересылки. Пересылка последних 100H байт будет неправильной, так
    как потеряны исходные данные блока.
 
      В части (b) примера указатели и источника, и результата
    установлены на концы блоков. Флаг направления установлен так, что
    содержимое указателей уменьшается после пересылки. При таком
    способе данные пересылаются верно.
 
      Программы ввода-вывода для IBM PC дают характерный пример
    использования флага направления для перемещения изображения на
    экране дисплея. Программа ввода-вывода использует команды пересылки
    строк микропроцессора 8088 для пересылки данных внутри буфера
    дисплея. Когда программа передвигает изображение на экране вверх,
    команды пересылают данные в меньшие адреса памяти. Когда программа
    опускает символы на экране вниз, команды пересылают данные в
    большие адреса памяти. В каждом случае программа устанавливает или
    сбрасывает флаг направления в соответствии с направлением
    пересылаемых данных.




Флаг нуля



Флаг нуля.


    Флаг  нуля    (ZF)  показывает,   что  результат  последней  операции
    равнялся  нулю. Этот  флаг используется  в программах  для проверки
    двух  чисел  на  равенство.  Допустим,  в  программе вычитаются два
    числа.  Результат  будет  нулевым,    если  значения    идентичны  и не
    нулевым, если они различны.




Флаг переноса



Флаг переноса


    Флаг переноса (CF) служит  для поддержания процессором многоразряд-
    ной арифметики. Обычно при выполнении арифметических операций вроде
    сложения  или  вычитания  8088  может   работать  с  не  более  чем
    16-битовыми   числами.  Однако   в    некоторых   случаях  приходится
    манипулировать с числами превышающими 2**16. Например, для сложения
    двух  32-битовых чисел  программе придется  сложить сначала младшие
    части  чисел, а  затем -   старшие. На  Фиг 3.11  показано сложение
    32-битовых чисел 22223333H и 44445555H.
      В этом примере складываются  сначала младшие 16-битовые згначе-
    ния с  получением результата 8888H. Затем  складываются старшие 16-
 
          второе сложение         первое сложение
          ---------------------------------------
             2222              3333
             4444              5555
             ----              ----
             6666              8888     Фиг. 3.11
          --------------------------------------- 32-битовое сложение
 
    битовые  значения с  результатом 6666H.  32-битовый результат равен
    66668888H.    Для  получения    32-битового  результата  требуется  два
    16-битовых    сложения.  Для    48-битового  числа  потребуется уже три
    16-битовых сложения и т.д. Для выполнения сложения программа должна
    расчленять каждое большое число на 16-бтовые куски.
      Однако, приведенный пример  достаточно прост. Результат первого
    16-битового сложения не влиял на второе. В общем же случае сложения
    возможен  перенос  из  одной  позиции  в  другую.  Когда  процессор
    выполняет слоожение двух 16-битовых  чисел, он автоматически выпол-
    няет переносы. Когда же  программа складывает два 32-битовых числа,
    как в нашем  примере, то ей приходится запоминать  перенос в первом
    сложении  и   использовать      его  при   сложении  вторых  16-битовых
    значений.  На  Фиг.  3.12 показано  сложение  чисел  22224444H  и
    3333EEEEH. В этом примере перенос от первого сложения отражается на
    втором сложении.
 
      втоорое сложение       первое сложение
      --------------------------------------------
          2222                    4444
          3333                    EEEE
             1 (перенос от первого)
          ----                   -----
          5556                   13332
      --------------------------------------------
         Фиг. 3.12 32-битовое сложение с переносом
 
      Первое 16-битовое сложение 4444H и EEEEH дает результат 13332H.
    Поскольку результат имеет длину 17 бит,  он не может быть помещен в
    16-битовый    регистр. Флаг  переноса регистра  состояний примет этот
    дополнительный бит арифметической информации. При втором 16-битовом
    сложении складываются не только числа  2222H и 3333H, но и значение
    флага переноса. Существует две  формы команды сложения: команда ADD
    складывает    два  16-битовых  числа,  давая      17-битовый результат, а
    команда сложения с переносом ADC  складывает два 16-битовых числа и
    значение  флага  переноса,      давая  также  17-битовый  результат.  В
    примере  на Рисунок 3.12  для первой  операции сложения  использовалась
    команда ADD, а для второй операции сложения команда ADC.
      Оба приведенных примера используют флаг переноса для выполнения
    арифметики    повышенной точности.  В первом      примере после  сложения
    3333H  и  5555H  получился      нулевой  перенос;  когда  команда  ADC
    прибавляет    значение переноса  к числам  2222H и  4444H, получается
    правильный    результат 6666H.  Во втором  примере флаг  переноса был
    установлен,так как был перенос из младшей части суммы в старшую.
      В случае арифметики еще  большей точности программа может снова
    и снова  использовать  в  процессе    сложения  флаг переноса. Каждое
    16-битовое    сложение устанавливает  флаг переноса  в соответствии с
    его результатом, а программа может сложить следующие по старшинству
    части чисел с полученным значением    флага переноса. В каждом случае
    флаг  переноса содержит  семнадцатый бит  предыдущего результата, и
    программа должна использовать это  значение при сложении следующих,
    более старших, частей чисел.
      Флаг переноса служит и для  другой важной цели. Когда программа
    выполняет вычитание, существует возможность  заема из одной позиции
    в другую.  Флаг  переноса  показывает  при  вычитании необходимость
    заема из одной части числа в другую.
      Вычитать целые    числа, в несколько слов  длиной программа может
    таким же путем, как и  складывать. Сначала вычитаются младшие части
    чисел, с получением 16-битового результата. Команда вычитания (SUB)
    устанавливает  флаг  переноса,  отражая  заем. Следующее 16-битовое
    вычитание программа выполняет с  заемом. Команда вычитания с заемом
    (SBB)  наряду  с  обычным  вычитанием  вычитает  из результата флаг
    переноса. Как и при сложении программа может осуществлять вычитание
    целых чисел произвольной длины,  используя флаг переноса в качестве
    значения заема.
      Микропроцессор 8088  трактует флаг переноса  как истинный заем,
    то есть если в результате вычитания появляется заем, микропроцессор
    устанавливает флаг переноса равным    1. Он показывает, что программа
    должна вычесть 1 из результата вычитания старших частей чисел. Если
    заема  нет,  процессор  сбрасывает    флаг  переноса  на  ноль.  Это
    означает, что программе не нужно вычитать 1 из старшей части числа.
      Микропроцессор устанавливает флаг  переноса как индикатор заема
    при расширенном вычитании. Наряду  с расширением точности программа
    может сипользовать  флаг переноса для  определения соотношения двух
    чисел.  Если флаг  переноса установлен,  вычитаемое значение больше
    уменьшаемого; если флаг переноса не установлен, вычитаемое значение
    меньше  или равно  уменьшаемому.  Это  означает, что  флаг переноса
    становится первичным  индикатором при определении  соотношения двух
    чисел: после того, как программа  вычитает два числа, флаг переноса
    указывает,    какое из  них  больше.  Таким способом    программа может
    проверять  целые числа  без  знака,  включая такие      приложения, как
    сортировка строк символов. В случае чисел со знаком для определения
    соотношения  чисел  программе  нужна  дополнительная  информация. В
    следующей  главе  в  разделе  "Условные  переходы"  обсуждаются все
    способы тестирования чисел.




Флаг переполнения



Флаг переполнения


    Флаг переполнения  OF - единственный флаг  в старшем байте регистра
    флагов,    который    устанавливается    обычными арифметическими
    операциями.  Остальные флаги  старшего байта  находятся под  прямым
    управлением   программиста.   Флаг      переполнения    -   еще   один
    арифметический флаг,  как флаг нуля  и переноса. Флаг  переполнения
    необходим для арифметики в дополнительном  коде в такой же степени,
    как флаг переноса для арифметики повышенной точности.
      В  арифметике  чисел,  представленных  в  дополнительном  коде,
    старший  бит  используется      для   хранения    знака  числа.  Сумматор
    микропроцессора  работает как  со знакопеременными      числами, так  и
    беззнаковыми.   Обычно  сложение   чисел  со   знаком  дает  верный
    результат.    Однако накоторые  из чисел,  представленных в  дополни-
    тельном коде, при сложении дают  неверный результат. Пример на Фиг.
    3.14  -  сложение  двух  8-битовых    чисел,      представленных    в  коде
    двоичного дополнения, - иллюстрирует этот  случай. Если 72H и 53H -
 
      Шестнадцатеричное Десятичный эквивалент
     ------------------------------------------------
           72H                 114
         + 53H               +      83
         ------              ------
          0C5H                 197
     ------------------------------------------------
 
                              Фиг. 3.14 8-битовое сложение
                                    с переполнением
 
    числа без знака, то результат их сложения верен. Если же это числа,
    представленные  в  дополнительном  коде  со  знаком,  то  результат
    сложения 0C5H  неверен, в коде  двоичного дополнения он  равен -59.
    сложение  положительных чисел  никогда не  дает в  результате отри-
    цательное. Результат сложения  оказался непредставиммым в диапазоне
    значений  8-битовых чисел  в двоичном  коде (от  127 до -128). Этот
    эффект  принято  называть  переполнением,  так  как  сумма вышла за
    пределы диапазона чисел, представимых в дополнительном коде.
      Важно  заметить, что  переполнение  и  перенос -  два различных
    флага и имеют  разное значение. На Фиг. 3.14  нет переноса, так как
    сложение без знака дает  правильный результат, а есть переполнение:
    что сложение  со знаком дает неверный  результат. Возможен и случай
    одновременно переноса  и переполнения, как  показано на Фиг.  3.15.
 
       Шестнадцатеричное   Двоичное дополнение     Беззнаковое
     ------------------------------------------------------------
            8EH           -114                  142
             0ADH         - 83                  173
            -----       -----                 ----
            1 3BH         -197                  315
     ------------------------------------------------------------
            Фиг. 3.15 8-битовое сложение с переносом и перепонением
 
    Здесь показан  пример сложения двух  отрицательных чисел. Результат
    -197 выходит  за пределы диапазона    представимости в дополнительном
    коде. Это показано тем, что 8-битовый результат 3BH - положительное
    число.  Кроме того  в этом      примере устанавливается  флаг переноса,
    означающий,   что   сложение   без    знака      дало число,      большее
    максимального представимого. В  случае 8-битовых чисел максимальное
    число равно 255.
      Вообще говоря, операция сложения  в процессоре
    выполняется одинаково над числами и со знаком, и без знака, а также
    с десятичными  числами.  Флаги переноса, дополнительного переноса и
    переполнения содержат  информацию о выполненной  операции, позволяя
    программе  определить  верный   результат  в  используемой    системе
    счисления.      Флаг      переполнения     показывает,   что    результат
    арифметической  операции   выходит    за  пределы   диапазона  чисел,
    представленных  в дополнительном  виде. Переполнение  отличается от
    переноса,  который показывает,  что произошел  перенос из  старшего
    бита результата.




Флаг прерываний



Флаг прерываний


    Флаг прерываний IF управляет внешними прерываниями. Во время
    выполнения тех фрагментов программы пользователя, где внешние
    прерывания разрешать нежелательно, программа может сбросить флаг
    прерываний. Пока флаг прерываний сброшен в 0, никакие внешние
    прерывания не смогут возникнуть. Когда программа устанавливает флаг
    прерываний равным 1, внешние устройства могут порождать прерывания.
    Управляет флагом прерываний программа пользователя.
 
      IBM PC использует несколько методов обслуживания прерываний.
    Флаг прерываний регистра состояния блокирует все внешние
    прерывания, за исключением прерываний, вызванных ошибками памяти.
    Для тех случаев, когда программе надо заблокировать только
    некоторые из прерываний, существует отдельный регистр масок
    прерываний. Этот регистр может запретить или разрешить отдельные
    внешние прерывания. В гл.8, описывающей аппаратуру IBM PC, будет
    рассмотрено использование этого регистра.




Флаг захвата



Флаг захвата


    Флаг захвата (специального прерывания) TF помогает при отладке
    программ. Этот флаг устанавливается не в результате работы
    микропроцессора, а - программой, с помощью специальной команды.
    Этот флаг называется также флагом трассировки или шага.
 
      Когда этот флаг установлен, после выполнения каждой команды
    возникает прерывание. Эффект при этом такой же, как если бы после
    каждой команды некоторое внешнее устройство запрашивало прерывание.
    Прерывание по трассировке передает управление в ячейку,
    определенную вектором прерывания 4. Во время процедуры прерывания
    микропроцессор сбрасывает флаг специального прерывания. Это
    позволяет программе обработки прерывания по трассировке избежать
    прерывания после каждой команды. Когда обработчик прерывания по
    трассировке возвращает управление программе пользователя, он
    восстанавливает начальное состояние регистра флагов, в котором флаг
    трассировки установлен. Микропроцессор выполняет следующую команду
    пользователя, и снова возникает специальное прерывание. Обработчик
    прерываний по трассировке получает управление после каждой команды
    до тех пор, пока программа пользователя не сбросит флаг захвата.
 
      Отладчик DOS использует флаг трассировки. Одной из функций
    отладчика является пошаговое выполнение, при котором перед каждым
    возвращением управления к отладчику выполняется одна команда
    программы пользователя. Это прерывание инициируется флагом захвата.
    Полное описание процедуры прерывания дано в разделе "Векторы
    прерываний".




Флаг знака



Флаг знака


    Флаг знака (SF) показывает,  является результат последней арифмети-
    ческой  операции  положиельным  или  отрицательным.  Установка бита
    знака отражает  значение старшего бита  последнего результата. Если
    последний  результат отрицателен,  то бит  знака устанавливается  в
    еденицу, а если положительный или нулевой, то - в ноль.




специальные ячейки памяти, называемые регистрами.



Модель программирования 8088

    Для  того,    чтобы понять 8088 и научиться программировать для него,
    мы начнем  с его внутреннего устройства.  Внутри процессора имеются
    специальные ячейки памяти, называемые регистрами. В регистрах можно
           ЪДДДДДДДДДДДДДВДДДДДДДДДДДДДї
      AX     і       AH    і  AL   і
           і               і        і
      BX     і       BH    і  BL   і
           і               і        і    Регистры общего
      CX     і       CH    і  CL   і       назанчения
           і               і        і
      DX     і       DH    і  DL   і
           АДДДДДДДДДДДДДБДДДДДДДДДДДДДЩ
 
           ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДї
           і            SI         і
           ГДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
           і            DI         і    Адресные регистры
           ГДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
           і            BP         і
           АДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ
 
           ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДї
           і            SP         і
           ГДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
           і            IP         і    Регистры управления
           ГДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
           і            FLAGS       і
           АДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ
 
           ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДї
           і            CS         і
           ГДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
           і            DS         і
           ГДДДДДДДДДДДДДДДДДДДДДДДДДДДґ  Сегментные регистры
           і            ES         і
           ГДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
           і            SS         і
           АДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ    Фиг. 3.1 Регистры 8088
      сохранять данные-операнды  или адреса памяти.  Поскольку регистры
    расположены внутри самого процессора, он имеет очень быстрый доступ
    к находящимся в них  данным, намного более быстрый, чем  к данным в
    памяти.  Если в  программе требуется  быстрыый доступ  к какой-либо
    переменной, то хранение ее значения в регистре ускоряет выполнение.
      Набор  регистров 8088 состоит из нескольких групп. Все регистры
    8088 показаны по группам на Фиг 3.1.


Оператор Assume



Оператор Assume


    После того    как сегменты в    программе определены, ассемблер  должен
    узнать,  как   будут  установлены  сегментные   регистры  во  время
    выполнения программы. В примере на    Фиг. 3.9 всего три сегмента, но
    болшая  программа  может  иметь  намного  больше.  Располагая всего
    четырьмя  сегментными регистрами,  большая программа  может адресо-
    ваться одновременно только к части доступных сегмментов. Ассемблеру
    необходимо сообщить, к каким  именно сегментам происходит адресация
    во      время  выполнения.  Это  делается  с  помощью  оператора ASSUME
    который  описывает для  ассемблера установки  сегментных регистров.
    Программист  должен   связать  каждый  сегментный регистр  с  тем
    сегментом, на который тот в данный момент указывает.
      Фиг. 3.9 иллюстрирует такие сегментные операции. В этом примере
    имеется три  сегмента: DATA, BUFFER  и CODE. Имена      для них выбраны
    произвольно. Их выбирает программист, а для ассемблера они не имеют
    значения.  Например,  вы  можете  назвать  сегмент      именем      CODE, а
    использовать его только для данных и наооборот. Лучше всего, конеч-
    но, называть  сегменты так, чтобы  их имена имели  какой-то смысл в
    данной программе. В нашем примере  сегменты DATA и BUFFER оба имеют
    внутри  ячейку данных.  Вряд ли  реальная программа  будет задавать
    сегмент  лишь с  одной ячейкой   памяти, но  сейчас это  служит для
    примера.  Если программа  обращается  к  данным во      многих участках
    адресуемого в 8088 пространства,  то ей требуется много определений
    сегментов. Например, программа  управления устройствами доступа IBM
    PC      может обращаться  к  памяти   в  системной  области   данных,
    устанавливать векторы прерываний в    начале памяти и выполняться как
    программа в  любом другом месте.  Каждая из этих  областей является
    сегментом и должна быть определена в программе.
      Утверждение ASSUME на Фиг. 3.9 предписывает ассемблеру работать
    с учетом следующей  установки сегментных регистров:  регистр CS со-
    держит начальный адрес сегмента CODE, регистр DS указывает на DATA,
    а регистр     ES  определяет    сегмент  BUFFER.   Утверждение  ASSUME
    (полагать,    считать -  прим. перев.)  означает именно  то, что  оно
    предписывает  ассемблеру.  Ассемблер  обрабатывает      исходный  текст
    программы  предполагая,  что  сегментные  регистры      установлены как
    указано в этом утверждении. Установка сегментных регистров, сделан-
    ная в  этом утверждении, остается  при ассемблировании в  силе пока
    другое такое же утверждение не определит новые установки. Ассемблер
   обрабатывает эти  утверждения последовательно, даже  если программа
    ветвится  и закручивается  в циклы.  Утверждение ASSUME  остается в
    силе,  пока ассемблер  не встретит    при последовательном  просмотре
    программы следующее.  Заметим, что в утверждении  ASSUME не обязано
    определять    все сегментные    регистры. В  нашем примере  не объявлен
    регистр SS.  На практике содержимое сегментного  ргистра может быть
    временами  и неизвестно  в      программе.  В этих  случаях утверждение
    ASSUME должно указывать сегмент NOTHING. Например, утверждение
 
      ASSUME      ES:NOTHING
 
    сообщает ассемблеру, что программа    не знает, куда указывает допол-
    нительный сегментный регистр. Поскольку значение регистра неизвест-
    но, ассемблер не должен использовать его в адресных вычислениях.
      Важно отметить, что утверждение ASSUME не генерирует команд ма-
    шинного  языка. Это  директива ассемблеру  полагать, что сегментные
    регистры установлены в соответствии  с указанной в этом утверждении
    информацией.  Добиться  правильное    установки  сегментов  -  забота
    программиста. Аналогично, ассемблер не может проверить, что утверж-
    дение  ASSUME  при  выполнении  будет  соответствовать  содержимому
    сегментных    регистров. Из-за  того,  что  программа может  прийти к
    любому   конкретному  ASSUME   множеством  разных путей,      за  его
    корректность отвечает программист.    В нашем примере предполагается,
    что сегментные регистры устанавливаются  до выполнения данного кус-
    ка программы. Если они установленыы неверно, то программа будет вы-
    полняться неправильно даже если ассемблирование прошло успешно.
      Первая команда увеличивает значение VAR1, находящейся в сегмен-
    те данных. Ассемблер полагает, что регистр DS указывает на сегмент
    DATA  в соответствии  с утверждением  ASSUME. Поскольку  регистр DS
    предполагается при  использовании данных по умолчанию,  то для этой
    команды ассемблер не  генерирует сегментный префикс. Сформированная
    этой инструкцией 4-байтовая машинная команда не содержит сегментно-
    го      префикса.
      Вторая команда определяет переменную  VAR2, которая находится в
    сегменте  названном  BUFFER.  Программа  сообщила  ассемблеру,  что
    дополнительный сегментный регистр указывает  на сегмент BUFFER. Для
    увеличения VAR2 ассемблер генерирует четырехбайтовую команду машин-
    ного языка,  но ей предшествует  команда с однобайтовым  префиксом,
    которая  отменяет   использование  регистра  DS   в  этой  команде.
    Префиксный    байт 26H  говорит процессору  использовать при создании
    20-битового адреса памяти регистр ES.  В колонке объектных кодов на
    листинге ассемблер отмечает префиксную команду двоеточием.
      Третья      команда  изменяет  переменную  VAR3  в    сегменте  CODE.
    Утверждение ASSUME связывает этот сегмент с регистром CS. Ассемблер
    автоматически  генерирует  соответствующий  префикс  переназначения
    сегмента.  В  данном  случае  префикс  2EH  предписывает процессору
    использовать  при  вычислении  испольнительного  адреса регистр CS.
      Вначале  утверждение  ASSUME  покажется  излишеством.  В первое
    время при  написании программы естественно забывать  о его примене-
    нии. Ассемблер выдаст массу сообщений об ошибках чтобы помочь вам в
    вашей  забывчивости. Но  при достаточном  опыте, утверждение ASSUME
    помогает программисту ассемблера сосредоточиться на структурах дан-
    ных  в  программе.  Программист  должен  не  забывать устанавливать
    сегментные регистры  для адресации требуемых  для программы данных.
    Ассемблер  облегчит  бремя      запоминания  для  каждой  команды,  где
    располагаются  данные  и  какой   сегментный  регистр  должен  быть
    использован чтобы попасть к ним.
      Программа может  использовать утверждение SEGMENT  для передачи
    информации    другим      программам.  Оператор  SEGMENT      может  задавать
    выравнивание сегмента в памяти,  способ его комбинирования с други-
    ми      сегментами и  имя его   типа. Для  программистов IBM  PC особый
    интерес представляют два  вида выравнивания сегментов. Выравнивание
    по      параграфам  (тип  PARA)  размещает  начало  сегмента  с  начала
    параграфа -  ячейки памяти, адрес  которой в памяти  кратен 16-ти .
    Это  означает,  что  первый  байт  сегмента  будет иметь смещение 0
    относительно значения сегментного  регистра. Выравнивание по байтам
    (тип  BYTE), наоборот,  размещает сегмент  в любом      месте памяти. В
    этом случае сегментный регистр может  и не указывать на первый байт
    сегмента.  В программе  может потребоваться  ненулевое смещение для
    доступа к началу сегмента.
       Различные  способы  связывания  сегментов  задает  параметр типа
    связи.  Особенно   это  полезно  при   модульном  программировании.
    Описание PUBLIC приводит к объединению всех сегментов с одинаковыми
    именами  в один  большой  сегмент.    Например, можно  объединить все
    сегменты кодов.  Это приведет к соединению  разных подпрограмм в их
    собственных модулях с главной процедурой. Другой полезный тип связи
    - AT,  при указании  которого  в  сочетании с  адресным выражением,
    сегмент  располагается  по      заданному  абсолютному  адресу.  Такое
    объявление необходимо  при работе с данными  в фиксированном месте,
    например, с векторами прерываний в начале памяти.
      Намного  более    полное      описание  описание  утверждения SEGMENT
    можно найти  в справочном томе к  макроассемблеру IBM PC. Некоторые
    из      возможностей опертора  SEGMENT      мы  будем использовать  далее в
    примерах.




Оператор Segment



Оператор Segment


    Решить проблему  адресации сегментов поможет ассемблер.  В одной из
    своих  частей  программа  на  языке  ассемблера  должна  определить
    составляющие ее  сегменты. Кроме того  специальные команды сообщают
    ассемблеру,  какие сегменты  с каким  регистром связаны.  Благодаря
    этому ассемблер может, когда требуется, определить какой сегментный
    префикс нужен  в коде команды.  Если программист задает  ссылку, не
    связанную  с регистром  DS,  но  доступную через  другой сегментный
    регистр,  то  ассемблер  сам  сформирует  правильный  префикс.  Это
    позволяет программисту работать непосредственно с данными и текстом
    программы, оставив ассемблеру работу по осуществлению адресации.
      Объявление сегментов позволяет ассемблеру следить за тем, какие
    сегменты доступны через сегментные    регистры и определять возможные
    ошибки. Например,  в программе могут  появиться переменные, которые
    недоступны из-за того, что на  сегмент этой переменной не указывает
    ни один  из сегментных регистров.  Ассемблер квалифицирует это  как

          Microsoft (R) Macro Assembler Version 5.00              1/1/80 03:53:05
          Фиг. 3.9  Сегменты                                Page  1-1
 
                                        PAGE    ,132
                                        TITLE   Фиг. 3.9  Сегменты
 
           0000                   DATA    SEGMENT
           0000  01                     VAR1    DB        1           ; Переменная в сегменте DATA
           0001                   DATA    ENDS
 
           0000                   BUFFER  SEGMENT
           0000  02                     VAR2    DB        2           ; Переменная в сегменте BUFFER
           0001                   BUFFER  ENDS
 
           0000                   CODE    SEGMENT
           0000  03                     VAR3    DB        3           ; Переменная в сегменте CODE
 
                                        ASSUME  CS:CODE, DS:DATA, ES:BUFFER
 
           0001  FE 06 0000 R                 INC     VAR1      ; Переменная из сегмента DATA
           0005  26: FE 06 0000 R             INC     VAR2      ; Переменная из сегмента BUFFER
           000A  2E: FE 06 0000 R             INC     VAR3      ; Переменная из сегмента CODE
 
           000F                   CODE    ENDS
                                        END
 
                       Фиг. 3.9 Сегменты
    ошибку.  Она возникает  из-за того,  что в  программе не обеспечена
    адресуемость.  Это  ограничение,  но  лучше  обнаружить  ошибку при
    ассемблировании, чем во время работы программы.
      Оператор SEGMENT определяет все  сегменты, давая каждому из них
    имя.  Программа на  Фиг. 3.9  демонстрирует определение  нескольких
    сегментов.    В качестве  имени сегмента  может использоваться  любое
    допустимое имя переменной. Утверждение SEGMENT сообщает ассемблеру,
    что  все следующие  команды и данные во время  выполнения программы
    будут  находиться в  этом сегменте.  Оператор ENDS      указывает конец
    текущего сегмента. В этом  утверждении тоже указывается имя сегмен-
    та. Каждому утверждению  SEGMENT должно соответствовать утверждение
    ENDS. В противном случае ассемблер запутается и выдаст сообщение об
    ошибке.




Предназначение сегментов



Предназначение сегментов


    Каждый из  сегментных регистров имеет свое,  отмеченное выше назна-
    чение. В  некоторых случаях, однако,  более удобна связь  с данными
    вне  сегмента  данных,  например,  с  небольшой  областью  данных в
    программе. В большинстве случаев программа работает с данными в той
    области,  на  которую  указывает  регистр  DS,  но иногда программе
    требуется  ссылка на  локальную переменную,  находящуюся в    кодовом
    сегменте  программы.  Чтобы   осуществить  эту  ссылку,  приходится
    изменять обычное использование  сегментов. Фиг.3.8 показывает такую
    органзацию программы.
 
                ГДДДДДДДДДДДДДДДДДДДЕДДДДДД CS
                і Программа и і
                і             і
                і  локальные данные і
                і             ГДДДДДД CS:LOCAL_VALUE
                ГДДДДДДДДДДДДДДДДДДДґ
                і             і
                і             і
                і             і
                ЕДДДДДДДДДДДДДДДДДДДЕДДДДДД DS
                і Основная   і
                і             і
                і область даных     і
                і             і
                ГДДДДДДДДДДДДДДДДДДДґ
                і             і
 
       Фиг. 3.8 Переназначение CS на локальные данные.
 
      Вместо      изменения значения  регистра DS,  чтобы он  указывал на
    программный сегмент, команда изменяет  ссылку на данные, показывая,
    что переменная расположена в сегменте кодов (Code Segment).
 
      INC   CS:LOCAL_VARIABLE
 
    Это  делается с  помощью префикса  "CS:". В  машинном языке команда
    переопределения  сегмента выглядит    как однобайтовый  префикс перед
    обычной командой машинного языыка. 8088 понимает этот префикс пере-
    назначения    сегмента и  изменяет обычный  способ вычисления адреса.
    Вместо регистра DS процессор  использует для вычисления физического
    адреса  данных  регистр  CS.   Одного  префикса  в      команде  всегда
    достаточно, так  как 8088 может адресоваться  в ней не более  чем к
    одной ячейке памяти.
      Для нормального  обращения к данным  команда может использовать
    любой из  четырех сегментных регистров. Регистр  DS используется по
    умолчанию,    то есть  когда в  команде не  указан другой  сегментный
    регистр,  то  используется      DS.  Помните,  что  при использовании в
    адресных вычислениях регистра BP  сегментом по умолчанию становится
    стековый сегмент.  Команда может определить и  любой из трех других
    сегментных    регистров, указав  его в  адресном выражении. Некоторые
    команды, правда,  не могут пользоваться  переназначением сегментов.
    Это - команды   обработки строк.      Строковая  команда  определяет
    использование  регистров  неявным  образом,  и  оно  не  может быть
    изменено. В главе 4 мы обсудим строковые команды и их специфическое
    пользование сегментами.





Прямая адресация



Прямая адресация


    Простейший способ  определить операнд в  памяти - даать  имя ячейке
    памяти. В  дальнейшем программа использует  это имя в  командах для
    ссылки  на    соответствующий  участок  памяти.  Вот    как  этот метод
    используется в команде
 
      INC    OPND
 
    В примере  команда ассемблера
 
      OPND   DW ?
 
    объявляет  OPND участком  памяти  длиной  в слово.      Когда программа
    ипользует OPND в качестве операнда, ассемблер помещает адрес OPND в
    машинную команду. В данном примере    вы можете видеть адрес 0123 как
    часть  команды  в  объектном  коде.  Этот  способ  называют  прямой
    адресацией, поскольку команда непосредственно в себе содержит адрес
    операнда.




Регистр флагов



Регистр флагов


    Последний  управляющий регистр  - 16-битовый  регистр флагов.  Этот
    регистр содержит  информацию, которая используется побитно,  а не в
    качестве 16-битового числа. Биты  флагового регистра имеют значение
    для процессора по-отдельности. Некоторые  из этих бит содержат коды
    условий,  установленные  последней    выполненой  командой. Программа
    пользуется этими кодами для управления своим выполнением. Программа
    может  тестировать коды  условий  и  на основе  полученных значений
    выбирать  последовательность  выполнения.  Другие  биты  в регистре
    флагов  показывают  состояние  процессора  при  выполнении    текущей
    команды. Эти биты управляются специальными командами.
      Регистр флагов лучше всего описывать последовательно, по одному
    биту. Структура регистра флагов  показано на Фиг. 3.10. Заметим,
    что  здесь определены  не все  биты. Остальные  зарезервированы, то
    есть в  настоящее время их      значение не определено.  Однако в даль-
    нейших версиях  процессора они могут  быть использованы для  каких-
    нибудь специальных целей. Поэтому никогда не следует расчитывать на
    неизменность значения зарезервированных бит.
 
    номер бита    15 14 13 12 11 10  9  8  7  6  5  4  3    2  1  0
             ЪДДВДДВДДВДДВДДВДДВДДВДДВДДВДДВДДВДДВДДВДДВДДВДДї
             іXXіXXіXXіXXіOFіDFіIFіTFіSFіZFіXXіAFіXXіPFіXXіCFі
             АДДБДДБДДБДДБДДБДДБДДБДДБДДБДДБДДБДДБДДБДДБДДБДДЩ
                  Фиг. 3.10 Регистр флагов
 
      Все флаги младшего  байта регистра устанавливаются арифметичес-
    кими или логическими операциями  процессора. Например, операция ADD
    устанавливает  все  флаги  в  младшем  байте  в  соответствии  с ее
    результатом. За исключением флага  переполнения, все флаги старшего
    байта устанавливаются специально  предназначенными для этого коман-
    дами.  Флаги старшего  байта отражают  состояние процессора  8088 и
    будут влиять на режим выполнения программы. Флаги в младшем байте -
    это  коды условия  и могут      быть испольлзованы  в командах условных
    переходов для изменения порядка выполнения программы.




Регистры адресации



Регистры адресации


    В  процессоре 8088 имеется четыре 16-битовых регистров, которые мо-
    гут принимать  участие в адресации операндов.  Один из них является
    одновременно регистром общего назначения  - регистр базы BX. Другие

           Microsoft (R) Macro Assembler Version 5.00              11/17/88 21:42:25
           Фиг 3.2 Адресация операндов                      Page   1-1
 
                                         PAGE    ,132
                                         TITLE   Фиг 3.2 Адресация операндов
 
            0000                   CODE    SEGMENT
 
                                         ASSUME  CS:CODE,DS:CODE,SS:CODE
 
            0123                         ORG     123H
            0123  ????             OPND    DW      ?
 
            0200                         ORG     200H
 
            0200  43                           INC     BX        ; Увеличение регистра
            0201  FF 06 0123 R                 INC     OPND      ; Увеличение ячейки памяти
            0205  FF 07                  INC     WORD PTR [BX]   ; Увеличение слова памяти
 
            0207  FF 87 0123 R                 INC     [OPND+BX]       ; Смещение плюс индекс
            020B  FF 84 0123 R                 INC     [OPND+SI]
            020F  FF 84 0123 R                 INC     OPND[SI]        ; Другой способ - тот же результат
            0213  FF 85 0123 R                 INC     OPND + [DI]
            0217  FF 86 0123 R                 INC     [OPND] + [BP]
 
            021B  FF 00                  INC     WORD PTR [BX + SI]      ; База плюс индекс
            021D  FF 03                  INC     WORD PTR [BP] + [DI]
 
            021F  FF 81 0123 R                 INC     [OPND + BX + DI] ; База + индекс + смещение
            0223  FF 82 0123 R                 INC     OPND[BP][SI]
 
            0227                   CODE    ENDS
                                         END
 
                                        Фиг 3.2 Адресация операндов
    три  - это    указатель базы    (Base Poiner  - BP),  индекс источника
    (Source Index -  SI) и индекс назначения (Destination  Index - DI).
    Программа  может  использовать  регистры  BP,  SI  и  DI в качестве
    16-битовых операндов, но отдельные байты в них недоступны. Основное
    назначение    этих   регистров  -  поставлять   16-битовые  значения,
    используемые в формировании адресов операндов.
      Каждая команда в 8088 задает для выполнения некоторую операцию.
    Разные операции  могут иметь от  нуля до двух  операндов. Например,
    команде  разрешения  прерываний  Set  Interrupt  (STI)  операнды не
    нужны. Команда увеличения (INC)  требует, чтобы программист опреде-
    лил  один операнд,  - регистр  или ячейку  памяти, - который должен
    быть увеличен  на еденицу. Команда ADD  (сложение) должна иметь два
    операнда -    складываемые величины. Некоторые  команды неявно задают
    расположение операнда, но большинство команд позволяют программисту
    выбирать  в качестве  операнда регистр  или ячейку      памяти. Если  в
    качестве операнда  выбран регистр, то  программисту остается только
    указать его имя. Для указания же в качестве операнда участка памяти
    у вас есть много различных способов.
      Хорошим  примером служит  команда INC.    Она имеет  единственный
    операнд.  На Фиг.  3.2 изображен  листинг ассемблера  с несколькими
    различными вариантами  команды INC. Первая  команда INC называет  в
    качестве операнда регистр BX. Заметим,  что в поле операндов в этом
    случае кроме BX ничего нет. Остальные команды в примере указывают в
    качестве операнда ячеку памяти. И  хотя в них иногда появляется имя
    регистра BX,  он не является здесь    самим операндом, а используется
    для определения его адреса.




Регистры общего назначения



Регистры общего назначения


    В первую группу  входят регистры, используемые  в основном для  вы-
    числений. Все эти общие регистры  имеют размер 16 бит, но программа
    может работать и со старшими или младшими 8-ю битами каждого регис-
    тра отдельно. Например. регистр AX состоит из 16 бит. Программа мо-
    жет обратиться к старшим 8 битам AX  как к регистру AH, а младшие 8
    бит образуют регистр  AL. То же самое верно для  регистров BX, CX и
    DX. Программа может рассмматривать    эту группу регистров как четыре
    16-битовых, восемь 8-битовых или некоторую комбинацию 8- и 16-бито-
    вых регистров.
      Основное назначение группы общих  регистров - хранить операнды.
    Общие регистры характерны способностью  хранить как слово, так байт
    данных.  Однако эти  регистры при  выполнении определенных операций
    имеют   специальное  назначение,   либо  они   могут  иметь  особые
    возможности помимо тех, которые  имеются у остальных регистров этой
    группы.  В    следующих  разделах  отмечены  некоторые из специальных
    функций этих регистров.
      Регистр  AX соответствует  сумматору более  ранних процессоров.
    Хотя  8088    значительно  более  универсален,   например,  в  части
    арифметических операций,  чем ранние машины  вроде процессора 8080,
    регистр  AX  имеет  несколько   специальных  функций.  Фирма  Intel
    оптимизировала набор команд 8088,  привлекая к выполнению некоторых
    операций   регистр  AX.   Например,   существуют  непосредственные
    операции,  в  которых  один   из  операндов  подразумевается  самой
    командой.  Непосредственные операции  с регистрами      AX и  AL (16- и
    8-битовый сумматоры  соответственно) обычно требуют  более короткой
    команды, чем  аналогичные операции с  привлечением других регистров
    общего  назначения.  А  меньший  размер  команды позволяет получать
    более компактные и быстродействующие программы.
      Регистр  BX служит как регистром для вычислений, так и адресным
    регистром. При использовании в качестве 16-битового регистра он мо-
    жет служить для определения  адреса операнда. Способы адресации для
    микропроцессора 8088 выделены в следующий пункт.
      Набор команд  8088 использует регистр CX  в качестве счетчика к
    некоторым иструкциям. Эти команды  используют находящееся в CX зна-
    чение как указатель числа итераций команды или фрагмента программы.
      Регистр   DX      служит      как   расширение    аккумулятора   для
    многоразрядных  операций  умножения  и  деления.  В этих 32-битовых
    операциях участвут одновременно регистры AX и DX.




Сегментные регистры



Сегментные регистры


    INTEL 8088    имеет четыре сегментных  регистра: CS,DS,SS и  ES - для
    кодового,     данных-,   стекового    и   дополнительного   сегментов
    соответственно.  Это их  обычное использование,  но применение этих
    регистров может именяться в соответствии с потребностями программы.
      8088  использует регистр  сегмента программы  для идентификации
    того  сегмента,  который  содержит    выполняемую  в  данный  момент
    программу. В сочетании с  указателем команд регистр CS используется
    для указания текущей команды.  Каждая выполняемая команда находится
    в ячейке, на которую указывает пара регистров CS:IP.
      Комбинация сегментного  регистра  с  регистром   смещения  для
    указания физического  адреса записывается в  виде сегмент:смещение,
    например, CS:IP. Значение сегмента стоит перед двоеточием, смещение
    - после.  Такая  нотация  используется   и  для  регистров,  и  для
    абсолютных    адресов.  Вы  можете  писать  такие  адреса как CS:100,
    DS:BX, 570:100, или 630:DI.
      Регистр сегмента данных (DS)  процессор использует для обычного
    доступа  к    данным.  Схемы    адресации  для    операндов,  которые  мы
    рассматривали в  предыдущем пункте, дают  16-битовое смещение, и  в
    большинстве случаев для формирования исполнительного адреса процес-
    сор комбинирует это смещение с ргеистром DS.
      Регистр  сегмента стека  указывает на  системный стек.      Команды
    PUSH, POP, CALL и RET управляют данными в стеке в позиции по адресу
    SS:SP.  Регистр  SP  -  указатель  стека  -  служит для определения
    смещения  в стеке.  Кроме  того,  сегмент стека  подразумевается по
    умолчанию  при адресации  с  использованием  регистра BP.  Это дает
    доступ  к  данным  в  стеке  с  использованием в качестве указателя
    регистра  BP. В  следующей главе  есть пункт  о стековых операциях,
    который  демонстрирует, каким  образом адресация  через BP упрощает
    связь с данными в стеке.
      Наконец, регистр дополнительного сегмента используется 8088 для
    доступа к  данным, когда требуется    более одного сенмента.  Обычной
    операцией такого рода является  копирование данных из одной области
    памяти в  другую. Между областями, находящимися  не внутри одного и
    того же блока памяти размером 64К, невозможно произвести обмен дан-
    ными, используя единственный сегментный  регистр. Имея в распоряже-
    нии дополнительный  сегментный регистр, программа,      как показано на
    Фиг. 3.7,  может указать одновременно исходный  и целевой сегменты.
    Регистр  DS  указывает  область  исходных  данных,      а  регистр ES -
 
                  і                і
                  ГДДДДДДДДДДДДДДДДДДДДґ ДДДДД DS
     Копировать   і     Сегмент -      і
      отсюда      ДДДДДДДДґ              і
             і    і     источник         і
             і    ГДДДДДДДДДДДДДДДДДДДДґ
             і    і                і
             і    і                і
             і    ГДДДДДДДДДДДДДДДДДДДДґ ДДДДД ES
             і    і      Сегмент         і
             і    і                і
       сюда ДДДДДДДДґ    назначения      і
                  ГДДДДДДДДДДДДДДДДДДДДґ
 
         Фиг.3.7 Копирование из сегмента в сегмент
 
    сегмент  назначения.  Для  передачи  данных  существуют специальные
    строковые команды,  которые автоматически используют  регистры DS и
    ES для указания исходного и целевого регистров.




Указатель команд



Указатель команд


    Указатель команд - это  16-битовый регистр, который содержит смеще-
    ние очередной команды. Как      показано в предыдущем пункте, Процессор
    использует регистр CS совместно с регистром IP для формирования 20-
    битового физического адреса. Регистр CS определяет сегмент выполня-
    емой программы, а IP задает смещение.
      Поскольку  в  задании  адреса  очередной  команды участвует два
    регистра,  существует  несколько  способов  задать      ход  выполнения
    программы.    Наиболее обычный  из этих  способов осуществляется  при
    нормальном выполнении программы. При извлечении процессором команды
    из      памяти и  ее выполнении  значение регистра  IP увеличивается на
    размер команды  в байтах. Тепер  пара CS:IP указывает  на следующую
    команду.
      Для  изменения порядка  выполнения команд  используются команды
    перехода. Команда перехода одного вида изменяет только регистр IP и
    дает переход  внутри одного сегмента. Этот  тип перехода называется
    внутрисегментным  или  близким  (NEAR)  переходом. Спецификация для
    него  требует  лишь  новое      значение  для  регистра  IP. Регистр CS
    остается без изменений. Близкий переход может передавать управление
    только  внутри   текущего  сегмента,  поэтому   дальность  перехода
    ограничена сверху 64K байт. Для перехода к боле отдаленному участку
    программы требуется переход другого типа.
      Переход второго типа называется межсегментным или далеким (FAR)
    переходом. При этом переходе процессор назначает новые значения как
    для IP так    и для CS. Этот переход  позволяет выполнять новую прог-
    рамму расположенную  в любом месте адресного  пространства 8088. Но
    для  выполнения  такого  перехода  команда  должна определить новые
    значения для  обоих регистров -  CS и IP.  При прямом переходе  это
    требует пяти-байтовой команды : один байт  на код операции и по два байта для регистров CS и IP.




Указатель стека



Указатель стека


    Регистр  указателя стека  (SP)  -  это 16-битовый  регистр, который
    определяет    текущее  смещение  вершины  стека. Процессор использует
    указатель стека совместно с регистром сегмента стека для формирова-
    ния физического  адреса. Процессор использует  пару регистров SS:SP
    для всех  стековых ссылок, включая    PUSH, POP, CALL  и RETURN. Пара
    SS:SP  всегда  указывает  текущую     вершину  стека.  Когда  команда
    помещает в стек слово, регистр  SP уменьшается на два. При извлече-
    нии из  стека слова процессор  увеличивает регистр SP  на два. Стек
    растет в  направлении меньших адресов  памяти. Все стековые  опера-
    ции используют  значения размером в слово.  Отдельный байт не может
    быть ни помещен в стек ни взят из него.
      Процессор изменяет регистр SP  для того чтобы отразить действия
    над стеком. На  регистр SS ни одна из  стековых операций не влияет.
    Программа устанавливает регистр SS    независимо от какой либо опера-
    ции  PUSH  (поместить  в  стек)  или  POP  (извлечь), после чего он
    указывает  на  сегмент  стека.  Это  означает,  что  системный стек
    ограничен  в  размере  64  килобайтами.  Например,      если  программа
    устанавливает регистр SS  в 1000H, а регистр SP -  на 0, то первое,
    что  будет помещено  в стек,  разместится по  адресам 1000:FFFFH  и
    1000:FFFEH.   Последовательно  помещаемые   в  стек   данные  будут
    размещаться  в  нем  по  все  более  младшим адресам, пока последий
    объект  не    будет  расположен   в  1000:0001H  и  1000:0000H.  Если
    программа  поместит в  стек в  этот момент  еще что-нибудь,  то оно
    разместится  в 1000:FFFFH  и 1000:FFFEH,  то есть  в первых  байтах
    используемых  стеком.  Поскольку  стек  теперь  "замкнулся",  ранее
    помещенные в него данные разрушены.
      При нормальном использовании длина стека не достигает 64K. Если
    программа  устанавливает стек  в 512  байт, например,  то она может
    инициализировать  пару SS:SP  как 1000:2000H.  Первая ячейка  стека
    будет 1000:01FFH, а последняя доступная - 1000:0000H. Если програм-
    ма поместит в  стек более 256 слов, уменьшение  регистра SP вызовет
    проход  его  значения  через  нуль    и  приведет к размещению данных
    сначала  сегмента  стека.  После  этого  программа      будет  помещать
    стековые   данные   в   область,   которая  в   данном  случае  не
    предназначалась для  стека - начиная  с 1000:FFFFH. При  этом может
    произойти одна из двух неприятных  вещей. Стек может перекрыть коды
    или  данные программы  и разрушить    их, либо  стековые данные будут
    направляться  в пространство,  которое не  имеет физической памяти.
    Любую из этих вещей очень  трудно обнаружить при отладке программы,
    поэтому единственный  выход - оставлять для  стека как можно больше
    места.  В     случае      персонального  компьютера   IBM,  использующего
    дисковую  операционную систему  IBM рекомендуется  размер стека  не
    меньше  128  байт.  Это  дает  достаточно  места для удовлетворения
    потребностей  в стеке  различных служебных  программ DOS  и системы
    вместе с обычными запросами самой программы.




Управляющие рагистры



Управляющие рагистры


    Для  операций  управления  в  процессоре  8088 используются главным
    образом три  16-битовых регистра. Это указатель  стека (SP), указа-
    тель команды (IP) и  регистр флагов. Два регистра-указателя процес-
    сор использует для необходимой при выполнении программы адресации в
    памяти. Регистр  флагов содержит коды  состояний, которые программа
    может использовать для управления своим выполнением.

Векторы прерываний



Векторы прерываний


    Еще одна важная составная часть микропроцессора 8088 - механизм
    прерываний. Эта компонента системы встроена в микропроцессор, и
    обеспечивает эффективные методы обработки прерываний.
 
      Когда микропроцессор 8088 получает сигнал о необходимости
    прерывания, он определяет, какое из усройств требует обслуживания
    посредством аппаратной процедуры, известной как цикл подтверждения
    прерывания. В IBM PC для обслуживания внешних прерываний
    используется контроллер прерываний 8259 фирмы Intel. Контроллер
    прерываний программируется так, чтобы выдавать однобайтовое число в
    ответ на цикл подтверждения прерывания микропроцессора 8088. Это
    число, находящееся в диапазоне от 0 до 255, - номер прерывания
    внешнего усройства, вызвавшего прерывание. В персональной ЭВМ
    контроллер прерываний обслуживает восемь внешних прерываний,
    которым соответствуют номера от 8 до 15.
 
      Как только микропроцессор 8088 получает номер прерывания, он
    должен передать управление соответствующей программе обработки
    прерывания. Первые 1024 байт памяти микропроцессора 8088
    зарезервированы для векторов прерываний. Каждому из 256 возможных
    прерываний отводится четырехбайтовая область. Прерывание 0 имеет
    четыре байта по адресам от 0 до 3, прерывание 1 - от 4 до 7, и т.д.
    Каждая четырехбайтовая ячейка содержит указатель на соответствующий
    обработчик конкретного прерывания. Первые два байта содержат
    смещение адреса программы обработки прерывания, а последние два
    байта - сегмент. Для задания значения этого поля может
    использоваться оператор определения двойного слова DD.
 
      Так же, как и вызов подпрограммы, прерывание должно сохранить в
    стеке адрес возврата. Поскольку обработчик прерывания может
    находиться в любом месте адресного пространства микропроцессора, он
    должен обслужить прерывание, как вызов типа FAR, т.е. перед тем,
    как микропроцесоор передаст управление обработчику прерывания, он
    сохранит сегмент и смещение текущей команды в программе. Кроме того
    возврат из программы обработки прерывания должен вернуть машину в
    точности в то состояние, в котором она была в момент возникновения
    прерывания. Чтобы помочь в этом, микропроцессор 8088 также
    сохраняет регистр флагов в стеке. Это означает, что эти действия
    уже не придется выполнять каждой программе обработки прерываний.
    Сохранение регистра флагов означает также сохранение и текущего
    состояния флага разрешения прерываний. Принятие внешнего прерывания
    сбрасывает флаг разрешения прерывания, так что программа обработки
    прерывания уже не может быть прервана другим прерыванием. Команда
    возврата из прерывания, которая восстанавливает регистр флагов,
    автоматически деблокирует систему прерываний восстановлением флага
    прерываний в состояние предшествующее возникновению прерывания.
 
      Когда возникает прерывание, микропроцессор помещает в стек
    региср флагов, за которым следуют регистры CS и IP. 8088 использует
    номер прерывания, чтобы считать указатель на программу обработки
    прерывания, и передать ей управление. Теперь уже эта программа
    отвечает за сохранение регистров, которые она использует, и
    восстановление их перед возвратом управления в прерванную
    процедуру. Для возврата из прерывания используется специальная
    команда IRET. Она извлекает верхние три слова из стека и помещает
    их в регистры IP, CS и регистр флагов. В следующих главах мы
    приведем несколько примеров, использующих механизм прерываний.
 
      Программист может использовать механизм прерывания
    непосредственно, без запроса внешних прерываний. Существуют
    команды, которые заставляют микропроцессор работать так, как будто
    при их выполнения возникло внешнее прерывание. Такие действия
    называются программными прерываниями, так как они порождаются
    программами, но имитируют действия обычных прерываний. Процессор
    помещает все три управляющих регистра в стек и выбирает вектор
    прерывания по указанному программой однобайтовому значению.
    Микропроцессор использует записанный в начале памяти вектор
    прерывания в качестве указателя подпрограммы обработки прерывания.
 
      Программные прерывания придают большую гибкость системе 8088.
    В  случае обычных вызовов подпрограммы программист до ее выполнения
    обязан знать, где она находится. Но если программа вызывает под-
    программу, используя программное прерывание, то подпрограмма может
    находиться в любом месте адресного пространства, и вызывающей
    программе нет нужды знать ее местонахождение. Единственным пара-
    метром, котрый требуется от программиста, вызывающего подпрограмму,
    является номер вектора прерываний. Управляющие программы и опера-
    ционная система фирмы IBM очень выгодно используют этот механизм.
    Программные прерывания дают доступ к сервисным программам системы.
    Программам пользователя не нужно знать точные адреса, которые могут
    изменяться в разных версиях системного программного обеспечения.
    Кроме того, сервисные подпрограммы могут быть подменены в любой
    момент времени простой заменой четырехбайтового вектора,
    указывающего на новую программу, без всякой модификации программ,
    использующих эти подпрограммы. В гл.10 мы приведем несколько
    примеров, которые покажут, использование такого подхода.




Вычисление адресов



Вычисление адресов


    В способе  прямой адресации  памяти привлекательна      простота, но во
    многих случаях программа вынуждена вычислять действительный адрес в
    памяти.  Простейший  пример  -   операции  с  вектором,  одномерным
    массивом.  В  программе  на  языке    Фортран  такую    структуру можно
    создать оператором
 
      DIMENTION   OPND(20)
 
    В других  языках  высокого      уровня      существуют  аналогичные способы
    создания  массивов.  При  выполнении  программа  получает  доступ к
    разным  элементам в  соответствии со  значением индекса,  например,
    OPND(5).  Написание  программы  на    языке      ассемблера  требует  от
    программиста  вычисления  местонахождения  пятого  элемента  в поле
    данных OPND. Затем программа может использовать полученное значение
    для прямой адресации. Однако, в  случае с выражением OPND(I), где I
    вычисляется в  ходе выполнения программы,  способа прямого указания
    правильного адреса для программы на языке ассемблера не существует.
    Адрес должен вычисляться в ходе выполнения программы.
      Набор команд 8088 допускает  несколько способов определения ис-
    полнительного адреса (Effective Address - EA) операнда. Эти способы
    вычисления    адреса      называют  способами  адресации.  Их  количество
    предназначено  для  облегчения  задачи  определения  исполнительных
    адресов. Благодаря правильному выбору способа адресации программист
    может минимизировать количество вычислений в программе.
      Формула для определения I-го элемента массива OPND такова:
 
      EA = адрес базы OPND + (I * длина),
 
    где длина  - это длина  каждого элемента массива.  В данном примере
    OPND  - массив,  состоящий из  слов, поэтому  каждый элемент  в нем
    имеет длину 2 байта. Тогда формула выглядит так:
 
      EA = адрес базы + (I * 2)
 
      Для вычисления этого адреса требуется по крайней мере один  ре-
    гистр,  содержащий адрес операнда. Программа может вычислить испол-
    нительный адрес, оставив результат в  одном  из  регистров.  Тогда,
    вместо указния адреса в самой команде INC,  можно  просто  указать,
    какой из регистров его содержит.
      Для хранения адресов операндов программа может использовать лю-
    бой  из  четырех адресных регистров. Так, в нашем примере программа
    добавляет к адресу базы 2*I и помещает результат в регистр BX.  Со-
    ответствующий элемент вектора в этом случае будет увеличиваться ко-
    мандой
 
      INC    WORD PTR [BX]
 
      Выражение [BX] сообщает ассемблеру, что регистр BX содержит ад-
    рес операнда,  а не является операндом  сам по себе. Скобки  [ и ],
    заключающие  какое-либо  значение,    указывают  ассемблеру,  что это
    значение  - адрес.  Другая часть  операндного выражения,  WORD PTR,
    требуется     ассемблеру   для   информации,      что  операнд  является
    переменной типа  WORD (слово). Далее мы  обсудим оператор PTR более
    подробно.