Введение

Алгоритм команды RET

 

RC <– [PC]
Дешифрация
SP <– SP - LR
PC <– [SP]
SP <– SP - LR
RF <– [SP]

 


 

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

 

Микрооперации 3, 4: Читаем слово данных из стека. Что прочитается? То? что сохранялось последним – то есть адрес возврата. Прочитанный из системного стека адрес возврата заносим в Программный счётчик (PC). Смотрите, на действия что были описаны в разделе [3.10.4] "Алгоритм команды POP" микрооперации 3, 4 этого алгоритма.

 

Микрооперации 5,6: Теперь - восстанавливаем регистр флагов. Смотрите, на действия что были описаны в разделе [3.10.4] "Алгоритм команды POP" микрооперации 3, 4 этого алгоритма.

3.12 Сохранение/Восстановление регистров

1) Команды CALL и RET сохраняют/восстанавливают только те 2 регистра, которые при вызове подпрограммы необходимо сохранять/восстанавливать всегда: RF и PC. Выполняют нужную но – минимально необходимую работу.

 

2) Однако состояние процессора определяется не только регистром RF. Программа обычно использует и другие регистры для хранения каких то данных, и они - тоже должны сохраняться/восстанавливаться, чтобы при возврате из подпрограммы - они оказались в том же состоянии, что и при вызове. Если так и есть - программист должен сам позаботиться об их сохранении/восстановлении этих регистров. Сохраняются они так же в системном стеке, но не автоматически при вызове команды CALL, а специально вставленными программистом в программу командами PUSH и POP.

Используются 2 способа программирования сохранения/восстановления регистров:

а) Сохранение./Восстановление в программе

б) Сохранение/Восстановление в подпрограмме

 

 

3.12.2 Сохранение/Восстановление в программе

Второй раз в курсе займёмся не вопросом "как процессор выполняет те или иные команды" а вопросом: "как эти команды используются". Пишем программу и подпрограмму.

 

В данном случае задачу сохранения/Восстановления полностью на себя берет на себя программист, пишущий программу.

 

Рассмотрим текст программы и подпрограммы. Отмечены только те команды что имеют отношение к вызову и возврату:

 

 

Текст программы Текст подпрограммы
Начало программы CLI (1) PUSH R1 … (2) PUSH Rn CALL #Adr (3) POP Rn … (4) POP R1 STI (5) Окончание программы   STI (6) Тело подпрограммы CLI (7) RET (8)

 

 

Комментарии:

 

(1) – Начало подготовки перехода к подпрограмме, предстоит работа со стеком для сохранения регистров. Это – критическая секция. Этот процесс - не должен прерываться обработкой прерывания, иначе последовательность данных в стеке будет нарушена. Пока не будет закончен переход к вызываемой подпрограмме – обработку прерываний необходимо запретить. Командой CLI мы запрещаем обработку прерывания. Говорят: "открываем критическую секцию перехода к подпрограмме". Смотрите: [1.10], [3.5.6]

 

(2) – Сохранение регистров в системном стеке, сохраняются те n регистров, которые реально используются в программе.

 

(3) – Вызов подпрограммы.

 

(6) – После перехода в подпрограмму и конца работы со стеком нужно вновь разрешить обработку прерываний командой STI. Говорят "закрываем критическую секцию перехода к подпрограмме".

 

(7) – Начинается процесс возврата. Открываем критическую секцию возврата к программе.

 

(8) – Возврат в программу.

 

(4) – Вернуться то вернулись, но необходимо ещё восстановить то состояние регистров - что было на момент вызова. Восстанавливаем регистры из системного стека (порядок восстановления, в соответствии с принципом работы стековой памяти [3.10.1] – обратный порядку восстановления)

 

(5) – Закрываем критическую секцию возврата в программу.

 

 

3.12.3 Сохранение/Восстановление в подпрограмме

В данном случае задачу регистров берет на себя программист, пишущий подпрограмму.

Поскольку, программист пишущий подпрограмму - не обязан знать какие именно из регистров использует программа, может показаться что есть проблема – а какие же регистры ему сохранять и восстанавливать?

На самом деле всё просто - регистры для сохранения/восстановления выбираются по другому принципу: Сохраняются, а по окончании подпрограммы восстанавливаются не те регистры что использует программа, а те регистры - которые использует подпрограмма. Использует и, следовательно - меняет. Результат тот же: восстановив прежние значения - подпрограмма вернёт программе регистры в своём прежнем состоянии.

 

Текст программы Текст подпрограммы
Начало программы PUSH R1 … (4) PUSH Rm
CLI (1)
CALL #Adr (2)
STI (3) STI (5)
Окончание Тело подпрограммы
CLI (6)
POP Rm … (7) POP R1
RET (8)

 

 

(1) – открывается критическая секция перехода к подпрограмме;

 

(2) – переход к подпрограмме;

 

(4) – сохранение m регистров. 1…m – регистры что далее будет использовать программист пишущий подпрограмму;

 

(5) – закрывается критическая секция перехода к подпрограмме;

 

(6) – открывается критическая секция возврата в программу;

 

(7) - восстановление регистров ( порядок – обратный порядку сохранения;

 

(8) – возврат в программу;

 

(3) - закрываем критическую секцию возврата в программу.

 

 

3.12.3 Выбор способа сохранения/восстановления регистров

1) Если рассматривать ситуацию с точки зрения минимизации размера исполняемого кода – как правило предпочтительней сохранение/восстановление в подпрограмме: команды работы со стеком прописаны 1 раз в подпрограмме, а не многократно - при каждом очередном вызове подпрограммы.

 

2) Если рассматривать ситуацию с точки зрения скорости работы – ситуация не однозначна. Псё зависит от того как соотносятся между собой величины n и m :

 

Пусть:

n – число регистров используемых программой;

m – подпрограммой;

 

Тогда:

 

- если m<n – быстрее сохранение/восстановление в подпрограмме.

- если n<m - проще сохранение/восстановление в подпрограмме

 

3) При программировании на Assembler - выбор способа – воля программиста, вопрос договора между программистами. Причём в зависимости от случая может быть использован и один, и другой способ.

 

4) Трансляторы с языков высокого уровня по умолчанию используют - один из двух способов. Согласно стандарту на язык разные языки программирования по умолчанию могут использовать разные способы:.

Пример:

Стандарт Си (и стандарты других языков производных от этого языка) - предписывает сохранение/восстановление в подпрограмме;

Стандарт Паскаль (и стандарты других языков производных от этого языка) – в программе.

 

5) Если программисту на языке высокого уровня не нравится стандартный способ – он может изменить его опциями компилятора.

3.12.4 Сохранение/восстановление и вызов внешних подпрограмм и функций.

1) "Внешняя подпрограмма" – подпрограмма написанная совершенно отдельно от вызывающей программы, возможно на другом языке программирования, раздельно компилируемая. "Внешние подпрограммы" – вполне могут быть написаны на языке использующем другой способ сохранения/восстановления. И тут – возникает проблема:

 

Пусть транслятор языка А – сохраняет/восстанавливает регистры в программе

Пусть транслятор языка B – сохраняет/восстанавливает регистры в программе

 

Пусть из программы вызывается внешняя подпрограмма, написанная на другом языке программирования:

 

Если программа на языке А, а подпрограмма на В – сохранять/восстанавливать будет как программа так и подпрограмма, произойдёт двойное сохранение/восстановление регистров. Ошибки - не случится, но уйдет дополнительное время на двойное сохранение/восстановление.

Если программа на языке В, а подпрограмма на А – всё хуже: никто не сохранит не восстановит регистры, и возникает трудно обнаруживаемая.

 

 

Вывод: если программист использует язык программирования предполагающий сохранение/восстановление в подпрограмме – он должен быть особенно внимателен. Знать какой способ использует вызываемая внешняя подпрограмма и при необходимости опциями компилятора изменить умолчание для транслятора. С этой точки зрения – языки предполагающие по умолчанию сохранение/восстановление в подпрограмме более опасны с точки зрения вероятности возникновения ошибки, и требуют дополнительных знаний от программиста с таковым языком работающим. Именно поэтому разработчик "паскаль" Николас Вирт предпочел в своём языке использовать более безопасный, хоть, как правило, и дающий больший размер кода способ сохранения/восстановления.