Введение
Аспект архитектуры набора инструкций процессоров
Режимы адресации являются аспектом архитектуры набора инструкций в большинстве конструкций центральных процессоров (ЦП). Различные режимы адресации, определенные в данной архитектуре набора инструкций, определяют, как инструкции машинного кода в этой архитектуре идентифицируют операнды каждой инструкции. Режим адресации указывает, как вычислить эффективный адрес операнда в памяти, используя информацию, содержащуюся в регистрах и/или константы, содержащиеся в самой инструкции или в другом месте. В программировании режимы адресации представляют основной интерес для программистов на языке ассемблера и разработчиков компиляторов. См. также ортогональный набор инструкций, который рассматривает возможность использования любого режима адресации любой инструкцией.
Кавеат
Не существует общепринятых названий для режимов адресации: разные авторы и производители компьютеров могут использовать различные названия для одного и того же режима адресации или одни и те же названия для разных режимов адресации. Более того, режим адресации, который в одной архитектуре рассматривается как единый, может представлять функциональность, которая в другой архитектуре охватывается двумя или более режимами адресации. Например, некоторые архитектуры с комплексным набором команд (CISC), такие как Digital Equipment Corporation (DEC) VAX, рассматривают регистры и литеральные или непосредственные константы как еще один режим адресации. Другие, такие как IBM System/360 и его последователи, и большинство архитектур с упрощенным набором команд (RISC), кодируют эту информацию непосредственно в инструкции. Таким образом, последние машины имеют три различных мнемокода для копирования одного регистра в другой, копирования литеральной константы в регистр и копирования содержимого ячейки памяти в регистр, в то время как VAX использует только одну инструкцию "MOV". Сам термин "режим адресации" допускает различные интерпретации: либо как "режим вычисления адреса памяти", либо как "режим доступа к операнду". Согласно первой интерпретации, инструкции, которые не выполняют чтение или запись в память (например, "добавить литерал к регистру"), не рассматриваются как имеющие "режим адресации". Вторая интерпретация позволяет использовать такие машины, как VAX, которые используют биты режима операнда для выбора регистра или литерального операнда. Первая интерпретация применима только к инструкциям, таким как "load effective address", которая загружает адрес операнда, а не сам операнд. Перечисленные ниже режимы адресации разделены на режимы адресации кода и режимы адресации данных. Большинство компьютерных архитектур поддерживают это различие, однако существуют (или существовали) архитектуры, которые позволяют (почти) все режимы адресации использовать в любом контексте. Приведенные ниже инструкции приведены исключительно в качестве иллюстрации режимов адресации и не обязательно соответствуют мнемоникам, используемым в конкретном компьютере. Некоторые компьютеры, например, IBM 709 и RCA 3301, не имеют единого поля режима адресации, а используют отдельные поля для косвенной адресации и индексации.
Важный случай использования
Некоторые архитектуры наборов команд, такие как Intel x86 и IBM/360 и их последователи, имеют инструкцию вычисления эффективного адреса. Она вычисляет эффективный адрес операнда и загружает его в регистр, не обращаясь к ячейке памяти, на которую он указывает. Это может быть полезно при передаче адреса элемента массива в подпрограмму. Также это может быть хитрым способом выполнения большего числа вычислений в одной инструкции; например, использование такой инструкции с режимом адресации "база+индекс+смещение" (описан ниже) позволяет сложить два регистра и константу в одной инструкции и сохранить результат в третий регистр.
Простые режимы адресации кода
Ниже приведены некоторые простые режимы адресации кода. Терминология может различаться в зависимости от платформы.
Процессоры, не использующие последовательное выполнение
Процессоры, не использующие последовательное выполнение с програмным счетчиком, крайне редки. В некоторых процессорах каждая инструкция всегда задает адрес следующей инструкции. Такие процессоры имеют указатель инструкции, который хранит этот заданный адрес; это не програмный счетчик, поскольку отсутствует механизм его инкрементации. К таким процессорам относятся некоторые компьютеры с барабанной памятью, как IBM 650, машина SECD, Librascope LGP 30 и RTX 32P. Другие вычислительные архитектуры идут гораздо дальше, стремясь обойти "бутылочное горлышко" фон Неймана, используя различные альтернативы программному счетчику.
Условное исполнение
Некоторые компьютерные архитектуры имеют условные инструкции (например, ARM, но не для всех инструкций в 64-битном режиме) или условные инструкции загрузки (например, x86), что в некоторых случаях может избавить от необходимости использования условных переходов и предотвратить очистку конвейера команд. Инструкция, такая как "сравнение", используется для установки флага состояния, а последующие инструкции содержат проверку этого флага состояния, чтобы определить, будут ли они выполнены или проигнорированы.
Простые режимы адресации данных
Ниже приведены некоторые простые режимы адресации данных. Терминология может различаться в зависимости от платформы.
Непрямая или отложенная память
Любой из режимов адресации, упомянутых в этой статье, может иметь дополнительный бит для указания на косвенную адресацию, то есть адрес, вычисленный с использованием определенного режима, на самом деле является адресом ячейки памяти (обычно полного слова), содержащей фактический эффективный адрес. Косвенная адресация может использоваться как для кода, так и для данных. Она может значительно упростить реализацию указателей, ссылок или дескрипторов, а также облегчить вызов подпрограмм, которые иначе не были бы доступны для адресации. Косвенная адресация влечет за собой снижение производительности из-за дополнительного обращения к памяти. Некоторые ранние миникомпьютеры (например, DEC PDP-8, Data General Nova) имели лишь несколько регистров и ограниченный диапазон прямой адресации (8 бит). Поэтому использование косвенной адресации памяти было практически единственным способом обращения к значительному объему памяти. Половина из восьми режимов адресации DEC PDP-11 являются отложенными. Отложенная адресация по регистру @Rn эквивалентна косвенной адресации по регистру, как определено выше. Режимы предопределения с отложенной адресацией @(Rn), постопределения с отложенной адресацией @(Rn)+ и индексированной отложенной адресации @nn(Rn) указывают на адреса в памяти, которые считываются для получения адреса параметра. Отложенные режимы PDP-11, в сочетании со счетчиком команд, обеспечивают абсолютную и относительную адресацию относительно счетчика команд.
Устаревшие режимы адресации
Перечисленные здесь режимы адресации использовались в период с 1950 по 1980 год, но в настоящее время недоступны на большинстве современных компьютеров. Этот список далеко не исчерпывающий; время от времени применялись и другие интересные и необычные режимы адресации, например, абсолютная адресация минус логическое ИЛИ двух или трех индексных регистров.
Непрямая многоуровневая память
Если размер слова превышает размер адреса, то слово, на которое ссылаются при косвенной адресации памяти, само может содержать флаг косвенности, указывающий на необходимость выполнения еще одного цикла косвенной адресации. Этот флаг называется битом косвенности, а результирующий указатель – помеченным указателем, где бит косвенности указывает, является ли указатель прямым или косвенным. Необходимо следить за тем, чтобы цепочка косвенных адресов не замыкалась на себя, иначе при разрешении адреса можно попасть в бесконечный цикл. IBM 1620, Data General Nova, серия HP 2100 и NAR 2 поддерживали многоуровневую косвенную адресацию памяти и могли входить в такой бесконечный цикл вычисления адреса. Режим косвенной адресации памяти в Nova оказал влияние на изобретение косвенно-потокового кода. Компьютер DEC PDP 10 с 18-битными адресами и 36-битными словами позволял использовать многоуровневую косвенную адресацию с возможностью применения индексного регистра на каждом этапе. Перед декодированием каждого слова адреса выполнялся запрос к системе приоритетных прерываний. Таким образом, цикл косвенной адресации не препятствовал выполнению подпрограмм обслуживания устройств, включая обработчик истечения временного кванта прерываний в планировщике с вытесняющей многозадачностью. Инструкция цикла обрабатывалась как любая другая вычислительная задача.
Регистры с отображением в памяти
На некоторых компьютерах адреса указывали на регистры, а не на основную память или на основную память, используемую для реализации этих регистров. Хотя на некоторых ранних компьютерах адреса регистров располагались в верхней части адресного пространства, например, на IBM 650 и IBM 7070, тенденция заключалась в использовании адресов регистров только в нижней части и в использовании только первых 8 или 16 ячеек памяти (например, ICL 1900, DEC PDP 10). Это означало, что не требовалась отдельная инструкция "сложить регистр с регистром" – можно было просто использовать инструкцию "сложить память с регистром". В ранних моделях PDP 10, не имевших кэш-памяти, короткий внутренний цикл, загруженный в первые несколько ячеек памяти (где быстрые регистры были доступны при их установке), выполнялся значительно быстрее, чем в памяти на магнитных сердечниках. Более поздние модели серии DEC PDP 11 отображали регистры на адреса в области ввода-вывода, но это было сделано главным образом для обеспечения удаленной диагностики. Сбивает с толку то, что 16-битные регистры отображались на последовательные 8-битные байтовые адреса.
Непрямая и автоматическая инкрементация памяти
Миникомпьютер DEC PDP 8 имел восемь специальных ячеек памяти (по адресам с 8 по 15). При доступе к ним через косвенную адресацию памяти, эти ячейки автоматически инкрементировались перед использованием. Это упрощало последовательный просмотр памяти в цикле, не требуя использования аккумулятора для инкремента адреса. Миникомпьютер Data General Nova имел 16 специальных ячеек памяти по адресам с 16 по 31. При доступе к ним через косвенную адресацию памяти, ячейки с адресами 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`; конкретное значение кратности определяется системно-зависимым оператором времени компиляции `sizeof`.
Индекс следующей инструкции
Эллиот 503, Эллиот 803 и бортовой компьютер Apollo Guidance Computer использовали только абсолютное адресирование и не имели индексных регистров. Таким образом, косвенные переходы или переходы через регистры не поддерживались в наборе команд. Вместо этого, можно было дать команду добавить содержимое текущего машинного слова к следующей инструкции. Добавление небольшого значения к следующей выполняемой инструкции, например, могло изменить JUMP 0 на JUMP 20, тем самым создавая эффект перехода с использованием индекса. Следует отметить, что инструкция модифицируется "на лету" и остаётся неизменной в памяти, то есть это не самомодифицирующийся код. Если добавляемое к следующей инструкции значение было достаточно большим, оно могло изменить как операнд (код операции) этой инструкции, так и её адрес, или только операнд.