ПОДПРОГРАММЫ И СТЕК

В программировании часто встречаются ситуации, когда одинаковые дейст­вия необходимо выполнять многократно в разных частях программы (напри­мер, вычисление функции sin*). При этом с целью экономии памяти не сле­дует многократно повторять одну и ту же последовательность команд — дос­таточно один раз написать так называемую подпрограмму (в терминах языков высокого уровня — процедуру) и обеспечить правильный вызов этой подпро­граммы и возврат в точку вызова по завершению подпрограммы.

Для вызова подпрограммы необходимо указать ее начальный адрес в памяти и передать (если необходимо) параметры — те исходные данные, с которыми будут выполняться предусмотренные в подпрограмме действия. Адрес под­программы указывается в команде вызова call, а параметры могут переда­ваться через определенные ячейки памяти, регистры или стек.

Возврат в точку вызова обеспечивается сохранением адреса текущей коман­ды (содержимого регистра PC) при вызове и использованием в конце подпро­граммы команды возврата ret, которая возвращает сохраненное значение ад­реса возврата в PC.

Для реализации механизма вложенных подпрограмм (возможность вызова подпрограммы из другой подпрограммы и т. д.) адреса возврата целесообраз­но сохранять в стеке. Стек ("магазин") — особым образом организованная безадресная память, доступ к которой осуществляется через единственную ячейку, называемую верхушкой стека. При записи слово помещается в вер­хушку стека, предварительно все находящиеся в нем слова смещаются вниз на одну позицию; при чтении извлекается содержимое верхушки стека (оно при этом из стека исчезает), а все оставшиеся слова смещаются вверх на одну позицию. Такой механизм напоминает действие магазина стрелкового ору­жия (отсюда и второе название). В программировании называют такую дис­циплину обслуживания LIFO (Last In First Out, последним пришел — первым вышел) в отличие от дисциплины типа очередь— FIFO (First In First Out, первым пришел — первым вышел).

В обычных ОЗУ нет возможности перемещать слова между ячейками, поэто­му при организации стека перемещается не массив слов относительно неподвижной верхушки, а верхушка относительно неподвижного массива. Под стек отводится некоторая область ОЗУ, причем адрес верхушки хранится в специ­альном регистре процессора — указателе стека SP.

В стек можно поместить содержимое регистра общего назначения по команде push или извлечь содержимое верхушки в регистр общего назначения по команде pop. Кроме того, по команде вызова подпрограммы call значение программного счетчика PC (адрес следующей команды) помещается в вер­хушку стека, а по команде ret содержимое верхушки стека извлекается в PC. При каждом обращении в стек указатель SP автоматически модифицируется.

В большинстве ЭВМ стек "растет" в сторону меньших адресов, поэтому пе­ред каждой записью содержимое SP уменьшается на 1, а после каждого из­влечения содержимое SP увеличивается на 1. Таким образом, SP всегда ука­зывает на верхушку стека.

Цель настоящей лабораторной работы — изучение организации программ с использованием подпрограмм. Кроме того, в процессе организации циклов мы будем использовать новые возможности системы команд модели ЭВМ, которые позволяют работать с новым классом памяти — сверхоперативной (регистры общего назначения — РОН). В реальных ЭВМ доступ в РОН зани­мает значительно меньшее время, чем в ОЗУ; кроме того, команды обраще­ния с регистрами короче команд обращения к памяти. Поэтому в РОН разме­щаются наиболее часто используемые в программе данные, промежуточные результаты, счетчики циклов, косвенные адреса и т. п.

В системе команд учебной ЭВМ для работы с РОН используются специаль­ные команды, мнемоники которых совпадают с мнемониками соответствую­щих команд для работы с ОЗУ, но в адресной части содержат символы реги­стров RO—R9.

Кроме обычных способов адресации (прямой и косвенной) в регистровых командах используются два новых — постинкрементная и преддекрементная (см. табл. 8.5). Кроме того, к регистровым относится команда организации цикла JRNZ R,M. По этой команде содержимое указанного в команде регист­ра уменьшается на 1, и если в результате вычитания содержимого регистра не равно 0, то управление передается на метку м. Эту команду следует ставить в конце тела цикла, метку м — в первой команде тела цикла, а в регистр R по­мещать число повторений цикла.