Материал: Архитектура и программирование MIPS-процессоров. Разинкин К.А

Внимание! Если размещение файла нарушает Ваши авторские права, то обязательно сообщите нам

$v0, восстанавливает указатель стека и возвращается к вызывающей функции. В этом случае нет необходимости восстанавливать регистры $ra и $a0 потому, что они не менялись. Если n > 1, функция рекурсивно вызывает factorial(n–1). Затем она восстанавливает значение n ($a0) и адрес возврата ($ra) из стека, выполняет умножение и возвращает результат. Инструкция умножения (mul $v0, $a0, $v0) умножает $a0 и $v0 и помещает результат в $v0.

На рис. 2.16 показан стек в процессе выполнения функции factorial(3). Мы предполагаем, что $sp изначально указывает на 0xFC, как показано на Рис. 2.16 (a). Функция создаёт кадр стека из двух слов для хранения $a0 и $ra. При первом вызове factorial сохраняет $a0 (содержащий n = 3) по адресу 0xF8 и $ra по адресу 0xF4, как показано на Рис. 2.16

(b). Затем функция меняет $a0 на n = 2 и рекурсивно вызывает factorial(2), при этом значение $ra меняется на 0xBC. При втором вызове функция сохраняет $a0 (содержащий n = 2) по адресу 0xF0 и $ra по адресу 0xEC. В этот раз мы знаем, что $ra содержит 0xBC. Затем функция меняет $a0 на n = 1 и рекурсивно вызывает factorial(1). При третьем вызове она сохраняет $a0 (содержащий n = 1) по адресу 0xE8 и $ra по адресу 0xE4. На этот раз $ra опять содержит 0xBC. Третий вызов factorial возвращает значение 1 в регистре $v0 и освобождает кадр стека перед тем, как вернуться ко второму вызову. Второй вызов восстанавливает значение n=2, восстанавливает значение 0xBC в $ra (так получилось, что он уже содержит это значение), освобождает кадр стека и возвращает $v0 = 2 × 1 = 2 первому вызову. Первый вызов восстанавливает n = 3, восстанавливает адрес возврата к вызывающей функции в $ra, освобождает кадр стека и возвращает $v0 = 3 × 2 = 6.

На рис. 2.16 (c) показан стек после завершения рекурсивно вызванных функций. Когда функция factorial возвращает управление вызвавшей ее функции, указатель стека находится в своём изначальном положении (0xFC), содержимое стека выше

86

значения указателя стека не менялось и все оберегаемые регистры содержат свои изначальные значения. Регистр $v0 содержит результат вычисления (6).

Рис. 2.16. Стек до (a), после последнего рекурсивного вызова (b) и после завершения (c) вызова

функции factorial при n = 3

Дополнительные аргументы и локальные переменные

У функций могут быть более четырёх аргументов и локальных переменных. Стек используют для хранения этих временных значений. Следуя соглашениям архитектуры MIPS, если у функции больше четырёх аргументов, то первые четыре из них, как обычно, передаются через регистры для аргументов. Дополнительные аргументы передаются на стеке, прямо над указателем стека $sp. Вызывающая функция должна расширить стек для дополнительных аргументов.

На рис. 2.16 (a) показан стек вызывающей функции при вызове функции, принимающей более четырёх аргументов. Функция также может объявлять локальные переменные или массивы.

С локальными переменными, объявленными внутри функции, может работать только сама эта функция. Локальные переменные хранятся в регистрах $s0–$s7; если локальных пе-

87

ременных слишком много, их можно хранить в кадре стека функции. В частности, локальные массивы хранятся в стеке.

На рис. 2.17 (b) показана структура стека вызываемой функции.

Рис. 2.17. Использование стека перед вызовом (a) и после вызова (b)

Кадр стека содержит аргументы самой функции, адрес возврата и любые оберегаемые регистры, которые функция может менять. Он также содержит локальные массивы и любые дополнительные локальные переменные. Если у вызываемой функции более четырёх аргументов, она находит их в кадре стека вызывающей функции. Доступ к дополнительным аргументам – это единственный случай, когда функции позволено читать данные из стека за пределами собственного кадра.

2.7. Режимы адресации

В архитектуре MIPS используются пять режимов адресации: регистровый (англ.: register-only), непосредственный (англ.: immediate), базовый (англ.: base), относительно счетчика команд (англ.: PC-relative) и псевдопрямой (англ.: pseudodirect). Первые три режима (регистровый, непосредственный и базовый) определяют способы чтения и записи операндов. Последние два (режим адресации относительно счетчика команд и

88

псевдопрямой режим) определяют способы записи счётчика команд (англ.: program counter, PC).

Регистровая адресация

При регистровой адресации регистры используются для всех операндов-источников и операндов-назначений (иными словами – для всех операндов и результата). Все инструкции типа R используют именно такой режим адресации.

Непосредственная адресация

При непосредственной адресации в качестве операндов наряду с регистрами используют 16-битные константы (непосредственные операнды). Этот режим адресации используют некоторые инструкции типа I, такие как сложение с константой (addi) и загрузка константы в старшие 16 бит регистра (lui).

Базовая адресация

Инструкции для доступа в память, такие как загрузка слова (lw) и сохранение слова (sw), используют базовую адресацию. Эффективный адрес операнда в памяти вычисляется путем сложения базового адреса в регистре rs и 16-битного смещения с расширенным знаком, являющегося непосредственным операндом.

Адресация относительно счетчика команд

Инструкции условного перехода, или ветвления, используют адресацию относительно счетчика команд для определения нового значения счетчика команд в том случае, если нужно осуществить переход.

Смещение со знаком прибавляется к счетчику команд (PC) для определения нового значения PC, поэтому тот адрес, куда будет осуществлен переход, называют адресом относительно счетчика команд.

В приведённом ниже примере кода показана часть функции factorial из предыдущего примера.

89

Пример Вычисление целевого адреса ветвления

0xA4

beq $t0, $0, else

0xA8

addi $v0, $0, 1

0xAC

addi $sp, $sp, 8

0xBO

jr $ra

0xB4 else: addi $a0, $a0, −1

0xB8 jal factorial

На рис. 2.18 показан машинный код для инструкции beq. Целевой адрес ветвления (англ.: branch target address,

BTA) – это адрес инструкции, которая будет выполнена следующей в том случае, если случится ветвление. На Рис. 2.18 у инструкции beq целевой адрес ветвления равен 0xB4 – это адрес инструкции с меткой else.

Рис. 2.18. Машинный код для инструкции beq

16-битный непосредственный операнд задаёт число инструкций между целевым адресом ветвления и инструкцией, находящейся сразу после инструкции перехода (т.е. инструкции по адресу PC + 4). В нашем случае непосредственный операнд равен 3 потому, что целевой адрес ветвления (0xB4) расположен через 3 инструкции после инструкции с адресом PC +

4 (0xA8).

Процессор вычисляет целевой адрес ветвления, выполняя знаковое расширение 16-битного непосредственного операнда до 32 бит и умножая полученное значение на 4 (чтобы преобразовать слова в байты), после чего добавляя это произведение к значению PC+4.

90

Источник: https://studfile.net/preview/16568788/