2.5.1. Безусловный вызов.
Дополнительно к прямым командам вызова подпрограмм, реализованным в системе команд процессора, программисты часто применяют непрямой вызов подпрограмм с помощью промежуточной вызывающей программы. В этом случае вызов выполняется вызовом этой промежуточной программы, например, CALL TRANS. Вместо TRANS, конечно стоит ее двухбайтный адрес. Далее процедура TRANS передает управление вызываемой программе. Это выполняется уже не через CALL, а через JP. Возврат выполняется из вызываемой подпрограммы, в конце которой стоит команда RET.
Типовые конструкции процедуры TRANS, в зависимости от того, как передается адрес вызываемой программы, приведены ниже.
211. Адрес вызова передается через HL. TRANS JP (HL)
в индексном регистре.
JP (xy) в DE. EX DE, HL JP (HL) в BC. LD H, B LD L, C JP (HL)
ИЛИ
PUSH BC RET
Второй вариант работает медленнее, зато не портит HL 215. Адрес в адресах ADDR и ADDR+1. TRANS: LD HL,(ADDR)
JP (HL)
212 Адрес TRANS 213. Адрес TRANS
2.5.2. Условный вызов.
Команды вызова подпрограмм по условию могут быть расширены
так же, как мы это сделали с командами условного перехода. Единственное изменение, которое надо сделать - это поменять команды перехода на команды вызова. Например, вместо JR NZ,ADDR надо поставить CALL NZ, ADDR или вместо JP P,ADDR - CALL P,ADDR.
2.6. КОНСТРУКЦИИ ВОЗВРАТА
2.6.1. Безусловный возврат.
Инструкция RET автоматически выполняет переход в адрес, который находится на вершине стека. Если же Ваш адрес возврата находится где-либо в другом месте (например в регистровой паре или, скажем в двух ячейках памяти) , то передать туда управление можно исполнением перехода с косвенной адресацией.
2.6.2. Возврат по условию.
Возврат по условию для Z-80 выполняется конструкциями, аналогичными конструкциям условного перехода. Надо только заменить мнемонику JR или JP на RET и не давать адрес перехода.
Например, RET NC вместо JP NC, NN
RET N вместо JP N,NN
2.6.3. Возврат со смещением.
Возможен случай, когда Вам надо выполнить возврат не точно по адресу, находящемуся на вершине стека, а несколько отступя от него, например, чтобы пропустить какие-либо данные, параметры, списки и т.п. неисполнимые вещи.
POP DE адрес возврата помещается в DE
LD HL,NN в HL загружается величина смещения
ADD HL,DE вычисляется новый адрес возврата
JP (HL) переход по рассчитанному адресу
Возможен вариант, когда Вы не хотите возвращаться по адресу, содержащемуся на вершине стека, а планируете переход по
другому адресу, скажем NN. Тогда можете действовать так:
LD HL,NN загрузка в HL нового адреса возврата
EX HL, (SP) обмен между HL и указателем стека. Теперь на
стеке содержится новый адрес возврат.
2.6.4. Возврат после прерывания.
Поскольку обычно работа процедуры обработки прерываний начинается с того, что запоминается на стеке содержимое всех
то и возврат после прерывания должен производиться с
восстановлением этих регистров, причем строго противоположен порядку сохранения порядок восстановления Например:
В ПРЕРЫВАНИЕ |
ВЫХОД |
ИЗ |
PUSH |
AF |
POP |
IY |
PUSH |
BC |
POP |
IX |
PUSH |
DE |
POP |
HL |
PUSH |
HL |
POP |
DE |
PUSH |
IX |
POP |
BC |
PUSH |
IY |
POP |
AF |
|
|
EI |
|
|
|
RETI |
|
разрешение возврат
2.7. ПРОЧИЕ КОНСТРУКЦИИ 2.7.1. Пауза.
Процессор имеет команду NOP, которая ничего не делает, кроме как увеличивает на единицу содержимое программного счетчика (регистр PC) .
Того же результата можно добиться и другим путем. Вот список команд, которые тоже не выполняют никакие действия: LD A,A LD B,B LD C,C LD D, D
LD E, E LD H, H LD L, L
216. Сохранение на стеке одиночного регистра.
PUSH reg PUS H rp сохранение ре гистров ой пары
INC SP отбрасывание младшего байта
217. Сохранение на стеке содержимого ячейки памяти. PUSH (ADDR) LD A, (ADDR) поместить в аккумулятор
содержимое ячейки памяти PUSH AF сохранение содержимого пары AF
INC SP отбросить содержимое флагового
регистра
218. Сохранение на стеке содержимого двух идущих подряд ячеек памяти ADDR, ADDR+1.
LD HL,(ADDR) содержимое заданного адреса
помещается в регистр HL PUSH HL сохранение на стеке
219. Сохранение на стеке состояния триггера прерываний IFF
LD A, I после такой операции состояние
триггера прерываний заносится во флаг Р/О микропроцессора PUSH AF сохранение флагового регистра
220. Вызов со стека содержимого одиночного регистра (при условии, что он был сохранен там так, как указано в п. 217) .
DEC SP указатель стека переводится на
одну позицию вверх POP rp вызов содержимого стека в
регистровую пару (содержимое младшего байта пары остается неопределенным)
221. Вызов со стека содержимого одной ячейки памяти.
DEC SP POP AF
LD (ADDR) ,A в результате работы этой
конструкции непредсказуемо изменение флагов регистра F
222. Вызов со стека содержимого двух ячеек памяти.
POP HL
LD (ADDR) , HL
223. Восстановление режима прерываний таким, каким он был до сохранения на стеке.
POP AF восстановление флагового
регистра
переход на включение запрещение прерываний выход"
переход на разрешение прерываний выход на процедуры
2.7.3. Конструкции десятиричной арифметики в двоичном
выражении (BCD-арифметики).
224. Проверка на то, что в аккумуляторе содержится полноценное десятиричное число.
LD reg, A ADD A,0
DAA перевод содержимого
аккумулятора в BCD-арифметику аккумулятор изменился? если изменился, то в нем было не десятиричное число и выполняется переход на заданный адрес NN 22 5. Десятиричное приращение аккумулятора. ADD A,1 DAA
22 6. Десятиричное уменьшение аккумулятора. SUB A, 1 DAA
JP PE,ON DI
JR EXIT
EI
NOP
Можно применять и такую конструкцию: ADD A,99 DAA
исполнение копии аккумулятора
227. Таблица однобайтных величин. В регистровой паре HL содержится базовый адрес таблицы, а в аккумуляторе - порядковый номер элемента в этой таблице. Требуется поместить в аккумулятор содержимое данного элемента.
LD E, A
LD D,0 аккумулятор конвертируется в
16-битный индекс ADD HL,DE определен адрес элемента
LD A, (HL) помещаем заданный элемент в A
Эта процедура обычно используется, когда надо произвести какую-либо перекодировку данных.
22 8. Таблица двухбайтных элементов. Базовый адрес находится В HL. В аккумуляторе - порядковый номер элемента. Требуется
найти этот элемент и поместить его в регистровую пару HL.
EX DE,HL базовый адрес переносится в DE
преобразование индекса в 2-байтный
удвоение индекса (необходимо потому, что в таблице двухбайтные числа и адрес элемента относительно начала таблицы вдвое больше номера элемента)
расчет адреса элемента взять младший байт перейти к старшему байту таблицы
взять старший байт передать результат в HL
LD L, A LD H, 0
ADD HL, HL
ADD HL, DE LD E, (HL) INC HL
LD D, (HL) EX DE, HL
Примечание: здесь удвоение применялось инструкцией ADD HL,HL, в то время как можно было бы сразу дать ADD A,A. Дело в том, что ADD A,A работает в дополнительной двоичной арифметике, и потому результат будет верен только для байтов от 0 до 127, а ADD HL,HL позволяет использовать любое однобайтное число.