Рекурсивной процедурой называется такая процедура, которая содержит вызов самой себя. Для построения такой процедуры необходимо выполнить несколько требований, а именно: обеспечить ограничение глубины вложенности вызовов процедуры, т.к. в противном случае процедура будет вызывать саму себя до бесконечности; зарезервировать для стека достаточно памяти, чтобы ее хватило на запоминание адресов возврата и параметров, которые передаются процедуре через стек для всех вложенных вызовов. Исследовать особенности вычислений] выражения с факториалом “Z = X!/Y” по программе N3 ,|где X, Y — независимые переменные, Z — результат, представленный в виде двух слов: частного и остатка от деления.
1) Введите программу N 3 (рис. 4.8) в память микро-ЭВМ, начиная с адреса 0000h:0100h (см. п. 2.2.1).
Адрес Содержимое Команда Комментарий
CS:0100 FA CLI ;Замаскировать прерывания
CS:0101 B84001 MOV AX,140h ;Установить адрес процедуры
CS:0104 A30000 MOV [0],AX ;обработки прерывания при
CS:0107 8CC8 MOV AX,CS ;переполнении для команд
CS:0109 A30200 MOV [2],AX ;деления на DIV и IDIV
CS:010C FB STI ;Включить систему прерываний
CS:010D FF360002 PUSH [200h] ;Включить в стек аргумент
CS:0111 E86C00 CALL 180h ;и вызвать процедуру
CS:0114 7210 JS 126h ;Переход при переполнении.
CS:0116 31D2 XOR DX,DX ;Разделить результат в AX на
CS:0118 F7360202 DIV [202h] ;число в DS:[202h] (слово)
CS:010C 803E040200 CMP [204h],0 ;Если при делении произошло
CS:0121 7503 JNZ 126h ;переполнение, то переход,
CS:0123 CC JNT 3 ;иначе прерывание 3.
CS:0124 EBDA JMP 100h ;Переход на начало программы
CS:0126 CC INT 3 ;Отладочное прерывание.
CS:0127 FE0E0402 DEC [204h] ;Восстановить счетчик.
CS:012B EBD3 JMP 100h ;Переход на начало программы.
CS:0140 FE060403 INS 204h ;Процедура обработки преры-
CS:0144 CF IRET ;вания при переполнении. …
CS:0180 55 PUSH BP ;Сохранить BP и установить
CS:0181 89E5 MOV BP,SP ;для доступа к аргументу.
CS:0183 8B4604 MOV AX,[BP+4] ;Загрузить в АХ аргумент.
CS:0186 3D0100 CMP AX,1 ;Если аргумент равен 1,
CS:0189 740C JE 197h ;то результат равен 1.
CS:018B 48 DEC AX ;Иначе включить в стек аргу-
CS:018C 50 PUSH AX ;мент, уменьшенный на 1.
CS:018D E8F0FF CALL 180h ;Вызов этой же процедуры.
CS:0190 7205 JC 197h ;Переход по переполнению.
CS:0192 52 PUSH DX ;Выполнить умножение АХ
CS:0193 F76604 MUL [BP+4] ;на значение аргумента
CS:0196 5A POP DX ;(CF =1, если DX не равно 0).
CS:0197 5D POP BP ;Восстановить ВР
CS:0198 C20200 RET 2 ;Возврат с очисткой стека.
…
DS:0200 03 05 00 00 00 ;Данные для программы.
Рис. 4.8. Программа N 3
2) Для подготовки программы к выполнению занесите в регистры процессора и ячейки памяти данные, необходимые для выполнения программы (см. п. 2.2.2): в сегментный регистр CS — начальный адрес используемого сегмента кода (OOOOh); в сегментный регистр DS начальный адрес сегмента данных (OOOOh); в ячейки памяти DS:[200h] и DS:[204h] соответственно значения X и Y; обнулите счетчик прерываний по ошибкам деления DS:[204h].
3) Выполните введенную ранее в память программу в пошаговом режиме (см. п. 2.2.3). Контролируйте содержимое регистров процессора по ходу выполнения программы.
4) Выполните программу в режиме автоматического выполнения, (см. п. 2.2.5), изменив исходные данные (содержимое ячеек памяти с адресами DS:200h, DS:202h и обнулив DS:204h). Добейтесь возникновения переполнения разрядной сетки при вычислении факториала и прерывания при делении. Полученные при этом значения исходных переменных X, Y и результата Z запишите в отчет. Объясните полученные результаты.
5) Выполните команду деления по циклам шины, для чего занесите в ячейку DS:202h число 0 (деление на нуль), выполните программу до команды деления в пошаговом режиме, а затем перейдите в режим выполнения по циклам шины (см. примечание к п. 2.2.6).
Запишите в отчет полученное при этом состояние системной шины, включая возврат из процедуры обработки прерывания ошибок деления.
6) Получите состояние стека при вычислении факториала числа 3 (три вложенных вызова процедуры с адресом CS:180h). Объясните полученные результаты.
