Косвенная адресация

Документированная возможность – регистр, используемый для косвенной адресации, содержит только целое неотрицательное число. Фактически значением его может быть любое число. Пусть число, которое содержится в регистре используемом для косвенной адресации, записано в виде ±M1•M2M3M4M5M6M7M8|±P1P2, где M – цифры мантиссы, P – цифры порядка. При этом предполагается, что всегда 8 цифр мантиссы, просто последние могут быть нулевыми и обычно не отображаются.

При косвенном обращении сначала исходное число преобразуется по правилам, описанным ниже, а затем записывается обратно, причём для команд FL0FL3 иногда нет. При этом всегда (!) цифры M7M8 преобразованного числа определяют адрес перехода или номер регистра. Обратите внимание, что преобразованное число не нормализуется перед сохранением обратно, тем самым могут быть числа с ведущими нулями. Обычно это используется или для генерации специальных изображений или в комбинации с другими недокументированными операциями, которым важны только цифры мантиссы. Пример в разделе Восстановление X2 с сохранением первой цифры числа в X.


Вариант +M1.M2M3M4M5M6M7M8|+P1P2, т. е. число больше или равно единицы (N ⩾ 1.0)

В этом случае к числу слева дописывается 7 − P2 нулей при условии, что результат положительный, выталкивая остальную часть мантиссы право. Порядок числа в нормализованном виде при этом не меняется.
Для наглядности приведём таблицу преобразования на основе простой мантиссы, чтобы было видно, какие разряды куда попадают:

До P2 7 − P2 Нулей После Оно же
1.2345678 0 7 7 00000001. 1.
12.345678 1 6 6 00000012. 12.
123.45678 2 5 5 00000123. 123.
1234.5678 3 4 4 00001234. 1234.
12345.678 4 3 3 00012345. 12345.
123456.78 5 2 2 00123456. 123456.
1234567.8 6 1 1 01234567. 1234567.
12345678. 7 0 0 12345678. 12345678.
1.2345678 08 8 −1 0 1.2345678 08 1.2345678 08
1.2345678 09 9 −2 0 1.2345678 09 1.2345678 09
1.2345678 10 0 7 7 0.0000001 17 1. 10
1.2345678 11 1 6 6 0.0000012 17 1.2 11
1.2345678 96 6 1 1 0.1234567 97 1.234567 96
1.2345678 97 7 0 0 1.2345678 97 1.2345678 97
1.2345678 98 8 −1 0 1.2345678 98 1.2345678 98
1.2345678 99 9 −2 0 1.2345678 99 1.2345678 99

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


Вариант +M1.M2M3M4M5M6M7M8|−P1P2, т. е. само число неотрицательное, но меньше единицы (0.0 ⩽ N < 1.0)

В этом случае число дописываемых слева нулей определяется так. Вычисляется 7 + P2, и если последняя цифра результата < 8, то это и определяет число нулей. Иначе ничего не делается.

До P2 7 + P2 Нулей После Оно же
1.2345678-01 1 8 0 1.2345678-01 1.2345678-01
1.2345678-02 2 9 0 1.2345678-02 1.2345678-02
1.2345678-03 3 10 0 1.2345678-03 1.2345678-03
1.2345678-04 4 11 1 0.1234567-03 1.234567 -04
1.2345678-05 5 12 2 0.0123456-03 1.23456 -05
1.2345678-06 6 13 3 0.0012345-03 1.2345 -06
1.2345678-07 7 14 4 0.0001234-03 1.234 -07
1.2345678-08 8 15 5 0.0000123-03 1.23 -08
1.2345678-09 9 16 6 0.0000012-03 1.2 -09
1.2345678-10 0 7 7 0.0000001-03 1. -10
1.2345678-11 1 8 0 1.2345678-11 1.2345678-11
1.2345678-12 2 9 0 1.2345678-12 1.2345678-12
1.2345678-23 3 10 0 1.2345678-23 1.2345678-23
1.2345678-24 4 11 1 0.1234567-23 1.234567 -24
1.2345678-99 9 16 6 0.0000012-93 1.2 -99

Вариант −M1.M2M3M4M5M6M7M8|±P1P2, т. е. само число отрицательное (N < 0.0)

В этом случае всё определяется как указано выше, только дописываются не нули, а девятки. Знак самого числа сохраняется.
Пример: -123. перейдёт в -99999123. , т. е. адрес перехода = 23.
Пример: -1.23 -02 не изменится, т. е. адрес перехода будет равен нулю.
Пример: -1.2345678-08 станет как -9.9999123-03, т. е. адрес перехода = 23.

Тут нужно сделать замечание. На самом деле девятки определяются кодом знака числа. Для минуса, как кода шестнадцатеричной цифры A, это 10 − 1. Для плюса, как кода 1, это 1 − 1 = 0. Для проверки возьмём число с цифрой вместо знака (см. Числа, у которых вместо знака стоит цифра для алгоритма получения). Например 2E. , где двойка стоит на месте знака. При косвенной адресации: x→П9КП→x9П→x9, двойка уменьшается на единицу и становится 21111111E. . Аналогично для других чисел, например, если для 9E. , которое 2E. после /-/, выполнить косвенную адресацию, то получим 98888888E. .

Теперь рассмотрим ситуацию, когда само значение регистра ещё и меняется как описано в документации. Обращаю внимание, что изменения происходят не при любом косвенном обращении, а только когда значение адреса для перехода вычисляется. Например, в условном операторе Кx<04 регистр R4 будет модифицирован только когда x⩾0, т. е. когда понадобится вычислить адрес перехода.


Регистры R0…R3

Для них преобразованное (!) значение предварительно уменьшается на 1 без (!) учёта порядка и знака. В расчёт берутся только, но все, цифры мантиссы. При этом, если был ноль, то преобразуется в −99999999. Из того, что знак не учитывается, выходит, что для отрицательных чисел получается увеличение числа в арифметическом смысле, а не уменьшение. Примеры:

123. , что представляется как 1.23|+02, перейдёт в 0.0000123|+07, затем уменьшится до 0.0000122|+07 и превратится в 00000122. , т. е. адрес перехода = 22.
1.23 -02, что представляется как 1.2300000|−02 уменьшится до 1.2299999|−02, превратится в 1.2299999-02, т. е. адрес перехода = 99.
-123. , что представляется как −1.23|+02, преобразуется в −9.9999123|+07, затем уменьшится до −9.9999122|+07, превратится в -99999122. , т. е. адрес перехода = 22.
-1.2345678-08, преобразуется в −9.9999123|−03, затем уменьшится до −9.9999122|−03, превратится в -9.9999122-03, т. е. адрес перехода = 22.

Обратите внимание, что при уменьшении мантиссы до нуля порядок числа сохраняется. Например, если исходно было 1.|−20, то после преобразования будет 0.0000001|−13, а после уменьшения станет 0.0000000|−13, т. е. 0. -13. Правда такой ноль, кроме необычного вида, в операциях ничем от простого нуля не отличается. Но в сочетании с другими недокументированными возможностями, которые могут объединить мантиссу и порядок от разных чисел (см. Восстановление X2 с сохранением первой цифры числа в X) это может пригодится. Таким же образом из 1.|+90 получается 0. 97.

Важно, что число сначала преобразуется, а потом уменьшается без учёта знака. Возьмём число −1. Оно преобразуется в -99999991. , и только потом уменьшится до -99999990. . Здесь знак играет роль только при преобразовании, выбирая, что именно допишется слева.


Регистры R4…R6

Для них преобразованное значение предварительно увеличивается на 1, так же без учёта порядка и знака. При этом, если было −99999999 (все девятки), то преобразуется в ноль. Например, −9, или −99 преобразуется в 00000000. По аналогии с замечания для отрицательных чисел, число +99999999 (все девятки) преобразуется в число с цифрой на месте знака: 200000000. (на месте знака стоит 2). Оно ведёт себя как обычный ноль. Примеры:

123. , что представляется как 1.23|+02, перейдёт в 0.0000123|+07, затем увеличится до 0.0000124|+07 и превратится в 00000124. , т. е. адрес перехода = 24.
1.23 -02, что представляется как 1.2300000|−02, увеличится до 1.2300001|+02 превратится в 1.2300001-02, т. е. адрес перехода = 01.
-123. , что представляется как −1.23|+02 преобразуется в −9.9999123|+07, затем увеличится до −9.9999124|+07, превратится в -99999124. , т. е. адрес перехода = 24.
-1.2345678-08, преобразуется в −9.9999123|−03, затем увеличится до −9.9999124|−03, превратится в -9.9999124-03, т. е. адрес перехода = 24.


Команды FL0FL3

Для них действуют те же правила, что для регистров R0…R3. В случае, если вся мантисса преобразованного значения состоит из нулей, то происходит завершение цикла и преобразованное значение НЕ записывается обратно в регистр. Примеры:

123. , что представляется как 1.23|+02, перейдёт в 0.0000123|+07, затем уменьшится до 0.0000122|+07 и превратится в 00000122. , цикл продолжается.
1.23 -02, что представляется как 1.2300000|−02 уменьшится до 1.2299999|−02, превратится в 1.2299999-02, цикл продолжается.
1.23 , преобразуется в 00000001, уменьшается до 00000000. Нулевая мантисса – цикл завершится, а исходное число не изменится, т. е. останется 1.23 .
1.23 -10, что представляется как 1.23|−10, преобразуется до 0.0000001|−03, уменьшается до 0.0000000|−03. Цикл завершится, а исходное число не изменится.

Рассмотрим несколько вариантов с единицей, у которой отрицательная степень.

Число После преобразования После уменьшения на 1
1. -01 1.0000000-01 0.9999999-01
1. -02 1.0000000-02 0.9999999-02
1. -03 0.1000000-03 0.0999999-03
1. -09 0.0000010-09 0.0000009-03
1. -10 0.0000001-09 0.0000000-03

Получается, что цикл завершится только для последнего случая, при этом в регистре останется первоначальное число. Но если число отрицательное, то тут уже идёт заполнения не нулями и опять не получится закончить цикл:

Число После преобразования После уменьшения на 1
-1. -10 -9.9999991-09 -9.9999990-03

Мантисса содержит шестнадцатеричные цифры

В этом случае уменьшение шестнадцатеричной цифры идёт до 9, а затем, как обычно. При уменьшении ниже 0 идёт заём (уменьшение на 1 предыдущей, возможно шестнадцатеричной цифры), при это текущая цифра будет не F, а, как обычно, 9.

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

К сожалению, если идёт увеличение, то число с шестнадцатеричными цифрами предварительно подвергается нормализации (справа налево, смысл как указано в списке терминов): буквы считаются как двузначные, с переносом лишней единицы в старший разряд. Например, сложение числа 9AE и 1 будет так: E = 14, значит последняя цифра 4 + 1 = 5 и 1 в уме; затем A = 10 + 1 в уме, будет 11, т. е. 1 и 1 в уме; далее 9 + 1 = 10. Итого 1015. Это значит, что косвенная адресация через R4…R6 всегда уберёт шестнадцатеричные цифры из числа. При этом нестандартный знак числа (см. замечание в варианте для отрицательных чисел) остаётся.


Порядок содержит шестнадцатеричные цифры

Без специальных ухишрений можно получить только 1.|±HH, используя оператор F10x.

Для чисел вида 1.|+0H (одна цифра) никаких преобразований не производится, а значит адрес перехода всегда будет нулевым. Если идёт увеличение или уменьшение (через выбор регистра), то мантисса увеличивается или уменьшается в соответствии с правилами выше, а знак и порядок не меняется. Пример: если в регистр R0 записать 1. 0E и выполнить КП→x0, то результатом станет уменьшение мантиссы 100000000 до 09999999, т. е. 0.9999999 0E.

Для чисел вида 1.|−0H (тоже одна цифра) так же никаких преобразований не производится. Единственное, хочу заострить внимание на значении такого числа. В этом случае порядок подразумевается по модулю 16, т. е. −E, это −14 или 2. Получается, что 1.|−0E = 100, 1.|−0D = 1000, 1.|−0C = 10000, 1.|−0B = 100000, а… 1.|−0A не получается (будет сразу 1.|−10, им и останется).

Для двузначных чисел порядка ситуация похожая. Возьмём, для примера, 1.|+B0 ( 1. L0). Кстати, 1.|+AA будет автоматически переведено в 1.|+B0, как и 1.|+0A будет автоматически переведено в 1.|+10 (чем-то именно A не нравиться, для остальных цифр такого не замечено, хотя и тут можно обмануть, если для 1.|−BB набрать ВП55). Здесь, как и для обычных положительных порядков, будет дописано 7 − 0 = семь нулей, число должно превратиться в 0.0000001|+B7, но фактически при изменении порядка он (порядок) будет нормализован и станет +117, что приведёт к 0.0000001|+117. Т. е. в качестве адреса перехода будет 01, но само число из регистра уже лучше не извлекать, т. к. оно будет сверхчислом и на экране отображаться как ЕГГ0Г . Аналогично у числа 1.|+B1 допишется 7 − 1 = 6 нулей, число станет 0.0000010|+117, т. е. адрес перехода = 10 и число по-прежнему не стоит извлекать.

Если у двузначных чисел порядок отрицательный, то срабатывает правило сумма = 160, это значит, что внутренне порядок меняется на число по модулю 160. Для примера, возьмём 1.|−C0 ( 1. -C0). Это эквивалентно 1.|−120, а по правилу сумма = 160, как 1.|+40. Используя правило преобразования для чисел больше единицы, получаем, что число будет преобразовано в 0.0000001|+47, соответственно адрес перехода 01, а полученное после косвенной адресации число можно просто извлечь из регистра: будет 0.0000001 47 Для сравнения, если взять 1.|−C1, то правило сумма = 160, приведёт к 1.|+39, что не поддаётся преобразованию (9 > 7), а значит само число после косвенной адресации не изменится и останется 1. -C1 (адрес перехода равен 00). И, да, к этому числу можно прибавить 0, чтобы увидеть 1. 39. Да, для 1.|−C1 можно применить правила косвенной адресации для отрицательных степеней, и понять, что преобразования не будет, т. к. 7 + 1 не меньше восьми. И для 1.|−C0 это правило так же укажет на необходимость дописать 7 + 0 = 7 нулей, но вот порядок будет преобразован по выше указанному правилу =160.

У правила сумма = 160 возникает ещё один интересный побочный эффект. Детали см. в разделе Числа с отрицательной нулевой степенью.

Если идёт увеличение или уменьшение (через выбор регистра), то мантисса увеличивается или уменьшается в соответствии с правилами, уже описанными разделами выше.


Значение – номер регистра, а не адрес

Если косвенное значение используется для вычисления регистра, то его номер так же определятся двумя последними цифрами, разбиваясь на два варианта, когда первая цифра нулевая, и когда нет:

Первая нольПервая НЕ ноль
00→R0#0→Ra
01→R1#1→Rb
02→R2#2→Rc
03→R3#3→Rd
04→R4#4→Re
05→R5#5→R0
06→R6#6→R0
07→R7#7→R1
08→R8#8→R2
09→R9#9→R3
0A→Ra#A→R4
0B→Rb#B→R5
0C→Rc#C→R6
0D→Rd#D→R7
0E→Re#E→R8
0F→R0#F→R9

Практическое использование

Вот пример использования знаний косвенной адресации для номеров регистров: программа заполняет регистры R0…R3 инвертированными случайными числами, при этом используется только один регистр R0.

 # |  00 01 02 03 04 05 06 07 08 09
 00 |  Cx x→П0 КСЧ КИНВ Кx→П0 П→x0 Fx≥0 02 С/П

Ещё практических советов. Уменьшение шестнадцатеричной цифры для БЗ-34 было единственным способом из цифры E получить остальные цифры. В МК-61 с приходом бинарных операций стало проще, но т. к. первая цифра всё ещё не во власти этих операций, то через косвенную адресацию получается быстрее, чем через дробную часть и ввод порядка.

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