Как ориентироваться в машинном языке 1969 г.

Данные - хранение 16-битных данных. Работа со стеком.


           КОМАНДЫ  ОПЕРАЦИЙ ЗАГРУЗКИ ДЛЯ ДВУХ РУК
 ??????????????????????????????????????????????????????????????? 

                             TIME    EFFECT  ON  FLAGS
       MNEMONIC        BYTES      ????????????????????????
                             TAKEN
                                   C   Z   PV  S   N   H
 ??????????????????????????? ?????????????????????????????

  LD REG PAIR,NUMBER    3/4   10   -   -   -   -   -   -
  LD IX,NUMBER           4    14   -   -   -   -   -   -
  LD IY,NUMBER           4    14   -   -   -   -   -   -
 ??????????????????????????? ?????????????????????????????

  LD (ADDRESS),BC OR DE  4    20   -   -   -   -   -   -
  LD (ADDRESS),HL        3    16   -   -   -   -   -   -
  LD (ADDRESS),IX        4    20   -   -   -   -   -   -
  LD (ADDRESS),IY        4    20   -   -   -   -   -   -
 ??????????????????????????? ?????????????????????????????

  LD DC OR DE,(ADDRESS)  4    20   -   -   -   -   -   -
  LD HL,(ADDRESS)        3    16   -   -   -   -   -   -
  LD IX,(ADDRESS)        4    20   -   -   -   -   -   -
  LD IY,(ADDRESS)        4    20   -   -   -   -   -   -
 ??????????????????????????? ?????????????????????????????

         Такому решению нет никакого оправдания. Можно только
сказать,  что  так  решили  конструкторы  Z80  и  нам  теперь
приходится с этим мириться. 
         Очень  желательно, чтобы вы внимательно это прочли и
удостоверились,   что   освоили  это  обращение  традиционных
правил. Скорее всего именно это станет единственным важнейшим
источником ошибок в программах: 
     -  в регистрах: старший бит хранится первым; 
     -  в памяти и программах: младший бит хранится первым. 
         Этот  факт  нельзя  прочитать  и  забыть,  поскольку
каждый  раз,  когда  вам  придется  иметь  дело  с 16-битовой
командой  на  машинном  языке нужно будет тщательно продумать
порядок младших и старших битов. Однако, не стоит из-за этого
расстраиваться  -  работать  на  Z80  без  16-битовых  команд
практически  невозможно, так что это цена, которую приходится
платить. 
         Вы  сами  можете  проверить  этот факт, выполнив эту
команду  с  помощью  "Редактора  машинного языка в коде EZ" и
затем прочитав содержимое памяти с помощью команды MEM. 

                  ЗАГРУЗКА 16-БИТОВЫХ ЧИСЕЛ

         Группа  команд  загрузки  16-битовых  чисел,  говоря
упрощенно,  сводится  к  загрузке  16-битового  числа  в пару
регистров. Общий вид мнемонического сокращения: 

                           LD RR,NN

         Вновь  мы  применяем  двухбуквенное  обозначение для
16-битовых   чисел.   RR   -   обозначает  произвольную  пару
регистров,  NN-  произ-  вольное 16-битовое число. Для тех из
вас,   кто   лишен   преимуществ   ассемблера,т.е.  если  вам
приходится  в  ручную  переводить мнемонические обозначения в
машинный  код  с  помощью помещенных в конце книги таблиц, то
рассмотренный нами вопрос о порядке 16-битовых чисел в памяти
становится  принципиальным.  Даже  если у вас есть ассемблер,
нужно  знать  об  этом  обратном  порядке, чтобы уметь читать
текст машинной программы при просмотре памяти. 
         Давайте рассмотрим конкретный пример: 
загрузить 258 в HL мнемоническое обозначение: 

                         LD HL,0102H

         Команда,   соответствующая   LD   HL,NN,  как  можно
удостовериться, посмотрев в конец книги: 

                           21 XX XX

         Это  означает, что вместо XX XX нужно вставить число
0102H.  Но  из-  за правила перестановки мы не станем вводить
его  в  виде  0102H.  Поэтому  правильно  будет  записать эту
команду так: 

                           21 02 01

В наших примерах мы будем показывать это так 

           21 02 01    LD HL,0102H         (= 258)

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

            ДРУГИЕ  КОМАНДЫ ЗАГРУЗКИ ДЛЯ 16 БИТОВ

         Помимо   возможности   загрузки   16-битовых   чисел
непосредственно  в  пары регистров у нас есть еще возможность
загрузки   16-битовых   чисел   непосредственно  в  индексные
регистры: 

                           LD IX,NN
                           LD IY,NN

         Мы  можем  также управлять обменом информацией между
парой  регистров  и  двумя последовательными ячейками памяти.
Это  16-бито-  вый  эквивалент  загрузки информации из одного
регистра в одну ячейку памяти. Общий вид команды следующий: 

                          LD (NN),RR
                          LD (NN),IX
                          LD (NN),IY

         Напомним,  что  скобки  это  сокращенное обозначение
содержимого,   так   что   последняя   команда  читается  как
"загрузить   содержимое   регистра   IY   в   ячейку   памяти
NN".Поскольку  мы  имеем дело с 16-битовыми числами, на самом
деле  мы загружаем указанную ячейку памяти и следующую за ней
пару   регистров.   Нет  необходимости  задавать  оба  адреса
(поскольку  ЦП  может вычислить адрес второй ячейки), но надо
проявить  внимание,  чтобы  не  спутать  8-битовые операции с
16-битовыми.  Здесь также проявляется взаимообразный характер
многих  команд,  так  что  мы  можем  также  загрузить в пару
регистров  или  в  индексный  регистр  все,  что  находится в
конкретной паре ячеек памяти: 

                          LD RR,(NN)
                          LD IX,(NN)
                          LD IY,(NN)

                          УПРАЖНЕНИЕ

         Мы  знаем  из  руководства  "Спектрум", что получить
начало   свободного   пространства   памяти  можно,  проверив
содержимое ячеек 23653 и 236545. 
         На  языке  "Бейсик"  мы  можем  задать это с помощью
строки 

             PRINT PEEK 23653 + 256 * PEEK  23654

         Мы  теперь  выполним  то же самое действие с помощью
машинного языка: 

              (23653 = 5C65H)
              ED 48 65 5C         LD BC,(23653)
              C9                  RET

         Обратите внимание на то, что числа вводятся так, что
первым  идет младший байт, и у вас совершенно неверный ответ,
если будете вводить их в обратном порядке. 
         При  работе  на  "Спектрум"  нам  известно,  что как
только   программа  закончена,  положение  свободной  области
памяти  оказывается  фиксированным и нам его нужно определить
только  один  раз для каждой программы. Мы используем регистр
BC для получения информации, поскольку значением USR является
содержимое  пары  регистров  BC  при  завершении программы на
машинном  языке.  Обратите  внимание,  что команда LD BC,(NN)
состоит  из  четырех  байтов. Вы можете с помощью аналогичных
программ   определять   значения   произвольных  двухбайтовых
переменных, перечисленных в руководстве "Спектрум". 

                         В Ы В О Д Ы

         Мы  можем  загрузить 16-битовые числа в любую из пар
регистров  или  в  индексные регистры либо задавая 16-битовое
число,   либо  ячейку  памяти,  где  оно  должно  находиться.
Аналогичным  образом  мы можем передавать в память 16-битовое
слово  из  любой  пары  регистров или из индексных регистров.
Единственное,  на  что  нужно  обратить  особое внимание, это
специфический порядок, в котором хранятся 16-битовые числа ЦП
Z80 в памяти ( и тем самым в командах программы, использующих
16-битовые числа). 
         Младший байт всегда хранится первым !! 

                      РАБОТА  СО  СТЕКОМ

         Вы  можете  вспомнить  развитое  нами в начале книги
представление  о  стеке как месте, в котором ЦП может хранить
информацию, не заботясь о запоминании ее конкретного адреса. 

                  КОМАНДЫ ОПЕРАЦИЙ СО СТЕКОМ
 ???????????????????????????????????????????????????????????????? 

                                  EFFECT  ON  FLAGS
                       TIME ??????????????????????????????
     MNEMONIC    BYTES
                       TAKEN  C    Z   PV    S    N    H
 ????????????????????? ????????????????????????????????????

  PUSH REG PAIR    1    11    -    -    -    -    -    -
  PUSH IX OR IY    2    15    -    -    -    -    -    -
 ????????????????????? ???????????????????????????????????

  POP REG PAIR     1    10    -    -    -    -    -    -
  POP IX OR IY     2    14    -    -    -    -    -    -
 ????????????????????? ???????????????????????????????????

  LD SP,ADDRESS    3    10    -    -    -    -    -    -
  LD SP,(ADDRESS)  3    20    -    -    -    -    -    -
  LD SP,HL         1     6    -    -    -    -    -    -
  LD SP IX OR IY   2    10    -    -    -    -    -    -
 ????????????????????? ???????????????????????????????????

REG PAIR - пара регистров; 
OR - или; 
ADDRESS - адрес

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

                           PUSH RR
                           PUSH IX
                           PUSH IY

Общий вид команд выталкивания информации из стека: 

                           POP RR
                           POP IX
                           POP IY

         Это  очень  простые команды и вы, конечно, заметите,
что нет необходимости задавать адрес. 
         Для обычных пар регистров (не индексных) эти команды
имеют длину всего один байт и поэтому экономны с точки зрения
практики программирования. 
         Команды  PUSH, кроме того, не портят регистров, т.е.
16-битовый  регистр  после выполнения команды PUSH продолжает
содержать  ту же информацию, что и до нее. Обратите внимание,
что  поскольку  мы  можем  выполнять  операции PUSH и POP для
произвольных пар регистров, регистр, для которого выполняется
команда  POP,  не  обязан  быть  тем  же  самым, для которого
выполнялась команда PUSH. 
         Например: 

                           PUSH BC
                           POP  HL

         Результат выполнения этих двух команд состоит в том,
что  содержи-  мое регистра BC не изменяется, а содержание HL
становится равным содержимому регистра BC во время выполнения
команды PUSH. 
         Это по существу добавляет команду типа 

                          LD RR,RR'

к  группе  команд  загрузки  16-битовых  чисел,  которая явно
отсутствовала.  Поскольку каждая из команд PUSH и POP для пар
регистров  имеет  длину всего 1 байт, затраты, с точки зрения
памяти, не очень велики. 
         Другим дополнительным преимуществом является то, что
мы  можем выполнять команды PUSH и POP для пары регистров AF.
Это  одна  из многих команд, в которых AF рассматривается как
пара  регистров и, очевидно, в этом есть смысл, поскольку нам
не  раз  придется  сохранять содержимое флагов. Это означает,
что   вы  можете  выполнить  PUSH  AF,  провести  вычисления,
нежелательным  побочным  эффектом которых может быть изменени
флагов,   и  затем  выполнить  POP  для  AF,  оставляя  флаги
неизменными. 

                      РАБОТА  СО  СТЕКОМ

         Как  вы  знаете,  действительные преимущества команд
PUSH  и  POP  состоят  в том, что нам не приходится думать об
адресах   чисел,   над   которыми  эти  команды  выполняются.
Согласитесь,  что  не  всегда имеет смысл, чтобы одна и та же
область памяти служила стеком независимо от того, будет у вас
16К  или  48К.  Наи  самом  деле ЦП отслеживает адрес стека с
помощью  указателя  стека,  который  можно считать 16-битовым
регистром.  Мы  кратко упомянули об этом, когда рассматривали
регистры,  но  ничего  не  говорили  об этом при рассмотрении
команд  LOAD и тому подобных, поскольку это не такой регистр,
который  можно обрабатывать так же, как и остальные регистры.
Основное,  что  желательно  уметь делать с указателем стека -
это  определять  его  положение  в памяти, и именно такой тип
команды имеется: 

                           LD SP,NN
                           LD SP,(NN)
                           LD SP,IX
                           LD SP,IY

         Вы   можете  проверить  стек  "Спектрум"  с  помощью
команды  MEM программы "Редактора машинного языка в коде EZ",
просматривая последние 30 - 40 байтов перед RAMTOP. 
         Не  изменяйте  содержимое  ячеек  стека! Почти любое
изменение  приведет к остановке "Спектрум" - экран погаснет и
вам  придется  вновь включать питание. Так происходит потому,
что   операционная   система   помещает   много   информации,
необходимой  ей, в стек, и изменения приводят к тому, что она
идет  в  разнос. По этой же самой причине не пытайтесь менять
положение  указателя  стека,  если  только  у  вас нет полной
уверенности в том, что вы делаете. 
ЗАМЕЧАНИЕ: в  правильно  организованной  программе количество
           команд  POP  и PUSH должно совпадать независимо от
           того, по какой ветви шла программа. Любые ошибки в
           подсчете могут привести к странным результатам. 

                          УПРАЖНЕНИЕ

         Мы  можем применить эти команды для проверки адреса,
по  которому  вызывается  программа  USR  путем  выталкивания
значения  из  стека  в регистр возврата BC. Как это делается,
покаывает следующая программа: 

              C1     POP BC   : GET ADDRESS IN BC
              C5    PUSH BC   : PUT BACK ON THE STACK
              C9     RET
 GET ADDRESS IN BC - получить адрес в BC;
 PUT IN BACK ON THE STACK - поместить его обратно в стек

             АРИФМЕТИЧЕСКИЕ  КОМАНДЫ ДЛЯ ДВУХ РУК
 ??????????????????????????????????????????????????????????????? 

                                EFFECT  ON  FLAGS
                       TIME ??????????????????????????????
     MNEMONIC    BYTES
                       TAKEN  C    Z   PV    S    N    H
 ????????????????????? ???????????????????????????????????

  ADD HL,REG PAIR  1    11    #    -    -    -    0    ?
  ADD HL,SP        2    11    #    -    -    -    0    ?
  ADD HL,REG PAIR  2    15    #    #    #    #    0    ?
  ADD IX,SP        2    15    #    #    #    #    0    ?
  ADD IX,BC OR DE  2    15    #    -    -    -    0    ?
  ADD IX,IX        2    15    #    -    -    -    0    ?
  ADD IX,SP        2    15    #    -    -    -    0    ?
  ADD IY,BC OR DE  2    15    #    -    -    -    0    ?
  ADD IY, IY       2    15    #    -    -    -    0    ?
  ADD IY,SP        2    15    #    -    -    -    0    ?
 ????????????????????? ???????????????????????????????????

  SBC HL,REG PAIR  2    15    #    #    #    #    1    ?
  SBC HL,SP        2    15    #    #    #    #    1    ?
 ????????????????????? ???????????????????????????????????

             ? - означает, что результат неизвестен.

             АРИФМЕТИЧЕСКИЕ ДЕЙСТВИЯ ДЛЯ ДВУХ РУК

         Одно    из   преимуществ   возможности   16-битового
представления  чисел  в,  по  сути дела, 8-битовом процессоре
состоит  в  том,  что мы можем применять 16 битов для задания
адреса  и  для  выполнения  вычислений  над целыми числами до
65355  (или в диапазоне от -32768 до +32767, если допускаются
отрицательные  числа).  В  свете вышесказанного легко понять,
почему  в  некоторых  ранних  моделях  микро-ЭВМ,  таких  как
первоначальная   модель  "Синклер-ZX80",  все  арифметические
действия  на  языке "Бейсик" ограничивались целыми числами из
диапазона  -32000  до  +32000.  Но даже несмтря на то, что мы
можем  выполнять  некоторые арифметические действия с помощью
двух  рук, наш заголовок этой главы содержит намек на то, что
будет  дальше.  Арифметические  действия над числами для двух
рук  несколько  менее  удобны, чем для одной руки. Не хватает
широкого спектра вариантов. 

               ПРИВИЛЕГИРОВАННАЯ ПАРА РЕГИСТРОВ

         Совершенно   так   же,   как   регистр   A  является
привилегированным  с точки зрения арифметических действий для
одной  руки,  есть  и  привилегированная  пара  регистров для
арифметических  действий  над  числами для двух рук. Это пара
регистров HL. Эта привилегированность не столь явно выражена,
как в случае 8-битовых чисел, так что мы не опускаем имя пары
регистров. 

                           СЛОЖЕНИЕ

            Операции сложения вполне прямолинейны:

                          ADD HL,DC
                          ADD HL,DE
                          ADD HL,HL
                          ADD HL,SP

но именно так они и записываются. 
         Обратите внимание, что не удается сложить абсолютное
число  с  HL.  Например,  не  допускается  ADD  HL,NN.  Чтобы
выполнить вычисления такого типа, нам нужно: 

                           LD DE,NN
                          ADD HL,DE

         Когда   вы  учтете,  что  теперь  у  нас  связанными
оказались  четыре из 8-битовых регистров, которых всего 7, вы
сразу  поймете,  что вы не захотите это делать слишком часто.
Обратите также внимание, что между HL и индексными регистрами
нельзя  выполнить  сложение.  Вы  также  вспомните,  что  нет
команды  LOAD, которая позволяла бы вам передавать содержимое
IX  или  IY  в  BC  или  DE,  так  что  единственным способом
выполнения такого сложения было бы: 

                           PUSH IX
                           POP  DE
                           ADD  HL,DE

         Один  из  моментов,  о котором следует упомянуть это
регистр  SP  -  указатель  стека.  Это одна из очень немногих
операций,в  которых  SP обрабатывается как настоящий регистр,
но   вы  не  можете  применять  его  в  качестве  переменной.
Подумайте,  что  случилось  бы со всеми командами POP и PUSH,
если  бы  вы произвольным образом меняли содержимое указателя
стека. 

                    ВОЗДЕЙСТВИЕ  НА  ФЛАГИ

         16-битовые  арифметические  операции - это именно та
область,  в  которой  флаг переноса играет присущую ему роль,
поскольку,  как  можно видеть из таблицы, помещенной в начале
этой  главы,  единственный  другой флаг, на который оказывает
влияние команда ADD (сложение) это флаг вычитания (и все, что
он  в  этом случае означает - это то, что команда сложения не
является  вычитанием.  Флаг  переноса  будет установлен, если
имеется переполнение в старшем бите H. Любое переполнение в L
автоматически помещается в результате вычисления в H. 

                     СЛОЖЕНИЕ С ПЕРЕНОСОМ

         Из-за  ограниченного  характера работы с 16-битовыми
числами  мы  можем  выполнять сложение цепочкой точно так же,
как и в 8-битовом случае. Команда "сложение с переносом" - ее
мнемоническое  обозначение  ADC  (ADD WITH CARRY) - действует
аналогично   команде   ADD   и  имеет  тот  же  диапазон  пар
регистров: 

                          ADC HL,BC
                          ADC HL,DE
                          ADC HL,HL
                          ADC HL,SP

                     16-БИТОВОЕ ВЫЧИТАНИЕ

         Это  тоже  достаточно простая операция, но вычитания
без  переноса не бывает: если вы не уверены в состоянии флага
переноса,  удостоверьтесь,  что  в  вашей  программе  имеется
строка,   очищающая  флаг  переноса  перед  каждой  операцией
вычитания 

                          SBC HL,BC
                          SBC HL,DE
                          SBC HL,HL
                          SBC HL,SP

(у последней команды имеется очевидное применение: установить
HL  на  конец  памяти, используемой вашей программой, экраном
дисплея и переменными; вычесть SP и результат (отрицательный)
будет  задавать  количество  свободной  памяти. Сможете ли вы
написать  простую программу, выполняющую все это? Посмотрев в
конец главы, вы сможете проверить свое решение). 

   ВОЗДЕЙСТВИЕ АРИФМЕТИЧЕСКИХ ОПЕРАЦИЙ С ПЕРЕНОСОМ НА ФЛАГИ

         Вы,   возможно,   заметили,  что  три  других  флага
изменяются  в  результате  команд  "сложение  с  переносом" и
"вычитание  с переносом", хотя они не изменялись в результате
простых  команд  16-битового сложения. Эти флаги - флаг нуля,
флаг знака и флаг переполнения. Каждый из них устанавливается
в соответствии с результатом операции. 

        АРИФМЕТИЧЕСКИЕ ОПЕРАЦИИ С ИНДЕКСНЫМ РЕГИСТРОМ

         Индексные  регистры  ограничиваются только операцией
сложения без переноса.Более того, диапазон регистров, которые
можно   складывать   с   индексными  регистрами,  чрезвычайно
ограничен: 
    - сложение с парой регистров BC или DE; 
    - сложение индексного регистра с самим собой; 
    - сложение с указателем стека. 

       УПРАЖНЕНИЕ НА РЕШЕНИЕ ЗАДАЧИ О СВОБОДНОЙ ПАМЯТИ

         Конец пространства памяти, используемого программой,
определяется  содержимым  ячейки памяти STKEND. В руководстве
по  "Спектрум"  она  определяется  адресами  23653  и  23654.
Очевидно,  если  мы  загрузим содержимое этой ячейки в HL, то
задача наполовину будет решена: 

                        LD HL,(STKEND)

         Затем  нужно вычесть "указатель стека" (SBC HL,SP?).
Из-за   переноса   нам  необходимо  очистить  флаг  переноса.
Наиболее  легко  это  достигается  с помощью команды "AND A",
рассмотренной в этой книге раньше. 

                            AND A
                            SBC HL,SP

         Можете считать задачу решенной на три четверти, если
вы  знали,  что  нужно  учесть  перенос,  но не знали как это
сделать.Если  вы  вовсе  забыли  о переносе, задача решена на
четверть. Поскольку указатель стека задает положение в памяти
выше,  чем  наибольший  адрес  вашей  программы  (иначе у вас
возникли    бы    серьезные   трудности),   результат   будет
отрицательным.  Теперь  давайте  получим  количество  байтов,
оставшихся свободными, в виде пололжительного числа с помощью
регистра BC (точно так же для этого подошел бы и регистр DE).
Сначала   мы   хотим   сдвинуть  HL  и  BC,  но  нет  команды
"загрузить".  Для  такого  действия нам придется использовать
последовательно команды PUSH и POP: 

                           PUSH HL
                            POP BC

         В HL по прежнему находится та же информация, так что
HL  =  BC.  Чтобы  получить  HL = -BC, нужно вычесть BC из HL
дважды  (но  не  забудьте,  что  флаг переноса только что был
установлен  командой  вычитания, так что его необходимо вновь
очистить): 

                          AND A
                          SBC HL,BC
                          SBC HL,BC

в  HL  теперь  содержится  отрицательное  значение, по модулю
равное   прежнему,   т.е.   положительное   число  оставшихся
свободными байтов. 
         Теперь  нам  нужно  получить  это число снова в паре
регистров  BC, чтобы получить результат из функции USR. Чтобы
получмть HL назад в BC: 

                           PUSH HL
                            POP BS

             и, наконец, возврат из функции USR:

                             RET

         Правильно ли вы написали программу? 
         Обратили  ли  вы  внимание,  как удобно пользоваться
стеком. 

                       ЦИКЛЫ И ПЕРЕХОДЫ

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

          ЭКВИВАЛЕНТ  "GO  TO"  НА  МАШИННОМ  ЯЗЫКЕ

         В  "Бейсике"  вы  знаете команду "GO TO", передающую
управление  вашей  программой  командам  в  той  строчке,  на
которую  указывает "GO TO". Нет ничего проще, чем реализовать
это  на  машинном  языке.  Просто  задайте  ячейку  памяти, в
которой  вы хотели бы чтобы ЦП обнаружил следующую команду, и
задача  наполовину решена. Наиболее простой вариант - команда
"перейти на" (JUMP TO) 

                           JP XX XX
                           JP (HL)
                           JP (IX)
                           JP (IY)

         Можно   сделать  так,  чтобы  одна  из  этих  команд
зависела  от  состояния  одного  из  флагов,  например, флага
переноса. Эта команда условного переноса имеет вид: 

                           JP CC,NN

где  CC - условие, выполнение которого проверяется. Если бы у
нас было, например, 

                          JP Z,0000

то  это  читалось  бы  "переход по адресу 000, если флаг нуля
установлен".  (Это адрес, по которому "Спектрум" осуществляет
переход  при  включении питания, и в таком виде команда JP на
нуль  может применяться в программе и на машинном языке, если
вы  захотели  очистить  всю  память и начать заново с помощью
"K"). 
         Теперь   обратите  внимание,  что  ЦП  не  допускает
никаких  ошибок.  Если  вы говорите JUMP, он сделает переход.
Поскольку  почти  любой код может быть воспринят как команда,
ЦП  не  принимает во внимание, что вы могли сделать переход в
середину  массива  данных  или  во  второй  байт двухбайтовой
команды:  он  будет  считывать  байт  по  найденному адресу и
считать,  что это - начало следующей команды. Способ, которым
ЦП  обрабатывает  команду  перехода  на самом деле совершенно
прост:  у  него  есть небольшой счетчик, называемый счетчиком
команд,  говорящий  ему,  где  искать  следующую  выполняемую
команду.  При  нормальном  ходе  программирования  (т.е.  без
переходов)  ЦП  проверяет  подлежащую  выполнению  команду  и
добавляет  к счетчику команд столько, сколько байтов содержит
команда.  Так,  если  он  встречает  2-байтовую  команду,  он
добавляет  2,  тогда  как  4-байтовая  команда  заставит  его
добавить 4 к счетчику команд. 
         Когда  он  встречает  команду  "перехода", он просто
замещает содержимое счетчика команд тем значением, которое вы
указали.  Именно поэтому вы не можете допустить проникновения
в программу каких-либо ошибок. 

             ДЛИННЫЕ ПЕРЕХОДЫ И КОРОТКИЕ ПЕРЕХОДЫ

         Мы    можем   считать   приведенные   выше   команды
эквивалентом  длинного  перехода  в машинном языке, поскольку
16-битовый  адрес  позволяет  нам осуществить переход в любое
место, куда позволяет перейти чип Z80. 
         Недостатки длинного перехода: 
а)часто  нам  нет  необходимости в таком длинном переходе, но
нам все-таки приходится применять 3-байтовую команду; 
б)мы  не можем без затруднений переместить программу в другую
часть памяти, потому что мы задаем абсолютный адрес. 
         Именно  для  преодоления  этих  двух недостатков был
введен   "короткий   переход".  Он  называется  относительным
переходом  и  позволяет  нам  совершать  переход  от  текущей
позиции  на +127 или на -128 байтов, т.е. расстояние перехода
можно задать в одном байте: 

          JP Д    - команда относительного перехода

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

                           JP CC,Д

где CC - проверяемое условие. 
         Значение  смещения  Д добавляется к счетчику команд.
Это  означает, что берется текущее значение счетчика команд и
к  нему прибавляется заданное вами относительное значение. Вы
можете  задавать  либо  положительное  (переход вперед), либо
отрицательное  (переход назад) значения. Если вы посмотрите в
предшествующей  главе об отрицательных числах, то вы поймете,
что   это   означает   ограничение   относительных  переходов
диапазоном от -128 до +127. 
         Обратите  внимание,  что  когда ЦП выполняет команду
относительного  перехода,  счетчик  команд  уже  указывает на
следующую  команду,  которая  выполнялась бы, если условие не
удовлетворялось.   Так   происходит   потому,  что  когда  ЦП
встречает  JP, он знает, что имеет дело с 2-байтовой командой
и  добавляет  2  к  счетчику  команд.  Поэтому счетчик команд
указывает на команду, следующую за относительным переходом. 
         Пример. В такой команде, как: 

                   ЯЧЕЙКА            ТЕКСТ
                   32000            ADD A,B
                   32001             JP Z,02H
                   32003             LD B,0
                   32005   NEXT      LD HL, 4000H

         Ниже  показано  как  ЦП  работает с этой программой,
если  игнорируется  команда перехода, расположенная по адресу
32001 (т.е. при сброшенном флаге нуля): 

                ЗАГРУЗИТЬ БАЙТ ПО АДРЕСУ 32000

         Поскольку в этом байте содержится команда, состоящая
только  из  одного  байта, счетчик команд нужно задать равным
32001. 

                      ВЫПОЛНИТЬ КОМАНДУ
       ЗАГРУЗИТЬ БАЙТ, ЗАДАННЫЙ СЧЕТЧИКОМ КОМАНД 32001

         Этот  байт будет являться частью 2-байтовой команды,
так  что  нужно  прибавить  2 к счетчику команд и сделать его
равным 32003. 

    ПОЛУЧИТЬ СЛЕДУЮЩИЙ БАЙТ, ЧТОБЫ СДЕЛАТЬ КОМАНДУ ПОЛНОЙ.
                      ВЫПОЛНИТЬ КОМАНДУ




СОДЕРЖАНИЕ:


  Оставте Ваш отзыв:

  НИК/ИМЯ
  ПОЧТА (шифруется)
  КОД



Темы: Игры, Программное обеспечение, Пресса, Аппаратное обеспечение, Сеть, Демосцена, Люди, Программирование

Похожие статьи:
Пролог - Новогодние приветствия.
Раскрутка - игры Dizzy 7, Вignose`s USA adventure.
Программистам - изучаем Бейсик (часть 4).
Мозаика - Гудков Иван о выпуске новой игры.
Part three - Вы мне должны деньги! - Извините, но это уже по моему усмотрению...

В этот день...   23 ноября