Косвенно-регистровый режим

В этом режиме, как и в регистровом, адресное поле не используется. Значение регистра интерпретируется как адрес операнда. Этот режим используется для разыменования указателей или для обращения к памяти по предварительно вычисленному адресу. Это позволяет эффективно управлять памятью и взаимодействовать с данными без необходимости использования дополнительных регистров для хранения адресов.

Некоторые процессоры, такие как PDP-11, VAX, МС68ОхО, имеют интересные варианты этого режима — адресацию с постинкрементом и предекрементом. Постинкремент означает, что после собственно адресации значение регистра увеличивается на величину адресуемого объекта. Предекремент, соответственно, означает, что регистр уменьшается на ту же величину перед адресацией. Эти механизмы предоставляют гибкость при манипуляциях с данными и упрощают доступ к памяти.

Эти режимы могут использоваться для разнообразных целей, например, для реализации операций над текстовыми строками или поэлементного сканирования массивов. Одно из основных назначений — реализация стека, который является критически важной структурой данных в большинстве современных вычислительных систем. Стек позволяет временно сохранять данные и управлять их жизненным циклом, что крайне важно для работы с подпрограммами и временными значениями.

Стек

Стек, или магазин, — это структура данных, над которой можно осуществлять две операции: проталкивание (push) значения и выталкивание (pop). Значения выталкиваются из стека в порядке, обратном тому, в котором проталкивались: LIFO (Last In, First Out, первый вошёл, последний вышел). Стековые структуры находят широкое применение при синтаксическом разборе арифметических выражений и в алголоподобных языках программирования [Кормен/Лейзерсон/Ривест 2000]. Они позволяют легко управлять промежуточными данными и обеспечивают быструю доступность информации, что существенно ускоряет выполнение программ.

Самая простая реализация стека — это массив и индекс последнего находящегося в стеке элемента. Этот индекс называется указателем стека (SP - Stack Pointer). Стек может расти как вверх, так и вниз. Широко применяются также реализации стеков в виде односвязных списков, которые обеспечивают динамическое управление памятью и позволяют избегать проблем, связанных с фиксированной длиной массивов.

При реализации стека скалярных значений удобно использовать непрерывную область памяти в качестве массива, регистр SP в качестве указателя и режимы адресации с постинкрементом и предекрементом при реализации команд проталкивания и выталкивания. Действительно, команда

MOVE x, -(SP)

приведёт к тому, что указатель стека уменьшится на размер x, и мы положим x в освободившуюся память. Напротив, команда

MOVE (SP)+, y

приведёт к получению значения и продвижению указателя стека в обратном направлении. Поэтому первая команда имеет также мнемоническое обозначение

PUSH x

а вторая

POP y

Если мы поместим несколько значений в стек командой PUSH, команда POP вытолкнет их из стека в обратном порядке. Стек можно использовать для хранения промежуточных данных (см. пример 2.3) и при реализации арифметических выражений. Например, команда

ADD (SP)+, (SP)

в точности воспроизводит описанную выше семантику безадресной команды ADD стековой архитектуры. Впрочем, безадресной команде ADD операнды не нужны, а в данном случае они просто не используются, но никуда не исчезают. Команда получается длиннее: у типичной стековой архитектуры команда сложения занимает 1 байт, у PDP-11 её имитация занимает 2 байта, а у VAX — целых три. Поэтому, если мы хотим использовать стековую технику генерации кода, лучше использовать процессор, который предназначен для этого.

Пример 2.3. Использование стека для хранения промежуточных значений:

void swap(int &a, int &b) {
    int t;
    t = a;
    a = b;
    b = t;
}

Для простоты мы не рассматриваем механизм передачи параметров и считаем, что они передаются в регистрах А и В:

.GLOBL swap
swap:
PUSH (A)
MOVE (B), (A)
POP (B)
RET.

Одно из основных назначений стека в регистровых архитектурах — это сохранение адреса возврата подпрограмм. Кроме того, если принятое в системе соглашение о вызовах подпрограмм предполагает, что вызываемая процедура должна сохранить все или некоторые регистры, которые использует сама, стек обычно применяют и для этого. Неортогональные процессоры, такие как х86, часто предоставляют специальные команды PUSH и POP, работающие с выделенным регистром SP (Stack Pointer), который не может быть использован для других целей. Таким образом, использование стека упрощает управление состоянием программы и минимизирует вероятность ошибок, связанных с потерей данных в процессе выполнения.