SAL – Shift Arithmetic operand Left – арифметический сдвиг операнда влево.
SAL операнд, количество_сдвигов
Флаги: SF, ZF, PF, CF. Флаг AF не определен. Флаг OF изменяется, если сдвиг осуществляется только на 1 разряд, иначе не определен. OF=1, если значение флага CF после сдвига и значение старшего бита результата различны, если совпадают – 0 (т.е. XOR от CF и старшего разряда результата).
Действие:
Сдвиг влево всех битов операнда. Каждый сдвиг влево эквивалентен умножению знакового числа на 2, поэтому команду удобно использовать для возведения операнда в степень 2. Старший бит операнда поступает в флаг CF. Если команда записана в формате:
SAL операнд, 1 - осуществляется сдвиг влево на 1 бит. В младший бит операнда загружается 0;
SAL операнд, CL - осуществляется сдвиг влево на число битов, указанное в регистре-счетчике CL. В процессе последовательных сдвигов старшие биты операнда, пройдя через флаг CF, теряются, а младшие заполняются 0;
16-ричный код (1 байт) | MOD Reg/OPC Reg/Mem (2-ой байт) | смещение disp_Lo, disp_Hi | формат операндов: приемник, источник |
D0 | MOD 100 Reg/Mem | Disp_Lo, Disp_Hi | Reg8/Mem8, 1 |
D1 | MOD 100 Reg/Mem | Disp_Lo, Disp_Hi | Reg16/Mem16, 1 |
D2 | MOD 100 Reg/Mem | Disp_Lo, Disp_Hi | Reg8/Mem8, CL |
D3 | MOD 100 Reg/Mem | Disp_Lo, Disp_Hi | Reg16/Mem16, CL |
C0 | MOD 100 Reg/Mem | Disp_Lo, Disp_Hi | Reg8/Mem8, imm8 |
C1 | MOD 100 Reg/Mem | Disp_Lo, Disp_Hi | Reg16/Mem16, imm8 |
100 - расширение кода операции при работе с непосредственным операндом, размещается в поле Reg/Opc в байте адресации.
Например, 1) MOV AL, 7h
SAL AL, 1 ; AL=0Eh=7*2, CF=0
2) MOV AX, -1 ; AX=FFFFh
MOV CL, 4
SAL AX, CL ; AX=FFF0h= -1*16= -16, CF=1
4) SAR операнд, значение — арифметический сдвиг вправо (рис.1.21)
SAR – Shift Arithmetic operand Right – арифметический сдвиг операнда вправо.
SAR операнд, количество_сдвигов
Флаги: SF, ZF, PF, CF. Флаг AF не определен. Флаг OF=0, если сдвиг осуществляется только на 1 разряд, иначе не определен.
Действие:
Сдвиг вправо всех битов операнда. Младший бит операнда поступает в флаг CF. Освобождающиеся старшие разряды заполняются значением старшего (знакового) разряда. Каждый сдвиг вправо эквивалентен делению знакового числа на 2, поэтому команду удобно использовать для деления операнда на целые степени 2.
Коды команды см. таблицу команды SAL. Но расширение кода операции при работе с непосредственным операндом, размещающееся в поле Reg/Opc в байте адресации, равно 111.
Например, 1) MOV AL, 7h
SAR AL, 1 ; AL=3=7/2, CF=1. Остаток потерян.
2) MOV BX, -8 ; BX=FFF8h
MOV CL, 2
SAR BX, CL ; BX=FFFEh= -2= -8/4, CF=0
знак
операнд CF
Рис. 1.21 Арифметический сдвиг вправо
При работе команды арифметического сдвига вправо значение знакового бита не меняется, знаковый бит заполняет освободившиеся места.
Пример
MOV AL,11010100B
MOV CL,3
SAR AL,CL ; результат -11111010
MOV AL,11010100b
SHR AL,CL ; результат — 00011010 — ЗНАК ЧИСЛА ПОТЕРЯЛСЯ!
Таким образом, можно производить умножение и деление с помощью сдвига, если один из сомножителей или делитель представляет собой степень 2. Причем, сдвиг производится процессором намного быстрее, чем умножение и деление:
MUL (8-битный регистр) — 70— 77 тактов
(16-битный) —118—133 тактов
IMUL (8-битный регистр) — 80— 98 тактов
(16-битный) —128—154 тактов
IDIV (8-битный регистр) —101—112 тактов
(16-битный) —165—184 тактов
сдвиг регистра на 1 позицию — 2 такта
Даже если мы работаем с числами, не являющимися степенями 2, оказывается, если мы хотим добиться максимальной скорости, можно представить множитель или делитель как сумму степеней 2.
ПРИМЕР задания
Написать фрагменты программы для умножения X*12 двумя способами: с помощью команды умножения и с помощью сдвига. Оценить время выполнения каждого фрагмента.
X*12 = X * (23 + 22) = X * 23 + X * 22
Чтобы умножить число X на 12, нужно произвести сдвиг X влево на 3 бита, и результат где-то запомнить, затем произвести сдвиг X влево на 1 бит. Потом оба результата сложить.
x db 30 x db 30
.......... ..........
mov al,x mov al,x
cbw
mov cl,2 cbw
sal ax,cl ; ax=ax*4 mov bx,10; 2 такта
mov bx,ax imul bx; 128 тактов
sal ax,1 ; ax=ax*2
add bx,axвсего 134 такта
cbw, sal, mov — 2 такта
add — 3 такта
всего 15 тактов
Таким образом, хоть первая программа и длинней, она будет выполняться намного быстрее (за 15 тактов), а вторая — за 134 такта. Отметим, что здесь не учитывается время для выборки переменной из сегмента данных.
5) ROL операнд, значение — сдвиг влево циклический (ROll Left) (рис.1.22)