2. Исследование команды вызова подпрограммы и возврата из нее
При записи программы на языке Ассемблера для вызова подпрограммы используется команда с мнемоникой CALL label, где label – это метка, соответствующая первой команде подпрограммы. Обычно имя этой метки соответствует имени (названию) подпрограммы. Возврат из подпрограммы выполняется по команде RET. Эти команды являются безусловными.
2.1. Создайте в Вашей папке файл с именем count.asm и запишите в него текст программы, которая определяет количество единиц в ячейке памяти данных. Адрес ячейки вводится из порта P1, а результат подсчета выводится в порт P2. Процедура определения количества единиц в байте осуществляется подпрограммой с именем BYTE. В подпрограмме используется регистр R0 для передачи входного параметра – адреса ячейки памяти данных, из которой берется байт для анализа. Выходной параметр подпрограммы – это регистр R1, в котором находится подсчитанное число единиц.
COUNT: MOV SP, # 38H ; Определить стек
MOV P2, #0 ; Вывести нули в порт P2
MOV R0, P1 ; Ввод адреса байта из порта P1
CALL BYTE ; Вызов подпрограммы подсчета единиц в байте
MOV P2, R1 ; Вывод количества единиц в порт P2
JMP $ ; Зацикливание программы
BYTE - подпрограмма подсчета единиц в байте
Входной параметр регистр R0 – адрес байта в ПД
Выходной параметр регистр R1 – количество единиц в байте
BYTE: MOV R7, #8 ; Загрузить счетчик разрядов байта
MOV R1, #0 ; Очистить счетчик единиц
MOV A, @R0 ; Пересылка байта в аккумулятор
CLR C
SHIFT: RRC A ; Сдвиг байта вправо через перенос
JNC MET1 ; Переход, если C=0
INC R1 ; Инкремент счетчика единиц
MET1: DJNZ R7, SHIFT ; Цикл сдвига, если (R7) 0
RET ; Возврат из подпрограммы
END ; Конец текста программы
Получите файлы count.obj и count.hex. Запустите симулятор AVSIM51 и загрузите в него файл для отладки. Перед выполнением программы запишите на вход порта P1 адрес ячейки ПД, где будет анализируемый байт (произвольное число в диапазоне от 08H до 37H). Затем занесите по указанному адресу произвольное число в ячейку ПД. Например, на входе порта запишите 20H, а в ячейку с адресом 0020H (дамп 2 на экране) занесите число 55H = 01010101.
Выполните программу в пошаговом режиме, наблюдая за изменением указателя стека и областью стека при вызове и возврате из подпрограммы. Повторите программу при других исходных данных в автоматическом режиме. Убедитесь в правильности ее работы.
2.2. Часто подпрограммы используют те же регистры, что и основная программа. Поэтому необходимо сохранять содержимое регистров основной программы на время работы подпрограммы. Можно сохранять регистры в стеке при входе в подпрограмму, а затем восстанавливать их содержимое перед выходом из подпрограммы. Однако, часто более удобным и коротким способом сохранения регистров является переключение банков регистров на время выполнения подпрограммы.
Рассмотрим программу, которая заполняет массив ячеек памяти данных константой, а затем подсчитывает контрольную сумму этого массива. Адрес начала массива вводится из порта P0, количество элементов (ячеек) массива вводится из порта P1, а значение константы – из порта P2. Результат работы программы – контрольная сумма выводится в порт P3. Основная программа использует регистры банка 0. Процедуру заполнения ячеек массива константой необходимо оформить как подпрограмму, которая использует регистры 1-го банка. После заполнения всех ячеек константой подпрограмма должна установить флаг F0. Подсчет контрольной суммы массива также необходимо оформить в виде подпрограммы, которая использует регистры 2-го банка. После выполнения всех указанных действий основная программа должна зациклиться.
Создайте в Вашей папке файл с именем check.asm и занесите в него текст программы
CHECK: MOV SP, #38H ; Определить стек
MOV P3, #0 ; Вывести нули в порт P3
MOV R0, P0 ; Ввод из порта P0 начального адреса массива
MOV R1, P1 ; Ввод из порта P1 количества элементов массива
MOV R2, P2 ; Ввод из порта P2 значения константы
CLR F0 ; Сбросить флаг F0
CALL FILL ; Вызов подпрограммы заполнения массива константой
CALL SUM ; Вызов подпрограммы подсчета контрольной суммы
MOV P3, A ; Вывод контрольной суммы в порт P3
JMP $ ; Зацикливание основной программы
; FILL – подпрограмма заполнения массива ячеек ПД константой
Входные параметры ячейка с адресом 00H – начальный адрес массива
ячейка с адресом 01H – количество элементов
ячейка с адресом 02H – значение константы
Выходной параметр флаг F0 – равен единице, если заполнение массива выполнено
Используется 1-й банк РОН
FILL: SETB RS0 ; Выбрать 1-й банк РОН
MOV R0, 00H ; Загрузить указатель адреса ячеек
MOV R7, 01H ; Загрузить счетчик элементов массива
LOOP: MOV @R0, 02H ; Пересылка константы в ячейку массива
INC R0 ; Адрес следующего элемента
DJNZ R7, LOOP ; Цикл записи, если (R7) 0
SETB F0 ; Установить F0=1
CLR RS0 ; Переход в 0-й банк РОН
RET Возврат из подпрограммы
; SUM – подпрограмма подсчета контрольной суммы массива ячеек ПД
Входные параметры ячейка с адресом 00H – начальный адрес массива
ячейка с адресом 01H – количество элементов
Выходной параметр регистр A – контрольная сумма массива
Используется 2-й банк РОН
SUM: SETB RS1 ; Выбор 2-го банка РОН
MOV R0, 00H ; Загрузить указатель адреса
MOV R7, 01H ; Загрузить счетчик элементов
CLR A ; Очистить аккумулятор
CYCLE: ADD A, @R0 ; Суммирование аккумулятора с содержимым ячейки
INC R0 ; Адрес очередного элемента массива
DJNZ R7, CYCLE ; Цикл суммирования, если (R7) 0
CLR RS1 ; Переход в 0-й банк РОН
RET Возврат из подпрограммы
END ; Конец текста программы
Получите файлы check.obj и check.hex. Запустите симулятор и загрузите в него файл для отладки. Перед выполнением программы отключите отображение меток и занесите исходные данные на входы портов. Адреса ячеек массива ПД – в диапазоне от 20H до 37H. Количество элементов в массиве – от 04H до 08H, а значение константы – 01H до FFH. Выполните программу в пошаговом режиме, наблюдая за переключением банков регистров (по значениям в RB), регистра-указателя стека и областью стека, а также ячейками памяти данных. Следите за выполнением каждой команды программы – это очень важно! Убедитесь в правильности работы программы. Затем осуществите прогон программы в автоматическом режиме, задав новые исходные данные.
