Базовый регистр

 

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

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

Мы сообщаем ассемблеру, какой регистр следует использовать в качестве базового и чему равно базовое значение, с помощью специальной псевдокоманды USING. В наиболее простом виде эта псевдокоманда записывается так:

USING адрес, регистр

Адрес в данном случае представляет перемещаемое имя, определенное в данной программе, а единственное ограничение на регистр — то, что он не может быть нулевым. Итак, команда USING говорит ассемблеру о следующем: «Начиная с этого момента и до появления новой директивы считать базовым регистром регистр с указанным номером, а базовым значением — адрес ячейки с указанным именем».

Базовым может быть любой регистр, кроме регистра 0. В большинстве программ для этой цели используется регистр 12. Например,

USING BASEPOS.12

означает, что имя BASEPOS, определенное в данной программе, является именем базовой ячейки, а регистр 12 теперь будет использоваться в качестве базового. Имени BASEPOS соответствует нулевое смещение; смещения, соответствующие именам, встречающимся после BASEPOS, представляют собой их адреса относительно базовой ячейки. В качестве базового регистра, соответствующего таким именам, будет использоваться регистр 12. Для загрузки исходного значения в базовый регистр можно было попытаться поступить так (неверно!):

LA 12,BASEPOS

Предположим, что эта команда находится в начале программы:

SUBR START 0

STM 14,12,12(13)

USING BASEPOS,12

LA 12,BASEPOS

BASEPOS

Но не будем спешить! Адресация операнда команды LA произведена с помощью имени BASEPOS. Перемещающему имени соответствуют определенный базовый регистр и значение смещения. Что в данном случае в качестве них следует выбрать ассемблеру? Пока ассемблеру не сказано, каким образом можно вычислить адрес некоторого имени, это имя нельзя использовать для адресации. Мы же получили порочный круг: попытались использовать конкретное имя для обеспечения возможности использования имен вообще.

Выйти из затруднительного положения, в котором мы оказались, можно с помощью пары команд:

BALR 12,0

USING *,12

Вспомним, что указание символа * в поле операндов эквивалентно ссылке на текущее значение счетчика размещения. Поскольку USING является псевдокомандой, она не преобразуется на этапе ассемблирования в какой-либо машинный аналог. Символ * в поле операндов псевдокоманды USING является просто ссылкой на адрес следующей за ней команды. Вспомним, что в случае, когда второй операнд равен 0, выполнение команды BALR не приводит к переходу, а вызовет только загрузку R1 значением адреса следующей команды. Итак, в нашем случае команда BALR загружает адрес следующей за ней команды в регистр 12. Команда USING говорит о том, что адрес следующей команды (т. е. в нашем случае содержимое регистра 12) является базовым адресом, а регистр 12 — базовым регистром. Таким образом, мы определили базовый регистр и базовый адрес без использования какого- либо символического имени.

Порядок рассмотренной пары BALR-USING очень существен. Задержим на минуту наше внимание и разберемся, к чему может привести указание USING перед командой BALR. Предположим, что в нашей программе пара BALR-USING записана в следующем порядке (неверно!):

USING *,12

BALR 12,0

Команда USING говорит о том, что адрес следующей команды (BALR) необходимо использовать в качестве базового, а в качестве базового регистра нужно взять регистр 12. Команда BALR производит загрузку адреса следующей за ней команды в регистр 12. Но этот адрес на 2 отличается от адреса, определенного в качестве базового командой USING. Теперь все действительные адреса будут на 2 отличаться от требуемых, и, вероятно, программа не будет выполняться должным образом.

Итак, мы рассмотрели все основные требования, предъявляемые к подпрограмме в случае, когда внутри нее самой не производится вызов. Изучению этого случая посвящен следующий раздел. Общая структура подпрограммы приведена на рис. 13.6. Здесь отражен*) также определение базового регистра.

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

Рис. 13.6. Структура подпрограммы.

Команда USING в общем виде выглядит так:

USING адрес, Rl, R2, R3,...

Здесь Rl, R2,... —перечень регистров, каждый из которых можно использовать в качестве базового. Пусть, например, ассемблеру дано следующее указание:

USING HERE,5,6,7

Первый регистр в списке будет использован в качестве базового для тех выражений, адреса которых могут быть представлены в виде суммы заданного базового адреса и смещения, величина которого не больше чем 4095. Остальные регистры будут базировать области, отстоящие от базовой ячейки на соответствующее число интервалов по 4096 байтов. В нашем примере регистр 5 будет использоваться как базовый для имен, имеющих значения смещения относительно HERE меньшие, чем 4096. Регистр 6 будет использован в качестве базового для имен, которым соответствуют объекты, отстоящие от HERE+4096 менее чем на 4096 байтов. Базовой ячейкой, соответствующей регистру 7, будет ячейка с адресом HERE+8192.

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

Как и в случае одного базового регистра, необходимо произвести загрузку всех регистров списка перед использованием имен, которым эти регистры могут соответствовать как базовые. Предположим, что определение одного базового регистра уже выполнено:

BALR 12,0

USING *,12

Теперь мы можем работать с перемещаемыми именами, которым соответствуют объекты, отстоящие от начала команды, следующей за USING, менее чем на 40% байтов. После этого загрузка регистров 5, 6, 7 может быть произведена уже так:

LM 5,7,HEREADDR

где область HEREADDR определена в нашей программе следующим образом:

HEREADDR DC A(HERE,HERE+4096,HERE+8192)

Здесь мы заодно продемонстрировали возможность использования групповой адресной константы в предложении DC. Приведенная выше команда эквивалентна следующей последовательности:

HEREADDR DC A(HERE)

DC A(HERE+4036)

DC A(HERE+8192)

Существуют и другие, более изощренные способы определения групп базовых регистров. Однако мы рекомендуем придерживаться описанного метода, так как он наиболее прост и работает всегда. Конечно, при этом требуется, чтобы имя HEREADDR было адресуемым, т. е. чтобы соответствующий ему адрес мог быть представлен в виде суммы допустимого значения смещения (не превосходящего 4096) и базового адреса, определенного ранее. На рис. 13.7 приведен пример применения описанного метода.

 

Рис. 13.7. Групповое задание базовых регистров.