Способы указания операндов

{toc_noshowall} Для указания регистра в качестве операнда достаточно задать в команде лишь его номер. Ссылки на операнды, находящиеся в памяти, при использовании символических имен также просты. Возможность использования индекс-регистра повышает гибкость определения операндов в памяти. Рассмотрим теперь некоторые дополнительные возможности адресации.

НЕЯВНОЕ УКАЗАНИЕ АДРЕСОВ

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

Именно ассемблер заменяет перемещаемые имена или выражения соответствующими парами в процессе трансляции программы на машинный язык. Для каждого перемещаемого имени или выражения подразумевается представление в виде пары «база+смещение». В команде

L 2,ABC

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

 

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

Явная форма указания адреса содержит номера базового и индексного регистров и смещение, заносимые в поле Х-типа. В наших символических обозначениях адресное поле команды формата RX языка ассемблера выглядит так:

D(X,B)

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

Команда LOAD в символической форме имеет, например, вид

L R1,S2(X2)

(в данном случае употреблена неявная спецификация). S2 обозначает перемещаемое имя или выражение. Эта же команда, но только с явным указанием адреса имеет вид

L R1,D2(X2,B2)

В будущем при описании команд работы с памятью адресные операнды будут указываться в явной форме.

Рис. 8.3. Применение явной адресации. В команде с меткой LOOP регистр 9 используется как индекс-регистр, а регистр 10 — в качестве базового.

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

А 7,100(5,10)

Действительным адресом, как всегда, является

смещение+ (индекс-регистр)+(базовый регистр)

В данном случае значение смещения есть 100=6416. Регистр 5 — индексный, а регистр 10 — базовый. Действительный адрес поэтому равен

64+(5)+(10)

Если

(5)=00000008

и

(10)=00020000

то выполнение указанной команды будет заключаться в сложении содержимого регистра 7 с содержимым слова, хранящегося в памяти по адресу 0002006С. В программе на рис. 8.3 приведен пример использования явной спецификации адреса в команде сложения.

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

5А75А064

Предположим, мы хотим записать содержимое регистра 3 по адресу на 4 большему, чем тот, который указан в регистре 6, производя при этом модификацию с использованием регистра 2 в качестве индексного. В этом случае для достижения цели мы должны записать команду

ST 3,4(2,6)

Отметим, что машине при вычислении конечного адреса все равно, какой регистр индексный, а какой — базовый. Мы также могли написать

ST 3,4(6,2)

поменяв ролями регистры 6 и 2. Однако для ассемблера базовый и индексный регистры имеют существенные отличия. В процессе трансляции ассемблер заносит номер подразумеваемого базового регистра в поле В для спецификации адреса. Индексный регистр никогда не может подразумеваться. Несмотря на то что для выполнения программы порядок указания регистров при явной спецификации несуществен, разумно все-таки соблюдать нормальный порядок их указания, так как это поможет самому программисту и тем, кто впоследствии будет читать его программу, различать их.

Предположим, что мы не хотим использовать индексацию. Скажем, нам нужно вычесть содержимое полуслова, имеющего адрес на 10 больший, чем тот, который указан в регистре 12, из числа, находящегося в регистре 11. В этом случае вместо номера индексного регистра нужно указать 0. Мы должны написать

SH 11,10(0,12)

Ассемблер допускает и простую форму записи явных адресов в случае, когда не требуется индексирования или базирования. Мы могли бы написать

SH 11,10(, 12)

или даже

SH 11,10(12)

опустив указание числа 0 и запятой.

Желательно воздерживаться от употребления этих сокращений, пока вы не убедитесь, что твердо усвоили принципы явной адресации и адресации вообще.

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

ST 5,0(0,8)

В разд. 8.1 мы видели, что применение базовых регистров и смещений позволило избежать абсолютной адресации. Но в некоторых случаях написания системных программ, и в частности при использовании команды LA, описываемой в следующем разделе, абсолютная адресация необходима. Если мы укажем адрес, для которого отсутствуют базовый и индексный регистры, то действительным адресом будет являться число, представленное смещением. Пусть мы хотим записать содержимое регистра 5 по адресу 8. Избежать базирования и индексирования можно, указав нули в соответствующих местах адресного поля (используется явная спецификация).

Таким образом, достаточно написать

ST 5,8(0,0)

В данном случае смещение равно 8. Так как ничто к нему не будет добавлено (базового и индексного регистров нет), действительный адрес равен смещению, т. е. 8.

Возможны и краткие формы записи:

ST 5,8(0)

или

ST 5,8()

или даже

ST 5,8

Опять же советую вам пока воздержаться от их использования.

Таким образом, ассемблер допускает два способа спецификации адресов памяти. Можно употреблять явную форму, самостоятельно задавая номер базового регистра и значение смещения, но можно и возложить задачу определения пары регистр — смещение на сам ассемблер. Это неявная форма спецификации. Неявно мы указываем операнды, хранящиеся в памяти с помощью перемещаемых имен и выражений.

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

 

Теперь разница между адресами и значениями, хранящимися по этим адресам, должна быть ясна. Если нет, то вам необходимо еще раз внимательно просмотреть предшествующий материал.

Зачастую приходится помещать адреса в регистры. Как указывалось в предыдущем разделе, регистр, содержащий некоторый адрес, может быть использован в качестве базового при явном указании операндов, находящихся в памяти. Часто также требуется заносить в регистры небольшие числа (константы) для последующего использования последних в качестве счетчиков циклов или индексации. Значения счетчиков циклов могут неоднократно изменяться при выполнении циклов. Для решения всех этих задач можно использовать команду LOAD ADDRESS (ЗАГРУЗКА АДРЕСА), часто дающую выигрыш во времени и памяти.

Команда LA имеет формат RX и служит для занесения в регистр действительного адреса. Обращение к памяти при этом не производится, конечное значение регистра адреса памяти посылается в R1. Рассмотрим команду

LA 9,NMBR

NMBR — это перемещаемое имя, которому соответствует подразумеваемая пара: базовый регистр — смещение. При выполнении этой команды в MAR вычисляется сумма базового значения и смещения, а затем результат посылается в регистр 9. Короче говоря, по этой команде действительный адрес, соответствующий NMBR, помещается в регистр 9.

Но адреса — 24-разрядные, а регистры общего назначения предназначены для хранения 32-разрядных полных слов. Содержимое MAR записывает в 24 младших разряда регистра, с 8-го по 31-й (имейте в виду, что счет разрядов начинается с 0). Первые 8 битов регистра при выполнении команды LA всегда заполняются нулями.

Предположим, что в данном случае базовый регистр двенадцатый

и

(12)=0060480С

Смещение же для NMBR пусть равно 200. Тогда действительный 24-разрядный адрес, соответствующий NMBR, равен 604А0С. Независимо от предыдущего содержимого регистра 9 после выполнения команды в нем будет число

(9)=00604А0С

Если бы мы написали

LA 9,NMBR(6)

и при этом

(6)=00000008 то в результате (проверьте) получилось бы

(9)=00604А14

Заметим, что совершенно иного результата мы достигли бы, выполнив команду

L 9,NMBR(6)

После ее выполнения в регистре 9 находилось бы полное слово, хранящееся по адресу 604А14.

Рис. 8.4. Применение команды LA для приращения содержимого регистра 9, используемого в качестве индекс-регистра.

Так как мы загрузили некоторый адрес в регистр 9, пользуясь командой LA, то его в дальнейшем можно использовать в качестве базового, например указывая его явно при задании некоторого операнда. На рис. 8.4 приведена программа, вычисляющая сумму 10 чисел, хранящихся в виде последовательных полных слов, начиная с NMBRS. В этой программе команда LA используется для загрузки адреса, соответствующего NMBRS, в регистр 10, который впоследствии указывается в качестве базового в адресном поле команды сложения. Сравните программу рис. 8.4 с программами, приведенными на рис. 7.3 и 8.3.

Работа с командой LA и явная спецификация операндов позволяют довольно эффективно выполнять некоторые арифметические действия над содержимым регистров. Результат, которого мы этим достигаем, таков: вычисляется сумма заданной константы (смещения) и чисел, хранящихся в двух регистрах (базовом и индексном), после чего эта сумма посылается в некоторый третий регистр. Эта команда, используемая в качестве арифметической, применяется очень широко.

Нужно, однако, помнить, что при работе с этой командой на конечные результаты накладываются ограничения, определяемые тем, что все возможные адреса — 24-битовые. Если в результате выполнения сложения исходных чисел должно получиться отрицательное число, например FFFFFFFE, то при применении команды LA в регистре, указанном на месте первого операнда, окажется довольно большое положительное число, 00FFFFFFE. Ни один из получающихся результатов не должен также превышать 224—1 = 16 777 215. В противном случае старшие разряды (с 0 по 7) будут отброшены, при этом получится неверный ответ.

Имея это в виду, попробуем поработать с командой LA. Предположим, мы написали команду

LA 5,6(8,10)

Действительный адрес равен

6+(8)+(10)

 

Рис. 8.5. Применение команды LA для загрузки констант в регистры. Регистр 10 используется как регистр базы и счетчик циклов.

Сумма вычисляется и засылается в регистр 5. Теперь рассмотрим команду

LA 6,0(6,6)

Действительный адрес равен

0+(6)+(6)=2Х(6)

Итак, в результате выполнения команды содержимое регистра 6 удваивается.

Для сложения содержимого регистра с некоторой константой в команде LA константа указывается в качестве смещения, а заданный регистр — в качестве первого операнда и базового регистра.

По команде

LA 10,4(0,10)

к (10) будет добавлено 4. Этот способ можно использовать для повышения эффективности работы с циклами. На рис. 8.5 приведена программа с рис. 8.3, модифицированная путем включения команды

LA 9,4(0,9)

используемой для увеличения на 4 содержимого счетчика циклов в регистре 9 вместо команды

А 9,= F'4'

Применение команды LA в подобных случаях более эффективно по трем причинам. Во-первых, включение в программу литерала означает, что для хранения соответствующего значения будет отведено целое машинное слово. Во-вторых, выполнение команды А длится дольше, чем выполнение команды LA поскольку число 4 перед выполнением сложения необходимо извлечь из памяти. Наконец, выполнение команды LA завершается непосредственно после вычисления суммарного адреса, а команда А требует засылки обоих операндов в арифметическое устройство для сложения после определения местонахождения литерала.

Рис. 8.6. Модификация программы с рис. 7.5 с использованием команд LA и явной адресации памяти.

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

LA 2,0(7,2)

производит вычитание числа 4 из содержимого регистра 2.

Наконец, если на месте базового и индексного регистров указать нули, то действительный адрес будет в точности равен значению смещения. Поэтому для загрузки 0 в регистр 3 достаточно написать

LA 3,0(0,0)

а после выполнения команды

LA 7,100(0,0)

в регистре 7 будет находиться число 00000064— 10010 в шестнадцатеричной форме. Так как значение смещения должно находиться в диапазоне от 0 до 4095, то числа из этого диапазона можно непосредственно загружать в регистр с помощью команды LA.

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

LA 3,0 и LA 7,100

по своему действию аналогичны приведенным выше.

На рис. 8.6 приведена программа, представляющая собой модификацию программы рис. 7.5 с помощью многократного использования команды LA. Хотя в данном конкретном случае применение команды LA дало нам незначительный выигрыш в памяти и эффективности, во многих других случаях команда LA может заменять две, а то и три другие команды.

 
Статьи раздела