Команды сдвига

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

Статья 409 - Картинка 1

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

Аналогично выполняются любые другие сдвиги. Рассмотрим в качестве еще одного примера сдвиг байта 10101110г на 3 разряда вправо.

Статья 409 - Картинка 2

В данном случае освободившиеся разряды располагаются в левом конце числа, содержимое же разрядов 5,6,7 утеряно. Заметим, что сдвиг не эквивалентен делению, если рассматривать содержимое байта как целое со знаком. Это очевидно, так как исходное число отрицательно, а результат положителен.

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

Приведенные выше примеры касались сдвигов содержимого отдельных байтов. Необходимо отметить, что во всех ЭВМ Систем 360 и 370 все команды сдвига оперируют над содержимым регистров.

Логические сдвиги

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

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

10 1000 0111 0010 1001 1100 1111 0110

Команда

SLL 5,6

(Shift Left Logical — СДВИГ ВЛЕВО КОДА) производит сдвиг содер¬жимого регистра 5 на 6 разрядов влево. Результат ее выполнения вы-

глядит так:

(5)=ООО11100101001110011110110000000

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

D2+(B2)

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

SLL R1,D2(B2)

Shift Left Logical

Сдвиг R1 влево наD2-f(B2) разрядов

SRL R1,D2(B2)

Shift Right Logical

Сдвиг (R1) вправо на D2+(B2) разрядов (учитываются последние6 разрядов)

Команды логического сдвига обычно используются для придания двоичной информации более компактной формы. Например, чтобы запомнить последовательность, состоящую из 100 чисел в форме полных слов, требуется 3200 битов памяти. Если известно, что все числа положительные и не превышают 64, то для хранения каждого числа на самом деле оказывается достаточно 6 битов, всего 600 битов для всей последовательности. (Если быть более точными, то при хранении 5 чисел в каждом полном слове потребуется всего 640 битов.) На рис. 14.4 изображен программный сегмент, выполняющий упаковку 5 таких чисел, первоначально находящихся в последовательных словах памяти, в регистр 7. Перед записью каждого следующего числа необходимо предварительно сдвинуть содержимое регистра 7 влево на шесть разрядов с тем, чтобы освободить место для вновь записываемого числа. Непосредственная запись может быть произведена с помощью команды О (ИЛИ). После ее выполнения число оказывается в последних шести разрядах регистра.

Статья 409 - Картинка 3

Рис. 14.4. Размещение в регистре 7 пяти 6-битовых чисел, расположенных в полных словах памяти, начиная с адреса NMBRS.

При проведении обратного преобразования (т. е. при переводе данных из компактной формы в обычную) удобно использовать сдвиг содержимого одного регистра в другой. Для этого предусмотрены две команды двойного сдвига: SLDL (Shift Left Double Logical — СДВИГ ВЛЕВО ДВОЙНОЙ КОДА) и SRDL (Shift Right Double Logical — СДВИГ ВПРАВО ДВОЙНОЙ КОДА).

SLDR R1,D2(B2)

Shift Left Double Logical

Сдвиг (R1.R1 + 1) влево на D2 + (B2) разрядов

SRDL R1,D2(B2)

Shift Right Double Logical

Сдвиг (R1.R1+1) вправо на D2 + (B2) (учитываются последние6 разрядов)

Здесь R1 на самом деле является ссылкой сразу на два регистра, R1 и R1 + 1. R1 при этом должен быть четным. При выполнении двойных сдвигов 64-разрядное содержимое двух регистров рассматривается как единое число. При левом сдвиге теряются старшие биты R1. Старшие биты R1 +1 занимают места в правом конце R1. Освобождающимися в данном случае являются младшие разряды R1 + 1.

Статья 409 - Картинка 4

Пусть регистры 4 и 5 содержат соответственно

(4) =0011 ООП ООН 0101 0110 0111 1000 1001

(5) = 1100 1011 1010 1001 1000 0111 0110 0101

По команде

SLDL 4,7

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

Статья 409 - Картинка 5

Двойной сдвиг вправо выполняется совершенно аналогично. Теряется содержимое младших разрядов R1 + 1. Биты из младших разрядов R1 попадают в старшие разряды R1 + 1. И, наконец, старшие разряды R1, освобождаясь, заполняются нулями.

Статья 409 - Картинка 6

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

L 11,BITDATA

SLDL 10,13

LA 10,0

SLDL 10,5

ST 10,BITS

На рис. 14.5 приведен программный сегмент, предназначенный для «распаковки» содержимого регистра 7 (см. программу рис. 14.4) и записи результатов в форме полных слов последовательно, начиная со слова NMBRS.

Арифметические сдвиги

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

(9) =0000 1000 ООП 1101 0111 0010 0100 0010

Статья 409 - Картинка 7

Рис. 14.5. Размещение пяти 6-битовых чисел, находящихся в регистре 7, в последовательных словах памяти, начиная с адреса NUMBRS.

Выполнение команды

SLL 9,3

в данном случае эквивалентно умножению на 23=8, так как в результате получается

(9)=0100 0001 1110 1011 1001 0010 0001 0000

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

(9) = 1000 ООП 1101 0111 0010 0100 0110 0000

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

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

(11)=0001 0010 0011 0100 0101 0110 0111 1000