Режимы адресации являются аспектом архитектуры набора команд в большинстве конструкций центрального процессора (ЦП). Различные режимы адресации, определенные в конкретной архитектуре набора команд, определяют, как инструкции машинного языка в этой архитектуре идентифицируют операнд (ы) каждой инструкции. Режим адресации определяет, как вычислить эффективный адрес операнда в памяти, используя информацию, хранящуюся в регистрах и/или константах, содержащихся в машинной инструкции или где-либо еще.
В компьютерном программировании режимы адресации представляют интерес в первую очередь для тех, кто пишет на ассемблере , и для разработчиков компиляторов . Соответствующую концепцию см. в разделе «Ортогональный набор команд» , который касается способности любой инструкции использовать любой режим адресации.
Общепринятых названий режимов адресации не существует: разные авторы и производители компьютеров могут давать разные названия одному и тому же режиму адресации или одни и те же названия разным режимам адресации. Более того, режим адресации, который в одной данной архитектуре рассматривается как один режим адресации, может представлять функциональность, которая в другой архитектуре покрывается двумя или более режимами адресации. Например, некоторые архитектуры компьютеров со сложным набором команд (CISC), такие как Digital Equipment Corporation (DEC) VAX , рассматривают регистры и литеральные или непосредственные константы как просто еще один режим адресации. Другие, такие как IBM System/360 и его преемники, а также большинство конструкций компьютеров с сокращенным набором команд (RISC), кодируют эту информацию внутри инструкции. Таким образом, последние машины имеют три различных кода инструкций для копирования одного регистра в другой, копирования константы в регистр и копирования содержимого ячейки памяти в регистр, в то время как VAX имеет только одну инструкцию «MOV».
Сам термин «режим адресации» может интерпретироваться по-разному: либо «режим вычисления адреса памяти», либо «режим доступа к операнду». Согласно первой интерпретации, инструкции, которые не читают из памяти и не записывают в память (например, «добавить литерал в регистр»), считаются не имеющими «режима адресации». Вторая интерпретация позволяет использовать такие машины, как VAX, которые используют биты режима операнда для регистрации регистра или литерального операнда. Только первая интерпретация применима к таким инструкциям, как «загрузка эффективного адреса», которая загружает адрес операнда, а не сам операнд.
Перечисленные ниже режимы адресации делятся на кодовую адресацию и адресацию данных. Большинство компьютерных архитектур сохраняют это различие, но существуют (или существовали) некоторые архитектуры, которые позволяют использовать (почти) все режимы адресации в любом контексте.
Инструкции, приведенные ниже, являются чисто репрезентативными и служат для иллюстрации режимов адресации и не обязательно отражают мнемонику, используемую каким-либо конкретным компьютером.
Некоторые компьютеры, например, IBM 709 , RCA 3301, [1] не имеют единого поля режима адреса, а имеют отдельные поля для косвенной адресации и индексации.
Архитектуры компьютеров сильно различаются по количеству режимов адресации, которые они обеспечивают аппаратно. Есть некоторые преимущества в исключении сложных режимов адресации и использовании только одного или нескольких более простых режимов адресации, хотя для этого требуется несколько дополнительных инструкций и, возможно, дополнительный регистр. [2] [3] Доказано [4] [5] [6] гораздо проще проектировать конвейерные ЦП, если доступны только простые режимы адресации.
Большинство RISC-архитектур имеют всего около пяти простых режимов адресации, в то время как CISC-архитектуры, такие как DEC VAX, имеют более дюжины режимов адресации, некоторые из которых довольно сложны. Архитектура IBM System/360 имела только три режима адресации; еще несколько были добавлены для System/390 .
Когда существует всего несколько режимов адресации, конкретный требуемый режим адресации обычно закодирован в коде инструкции (например, IBM System/360 и его преемники, большинство RISC). Но когда существует множество режимов адресации, в инструкции часто выделяется специальное поле для указания режима адресации. DEC VAX допускал использование нескольких операндов памяти почти для всех инструкций и поэтому зарезервировал первые несколько битов спецификатора каждого операнда для указания режима адресации для этого конкретного операнда. Сохранение битов спецификатора режима адресации отдельно от битов операции кода операции создает ортогональный набор команд .
Даже на компьютере со многими режимами адресации измерения реальных программ [7] показывают, что простые режимы адресации, перечисленные ниже, составляют около 90% или более всех используемых режимов адресации. Поскольку большинство таких измерений основано на коде, сгенерированном компиляторами из языков высокого уровня, это в некоторой степени отражает ограничения используемых компиляторов. [8] [7] [9]
Некоторые архитектуры набора команд, такие как Intel x86 и IBM/360 и его преемники, имеют адресную инструкцию с эффективной нагрузкой . [10] [11] При этом вычисляется эффективный адрес операнда и загружается в регистр без доступа к памяти, к которой он относится. Это может быть полезно при передаче адреса элемента массива в подпрограмму. Это также может быть разумным способом выполнения большего количества вычислений, чем обычно, за одну инструкцию; например, использование такой инструкции с режимом адресации «база+индекс+смещение» (подробно описано ниже) позволяет сложить два регистра и константу вместе в одной инструкции и сохранить результат в третьем регистре.
Ниже показаны некоторые простые режимы адресации кода. Номенклатура может различаться в зависимости от платформы.
+----+------------------------------+ |прыжок| адрес | +----+------------------------------+ (Действующий адрес ПК = адрес)
Эффективным адресом для абсолютного адреса команды является сам параметр адреса без каких-либо изменений.
+----+------------------------------+ |прыжок| офсет | прыжок относительно +----+------------------------------+ (Эффективный адрес ПК = адрес следующей инструкции + смещение, смещение может быть отрицательным)
Эффективный адрес для адреса инструкции относительно ПК — это параметр смещения, добавляемый к адресу следующей инструкции. Это смещение обычно подписывается, чтобы разрешить ссылку на код как до, так и после инструкции. [12]
Это особенно полезно в связи с переходами, поскольку типичные переходы происходят к соседним инструкциям (на языке высокого уровня большинство операторов if или while достаточно короткие). Измерения реальных программ показывают, что 8- или 10-битное смещение достаточно велико для примерно 90% условных переходов (примерно ±128 или ±512 байт). [13]
Еще одним преимуществом адресации относительно ПК является то, что код может быть независимым от позиции , т. е. его можно загрузить в любое место памяти без необходимости корректировки каких-либо адресов.
Некоторые версии этого режима адресации могут быть условными со ссылкой на два регистра («переход, если reg1 = reg2»), один регистр («переход, если reg1 = 0») или отсутствие регистров, неявно ссылаясь на какой-либо ранее установленный бит в регистре состояния. . См. также условное выполнение ниже.
+-------+-----+ |прыжокЧерез| рег | +-------+-----+ (Эффективный адрес ПК = содержимое регистра «reg»)
Эффективным адресом для косвенной команды Register является адрес в указанном регистре. Например, (A7) для доступа к содержимому адресного регистра A7.
В результате управление передается инструкции, адрес которой находится в указанном регистре.
Многие RISC-машины, а также CISC IBM System/360 и его преемники имеют инструкции вызова подпрограммы, которые помещают адрес возврата в адресный регистр - для возврата из этого вызова подпрограммы используется режим косвенной адресации регистра.
+------+ | нет | выполните следующую инструкцию +------+ (Эффективный адрес ПК = адрес следующей инструкции)
ЦП после выполнения последовательной команды немедленно выполняет следующую команду.
На некоторых компьютерах последовательное выполнение не считается режимом адресации.
Большинство инструкций на большинстве архитектур ЦП являются последовательными инструкциями. Поскольку большинство инструкций являются последовательными, разработчики ЦП часто добавляют функции, которые намеренно жертвуют производительностью других инструкций (инструкций ветвления), чтобы заставить эти последовательные инструкции выполняться быстрее.
Условные переходы загружают ПК одним из двух возможных результатов, в зависимости от условия: большинство архитектур ЦП используют другой режим адресации для «взятой» ветви и последовательное выполнение для «не взятой» ветви.
Многие функции современных процессоров — предварительная выборка инструкций и более сложная конвейеризация , выполнение вне очереди и т. д. — поддерживают иллюзию, что каждая инструкция завершается до начала следующей, давая одни и те же конечные результаты, хотя это не совсем то, что происходит внутри. .
Каждый « базовый блок » таких последовательных инструкций демонстрирует как временную, так и пространственную локальность ссылки .
Процессоры, не использующие последовательное выполнение со счетчиком программ, встречаются крайне редко. В некоторых процессорах каждая инструкция всегда указывает адрес следующей инструкции. Такие процессоры имеют указатель инструкций, содержащий указанный адрес; это не программный счетчик, поскольку нет возможности его увеличения. К таким процессорам относятся некоторые компьютеры с барабанной памятью, такие как IBM 650 , машина SECD , Librascope LGP-30 и RTX 32P. [14]
Другие вычислительные архитектуры идут гораздо дальше, пытаясь обойти узкое место фон Неймана, используя множество альтернатив программному счетчику .
В некоторых компьютерных архитектурах есть условные инструкции (например, ARM , но уже не для всех инструкций в 64-битном режиме) или инструкции условной загрузки (например, x86), которые в некоторых случаях могут сделать условные переходы ненужными и избежать очистки конвейера команд . Такая инструкция, как «сравнить», используется для установки кода условия , а последующие инструкции включают проверку этого кода условия, чтобы увидеть, соблюдаются ли они или игнорируются.
+------+-----+-----+ |пропуститьEQ| рег1| рег2| пропустить следующую инструкцию, если reg1=reg2 +------+-----+-----+ (Эффективный адрес ПК = адрес следующей инструкции + 1)
Пропускную адресацию можно рассматривать как особый вид режима адресации относительно ПК с фиксированным смещением «+1». Как и адресация относительно ПК, некоторые процессоры имеют версии этого режима адресации, которые относятся только к одному регистру («пропустить, если reg1 = 0») или ни к одному из регистров, неявно ссылаясь на некоторый ранее установленный бит в регистре состояния . У других процессоров есть версия, которая выбирает для проверки определенный бит в определенном байте («пропустить, если бит 7 в регистре 12 равен 0»).
В отличие от всех других условных ветвей, инструкция «пропустить» никогда не требует очистки конвейера инструкций , хотя может потребоваться игнорирование следующей инструкции.
Ниже показаны некоторые простые режимы адресации данных. Номенклатура может различаться в зависимости от платформы.
+------+-----+-----+-----+ | мул | рег1| рег2| рег3| reg1 := reg2 * reg3; +------+-----+-----+-----+
Этот «режим адресации» не имеет эффективного адреса и на некоторых компьютерах не считается режимом адресации.
В этом примере все операнды находятся в регистрах, и результат помещается в регистр.
Иногда это называют «база плюс смещение».
+------+-----+-----+----------------+ | нагрузка | рег | база| офсет | reg := RAM[база + смещение] +------+-----+-----+----------------+ (Эффективный адрес = смещение + содержимое указанного базового регистра)
Смещение обычно представляет собой 16-битное значение со знаком (хотя 80386 расширило его до 32 бит).
Если смещение равно нулю, это становится примером косвенной адресации регистра ; эффективный адрес — это просто значение в базовом регистре.
На многих RISC-машинах регистр 0 имеет фиксированное нулевое значение. Если регистр 0 используется в качестве базового регистра, это становится примером абсолютной адресации . Однако доступен только небольшой участок памяти (64 килобайта , если смещение равно 16 битам).
16-битное смещение может показаться очень маленьким по сравнению с размером текущей компьютерной памяти (именно поэтому 80386 расширил его до 32-битного). Могло быть и хуже: мэйнфреймы IBM System/360 имеют только беззнаковое 12-битное смещение. Однако применяется принцип локальности ссылок : в течение короткого промежутка времени большинство элементов данных, к которым программа хочет получить доступ, находятся довольно близко друг к другу.
Этот режим адресации тесно связан с режимом индексированной абсолютной адресации.
Пример 1. В подпрограмме программиста в основном интересуют параметры и локальные переменные, размер которых редко превышает 64 КБ , для чего достаточно одного базового регистра ( указателя кадра ). Если эта процедура является методом класса на объектно-ориентированном языке, то необходим второй базовый регистр, который указывает на атрибуты текущего объекта ( this или self в некоторых языках высокого уровня).
Пример 2. Если базовый регистр содержит адрес составного типа (запись или структура), смещение можно использовать для выбора поля из этой записи (размер большинства записей/структур составляет менее 32 КБ).
+------+-----+-----+----------------+ | добавить | рег1| рег2| постоянная | reg1 := reg2 + константа; +------+-----+-----+----------------+
Этот «режим адресации» не имеет эффективного адреса и на некоторых компьютерах не считается режимом адресации.
Константа может быть знаковой или беззнаковой. Например, move.l #$FEEDABBA, D0
чтобы переместить непосредственное шестнадцатеричное значение «FEEDABBA» в регистр D0.
Вместо использования операнда из памяти значение операнда хранится внутри самой инструкции. На машине DEC VAX литеральные размеры операндов могут иметь длину 6, 8, 16 или 32 бита.
Эндрю Таненбаум показал, что 98% всех констант в программе умещаются в 13 бит (см. философию проектирования RISC ).
+-----------------+ | прозрачный бит для переноски | +-----------------+ +-------------------+ | очистить аккумулятор | +-------------------+
Неявный режим адресации, также называемый режимом неявной адресации ( язык ассемблера x86 ), не указывает явно эффективный адрес ни для источника, ни для назначения (или иногда для обоих).
Код операции подразумевает либо источник (если есть), либо эффективный адрес назначения (или иногда и то, и другое).
Неявная адресация была довольно распространена на старых компьютерах (до середины 1970-х годов). Такие компьютеры обычно имели только один регистр, в котором можно было выполнять арифметические действия, — аккумулятор. Такие аккумуляторные машины неявно ссылаются на этот аккумулятор почти в каждой инструкции. Например, операция < a := b + c; > можно сделать с помощью последовательности < load b; добавить С; хранить а; > -- пункт назначения (аккумулятор) подразумевается в каждой инструкции «загрузка» и «добавление»; источник (аккумулятор) подразумевается в каждой инструкции «сохранения».
Более поздние компьютеры обычно имели более одного регистра общего назначения или ячейки ОЗУ, которая могла быть источником или местом назначения, или и тем, и другим для арифметических операций, поэтому более поздним компьютерам требовался какой-то другой режим адресации для указания источника и назначения арифметических действий.
Среди инструкций x86 некоторые используют неявные регистры для одного из операндов или результатов (умножение, деление, счет условного перехода).
Многие компьютеры (например, x86 и AVR) имеют один регистр специального назначения, называемый указателем стека , который неявно увеличивается или уменьшается при отправке или извлечении данных из стека, а эффективный адрес источника или назначения является (неявно) адресом, хранящимся в этом указатель стека.
Многие 32-битные компьютеры (например, 68000, ARM или PowerPC) имеют более одного регистра, который можно использовать в качестве указателя стека, поэтому используют режим адресации «косвенное автоинкрементирование регистров», чтобы указать, какой из этих регистров следует использовать при загрузка или извлечение данных из стека.
Некоторые современные компьютерные архитектуры (например, IBM/390 и Intel Pentium) содержат некоторые инструкции с неявными операндами для обеспечения обратной совместимости с более ранними разработками.
На многих компьютерах инструкции, которые меняют бит пользовательского/системного режима, бит разрешения прерываний и т. д., неявно указывают специальный регистр, в котором хранятся эти биты. Это упрощает аппаратное обеспечение, необходимое для перехвата этих инструкций, чтобы соответствовать требованиям виртуализации Попека и Голдберга - в такой системе логике ловушки не нужно просматривать какой-либо операнд (или конечный эффективный адрес), а только код операции. .
Было разработано несколько процессоров, в которых каждый операнд всегда неявно указывается в каждой инструкции — процессоры с нулевым операндом .
+------+-----+------------------------------------ --+ | нагрузка | рег | адрес | +------+-----+------------------------------------ --+ (Действующий адрес = адрес, указанный в инструкции)
Это требует места в инструкции для довольно большого адреса. Он часто доступен на машинах CISC с инструкциями переменной длины, например x86 .
Некоторые RISC-машины имеют специальную инструкцию Load Upper Literal , которая помещает 16- или 20-битную константу в верхнюю половину регистра. Затем его можно использовать в качестве базового регистра в режиме адресации по базе плюс смещение, который предоставляет младшие 16 или 12 бит. Комбинация позволяет получить полный 32-битный адрес.
+------+-----+-----+------------------------------ --+ | нагрузка | рег |индекс| адрес | +------+-----+-----+------------------------------ --+ (Эффективный адрес = адрес + содержимое указанного индексного регистра)
Это также требует места в инструкции для довольно большого адреса. Адрес может быть началом массива или вектора, а индекс может выбирать конкретный требуемый элемент массива. Процессор может масштабировать индексный регистр, чтобы учесть размер каждого элемента массива .
Обратите внимание, что это более или менее то же самое, что и режим адресации по основанию плюс смещение, за исключением того, что смещение в этом случае достаточно велико для адресации любой ячейки памяти.
Пример 1. В подпрограмме программист может определить строку как локальную константу или статическую переменную . Адрес строки хранится в буквальном адресе инструкции. Смещение — какой символ строки использовать в этой итерации цикла — хранится в индексном регистре.
Пример 2. Программист может определить несколько больших массивов как глобальные переменные или переменные класса . Начало массива сохраняется в буквальном адресе (возможно, измененном во время загрузки программы перемещающимся загрузчиком ) инструкции, которая ссылается на него. Смещение — какой элемент массива использовать в этой итерации цикла — хранится в индексном регистре. Часто инструкции в цикле повторно используют один и тот же регистр для счетчика цикла и смещений нескольких массивов.
+------+-----+-----+-----+ | нагрузка | рег | база|индекс| +------+-----+-----+-----+ (Эффективный адрес = содержимое указанного базового регистра + содержимое указанного индексного регистра)
Базовый регистр может содержать начальный адрес массива или вектора, а индекс может выбирать конкретный требуемый элемент массива. Процессор может масштабировать индексный регистр , чтобы учесть размер каждого элемента массива . Это можно использовать для доступа к элементам массива, переданным в качестве параметра.
+------+-----+-----+-----+----------------+ | нагрузка | рег | база|индекс| офсет | +------+-----+-----+-----+----------------+ (Эффективный адрес = смещение + содержимое указанного базового регистра + содержимое указанного индексного регистра)
Базовый регистр может содержать начальный адрес массива или вектора записей, индекс может выбирать конкретную требуемую запись, а смещение может выбирать поле внутри этой записи. Процессор может масштабировать индексный регистр, чтобы учесть размер каждого элемента массива .
+------+-----+-----+-----+ | нагрузка | рег | база|индекс| +------+-----+-----+-----+ (Эффективный адрес = содержимое указанного базового регистра + масштабированное содержимое указанного индексного регистра)
Базовый регистр может содержать начальный адрес массива или векторной структуры данных , а индекс может содержать смещение одного конкретного требуемого элемента массива.
Этот режим адресации динамически масштабирует значение в индексном регистре, чтобы учесть размер каждого элемента массива, например, если элементы массива представляют собой числа двойной точности с плавающей запятой, занимающие 8 байт каждое, то значение в индексном регистре умножается на 8, прежде чем быть используется при вычислении эффективного адреса. Масштабный коэффициент обычно ограничивается степенью двойки , поэтому можно использовать сдвиг , а не умножение.
+------+------+-----+ | нагрузка | рег1 | база| +------+------+-----+ (Эффективный адрес = содержимое базового регистра)
Некоторые компьютеры имеют это как отдельный режим адресации. Многие компьютеры просто используют базу плюс смещение со значением смещения, равным 0. Например, (A7)
+------+-----+-------+ | нагрузка | рег | база | +------+-----+-------+ (Эффективный адрес = содержимое базового регистра)
После определения эффективного адреса значение в базовом регистре увеличивается на размер элемента данных, к которому осуществляется доступ. Например, (A7)+ получит доступ к содержимому адресного регистра A7, а затем увеличит указатель адреса A7 на 1 (обычно на 1 слово). Внутри цикла этот режим адресации можно использовать для пошагового обхода всех элементов массива или вектора.
В языках высокого уровня часто считается хорошей идеей, чтобы функции, возвращающие результат, не имели побочных эффектов (отсутствие побочных эффектов значительно облегчает понимание и проверку программы). Этот режим адресации имеет побочный эффект, заключающийся в изменении базового регистра. Если последующий доступ к памяти вызывает ошибку (например, ошибку страницы, ошибку шины, ошибку адреса), приводящую к прерыванию, то перезапуск инструкции становится гораздо более проблематичным, поскольку может потребоваться вернуть один или несколько регистров в то состояние, в котором они находились раньше. инструкция изначально началась.
Было как минимум две компьютерные архитектуры, в которых возникли проблемы с реализацией восстановления после прерываний при использовании этого режима адресации:
+------+-----+-----+ | нагрузка | рег | база| +------+-----+-----+ (Эффективный адрес = новое содержимое базового регистра)
Перед определением эффективного адреса значение в базовом регистре уменьшается на размер элемента данных, к которому осуществляется доступ.
Внутри цикла этот режим адресации можно использовать для обхода всех элементов массива или вектора назад. Стек можно реализовать, используя этот режим в сочетании с предыдущим режимом адресации (автоинкремент).
См. обсуждение побочных эффектов в режиме автоинкрементной адресации.
Любой из режимов адресации, упомянутых в этой статье, может иметь дополнительный бит для обозначения косвенной адресации, т. е. адрес, рассчитанный с использованием некоторого режима, на самом деле является адресом местоположения (обычно полное слово ), которое содержит фактический эффективный адрес.
Косвенная адресация может использоваться для кода или данных. Это может значительно упростить реализацию указателей , ссылок или дескрипторов , а также упростить вызов подпрограмм, которые иначе не адресуются. Косвенная адресация действительно снижает производительность из-за необходимости дополнительного доступа к памяти.
Некоторые ранние миникомпьютеры (например, DEC PDP-8 , Data General Nova ) имели всего несколько регистров и лишь ограниченный диапазон прямой адресации (8 бит). Следовательно, использование косвенной адресации памяти было почти единственным способом обращения к сколько-нибудь значительному объему памяти.
Половина из восьми режимов адресации DEC PDP-11 отложена. Регистр отложенного @Rn аналогичен косвенному регистру, как определено выше. Режимы предварительной отсрочки @-(Rn), постинкрементной отложенной @(Rn)+ и индексированной отложенной @nn(Rn) указывают на адреса в памяти, которые считываются для нахождения адреса параметра. Режимы отсрочки PDP-11 в сочетании со счетчиком программ обеспечивают режимы абсолютной и относительной адресации ПК.
+------+------+---------+----------------+ | нагрузка | рег1 | база = ПК | офсет | +------+------+---------+----------------+ reg1 := ОЗУ[ПК + смещение] (Эффективный адрес = ПК + смещение)
Режим адресации относительно ПК можно использовать для загрузки в регистр значения, хранящегося в памяти программы, на небольшом расстоянии от текущей инструкции. Его можно рассматривать как частный случай режима адресации «база плюс смещение», при котором программный счетчик (ПК) выбирается в качестве «базового регистра».
Есть несколько процессоров, которые поддерживают ссылки на данные, относящиеся к ПК. К таким процессорам относятся:
MOS 6502 и его производные использовали относительную адресацию для всех инструкций перехода . Только эти инструкции использовали этот режим, переходы использовали множество других режимов адресации.
Архитектура x86-64 и 64-битная архитектура ARMv8-A [15] имеют режимы адресации относительно ПК, называемые «RIP-относительными» в x86-64 и «литеральными» в ARMv8-A. Motorola 6809 также поддерживает режим адресации относительно ПК.
Архитектура PDP -11 , архитектура VAX и 32-битная архитектура ARM поддерживают адресацию относительно ПК за счет указания ПК в файле регистров.
IBM z/Architecture включает специальные инструкции, например, Load Relative Long, с адресацией относительно ПК, если активна функция расширения общих инструкций.
При использовании этого режима адресации компилятор обычно помещает константы в пул литералов непосредственно перед или сразу после подпрограммы, которая их использует, чтобы предотвратить случайное выполнение этих констант в качестве инструкций.
Этот режим адресации, который всегда извлекает данные из памяти или сохраняет данные в памяти, а затем последовательно проваливается для выполнения следующей инструкции (эффективный адрес указывает на данные), не следует путать с «ветвью относительно ПК», которая не извлекает данные. из памяти или сохранения данных в памяти, но вместо этого переходит к какой-либо другой инструкции по заданному смещению (эффективный адрес указывает на исполняемую инструкцию).
Перечисленные здесь режимы адресации использовались в период 1950–1980 годов, но больше не доступны на большинстве современных компьютеров. Этот список ни в коем случае не является полным; время от времени использовалось много других интересных и своеобразных режимов адресации, например, абсолютное минус логическое ИЛИ для двух или трех индексных регистров. [16] [17]
Если размер слова больше адреса, то слово, на которое ссылаются для косвенной адресации памяти, само может иметь установленный косвенный флаг, указывающий на другой косвенный цикл памяти. Этот флаг называется битом косвенности , а результирующий указатель является помеченным указателем , причем бит косвенности указывает, является ли это прямым указателем или косвенным указателем. Необходимо следить за тем, чтобы цепочка косвенных адресов не ссылалась сама на себя; если это так, можно получить бесконечный цикл при попытке разрешить адрес.
IBM 1620 , Data General Nova , серия HP 2100 и NAR 2 имеют такую многоуровневую косвенную память и могут войти в такой бесконечный цикл вычисления адреса. Режим непрямой адресации памяти на Nova повлиял на изобретение косвенного многопоточного кода .
Компьютер DEC PDP-10 с 18-битными адресами и 36-битными словами допускал многоуровневую косвенную адресацию с возможностью использования индексного регистра на каждом этапе. Система приоритетных прерываний запрашивалась перед декодированием каждого адресного слова. [18] Таким образом, цикл с непрямой адресацией не будет препятствовать выполнению процедур обслуживания устройства, включая обработчик истечения интервала времени любого планировщика вытесняющей многозадачности . Инструкция цикла будет рассматриваться как любое другое задание, связанное с вычислениями.
На некоторых компьютерах были адреса, которые относились к регистрам, а не к первичному хранилищу или к первичной памяти, используемой для реализации этих регистров. Хотя на некоторых ранних компьютерах адреса регистров располагались в верхней части диапазона адресов, например, IBM 650 , [19] [a] IBM 7070 , [20] [c] тенденция заключалась в использовании только адресов регистров в нижней части диапазона адресов. конец и использовать только первые 8 или 16 слов памяти (например, ICL 1900 , DEC PDP-10). Это означало, что не было необходимости в отдельной инструкции «добавить регистр для регистрации» — можно было просто использовать инструкцию «добавить память для регистрации».
В случае ранних моделей PDP-10, которые не имели кэш-памяти, жесткий внутренний цикл, загружаемый в первые несколько слов памяти (где быстрые регистры были адресуемы, если они были установлены), работал намного быстрее, чем это было бы в память на магнитном сердечнике.
Более поздние модели серии DEC PDP-11 сопоставляли регистры с адресами в области ввода/вывода, но это было в первую очередь предназначено для обеспечения удаленной диагностики. Как ни странно, 16-битные регистры были сопоставлены с последовательными 8-битными байтовыми адресами.
Миникомпьютер DEC PDP-8 имел восемь специальных мест (по адресам с 8 по 15). При доступе через косвенную адресацию памяти эти ячейки автоматически увеличиваются перед использованием. [21] Это позволило легко перемещаться по памяти в цикле без необходимости использования аккумулятора для увеличения адреса.
Миникомпьютер Data General Nova имел 16 специальных ячеек памяти по адресам с 16 по 31. [22] При доступе через косвенную адресацию памяти адреса с 16 по 23 автоматически увеличивались перед использованием, а адреса с 24 по 31 автоматически уменьшались перед использованием.
Процессоры Data General Nova , семейства Motorola 6800 и семейства MOS Technology 6502 имели очень мало внутренних регистров. Арифметические и логические инструкции в основном выполнялись со значениями в памяти, а не с внутренними регистрами. В результате для многих инструкций требовалось двухбайтовое (16-битное) место в памяти. Учитывая, что коды операций на этих процессорах имели длину всего один байт (8 бит), адреса памяти могли составлять значительную часть размера кода.
Разработчики этих процессоров предусмотрели частичное решение, известное как адресация «нулевой страницы». Доступ к начальным 256 байтам памяти ($0000 – $00FF; также известная как страница «0») можно было получить, используя однобайтовый абсолютный или индексированный адрес памяти. Это сократило время выполнения инструкции на один такт и длину инструкции на один байт. Сохраняя часто используемые данные в этом регионе, программы можно сделать меньше и быстрее.
В результате нулевая страница использовалась аналогично файлу регистров. Однако во многих системах это приводило к интенсивному использованию области нулевой страницы операционной системой и пользовательскими программами, что ограничивало ее использование, поскольку свободное пространство было ограничено.
Режим адреса нулевой страницы был улучшен в нескольких последних моделях 8-битных процессоров, включая WDC 65816 , CSG 65CE02 и Motorola 6809 . Новый режим, известный как «прямая страничная» адресация, добавил возможность перемещать 256-байтовое окно нулевой страницы памяти из начала памяти (адрес смещения $0000) в новое место в пределах первых 64 КБ памяти.
CSG 65CE02 позволял перемещать прямую страницу на любую 256-байтовую границу в пределах первых 64 КБ памяти путем сохранения 8-битного значения смещения в регистре новой базовой страницы (B). Motorola 6809 может сделать то же самое с регистром прямой страницы (DP). WDC 65816 пошел еще дальше и позволил переместить прямую страницу в любое место в пределах первых 64 КБ памяти, сохранив 16-битное значение смещения в новом прямом регистре (D).
В результате большее количество программ смогло использовать улучшенный режим прямой адресации страниц по сравнению с устаревшими процессорами, которые включали только режим адресации с нулевой страницей.
Это похоже на адресацию масштабированного индекса, за исключением того, что инструкция имеет два дополнительных операнда (обычно константы), и аппаратное обеспечение проверяет, находится ли значение индекса между этими границами.
Другой вариант использует векторные дескрипторы для хранения границ; это упрощает реализацию динамически выделяемых массивов и при этом обеспечивает полную проверку границ.
Некоторые компьютеры имели специальные режимы косвенной адресации для подполей внутри слов.
В слове косвенной адресации символов серии GE /Honeywell 600 указаны либо 6-битные, либо 9-битные символьные поля в 36-битном слове.
DEC PDP-10 , также 36-битный, имел специальные инструкции, которые позволяли обрабатывать память как последовательность битовых полей фиксированного размера или байтов любого размера от 1 до 36 бит. Дескриптор последовательности из одного слова в памяти, называемый «указателем байта», хранит текущий адрес слова в последовательности, позицию бита в слове и размер каждого байта.
Существовали инструкции для загрузки и хранения байтов через этот дескриптор, а также для увеличения дескриптора, чтобы он указывал на следующий байт (байты не были разделены по границам слов). Большая часть программного обеспечения DEC использовала пять 7-битных байтов на слово (простые символы ASCII), при этом один бит на слово не использовался. Реализации C должны были использовать четыре 9-битных байта на слово, поскольку функция malloc в C предполагает, что размер int несколько кратен размеру char ; [23] фактическое кратное определяется системно-зависимым оператором времени компиляции sizeof .
Elliott 503 , [24] Elliott 803 , [24] [25] и компьютер управления Apollo использовали только абсолютную адресацию и не имели индексных регистров. Таким образом, набор команд не поддерживал непрямые переходы или переходы через регистры. Вместо этого ему можно было бы дать команду добавить содержимое текущего слова памяти к следующей инструкции . Добавление небольшого значения к следующей выполняемой инструкции может, например, изменить a JUMP 0
на JUMP 20
, создав тем самым эффект индексированного перехода. Обратите внимание, что инструкция модифицируется «на лету» и остается неизменной в памяти, т. е. это не самомодифицирующийся код . Если значение, добавляемое к следующей инструкции, было достаточно большим, оно могло бы изменить код операции этой инструкции, а также или вместо адреса.
*p++
языку программирования C , используемому для операций извлечения стека .*--p
языку программирования C , используемому для операций добавления в стек .... MIPS-X использует единственный режим адресации: базовый регистр плюс смещение.
Этот простой режим адресации позволяет начать вычисление эффективного адреса очень рано...
C54x имеет 17 режимов адресации данных, не считая доступа к регистрам, но четыре режима, имеющиеся в MIPS, составляют 70% режимов. На автоинкремент и автодекремент, встречающиеся в некоторых RISC-архитектурах, приходится еще 25% использования. Эти данные были собраны в результате измерения статических инструкций для C-вызываемой библиотеки, состоящей из 54 подпрограмм DSP, закодированных на языке ассемблера.
3 программы измерены на станке со всеми режимами адресации (VAX)... смещение 75% и немедленное
79% всех выполняемых инструкций можно заменить инструкциями RISC или синтезировать в инструкции RISC, используя только комбинацию базовых блочных инструкций.
Рисунок 2-9: Расчет эффективного адреса: проверьте «PI RQ ?»