Постановка задачи


На рисунке отображён участок ОЗУ, отмечены области занимаемые программой и подпрограммой, выделены команды играющие роль в процессе вызова и последующего возврата:

 

 

В программе CALL #Adr – команда вызова перехода

Где #Adr – адрес подпрограммы, заданный методом непосредственной адресации

 

K2 – команда в программе, непосредственно следующая за командой CALL.

 

AB – адрес возврата, или адрес команды в программе следующей за CALL.

 

K1 – первая команда подпрограммы

 

Adr – адрес подпрограммы, который ещё называют "адрес вызова" или "адрес перехода".

 

RET – команда возврата из подпрограммы

 

 

Теперь рассмотрим – какие действия необходимы при вызове и возврате.

 

 

1) При вызове будет необходимо перейти от выполнения команды CALL, к выполнению команды К1 ( показано стрелкой). Делаем вывод: алгоритм команды CALL должен предусматривать загрузку в программный счётчик адреса подпрограммы adr.

 

 

2) При возврате по команде RET необходимо перейти к выполнению, нет, только не той же команды с которой мы ушли из подпрограммы (так мы получим бесконечный цикл) – к выполнению команды сразу следующей в программе за командой CALL. Её адрес – "адрес возврата" нужно будет загружать в программный счётчик (PC) в ходе выполнения RET.

Откуда команда RET – "узнает" каков он, "адрес возврата"? Очень просто: ещё в ходе выполнения команды CALL по команде CALL процессор должен будет:

А) Вычислить адрес возврата;

Б) Запомнить его в системном стеке.

Тогда в ходе выполнения команды RET, по команде RET процессор просто прочитает адрес возврата из системного стека и - запишет его в программный счётчик.

 

Ещё не всё. Когда мы возвращаемся из подпрограммы - мы должны застать процессор в том же состоянии, в том же режиме работы каков был на момент вызова подпрограммы. Говорят "должны восстановить состояние процессора". Мы уже учили ранее – режим работы процессора определяет специальный регистр RF (регистр флагов). Смотрите [3.8] Поэтому команда CALL должна будет "запомнить состояние процессора", а именно – сохранить старое значение регистра RF в системном стеке, тогда команда RET сможет "восстановить старое значение регистра RF" – прочитать старое значение из регистра и занести его в RF.

 

Что интересно: сейчас вы уже знаете всё необходимое - чтоб самостоятельно написать алгоритмы команд и CALL #adr, и RET. Постановка задачи, необходимые специфические действия – описаны в этом разделе. В разделе [3.6.2] мы рассмотрели общие "стандартные" микрооперации. Там же рассмотрено – как вычисляется адрес следующей команды.

Нам потребуется работа с системным стеком? Какими микрооперациями обеспечивается запись и чтение в системный стек – мы также рассматривали в разделах [3.10.3], [3.10.4]. Видимо - эти же микрооперации потребуются и в ходе выполнения CALL и RET для того чтобы сохранить/восстановить адрес возврата и RF.

Попробуйте написать самостоятельно не заглядывая на следующую страницу курса.. Это для Вас – как очень полезное упражнение и маленький тест. Если вы сможете правильно написать алгоритмы (без подсказок) вы уже во многом разобрались как работает процессор и успешно осваиваете курс.

 


 

3.11.3 Алгоритм CALL #Adr

Проверьте Вашу работу. Вот алгоритм CALL #Adr :

 

RC ß [PC]
Дешифрация
[SP] ß RF
SP ß SP + LR
PC ß PC + LK
[SP] ß PC
SP ß SP + LR
PC ß #Adr

 

 

Микрооперации 1, 2: стандартные. См [3.6.2]

 

Микрооперации 3, 4: Сохраняем RF в стеке. Смотрите, те же действия что были описаны в разделе [3.10.3] "Алгоритм команды PUSH" микрооперации 3, 4 этого алгоритма.

 

Микрооперация 5: Наращиваем счетчик вершины стека - на величину длинны команды CALL. Вычисляем адрес возврата. После выполнения микрооперации – адрес возврата в программном счётчике. Смотрите [3.6.2]

 

Микрооперация 6: Заносим, теперь уже адрес возврата в системный стек. Опять - те же действия что были описаны в разделе [3.10.3] "Алгоритм команды PUSH" микрооперации 3, 4 этого алгоритма.

 

На этом – подготовка к переходу окончена, теперь:

 

Микрооперация 7: Собственно переход. Адрес перехода из поля атрибута команды заносится в PC. Теперь следующей выполняемая командой окажется первая команда подпрограммы.


Примечания:

 

1) Не было ошибкой если Вы самостоятельно написав этот алгоритм - сначала вычислили и сохранили в системном стеке адрес возврата, и лишь затем сохраняли RF. Порядок не важен. Одни процессоры могут сохранять в одном порядке, другие – в другом. Важно только чтоб команда RET читала сохранённые в стеке регистры в порядке - обратном порядку сохранения.

2) при вызове команды CALL не производится стандартная микрооперация проверка INT. Оно и понятно: появление INT означает запрос от внешнего устройства на переход к другой программе "программе обработке внешнего события" или "программе обработки прерывания". Было бы странным - только начав один переход тут же затевать и второй. Это только привело бы к путанице данных размещённых в системном стеке. Вот поэтому процессор при выполнении команды перехода даже и не проверяет – а есть ли сигнал INT.