Учебный курс. Часть 19. Циклический сдвиг

Автор: xrnd | Рубрика: Учебный курс | 13-05-2010 | Распечатать запись Распечатать запись

Циклический сдвиг отличается от линейного тем, что выдвигаемые с одного конца биты вдвигаются с другой стороны, то есть движутся по кольцу. В процессора x86 существует 2 вида циклического сдвига: простой и через флаг переноса (CF). У всех команд, рассматриваемых в этой части учебного курса, по 2 операнда, таких же, как у команд линейного сдвига. Первый операнд — сдвигаемое значение и место для записи результата. Второй операнд — счётчик сдвигов, который может находится в регистре CL или указываться непосредственно.

Простой циклический сдвиг

Циклический сдвиг вправо выполняется командой ROR, а влево — командой ROL. Схема работы этих команд представлена на рисунке (на примере 8-битного операнда):

Значение последнего выдвигаемого бита копируется в флаг CF. Для сдвигов на 1 бит устанавливается флаг OF, если в результате сдвига изменяется знаковый бит операнда. (Честно говоря, не помню, чтобы я этим когда-то пользовался. Но может вам пригодится 🙂 ) Примеры использования команд:

    rol bl,1         ;Циклический сдвиг BL на 1 бит влево
    ror word[si],5   ;Циклический сдвиг слова по адресу в SI на 5 бит вправо
    rol ax,cl        ;Циклический свдиг AX на CL бит влево

Циклический сдвиг через флаг переноса

Отличие от простого циклического сдвига в том, что флаг CF участвует в сдвиге наравне с битами операнда. При сдвиге на 1 бит выдвигаемый бит помещается в CF, а значение CF вдвигается в операнд с другой стороны. При сдвиге на несколько бит эта операция повторяется многократно. Циклический сдвиг через флаг переноса выполняется командами RCR (вправо) и RCL (влево).

Опять же для сдвигов на 1 бит устанавливается флаг OF, если в результате сдвига изменяется знаковый бит операнда. Примеры использования команд:

    rcr dh,3         ;Цикл. сдвиг DH на 3 бита вправо через флаг CF
    rcl byte[bx],cl  ;Цикл. сдвиг байта по адресу в BX на CL бит влево через флаг CF
    rcl dx,1         ;Цикл. сдвиг DX на 1 бит влево через флаг CF

Пример программы

В качестве примера напишем программу для подсчёта единичных битов в байте. Для анализа битов используется команда ROL в цикле. Цикл выполняется 8 раз — по числу битов в байте. Если очередной бит равен 1, то выполняем инкремент счётчика единичных битов.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
use16             ;Генерировать 16-битный код
org 100h          ;Программа начинается с адреса 100h
 
    mov al,[x]    ;AL = x
    xor bl,bl     ;BL = 0 (Здесь будем считать единичные биты)
    mov cx,8      ;Инициализация счётчика цикла
lp:
    rol al,1      ;Цилический сдвиг AL на 1 бит влево
    jnc bit0      ;Переход, если CF=0
    inc bl        ;Инкремент счетчика единичных битов
bit0:
    loop lp       ;Команда цикла
    mov [n],bl    ;Сохраняем результат в n
 
    mov ax,4C00h  ;\
    int 21h       ;/ Завершение программы
;----------------------------------------------------------------------
x  db 89h         ;Байт
n  db ?           ;Количество единичных битов в байте

Эту программу можно немного оптимизировать. Во-первых, использовать вместо условного перехода команду ADC со нулевым вторым операндом. Это позволит прибавить 1, если CF=1 и прибавить 0, если CF=0. Во-вторых, считать единичные биты можно в регистре AH, а обнулить его в начале с помощью команды MOVZX, совместив с загрузкой байта в регистр AL. Ноль для команды ADC можно взять в регистре CH, это делает команду короче и быстрее, чем при использовании непосредственного операнда. CH равен 0 во время выполнения цикла, так как CX изменяется от 8 до 0. Вот что получилось в итоге:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
use16             ;Генерировать 16-битный код
org 100h          ;Программа начинается с адреса 100h
 
    movzx ax,[x]  ;AL = x, AH = 0
    mov cx,8      ;Инициализация счётчика цикла
lp:
    rol al,1      ;Цилический сдвиг AL на 1 бит влево
    adc ah,ch     ;Прибавляем флаг CF к AH, так как CH = 0
    loop lp       ;Команда цикла
    mov [n],bl    ;Сохраняем результат в n
 
    mov ax,4C00h  ;\
    int 21h       ;/ Завершение программы
;----------------------------------------------------------------------
x  db 89h         ;Байт
n  db ?           ;Количество единичных битов в байте

Всего 6 команд для подсчета битов в байте. А попробуйте написать то же самое на языке высокого уровня 😉

Упражнение

Объявите в программе строку. Длина строки должна быть больше 8 символов и храниться в байте без знака. Напишите цикл для шифрования строки по алгоритму: первый символ циклически сдвигается вправо на 1 бит, второй символ — на 2 бита, …, 7-й — на 7 битов, 8-й — снова на 1 бит, 9-й на 2 бита и т.д. Затем напишите цикл для расшифровки строки и выведите её на экран.

Следующая часть »

Комментарии: