Polesse #07
25 мая 1999

Ассемблер - Стек, мнемоника - CALL...

┌──────────────────────────────────────────────────────────────┐
│ ████▓▓▓▓▒▒▒▒░░░░ АССЕМБЛЕР ДЛЯ НАЧИНАЮЩИХ  ░░░░▒▒▒▒▓▓▓▓█████ │
└──────────────────────────────────────────────────────────────┘

(C) THINKER
───────────

╔══════╗
│ СТЕК │  Это очень важное для программиста понятие, так что чи-
╚══════╝  тайте  внимательно,  а  я  постараюсь  объяснить,  как
можно понятнее. Допустим, Вам необходимо выполнить  какую-нибудь
процедуру, при этом рег. 'A' там используется, значит в нем пос-
ле выхода будет содержаться какое-то число,  а нам нужно,  чтобы
после  выполнения  процедуры рег. 'A' и рег. 'B' содержали те-же
значения,  что и перед этим.  Что делать?  Можно сохранить акку-
мулятор (так называют рег. 'A', помните?)  в какой-нибудь ячейке
памяти, тогда наша программка будет выглядеть так:

    LD   A,10       ; в 'A' заносим число 10
    LD   B,25       ; в 'B' заносим число 25
    LD   (65000),A  ; в ячейку памяти с адресом 65000 заносим
                    ; значение рег. 'A'
    LD   A,B        ; в рег. 'A' заносим значение рег. 'B'.
                    ; (Ведь в памяти мы можем оперировать только
                    ; с рег. A!)
    LD   (65001),A  ; в ячейку пямяти с адресом 65001 ложим 'А'
    CALL PROGR      ; переходим к подпрограмме (равносильно
                    ; RANDOMIZE USR PROGR, где PROGR - адрес)
    LD   A,(65001)  ; заносим в 'A' значение из ячейки памяти с
                    ; адресом 65001
    LD   B, A       ; заносим в 'B' содержимое рег.'А'
    LD   A, (65000) ; теперь в рег. 'B' у нас снова число 25, а
                    ; в рег. 'A' - 10
    RET             ; возврат

   Но можно было использовать и стек.  Для  этого существует две
мнемоники: PUSH ss и POP ss. PUSH ss сохраняет в стеке рег. пару
ss, а POP ss - вытаскивает. Для того, чтобы представить, как все
это  работает вообразим  себе  некий стакан,  куда падают числа.
Стакан - это наш стек,  a числа - это значения рег. пар.  В стек
можно заносить больше, чем  одну  рег. пару,  при этом,  если мы
сохранили три рег. пары, для того, чтобы вытащить первую нам не-
обходимо вытащить две последние. То есть, принцип "первым вошел,
последним вышел" - основной принцип машинного стека.
   Теперь перепишем нашу программку с использованием стека: ──┐
                                                              │
                Пояснения:                                    │
                                              ╔═══════════════╣
   Сохраняем в стеке регис-    LD     A,10  LD     A,10тровую пару  'AF',  ведь мы    LD     B,25  LD     B,25можем сохранять  там только    PUSH   AF    PUSH   AF пары. Вот, что происходит в   PUSH   BC стеке.  CALL   PROGR  POP    BC      AF──┐                              POP    AF      ║░▒▓1▓▒░║   ║       ║              RET         │       │   │       │                    ╚═══════════════╝
     │       │   │       │
     │       │   │░▒▓1▓▒░│
     ▀▀▀▀▀▀▀▀▀   ▀▀▀▀▀▀▀▀▀

   Теперь сохраняем в стеке 'BC':          BC──┐
                                               │
           PUSH   BC                       ║▓▒░2░▒▓║   ║       ║
                                           │       │   │       │
   Выполняем подпрограмму CALL PROGR,      │       │   │▓▒░2░▒▓│
вытаскиваем из стека 'BC':                 │░▒▓1▓▒░│   │░▒▓1▓▒░│
                                           ▀▀▀▀▀▀▀▀▀   ▀▀▀▀▀▀▀▀▀
           POP   BC                  

   Вытаскиваем из стека 'AF':                              ┌──AF
                                                           │
           POP   AF                        ║       ║   ║▓▒░2░▒▓║
                                           │       │   │       │
                     ┌──AF                 │▓▒░2░▒▓│   │       │
                     │                     │░▒▓1▓▒░│   │░▒▓1▓▒░│
     ║       ║   ║░▒▓1▓▒░║                 ▀▀▀▀▀▀▀▀▀   ▀▀▀▀▀▀▀▀▀
     │       │   │       │
     │       │   │       │     Обратите  внимание,  как работает
     │░▒▓1▓▒░│   │       │  принцип "LIFO" - "Last Input - First
     ▀▀▀▀▀▀▀▀▀   ▀▀▀▀▀▀▀▀▀  Output ( "Последним  пришел - первым
                            вышел").
           RET

╔═══════╗
│CALL ss│  Этими  мнемониками мы уже пользовались раньше,  но не
│  RET  │  вникали  в  сущность  работы.  Вот  что  происходит в
╚═══════╝  продессе выполнения этих команд:

   CALL  - в стек заносится адрес следующей за CALL команды, по-
том  выполняется переход  на адрес ss.  Команда CALL  может быть
условной, при этом  условие определяется так-же, как и в JP (JR)
(CALL Z,ss ; CALL  NZ,ss).
   RET - из стека извлекается число и происходит переход на этот
адрес.  Команда  RET  может  быть  условной,  при  этом  условие
определяется так-же как в JP (JR) и CALL (RET Z ; RET NZ).
   Из этого следует:   для того, чтобы нормально возвратиться из
подпрограммы, необходимо перед выходом сделать стек таким, каким
он был при выполнении CALL.  Например,  нам необходимо занести в
рег. 'B' число "3",  а с помощью подпрограммы  TEST,  в рег. 'C'
число, которое содержится  в ячейке памяти  23560, при этом рег.
'A' должен остаться без изменений:

┌──────ВЕРНО:───────┐ ┌-----------------НЕВЕРНО:---------------┐
│     LD   B,3      │ |      LD   B,3      |     LD    B,3     |
│     CALL TEST     │ |      CALL TEST     |     CALL  TEST    |
│     RET           │ |      RET           |     RET           |
│TEST PUSH AF       │ |TEST  PUSH AF       |TEST LD   A,(23560)|
│     LD   A,(23560)│ |      LD   A,(23560)|     LD   C,A      |
│     LD   C,A      │ |      LD   C,A      |     POP  AF       |
│     POP  AF       │ |      RET           |     RET           |
│     RET           │ └----------------------------------------┘
└───────────────────┘

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

╔═══════╗
│ INC s │  Операция инкремента. Увеличивает рег. s или рег. пару
╚═══════╝  s на единицу.1 (s-A,B,C,D,E,HL,BC,DE и еще некоторые,
           о которых вам знать пока необязательно).
╔═══════╗
│ DEC s │  Операция декремента. Уменьшает рег. s или рег. пару s
╚═══════╝  на единицу.

╔═══════╗
│  LDI  │  Очень полезная мнемоника процессора.  После получения
╚═══════╝  этой команды  компьютер действует по следующему алго-
           ритму:

   1) Заносится число из памяти с адресом 'HL' в ячейку памяти с
      адресом 'DE'
   2) Увеличивается 'HL' на 1        [ (HL) -> (DE) ]
   3) Увеличивается 'DE' на 1        [  HL+1 -> HL  ]
   4) Уменьшается 'BC' на 1          [  DE+1 -> DE  ]
   5) Если BC=0, устанавлива-        [  BC-1 -> BC  ]
      ется флаг P/V, иначе он         <    BC=0 ?    >
      сброшен                      ДА        │         НЕТ
                                   ┌─────────┴──────────┐
                             [ (f) P/V=0 ]        [ (f) P/V=1 ]
╔═══════╗
│  LDD  │  Тоже самое, что и LDI, только в пунктах 2) и 3)  рег.
╚═══════╝  пары не увеличиеаются, а уменьшаются.

╔═══════╗
│ LDIR  │  Еще более полезная команда - пересылка блока памяти с
╚═══════╝  увеличением адресов. Вот ее алгоритм:

   1) Заносится число из памяти с адресом 'HL' в ячейку памяти с
      адресом 'DE'.
   2) Увеличивается 'HL' на 1                    ┌────────┐
   3) Увеличивается 'DE' на 1            [ (HL) -> (DE) ] │
   4) Уменьшается 'BC' на 1              [  HL+1 -> HL  ] │
   5) Если BC<>0, следует переход        [  DE+1 -> DE  ] │
      на пункт 1                         [  BC-1 -> BC  ] │
                                          <    BC=0?   >  │
                                                 ├───НЕТ──┘
                                                Д│А
┌-----------------------------┐                  │
|В сущности LDIR соответствует|                КОНЕЦ
|    следующей программке:    |
|                             |   Проиллюстрируем  практическое
|    LABEL  LDI               |  применение LDIR. Например, нам
|           JR   PE,LABEL     |  нужно вывести на экран область
|           RET               |  памяти длиной 6144 байт,
└-----------------------------┘  начиная с 0:

                  LD   DE,0      ; ОТКУДА
                  LD   HL,16384  ; КУДА
                  LD   BC,6144   ; СКОЛЬКО
                  LDIR
                  RET


   Теперь предлагаю Вашему вниманию маленькую несложную програм-
мку, действие которой, Вы увидите на экране после нажатия клавиш
<6> или <7>.   Постарайтесь  понять,  что  она делает, объясните
каждую мнемонику, потом перепишите ее сами, по памяти, составляя
заново.

           IM    0         ; включаем опрос клавиатуры, устанав-
           EI              ; ливаем режим, разрешаем прерывания.
           LD    HL,5000
           PUSH  HL

OPROS      LD    A,(23560)
           CP    "6"
           JR    Z,LEFT
           CP    "7"
           JR    Z,RIGHT
           CP    " "
           JR    Z,EXIT
           JR    OPROS

EXIT       POP   HL
           RET

LEFT       POP   HL
           INC   HL
           PUSH  HL
           CALL  PRINT
           JR    OPROS

RIGHT      POP   HL
           DEC   HL
           PUSH  HL
           CALL  PRINT
           JR    OPROS

PRINT      LD    DE,#5800
           LDIR
           RET

________________________________________________________________

   Ну что-ж, я думаю на сегодня достаточно. Увидимся в следующем
номере.  Если при изучении данного материала у Вас возникнут ка-
кие-либо вопросы,  обращайтесь в редакцию "Полесья" либо найдите
другой способ со мной связаться. До новых встреч.





Другие статьи номера:

Ассемблер - Стек, мнемоника - CALL...

В паутине - График работы городских серверов.

Навезли новья - Обзор новинок ПО: Super Laser Squad, Gambit, Take It, Nether Earth + 22 Level, TrmsHob, Real Commander v1.61 & 1.7, Best View v2.8.

Рек-тайм - Реклама и объявления ...

События, факты - Завершение работы над трехлетним проектом Crime Santa Clause Deja Vu.


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

Похожие статьи:
Взгляд - Взгляд с платформы (о игре "8-ОТДЕЛ").
Розыск - Разыскиваются: PREFCLUB & APOLLO.
Я не слабоумный - задача была хитро придумана, но я ее одолел. Готово!

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