Подпрограммы как средство модульного программирования
В большинстве прикладных программ некоторые последовательности ко-манд встречаются не один раз,но оперируют разными данными.Такие после-довательности можно оформить в макрокоманды.Однако расширения мак-рокоманд целиком включаются в объектную программу и значительно уве-личивают ее длину.Гораздо удобнее включить повторяющуюся последова-тельность в объектную программу всего один раз,а в нужных точках вызы-вать ее для выполнения с текущими данными.Такая вызываемая последова-тельность команд,или своеобразная «программа в программе» называется подпрограммой или процедурой.
Подпрограмма представляет собой законченный модуль,который может вы-зываться любое число раз.Инициирование выполнения подпрограммы осущест-вляется путем указания ее имени в 3-байтной команде вызова CALL.Имя под-программы должно находиться в поле метки первой ее команды.При выполне-нии команды CALL текущее содержимое РС(адрес возврата) загружается в стек,а в РС загружается адрес перехода—второй и третий байт команды CALL. После этого начинает выполняться первая команда подпрограммы,затем вторая и т.д.Заключительной командой каждой подпрограммы должна быть 1-байтная команда возврата RET,которая извлекает адрес возврата из стека и передает его в РС.Следовательно,теперь будет выполняться команда,находящаяся в вызываю-щей программе сразу после команды CALL.
Практика программирования показывает,что целесообразно всегда запоми-нать содержимое регистров в начале и восстанавливать его в конце подпрог-рамм.Если,например, подпрограмма SUBR использует регистры А,В и С,она должна иметь следующий формат:
Метка Код Операнд Комментарий
SUBR: PUSH PSW ;Запоминание содержимого регист-
PUSH B ;ров в стеке
***
Команды подпрограммы
***
POP B ;Восстановление прежнего содержи-
POP PSW ;мого регистров
RET ;Возврат
Подпрограммы с таким форматом быстрее и проще отлаживать.Из-за специфики стека содержимое регистров восстанавливается в обратном порядке.
Примечание. В большинстве приводимых далее подпрограмм команды PUSH в начале и команды POP в конце подпрограммы не приводятся,так как они удлиняют листинги,но дают мало новой информации. При наличии команд PUSH и POP такие подпрограммы должны быть несколько модифицированы. Пусть,например,заключительный фрагмент подпрограммы имеет следующий вид:
Метка Код Операнд Комментарий
***
INR A
RZ
INX B
RET
Когда в подпрограмме требуется временное запоминание и восстановление содержимого регистров,этот фрагмент несколько изменяется:
Метка Код Операнд Комментарий
SUBR: PUSH PSW
PUSH H
***
INR A
JZ NOT
INX B
NOT: POP H
POP PSW
RET
Cпособы передачи параметров
При организации подпрограмм важно выбрать правильный способ передачи параметров.Например,при вызове подпрограммы деления DIVID необходимо передать ей делимое DVND и делитель DVSR, а сама подпрограм-ма должна возвратить частное QUOT. Делимое,делитель и частное представля-ют собой параметры,передаваемые между вызывающей программой и подпрог-раммой. В языках высокого уровня подпрограмма DIVID записывается следую-щим образом: DIVID (DVND, DVSR, QUOT).
DVND, DVSR и QUOT представляют собой фиктивные(формальные)па-раметры,в терминах которых составляются операторы собственно подпрограм-мы.При выполнении подпрограммы они заменяются другими переменны-ми,например,можно вызвать DIVID(NUM1,NUM2,RLST). Текущие значения переменных NUM1,NUM2, и формируемое значение RLST заменяют собой формальные параметры и называются фактическими (действительными) пара-метрами.
Для МП-систем разработано несколько способов передачи параметров, основные из которых рассматриваются ниже.
Общие данные
Понятие общих(глобальных) данных относится к данным,хранимым в тех ячейках памяти,к которым могут обращаться вызывающая программа и подпро-грамма.Например,при использовании подпрограммы деления DIVID две смеж-ные ячейки памяти с адресом DVND можно выделить для хранения 16-битового делимого,ячейку с адресом DVSR - для хранения 8-битного делителя,а сама подпрограмма должна формировать частное в ячейке с адресом QUOT.
Внутренние регистры
Второй способ заключается в передаче параметров во внутренних регистрах микропроцессора. Например,перед вызовом подпрограммы деления делимое загружается в регистры (H,L),а делитель – в регистр В.После вызова программа выполняет необходимые действия и возвращает результат в опреде-ленный регистр(регистры) микропроцессора. К примеру, частное может форми-роваться в регистре L,а положительный остаток – в регистре H.Основной недо-статок данного способа заключается в жестких ограничениях на число переда-ваемых параметров. В большинстве проводимых далее программ предполагается передача параметров через внутренние регистры, что несколько сокращает дли-ну листингов подпрограмм.
ОБЛАСТЬ ПАРАМЕТРОВ
Передача параметров через специально выделенную область ОП осуществля-ется следующим образом. Вызывающая программа до вызова подпрограммы записывает параметры в последовательных ячейках области параметров. Затем начальный адрес области загружается в один из указателей памяти микропро-цессора, чаще всего в регистры (H,L).Команда вызова CALL запоминает в стеке адрес возврата и передает управление первой команде подпрограммы.Информа-ция о нахождении параметров доступна подпрограмме,так как регистры (H,L) адресуют начало области параметров.С помощью команд MOV r ,М значения параметров считываются во внутренние регистры микропроцессора и обраба-тываются подпрограммой. В качестве недостатка этого способа отметим необ-ходимость выделения отдельной области параметров для каждой подпрограммы.
Иногда передавать параметры в смежных ячейках памяти по каким-либо причинам неудобно. В таких ситуациях целесообразно применить передачу подпрограмме адресов параметров, оформленных в виде таблицы. Перед вызо-вом подпрограммы начальный адрес ТВL таблицы адресов загружается в регистры (H,L).В подпрограмме адреса загружаются во внутренний указатель памяти, после чего производится считывание из памяти собственно значений параметров.