Описание автокода Madlen

(Глава III из книги Салтыков, Макаренко “Программирование на языке Фортран”)

Содержание

1. Введение

Автокод Madlen используется в мониторной системе «Дубна» как самостоятельный язык программирования нижнего уровня и как промежуочный язык при трансляции подпрограмм с Фортрана. При трансляции алгольных процедур (написанных на Алголе-ГДР), выхода на Madlen не происходит, однако пользователь имеет возможность получить расечатку текста транслированной процедуры в виде, сходном с автокодной записью. При необходимости можно получить автокодный текст транслированной алгольной процедуры путем обратной трансляции ее с языка загрузки на автокод.

Часть пакета задачи, написанная на автокоде, оформляется как отдельная’подпрограмма или несколько подпрограмм и транслируется независимо от других подпрограмм. Если автокодная подпрограмма оформлена по определенным правилам, то она может быть использована наравне с фортранными и алгольными подпрограммами (см. § 14).

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

Основу автокодной подпрограммы составляют автокодные команды, представляющие собой символическую запись машиппых команд. Каждая автокодная команда, как правило, транслируется в одну машинную команду (исключения описаны в § 15). То обстоятельство, что Madlen является промежуточным языком при трансляции с Фортрана, естественным образом отразилось на его структуре. Например, любой невыполняемый (декларативный) оператор Фортрана имеет автокодный аналог.

Транслятор с автокода выдает удобную для пользователя диагностику ошибок, имеет аппарат редактиования, позволяющий получать автокодный текст в виде, удобном для чтения, независимо от способа его пробивки. Все это в сочетании с высокой скоростью трансляции (200 операторов в секунду) делает автокод Madlen удобным и эффективным средством программирования при решении задач, требующих максимального использования специфики БЭСМ-6.

2. Операторы автокода

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

Формат автокодного оператора подобен формату машинной команды. Это означает, что отдельные его составные части боответствуют индекс-регистру, коду операции и адресной части машинной команды. Кроме того, всегда можно обозначить адрес ячейки, в которой находится данная команда, а также поставить признак того, что данная команда является левой, т. е. занимает 24 старших разряда машинного слова. Поскольку для записи каждой части автокодного оператора нет специально выделенных колонок перфокарты, эти части отделяются друг от друга специальными разделителями (запятая, двоеточие, точка).

Любой автокодный оператор может быть расположен в произвольных колонках перфокарты с 2-й по 42-ю включительно. Некоторые операторы имеют «длинную» структуру и могут располагаться по 72-ю колонку включительно. Колонки с 73-й по 80-ю всегда относятся к комментарию.

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

Большинство операторов автокода шаб1еп можно записать следующим образом:

    <метка> : <индекс-регистр> , <мнемокод> , <полный адрес>

Обязательными элементами оператора являются запятые, отделяющие мнемокод от указателя индекс-регистра и от полного адреса, записываемого в адреснй части. Мнемокод также всегда (за исключением единственного случая) присутствует в записи оператора. Остальные части оператора могут отсутствовать.

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

Примеры.

    *5 : 14 ,XTA,
   ABT :    ,A+X, INT
    /7 :    ,BSS,
       :    ,XTA, А+4
            ,A*X, =R5.
 PRINT8:    ,NAME,

3. Идентификаторы

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

Идентификатор — это последовательность букв и цифр, начинающаяся с буквы.

Под «буквами» в автокоде понимаются все буквы латинского и русского алфавитов и, кроме того, символы * и /. Максимально допустимая длина идентификатора равна 8 символам (пробелы игнорируются).

Таким образом, множество допустимых идентификаторов в автокоде шире, чем в Фортране или Алголе.

Перечислим остальные символы, составляющие алфавит языка Madlen, но не входящие в состав идентификаторов:

    + плюс              . точка
    — минус             = равенство
    ( левая скобка      : двоеточие
    ) правая скобка     ’ апостроф
    , запятая

В некоторых конструкциях языка (текстовых константах и комментариях) допустимы следующие энаки:

    ;, < >, [ ], _ (подчеркивание), !, $ или ◇.

Особую роль играет идентификатор, состоящий из одного символа *. Он обозначает адрес той команды, в которой он написан. Например, оператор ,UJ, *+2 означает безусловный переход на левую команду машинного слова, адрес которого равен адресу данной команды плюс 2.

Примеры идентификаторов:

    PROGRAM
    *15
    /101
    *AB*

4. Мнемокоды

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

Мнемокод — это определенная последовательность букв, понимаемых в смысле автокода, цифр и знаков + и —.

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

Мнемокоды команд, как правило, состоят из трех символов (см. приложение 1). Исключение составляют специальные мнемокоды (CALL, BASE и др.), а также мнемокоды экстракодов, имеющие иногда но нескольку равноправных обозначений (см. приложение 1А).

Второй символ мнемокода команды обычно определяет вид соответствующей машинной операции. В частности, для обозначения операций сложения, вычитания, умножения и деления используются символы +, —, * и /. Дадим толкование некоторых других указателей вида операций:

  • Т — пересылка (Transfer),
  • Z — условный переход по ω = 0 (Zerojump),
  • J — безусловный переход (Zump),
  • S — сдвиг (Shift),
  • A — логическое умножение (And),
  • O — логическое сложение (Or),
  • E — сравнение (Exclusive Or),
  • R — циклическое сложение (Round),
  • L — конец цикла (Loop).

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

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

  • А — сумматор (Accumulator);
  • S — магазин (Stack);
  • Y — регистр младших разрядов (Younger bits);
  • M — указатель индекс-регистра (Modifier);
  • E — «регистр» порядка, т. е. 48-42 разряды сумматора, в которых размещается порядок числа;
  • X — короткий адрес ячейки памяти;
  • V — длинный адрес, не модифицируемый по индекс-регистру;
  • U — длинный адрес, модифицируемый по индекс-регистру;
  • N — адрес, не являющийся адресом ячейки памяти и рассматриваемый по mod 27,

Примеры мнемокодов:

  • ATX — запись из сумматора в ячейку памяти с коротким адресом;
  • ASN — сдвиг сумматора на число разрядов, определяемое семью младшими разрядами исполнительного адреса;
  • UZA — условный переход по ω = 0 с модификацией адреса по индекс-регистру;
  • VTM — запись исполнительного адреса команды (без модификации по индекс-регистру) в индекс-регистр;
  • E+N — сложение порядка числа на сумматоре с адресом, определяемым семью младшими разрядами исполнительного адреса команды, минус 64.

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

5. Полный адрес

В адресной части команды разрешается записывать:

  1. идентификатор,
  2. целое десятичное число без знака,
  3. <восьмеричное число=""> В,
  4. *
  5. адрес типа «литерал» (см. § 6),
  6. полный адрес.

Полным адресом называется любая конструкция адресной части, состоящая не более чем из двух адресов типов 1) - 5), взятых, быть может, со знаками + или —. Адрес может быть пустым, ему соответствует нулевое значение.

Примеры.

    A
    *+2
    X+5
    C+30B
    -AB+C15

Адреса, записанные в виде десятичного или восьмеричного числа (или их комбинации со знаками + и —), являются абсолютными, т. е. они не зависят от расположения подпрограммы в памяти машины. Фактические значения адресов остальных типов будут определяться при загрузке подпрограммы в память машины. При этом вся адресная арифметика выполняется по модулю 215, т. е. у результирующего адреса берется 15 младших разрядов. Отрицательные значения берутся в дополнительном коде. Например, адресу —1 соответствует восьмеричный адрес 77777В,

6. Указатель индекс-регистра

Указатель индекс-регистра можно записывать в виде десятичного числа от 1 до 15. При этом пустой или нулевой указатели соответствуют отсутствию модификации. Однако удобнее использовать идентификаторы, так как это позволяет легко переопределять конкретные значения соответствующих индекс-регистров. В последнем случае идентификаторам должны быть поставлены в соответствие допустимые номера индекс-регистров (десятичные или <восьмеричные> В) с помощью операторов эквивалентности (см. § 10).

Отметим, что пустой и нулевой указатели индекс-регистра в некоторых случаях воспринимаются транлятором по-разному (см. § 15),

7. Метки

Метка обозначается идентификатором и выполняет несколько функций. Во-первых, она является описанием данного идентификатора, т. е. однозначно его определяет. Поэтому каждый идентификатор может быть указан в виде метки, как правило, не более одного раза. Во-вторых, метка, относящаяся к команде, означает, что данная команда будет помещена в левую половину машинного слова. В-третьих, адрес метки, указанной перед командой, константой или оператором с мнемокодом BSS, является внутренним адресом данной подпрограммы (см. § 15).

Метка отделяется справа двоеточием. Двоеточие без идентификатора метки (пустая метка) означает, что данную команду надо поместить в левую половину слова. При этом может случиться, что предыдущее машинное слово оказалось не полностью сформированным. В этом случае транслятор автоматически дополняет его правой командой с мнемокодом UTC (см. приложение 1).

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

Команды LIB, *60 и *66 всегда считаются помеченными, т.е. имеющими метку, даже если она не указана. Помеченными считаются также все команды, непосредственно следующие за командами

    VJM, FUN, PRINT, TAPE, DRUM, SJ, CTX,
    *50 - *57, *61 - *65, *67, *70 - *77.

Замечание. Описанные выше случаи автоматической помеченности не распространяются на восьмеричные коды операций, соответствующие указанным мнемокодам.

8. Константы

Автокод допускает 4 типа констант:

  • восьмеричные (OCT, LOG),
  • целые (INT),
  • вещественные (REAL),
  • текстовые (ISO, GOST, TEXT, TEL).

Константы могут быть заданы как специальными операторами (мнемокоды которых приведены выше в скобках), так и адресами типа «литерал», т. е. путем непосредственной записи константы в адресной части команды. В первом случае вид константы определяется ее адресной частью. Указатель индекс-регистра при трансляции констант не учитывается и может быть использован, например, для их нумерации. Указатель метки имеет тот же смысл, что и для команд. Отметим, что для правильной трансляции констант не требуется их помеченности, т. е. пустая метка перед константой не обязательна. Константы всегда транслируются в целое число машинных слов, причем для первых трех типов — в одно слово.

Константа типа OCT имеет в адресной части восьмеричное число, состоящее не более чем из 16 цифр (без буквы В справа). При трансляции константы эти цифры будут располагаться в машинном слове слева направо, начиная со старших его разрядов. Лишние (сверх 16) правые цифры будут отброшены, а недостающие до полного машинного слова — дополнены нулями справа.

Примеры.

Восьмеричная константа ,OCT, 4 транслируется в машинное слово 4000 0000 0000 0000, а константа ,OCT, 1777 7356 4216 3730 157 будет представлена в машине как 1777 7356 4216 3730.

Константы типа LOG аналогичны предыдущим с той лишь разницей, что заполнение машинного слова производится справа налево, начиная с младших его разрядов, и дополнение нулями производится слева, Отметим, что константы этого типа являются аналогами восьмеричных констант Фортрана.

Примеры.

Восьмеричная константа ,LOG, 4 транслируется в машинное слово 0000 0000 0000 0004 Однако константа ,LOG, 1777 7356 4216 3730 157 будет представлена в виде 1777 7356 4216 3730 т, е. так же, как и в случае константы типа OCT.

Константы типа INT могут иметь в адресной части любое целое десятичное число (без знака или со знаком -), не превосходящее 240-1. В результате трансляции такой константы будет образовано машинное слово, представляющее ненормализованное число с порядком 40 и с запятой, фиксированной в конце мантиссы (мантиссы отрицательных чисел представляются в дополнительном коде с 1 в 41-м разряде).

Примеры.

Целая константа ,INT, 38 транслируется в машинное слово 6400 0000 0000 0046 При этом десятичному числу 38 соответствует восьмеричное число 46, расположенное в младших разрядах мантиссы. В разрядах порядка (48-42) указано машинное представление порядка 4010.

Константа ,INT, —5 будет представлена в виде 6437 7777 7777 7773 Здесь мантисса представлена в дополнительном коде с 1 в 41-м разряде.

Константы типа REAL имеют в адресной части любое десятичное число, допустимое для БЭСМ-6. При этом правила записи аналогичны фортрапным, т.е. обязательна десятичная точка и допустимо использование буквы E с последующим целым числом в качестве показателя степени при 10.

Примеры.

а) Вещественная константа ,REAL, 1. транслируется в нормализованное машинное число 4050 0000 0000 0000 Здесь в разрядах 48-42 содержится двоичный код 1 000 001, а в разрядах 41-40 — код 01. Объединяя каждые три соседних двоичных разряда в один восьмеричный, получим в разрядах 48-40 восьмеричное число 405.

б) Константа ,REAL, 2.E1 будет представлена как 4252 0000 0000 0000. Здесь в разрядах 48-42 содержится двоичный код 1 000 101, а в разрядах 41-37 — код 01010, что соответствует порядку 5 и положительной нормализованной мантиссе, полученной из двоичного числа 10100, равного 2010. Объединяя по три соседних двоичных разряда в один восьмеричный, получим в разрядах 48-37 восьмеричное число 4252.

в) Отрицательная константа ,REAL, -1, будет транслирована в 4020 0000 0000 0000 (мантисса в дополнительном коде с нормализацией и с 1 в 41-м разряде).

Константы типа INT и REAL аналогичны целым и вещественным константам Фортрана, т. е. их запись и машинное представление идентичны.

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

Константы типа ISO (см. приложение 2) могут содержать до 128 символов, которым предшествует указатель nH, где n — число символов. Например, текстовая константа

    ,ISO, 6HBESM-6

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

При желании любой символ может быть задан своим кодом ISO, т. е. в виде восьмеричного числа (не преносходящего 377B), заключенного в апострофы (‘). Например, рассмотренная выше константа может быть записана в виде

    ,ISO, 6HB'105''123'M-6

Здесь вместо букв E и S указаны их представления в кодировке ISO (см. приложение 2), Заметим, что таким способом можно задавать любые восьмиразрядные комбинации 0 и 1, а не только те из них, которые соответствуют какому-либо символу ISO. Ниже будет рассмотрено использование этого способа для записи восьмеричных констант (см. § 16). Отметим, что символ «апостроф» может быть задан только в восьмеричном виде, например,

    ,ISO, 1H'47'

Важно отметить, что для записи констант типа ISO можно использовать часть перфокарты по 72-ю колонку включительно. Если в указателе nH значение n превышает число символов, информация о которых содержится по 72-ю колонку, то вместо недостающих символов будут добавлены пробелы.

Если n = 0 или значение n не указано, то транслятор полагает n = 6 и формирует машинное слово, состоящее из 6 пробелов. Если n не делится нацело на 6, то транслятор добавляет необходимое для получения целого числа машинных слов количество пробелов. Однако это действие не выполняется, если вслед за оператором с мнемокодом ISO будет написан оператор с мнемокодом CONT. Его адресная часть должна быть аналогична адресной части предыдущего оператора. Оператор с мнемокодом CONT в свою очередь может иметь продолжение.

Пример. Текстовая константа.

        ,ISO, 9HBESM-6␣JI
     Т: ,CONT, 2HNR
        ,CONT, 6H␣DUBNA

состоит из 17 символов, В результате трансляции будет образовано три машинных слова, содержащих указанный текст, дополненный справа одним пробелом (в 8 младших разрядах третьего слова).

Метка в операторах ISO и CONT совпадает с адресом слова, в которое помещен первый символ из адресной части соответствующего оператора, В приведенном примере метка T соответствует второму машинному слову (содержащему символ N).

Константы типа GOST полностью аналогичны константам предыдущего типа с той лишь разницей, что кодирование символов при образовании машинных слов будет выполнено в соответствии с кодом АЦПУ-128 (приложение 3).

Константы типа ISO аналогичны текстовым (холлеритовским) константам Фортрана. Использование констант типа GOST связано со спецификой печатающего устройства БЭСМ-6. Необходимость в такой кодировке возникает при выдаче на печать текстовой информации путем непосредственного обращения к экстракоду печати, что используется довольно редко.

Константы типа TEXT (приложение 4) отличаются от предыдущих кодировкой, а также тем, что в одно машинное слово записывается 8 символов, так как каждый символ кодируется 6 двоичными разрядами. Эта кодировка используется для внутреннего представления текстовой информации в системе «Дубна». В частности, в кодировке TEXT представлены все наименования подпрограмм в библиотечных каталогах. Поэтому при работе с библиотеками часто используется эта кодировка.

Константы типа TEL имеют 5-разрядную кодировку (см. приложение 5). Однако упаковка символов в машинные слова производится по 6 штук. При этом пятиразрядный код дополняется двумя нулями слева и одним нулем справа, превращаясь в восьмиразрядный. Указатели телетайпных регистров могут добавляться транслятором автоматически с соответствующим увеличением длины константы. Отметим, что константы этого типа обычно используются только в системных программах.

9. Адреса типа «литерал»

Адресами типа «литерал» называются адресные части команд, имеющих вид

    =   <восьмеричное число>
    =:  <восьмеричное число>
    =I  <целое десятичное число>
    =R  <вещественное число>
    =nH <список символов>

Знак = является признаком адреса типа «литерал». В первом случае восьмеричное число определяет константу типа LOG, во втором случае — типа OCT. Символы I, R и nH указывают, что константы имеют тип INT, REAL и ISO соответственно. В последнем случае n не должно превосходить 6, так как каждая команда может оперировать с одним машинным словом.

При появлении в полном адресе команды одной из указанных конструкций транслятор формирует соответствующую ей константу и заносит ее в машинное слово, которое автоматически резервируется в конце подпрограммы. Всюду, где встретится рассматриваемый адрес типа «литерал», он будет заменен транслятором на адрес указанного машинного слова.

Примеры.

     10 ,XTA, =-77      ,A*X, =R .5Е6
        ,AAX, =:774     ,XTS, =ЗHABC
        ,XTA, =I2     14,VTM, =R1.

Если адреса типа «литерал» имеют одинаковые указатели (скажем, R) и в результате трансляции приводят к одинаковым машинным словам, то такие адреса считаются эквивалентными и для определяемых ими констант будет отведена одна и та же ячейка. Однако такая экономия выполняется строго внутри данного класса адресов типа «литерал» и не затрагивает идентичных (в смысле машинного представления) констант, определенных другими способами.

Примеры.

    ,XTA, =R1.
    ,A*X, =R.99999 99999 999
    ,A/X, =:4050
    ,A+X, =6H'202''200''0''0''0''0’

В приведенных примерах все 4 константы будут транслированы в одно и то же машинное слово 4050 0000 0000 0000 (вторая константа будет транслирована идентично первой из-за ограничения машинной точности 12 десятичными знаками). Однако эквивалентными будут считаться лишь адреса первых двух констант, т, е. всего будет сформировано 3 машинных слова, в каждом из которых будет одна и та же машинная константа, написанная выше.

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

10. Описания

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

Описать идентификатор — это значит поставить ему в соответствие некоторое число (адрес некоторой ячейки памяти, номер индекс-регистра, адрес типа N и т. д.). Любой идентификатор может быть описан, вообще говоря, не более чем одним способом. Метки, как уже говорилось, сами являются описаниями.

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

    <метка)>: ,BSS, <полный адрес>

Примеры.

      А : ,BSS, 1
     *С : ,BSS,
    TAB : ,BSS, 100
      T : ,BSS, 25B
      Z : ,BSS, T - A

Здесь для идентификатора A зарезервирована одна ячейка памяти. Метке *C соответствует конструкция BSS с пустой адресной частью. Это значит, что адрес метки *C совпадает с адресом следующего за ней машинного слова, в данном случае с адресом метки TAB. Для идентификатора TAB отведен массив из 100 машинных слов. Это означает, что в подпрограмме можно использовать адреса вида TAB+n (0 <= п <= 99), каждый из которых будет соответствовать (n+1)-му слову из этого массива. Из примеров видно также, что количество резервируемых слов можно задавать в виде восьмеричного числа (с обязательной буквой В после числа). Последний из приведенных операторов означает, что число ячеек памяти, резервируемых для идентификатора 2, равно разности адресов T и A, т.е. в данном случае десятичному числу 101.

Отметим особую роль конструкции вида

    <метка> : ,BSS, <пусто>

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

Например, запись

     A :    ,BSS,
    *3 : 14 ,XTA,

означает, что написанная команда имеет две эквивалентные метки A и *3. Однако при необходимости между этими двумя операторами могут быть вставлены некоторые команды или другие операторы, и тогда указанные метки, вообще говоря, перестанут быть эквивалентными.

Опытные программисты, как правило, помечают нужные команды посредством «пустого» BSS, т. е. не привязывают метку жестко к определенной команде. Это дает возможность вставлять или изымать перфокарты, «эквивалентить» различные метки и т. д., не нарушая структуры подпрограммы.

Заметим, что описанная конструкция является автокодным аналогом фортранного оператора CONTINUE.

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

Общий вид этой конструкции

    <идентификатор> : ,EQU, <полный адрес>

Примеры.

    A: ,EQU, 17B
    C: ,EQU, A + 3
    L: ,EQU, * + 5
    T: ,EQU, =R1

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

Отметим, что идентификаторы, которым по смыслу соответствуют номера индекс-регистров или адреса типа N (см. § 4), могут быть описаны только через эквивалентности или их модификации.

Эквивалентности чаще всего располагают в начале подпрограммы, соблюдая порядок их следования. Отметим, что оператор эквивалентности имеет много общего с фортранным оператором EQUIVALENCE.

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

Мы рассмотрели способы описания внутренних объектов подпрограммы. Прежде чем перейти к описаниям внешних объектов, рассмотрим еще три типа операторов с мнемокодами NAME, END и CALL.

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

    <идентификатор> : ,NAME,
    <идентификатор> : <индекс-регистр> ,NAME,
    <идентификатор> : <индекс-регистр> ,NAME, ***

Наиболее часто используется первая из приведенных форм записи.

Мнемокод END служит признаком конца записи подпрограммы (аналогично фортранному оператору END).

Мнемокод CALL служит для вызова внешних подпрограмм с помощью оператора

    ,CALL, <идентификатор вызываемой подпрограммы>

Возможны и другие, нестандартные способы вызова подпрограмм (см. ниже).

Внешними объектами данной подпрограммы могут быть массивы, являющиеся общими для нескольких подпрограмм (в частности, аналоги фортранных COMMON-блоков), а также массивы специального вида, необходимые для организации обмена информацией с магнитными барабанами и магнитными лентами (дисками). Для описания таких внешних массивов в автокоде предусмотрено несколько типов операторов, наиболее удобным из которых является оператор с мнемокодом BLOCK. Этот оператор имеет вид

    /идентификатор\ : /характеристика\ ,BLOCK, / список \
    \   блока     /   \и тип массивов/         \массивов/

Характеристика массива определяется одной из букв:

  • L — массив — можно разместить, начиная с произвольной ячейки памяти;
  • P — страничный массив, начальный адрес которого должен быть кратным 102410;
  • S — секторный массив, начинающийся с адреса, кратного 25610.

Тип массива указывается одной из следующих букв:

  • P — собственный массив, т. е, массив, недоступный другим подпрограммам;
  • U — несобственный массив;
  • C — общий массив.

В настоящее время тип U не задействован и понимается как P. Отметим, что вместо массивов с указателем LP часто удобнее использовать конструкцию BSS, так как в этом случае массив будет внутренним и его можно базировать (см. § 15).

Общие массивы, в отличие от собственных, доступны любым подпрограммам, в которых они описаны теми же идентификаторами блоков. Если идентификаторы блоков, описывающих общие массивы, удовлетворяют определенным требованиям (см. § 14), то эти блоки являются автокодными аналогами фортранных COMMON-блоков.

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

Под массивы, описанные конструкцией BLOCK, резервируется участок памяти длиной, равной сумме длин массивов, указанных в списке этого блока. При этом адрес начала первого массива совпадает с адресом идентификатора блока.

Примеры.

    A : LC ,BLOCK, B(3), D(5), CD, EF(), *SQ(12)

Здесь описан общий массив (начинающийся с произвольного адреса) длиной 21 машинное слово. При этом длина массива CD равна 1, а начальные адреса массивов EF и *SQ совпадают,

    *ABC* : LC ,BLOCK, A, B(7), C(18)

Этот блок является автокодным налогом фортранного COMMON-блока, описанного оператором

    COMMON /ABC/ A, B(7), C(18)

В листе загрузки идентификаторы фортранных COMMON-блоков записываются «по-автокодному», т.е. обрамляются звездочками.

Конструкция BLOCK может располагаться по 72-ю колонку перфокарты включительно. Список в ее адресной части может быть продолжен применением конструкции CONT.

Пример.

    A : LC ,BLOCK, B(3)
           ,CONT , D(5), CD
           ,CONT , EF(), *SQ(12)

Это другая запись рассмотренного ранее примера.

Вместо описания группы массивов с помощью конструкции BLOCK можно использовать оператор описания отдельного массива с последующими эквивалентностями. Рассмотренный выше пример можно записать следующим образом:

      A : ,LC , 21
      B : ,EQU, A
      D : ,EQU, B+3
     CD : ,EQU, D+5
     EF : ,EQU, CD+1
    *SQ : ,EQU, EF

Здесь первый оператор описывает массив A длиной, равной общей длине блока (резервируя тем самым участок памяти длиной 21 слово), а все остальные массивы, составляющие блок, описываются в виде цепочки эквивалентностей. Этот пример иллюстрирует удобство конструкции BLOCK.

К числу внешних объектов подпрограммы относятся все подпрограммы, которые ею вызываются. Как сказано выше, вызов подпрограммы можно осуществить с помощью оператора с мнемокодом CALL. Этот стандартный способ вызова не требует (но и не исключает) специального описания вызываемой подпрограммы. Отметим, что в этом случае возврат в вызывающую подпрограмму производится на левую команду следующей ячейки, адрес которой автоматически запоминается в 13-м индекс-регистре.

Вызов подпрограммы можно осуществить также оператором

    13 ,VJM, <идентификатор подпрограммы>

или, например, так:

         13 ,VTM, *10
            ,UJ , <идентификатор подпрограммы>
    *10 :   ,BSS,

т. е. с возвратом на заранее предписанную ячейку (в данном случае на метку *10). Во всех подобных случаях необходимо описание вызываемой подпрограммы, что делается оператором

    <идентификатор подпрограммы> : ,SUBP,

Рассмотренный оператор является аналогом фортранного оператора EXTERNAL и, следовательно, он необходим в тех случаях, когда вызов подпрограммы производится через посредство другой подпрограммы (т. е. путем указания наименования вызываемой подпрограммы в качестве фактического параметра при вызове подпрограммы-посредника).

Рассмотрим теперь оператор вида

    <идентификатор> : ,ENTRY,

который служит для описания дополнительного входа в подпрограмму аналогично фортранному оператору ENTRY.

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

Отметим, что, в отличие от Фортрана, тип любого автокодного ENTRY (SUBROUTINE, FUNCTION и т. п.), равно как и список его формальных параметров, не обязан совпадать с таковыми у основного входа (см. § 14).

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

Заметим также, что команда, следующая за оператором с мнемокодом ENTRY, считается помеченной.

Укажем еще несколько описательных конструкций, используемых сравнительно редко.

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

Примеры.

    *20 : В ,BLOCK, A(23), D (2)
    *25 :   ,BLOCK, A(15), B (6)

Первая конструкция эквивалентна описаниям

    A : ,EQU, 20B
    D : ,EQU, A+23

Вторая конструкция равнозначна описаниям

    А : ,EQU, 25
    B : ,EQU, A+15

Еще одна разновидность конструкции BLOCK позволяет описывать последовательности эквивалентностей, что видно из примера

    M : I ,BLOCK, A, B(15), C(6)

Эта конструкция эквивалентна описаниям

    A : ,EQU, M
    B : ,EQU, A+1
    C : ,EQU, B+15

Идентификатор M, естественно, должен быть уже описан каким-то способом (например, через BSS). Это одно из немногих исключений из правила, согласно которому допускается не более чем однократное описание идентификатора в виде метки (см. § 7).

Отметим, что рассмотренные три разновидности конструкции BLOCK не резервируют ячеек памяти.

Рассмотрим еще несколько разновидностей эквивалентности. Конструкция вида

    <идентификатор> : ,WEQ, <полный адрес>

называется косвенной эквивалентностью. Она приписывает идентификатору значение, равное содержимому 1-15 разрядов слова с заданным полным адресом в момент загрузки подпрограммы.

Косвенная эквивалентность позволяет, в частности, резервировать (например, посредством оператора BSS) участки памяти переменной длины. В этом случае длина участка может быть задана, например, с помощью оператора DATA, написанного в PROGRAM. Ячейка памяти, куда засылается нужное значение длины (в виде целой константы) должна быть, естеcтвенно, элементом COMMON-блока, описанного в автокодной подпрограмме.

Конструкция

    <идентификатор> : ,P*P, (<полный адрес>) (<полный адрес>)

приписывает идентификатору значение, равное произведению полных адресов (по модулю 216), приведенных в адресной части.

Эта конструкция позволяет удобным образом резервировать участки памяти под многомерные массивы, в том числе под массивы с переменными размерностями (в сочетании с косвенной эквивалентностью).

Аналогично, конструкция

    <идентификатор> : ,P/P, (<полный адрес>) (<полный адрес>)

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

Замечание. В некоторых подпрограммах, составленных до 1970 г., в качестве заголовка использовалась конструкция

    : ,SUBP, <идентификатор>

являющаяся «наследием» автокода SIBESM-6. Использовать ее в качестве заголовка не рекомендуется.

11. Параметрические команды

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

    Z <восьмеричное число от 0 до 37B>

Параметрические команды транслируются как команды с длинным адресом.

Пример.

    5 ,Z31, 06412B

транслируется в машинную команду

    05 31 06412

12. Данные и рассылки

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

Группа данных начинается с оператора

    ,DATA,

и может состоять из констант любого типа. Указания о рассылке представляются последовательностью пар операторов вида

    n1 ,SET, A1
    n2 ,   , A2

где n1 и n2 — целые десятичные числа, А1 и А2 - полные адреса. Такая пара операторов осуществляет пересылку группы из n1 слов, начинающейся с адреса A1, в массив ячеек, начинающийся с адреса A2, n2 раз.

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

Отметим, что данные не загружаются в память машины. Загрузчик производит их рассылку согласно указаниям в подпрограмме, после чего уничтожает «оригиналы». Таким образом, данные можно использовать лишь по их новым адресам. Чаще всего это адреса из общих блоков.

Пример. Запись вида

        ,DATA,
     A: ,REAL, 1.
        ,ISO , 14НАВТОКОД MADLEN
      4 ,SET , A
      1 ,    , TABLE

означает однократную рассылку написанных выше констант (занимающих 4 машинных слова, начиная с адреса А) в ячейки памяти, начиная с адреса TABLE. При этом указанные константы расположатся в машинных словах TABLE и от TABLE+1 до TABLE+3 соответственно. По этим «новым» адресам (но не по «старым»!) их можно использовать в подпрограмме.

Рассмотренные конструкции выполняют те же функции, что и фортранный оператор DATA.

13. Комментарии

Комментарии в автокоде можно записывать по фортранным правилам (буква C в первой колонке перфокарты-комментария). Кроме того, на каждой перфокарте для комментария отведены колонки с 73-й по 80-ю. В большинстве случаев (за исключением операторов с мнемокодами ISO, BLOCK, CONT и некоторых других «длинных» операторов) поле комментария начинается с 43-й колонки. Для того чтобы запись оператора можно было продолжить за 42-ю колонку, в первой колонке надо пробить управляющий символ L. Однако необходимости в этом обычно не возникает. Наоборот, часто возникает необходимость размещения комментария ранее 43-й (или 73-й) колонки. Для этого служит точка, которая отделяет комментарий от адресной части команды.

Примеры.

    ,AAX, =:774 . ВЫДЕЛЕНИЕ ПОРЯДКА.
    ,E+N, 64    . НОРМАЛИЗАЦИЯ.

14. Правила оформления автокодных подпрограмм

При оформлении автокодных подпрограмм допускается нестандартность. Однако соблюдение определенных правил при оформлении автокодной подпрограммы позволяет ей, с одной стороны, не «мешать» работе других подпрограмм и, с другой стороны, вызывать ее некоторым стандартным образом (в том числе из фортранных и алгольных подпрограмм). Такая автокодная подпрограмма может быть включена в библиотеку программ общего пользования.

Первая группа правил касается использования индекс-регистров и режимов работы арифметического устройства.

Эти правила предусматривают, что индекс-регистры 1-7-7 можно использовать лишь при условии последующего восстановления их прежнего состояния. Индекс-регистры 8-—12 и 14 можно использовать без последующего восстановления. Это означает, что при выходе из любой подпрограммы состояние этих индекс-регистров не определено, т. е. указанные индекс-регистры могут быть «испорчены».

Индекс-регистр 13 играет особую роль — в нем хранится адрес возврата. Это означает, что если некоторая подпрограмма в свою очередь вызывает другую подпрограмму (скажем, посредством оператора CALL), то свой адрес возврата она должна, вообще говоря, сохранить (например, путем записи содержимого индекс-регистра 13 в некоторую ячейку памяти).

Индекс-регистр 14 является «рабочим» регистром. Его состояние «портится» любым экстракодом (остальные индекс-регистры экстракодами не «портятся»).

Индекс-регистр 15 является счетчиком магазина и устанавливается мониторной системой. Стандартное его значение равно 53401В, 55401В или 73401В (в зависимости от объема памяти, выделенной для задачи). Объем магазина во всех случаях равен 377В, Переполнение или исчерпание магазина диагностируется при счете.

Соглашение о регистре режима и блокировок предусматривает, что значение этого регистра при входе в автокодную подпрограмму равно 6 и должно быть таким же на выходе. Напомним, что это стандартное значение соответствует режиму выполнения арифметических операций с нормализацией и с блокировкой округления и, кроме того, значению признака группы «логическая». Установка этого стандартного значения проще всего делается командой ,NTR, 6.

Вторая группа правил касается способа передачи фактических параметров при совместном использовании фортранных (алгольных) и автокодных подпрограмм.

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

    CALL SUB (A, B, C)

Тогда надо написать такую последовательность операторов (не обязательно с использованием индекс-регистра 14):

    14 ,VTM, А
       ,ITS, 14
    14 ,VTM, В
       ,ITS, 14
    14 ,VTM, С
       ,ITS, 14
       ,CALL, SUB

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

Если подпрограмма SUB аналогична фортранной FUNCTION, а не SUBROUTINE, то вызов ее будет отличаться тем, что после возврата из такой подпрограммы необходимо выполнить одну из команд магазинного считывания. Чаще всего выполняют команду с мнемокодом STX. При этом происходит запись значения функции, полученного на сумматоре, в ячейку памяти и одновременно восстановление состояния сумматора, которое было до вызова подпрограммы.

Иногда при вызове FUNCTION адрес первого параметра засылают не в магазинном режиме (,ITA, 14 вместо ,ITS, 14). В этом случае после возврата из подпрограммы дополнительного магазинпого считывания не делают, оставляя на сумматоре значение функции.

Извлечение адресов фактических параметров из магазина производится в порядке, обратном порядку их записи в магазин. Напомним, что адрес последнего из них находится на сумматоре. Пусть мы составляем на автокоде подпрограмму, аналогичную фортранной SUBROUTINE SUB (A, B, C). Тогда извлечение адресов фактических параметров можно сделать, например, командами

    ,STI, 14 . C
    ,STI, 12 . B
    ,ATI, 11 . A

Как видим, в магазине осталось прежнее значение сумматора. Перед выходом из подпрограммы надо установить правильное состояние счетчика магазина, например, командой ,STX, либо 15,XTA, . Отметим, что после выполнения любой из этих команд будет установлен нужный признак группы «логическая». В случае FUNCTION такого дополнительного магазинного считывания делать нельзя. Иначе говоря, FUNCTION с N параметрами должна произвести «выталкивание» магазина N-1 раз, а SUBROUTINE — N раз.

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

В случае когда на автокоде пишется аналог фортранной SUBROUTINE без параметров, эта подпрограмма должна сохранить состояние сумматора (т. е. выполнить на входе 15,ATX, либо ,XTS, или ,ITS,), При выходе надо проделать обратную операцию восстановления состояния сумматора.

Аналогом фортранной PROGRAM на автокоде является подпрограмма, имеющая заголовок

     PROGRAM: ,NAME,

либо один из входов

     PROGRAM: ,ENTRY,

Третья группа правил касается выбора наименований подпрограмм (входов), совместимых с Фортраном (Алголом), и общих блоков, совместимых с фортранными COMMON-блоками.

Для того чтобы автокодную подпрограмму (либо отдельный ее вход) можно было вызывать из фортранной (алгольной) подпрограммы, наименование этой подпрограммы (или входа) должно быть идентификатором, допустимым для Фортрана или Алгола. Это означает, что рассматриваемый идентификатор должен состоять не более чем из 6 символов и не содержать символов * и /.

Аналогичное правило для идентификаторов общих блоков, совместимых с фортранными COMMON-блоками, выглядит так: идентификатор общего блока должен начинаться и оканчиваться звездочкой, а между звездочками должен содержать не более 6 символов, допустимых для фортранного идентификатора. Например, общий блок вида

    *BLOCK1* : LC ,BLOCK, A(10), B(25)

имеет тот же смысл, что и фортранный оператор

    COMMON /BLOCK1/ A(10), B(25)

Описание же вида

    BLOCK1 : LC ,BLOCK, X(5), Y(10)

не имеет фортранного аналога и, стало быть, этот блок недоступен никакой фортранной подпрограмме,

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

Приведем теперь схему построения подпрограммы на автокоде

    Заголовок
    Команды
    Константы и BSS
    Данные
    Указания о рассылке
    ,END,

Комментарии можно располагать ранее заголовка и в любом месте до ,END, . Описания могут располагаться в любом месте после заголовка с единственным условием: описание любого идентификатора (кроме меток) должно предшествовать его использованию. Операторы с мнемокодом BSS и непустой адресной частью (т. е. фактически резервирующие место в памяти) могут перемежаться константами. Их рекомендуется располагать после констант, которые в свою очередь обычно располагаются после команд. Пустые конструкции BSS могут располагаться произвольно среди команд и констант. Данные и указания о рассылке располагаются в конце подпрограммы.

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

15. Базирование

Как сказано выше, многие команды с коротким адресом требуют модификации своей адресной части. Самым простым способом такой модификации является запись вида

    ,UTC, A
    ,XTA,

вместо записи

    ,XTA, A

Возможна и такая запись:

    J ,VTM, A
    J ,XTA,

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

Суть базирования состоит в следующем. Большинство команд с коротким адресом оперирует либо с абсолютными адресами, допустимыми для таких команд (ASN, E+N, YTA, и т. п.), либо с внутренними адресами данной подпрограммы. Каждый внутренний адрес подпрограммы можно представить в виде *C+D, где *C - адрес начала подпрограммы и D не превосходит длины подпрограммы, которая обычно не превышает 07777В. Указанные команды с коротким адресом (являющимся внутренним адресом подпрограммы) вида

    ,<мнемокод>, A

переписывают так:

    J ,<мнемокод>, А - *С

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

    J ,VTM, *C

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

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

Наиболее употребительным является базирование по одному индекс-регистру или локальное базирование. На протяжении этой главы термином «базирование» обозначается именно такой способ базирования. Этим способом могут базироваться лишь внутренние адреса подпрограммы. Базирование выполняется на линейных участках подпрограммы, каждый из которых открывается заказом на базирование (см. ниже) и закрывается либо очередным заказом на базирование, либо отменой базирования (или оператором ,END,),

Базируются только команды, удовлетворяющие условиям:

  1. команда должна быть с коротким адресом,
  2. команда должна быть с пустым указателем индекс-регистра,
  3. полный адрес команды должен быть внутренним адресом подпрограммы.

Команды с непустым (в том числе и нулевым) указателем индекс-регистра, полные адреса которых являются внутренними адресами подпрограммы, транслируются в пару команд. Например, команда вида

    M ,XTA, A

транслируется так же, как пара команд

      ,UTC, A
    M ,XTA,

Заказ на базирование (без установки базового индекс-регистра) имеет вид

    I ,BAS, *C

Здесь *C есть адрес базы, I — базовый индекс-регистр. Более часто используют оператор вида

    I ,BASE, *С

который, кроме заказа на базирование, производит и установку базы. Этот оператор эквивалентен паре операторов

    I ,BAS, *C
    I ,VTM, *C

Отмена базирования производится либо новым заказом на базирование, либо оператором

    I ,BAS, <пусто>

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

    A - 10000B <= К <= А + 7777В

В качестве базового регистра часто используется один из индекс-регистров 8-^-12. В случае, когда подпрограмма содержит вызовы других подпрограмм, удобнее использовать в качестве базового регистра один из регистров 1-7,

Заметим, что точные сведения о том, какие адреса пробазированы, а какие нет, всегда можно получить из текста подпрограммы на языке загрузки, расположенного на листинге слева от автокодного текста (см. § 17). В случае базирования транслированная команда будет содержать базовый индекс-регистр.

Другим способом базирования является глобальное базирование всей памяти с помощью трех индекс-регистров. Суть этого способа (используемого в основном в больших программах) состоит в следующем. Адреса от —10000В до 07777В не требуют базирования. Остальные адреса могут быть базированы с помощью трех индекс-регистров, равных соответственно 20000В, 40000В и 60000В, так как любой из этих адресов отстоит от одного из трех указанных значений индекс-регистров не далее чем на 10000В влево и не далее чем на 07777В вправо. Заказ на глобальное базирование задается заголовком подпрограммы вида

    <идентификатор> : R ,NAME,

где R — целое десятичное число от 1 до 13. Базирование производится загрузчиком, который подбирает надлежащий индекс-регистр из набора K, K+1, K+2 для каждой из команд, подлежащих базированию. Значения индекс-регистров с номерами В, В+1, К+2, равные 20000В, 40000В и 60000В соответственно, устанавливаются самой подпрограммой.

При глобальном базировании базируются все команды с коротким адресом, пустым указателем индекс-регистра и адресной частью, превышающей 07777В. Тем самым исключается базирование команд с мнемокодами ASN, NTR и т. п., адреса которых базировать не надо. Команды с коротким адресом и непустым указателем индекс-регистра заменяются двумя командами, как описано ранее. Если такие команды базировать не надо, то заголовок подпрограммы должен быть видоизменен так:

    <идентификатор> : R ,NAME, ***

Параметрические команды во всех случаях не базируются,

Следующие два способа базирования предназначены в основном для использования при составления системных подпрограмм.

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

Заказ на такое базирование производится оператором вида

   M ,REL, B

Здесь в качестве M обычно указывается индекс-регистр 14 (устанавливаемый загрузчиком), а в качестве И — начальный адрес базируемого участка подпрограммы (например, начальный адрес подпрограммы).

При необходимости базирования адресов, зависящих от внешних объектов, заказ на базирование задается оператором вида

    M ,RELS, B

Отмена любого из двух видов базирования производится оператором

    M ,REL, <пусто>

16. Примеры автокодных подпрограмм

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

Рассмотрим подпрограмму вычисления скалярного произведения двух N-мерных векторов. Оформим ату подпрограмму как FUNCTION SCAL (A, B, N)

  SCAL:   ,NAME,    . FUNCTION SCAL (A, B, N)
          ,STI, 14  . N
          ,STI, 12  . B
          ,ATI, 11  . A
          ,NTR, 3
       14 ,XTA,
          ,UTC, =I1 . (*)
          ,X-A,     . 1-N
          ,ATI, 14
          ,NTR, 18
          ,XTA,
    *1:   ,BSS,
       11 ,XTS
       12 ,A*X,
       11 ,UTM, 1
       12 ,UTM, 1
       15 ,A+X,
       14 ,VLM, *1
          ,NTR, 6
       13 ,UJ,
          ,END,

Как видно из текста подпрограммы, базирование здесь не понадобилось, так как используется всего одна команда (*), удовлетворяющая всем условиям базирования.

Рассмотрим теперь подпрограмму перекодировки целого числа, не превосходящего 218-1, в код ISO. Здесь перекодировка означает, что каждая восьмеричная цифра этого числа перекодируется в соответствующую цифру, заданную в коде ISO (см. Приложение 2). Например, целое десятичное число 21, представленное в машине как 6400 0000 0000 0025, будет перекодировано в машинное представление, соответствующее к константе ,ISO, 6Н000025.

На первый взгляд решение этой задачи представляется сложным. Однако с помощью команды разборки (с мнемокодом AUX) получается очень простое и изящное решение. Сначала надо сдвинуть содержимое сумматора влево так, чтобы 18 младших его разрядов переместились в старшие разряды. Затем производится разборка 18 старших разрядов на все машинное слово так, чтобы каждая восьмеричная цифра оказалась в трех младших разрядах соответствующего байта. При этом пять старших разрядов каждого байта будут нулями. Теперь для получения нужного результата достаточно логически сложить содержимое сумматора с константой, имеющей 60В в каждом байте. Запишем решение в виде следующей автокодной подпрограммы.

    INTISO:   ,NAME,    . FUNCTION INTISO (INT)
            8 ,BASE, *
              ,ATI, 14  . INT
           14 ,XTA,
              ,ASN, 64-30
              ,AUX, =6H'7''7''7''7''7''7'
              ,AOX, =6H'60''60''60''60''60''60'
           13 ,UJ,
              ,END,

Мы использовали кодировку ISO для задания восьмеричных констант. Здесь это удобнее, чем использование констант типа OCT или LOG.

17. Стандартный массив

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

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

Индекс-регистр указывается в восьмеричном виде, а адресная часть состоит из 4 восьмеричных цифр у команд с коротким адресом и из 5 восьмеричных цифр у команд с длинным адресом.

Неполные машинные слова дополняются правыми командами

    00 22 00000

В случае, если команда базируется, в ней указывается базовый индекс-регистр, а адресная часть равна разности между полным адресом данной команды и адресом базы. Если этот относительный адрес оказался отрицательным, то в адресной части указывается адрес 4000В+N, где N есть номер строки в таблице описаний (это справедливо для всех отрицательных коротких адресов). Если используется адрес типа «литерал», то он базируется при наличии заказа на базирование. В случае, когда базируемая команда имеет непустой указатель индекс-регистра, она транслируется в две команды (см. § 15).

Если базирование не заказано, то любой крроткий адрес, не являющийся абсолютным, будет иметь вид 4000В+N, т. е. будет оформлен в виде ссылки на таблицу описаний. Заметим, что абсолютные адреса без модификации допустимы лишь в случаях, когда им соответствуют не ячейки памяти, а некоторые другие объекты (например, в командах с мнемокодами ASN, NTR, ATI и т. п.). Исключение составляют физические адреса и адреса специальных ячеек мониторной системы, используемые, как правило, в системных подпрограммах.

Длинный адрес вида 40000В+N означает ссылку на N-й адрес относительно начала подпрограммы, а длинный адрес вида 74000В+N — ссылку на N-ю строку таблицы описаний. Отметим, что начальная (нулевая) строка таблицы описаний содержит идентификатор данной подпрограммы в коде TEXT.

18. Диагностика ошибок

Транслятор с автокода обнаруживает всевозможные формальные ошибки в подпрограмме, не связанные со способом загрузки ее в память машины. Это означает, что «незаконное» использование коротких адресов не может быть обнаружено транслятором.

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

Некоторые ошибки прекращают дальнейшую трансляцию. К числу таких ошибок относятся (в скобках указана диагностика):

  1. отсутствие заголовка подпрограммы (ОТСУТСТВУЕТ ЗАГОЛОВОК ПОДПРОГРАММЫ),
  2. слишком большое число используемых идентификаторов либо наличие более 20 входов (ПЕРЕПОЛНЕНА ТАБЛИЦА ОПИСАНИЙ),
  3. для размещения подпрограммы требуется более 23 листов оперативной памяти (ДЛИНА ПОДПРОГРАММЫ ПРЕВЫШАЕТ ВОЗМОЖНОСТИ МАШИНЫ),
  4. при обнаружении свыше 100 ошибочных операторов (ОЧЕНЬ МНОГО ОШИБОК),
  5. при некоторых ошибках в адресе оператора Б83 (НЕЯВНООПРЕДЕЛЕННЫЙ ИДЕНТИФИКАТОР В85).

Остальные ошибки не препятствуют дальнейшей трансляции. Среди них наиболее часто встречаются ошибки, связанные с использованием неописанных идентификаторов либо идентификаторов, описанных более одного раза (дважды описанных). Отметим, что обнаружение таких идентификаторов входит в функции транслятора с автокода на этапе трансляции фортрапных подпрограмм с языка та<11еп на язык загрузки (остальные ошибки обнаруживаются транслятором с Фортрана).

19. Управляющие карты, редактирование, сервис

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

    *ASSEMBLER

которая служит признаком того, что далее следует автокодный текст. При отсутствии других управляющих карт (если печать не отменена картой *NO␣LIST) пользователь получает отредактированный текст автокодной подпрограммы, напечатанный в два столбца (билистинг), без текста стандартного массива. Для получения текста стандартного массива необходимы две подряд стоящие управляющие карты

    *CALL␣PUTFLAG*
    n1

Здесь n может принимать значение 0, 4 или 6. Если n = 0, то печать производится в два столбца. При n = 4 (или 6) печать производится в один столбец. При печати в виде билистинга «длинные» операторы будут распечатаны в две строки.

При наличии управляющей карты *FULL␣LIST после текста подпрограммы будет выдана таблица описаний, таблица ссылок и список неиспользованных идентификаторов.

Автокодный текст, выдаваемый на печать, редактируется, т. е. разделители (двоеточия, занятые и точки) печатаются в определенных позициях, метки и адресные части выравниваются по левым символам, а указатели индекс-регистров — по правым. Ошибочные операторы печатаются без редактирования.

Имеется возможность частичной распечатки текста подпрограммы, что делается с помощью управляющих карт *FULL␣LIST и *NO␣LIST, расположенных внутри подпрограммы. При этом режим печати, определенный в пакете перед подпрограммой, запоминается и восстанавливается после ее трансляции.

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

    *MOSU␣A

где А — пятизначный восьмеричный адрес, В этом случае текст подпрограммы будет печататься не с относительной адресацией (т, е, не с адреса 00000), а начиная с адреса А.

20. Советы и рекомендации

При автономной отладке автокодных подпрограмм, когда пакет задачи будет малым по объему, отлаживаемые подпрограммы часто будут загружаться по адресам памяти, не превосходящим 07777В, и тем самым при загрузке не будут выявлены случаи использования коротких адресов бея модификации. При загрузке по адресам, превосходящим 07777В, такая «отлаженная» подпрограмма может не пойти. Для исключения подобных случаев необходимо в отладочной PROGRAM описать фиктивный массив длиной не менее 3600. Во всяком случае, необходимо проследить, чтобы отлаживаемая подпрограмма была загружена в память, начиная с адреса не менее 10000В.

Если, наоборот, необходимо загрузить подпрограмму на адреса до 07777В, то в PROGRAM не должно быть больших массивов и соответствующая подпрограмма должна быть описана в PROGRAM оператором EXTERNAL (или его автокодным аналогом). Тогда она будет загружена вслед за PROGRAM. Отметим, что подпрограммы, описанные в операторе EXTERNAL, загружаются в обратном порядке, т. е. первой загрузится та, что описана последней.

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

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

Для печати текстовой строки (заданной в коде ISO) можно воспользоваться системной подпрограммой PRINT8. Обращение к ней является нестандартным и выглядит так:

    14 ,VTM, <начальный адрес информации>
       ,ITS, 14
    14 ,VTM, <конечный адрес информации>
       ,ITS, 14
    14 ,VTM, <номер начальной позиции на АЦПУ>
       ,ITS, 14
       ,CALL, PRINT8

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

Вместо PRINT8 можно использовать подпрограмму PRINTA со стандартным обращением, аналогичным фортранному оператору CALL PRINTA (АНАЧ, АКОН, NПОЗ).

Отметим, что за одно обращение к подпрограмме PRINT8 или PRINTA можно отпечатать только одну текстовую строку, излишек текста печати будет обрезан.

Для печати массива чисел в формате, аналогичном фортранному формату E, служит системная подпрограмма PRINTE. Обращение к ней аналогично фортранному оператору

    CALL PRINTE (АНАЧ, АКОН, N, M)

Здесь АНАЧ и АКОН — начальный и конечный адрес печатаемого массива чисел, N — количество чисел, печатаемых в одной строке, M — число энаков после запятой. Массив печатается слева направо по N чисел в каждой строке, с одним пробелом между числами. Отметим, что число позиций, отводимых под одно число, равно M+7.

Печать восьмеричных чисел (аналогично фортранному формату О) можно сделать о помощью подпрограммы PRINTO, обращение к которой аналогично обращению к PRINTE. При этом должно быть М <= 16, Если М < 16, то старшие разряды восьмеричной константы игнорируются.

21. Некоторые приемы программирования на автокоде

К использованию автокода чаще всего прибегают в тех случаях, когда возникает необходимость работать с частями машинного слова. Поэтому в большинстве таких подпрограмм отдельные операторы производят упаковку информации, другие — ее распаковку. Пользователю нелишне ознакомиться с некоторыми приемами упаковки и распаковки.

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

Пример. Пусть надо присоединить справа к машинному слову PACK очередные б разрядов, расположенные в младших разрядах слова BIT (остальные разряды этого слова произвольны). Это можно сделать такими командами:

       ,XTA, PACK
       ,ASN, 64-6
       ,XTS, BIT
       ,AAX, =77
    15 ,AOX,
       ,ATX, PACK

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

Распаковку удобно производить с использованием регистра младших разрядов. При распаковке слева направо, т. е. начиная со старших разрядов слова, сначала производится сдвиг влево, затем запись «остатка» в исходное машинное слово с последующей выдачей выделенного фрагмента из регистра младших разрядов в младшие разряды сумматора. При распаковке справа налево сначала производится сдвиг вправо, затем запись «остатка» в исходное слово и выдача выделенной части из регистра младших разрядов в старшие разряды сумматора.

Пример. Пусть надо распаковать 10 старших разрядов слова DEP, получив в исходном слове оставшиеся младшие разряды, а распакованные разряды — в слове INT в виде целого числа. Указанные операции можно проделать с помощью такой группы команд:

    ,XTA, DEP
    ,ASN, 64-10
    ,ATX, DEP
    ,YTA,
    ,AOX, =I0
    ,ATX, INT

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

Среди арифметических операций известную сложность представляют операции над ненормализованными (в частности, целыми) числами, особенно умножение и деление. Последние удобно производить с помощью специальных системных подпрограмм, именуемых IMUI и IDII соответственно. Первый операнд необходимо поместить в сумматор, а адрес второго занести в индекс-регистр 14. Например, умножение целого числа по адресу М на целое число по адресу N можно осуществить командами

       ,XTA, М
    14 ,VTM, N
       ,CALL, I*MU*I

Результат умножения, взятый по модулю 240, выдается на сумматор в виде целого числа. Аналогично можно производить операции над комплексными величинами и величинами с двойной точностью.

Заключение

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

Программист, пользующийся автокодом, должен помнить, что транслятор с автокода выполняет лишь функции «переводчика» с одного языка на другой. Это означает, что все машинные операции, которые должны быть выполнены в подпрограмме, необходимо задать в виде автокодных команд. Исключение составляет лишь рассылка данных, выполняемая загрузчиком согласно указаниям о рассылке. Транслятор с автокода, естественно, требует, чтобы исходная информация, т. е. запись подпрограммы на языке Madlen, была правильной, полной (отсутствие неописанных идентификаторов) и непротиворечивой (отсутствие дважды описанных идентификаторов).

Диагностика выдается лишь при нарушении правил записи операторов на входном языке, а также при явном несоответствии заданного оператора сути соответствующей команды (например, команды с мнемокодами VTM, VLM или VJM и пустым указателем индекс-регистра).