Instruções de Deslocamento
Instruções | Significado | Sintaxe | Operação | Flags Afetados |
SAL / SHL | Deslocamento lógico/aritmético a esquerda |
SAL D, contador ou SHL D, contador |
Deslocar (D) a esquerda pelo número de posições de bit indicado pelo contador, preenchendo as posições livres a direita com zeros
|
OF, CF |
SHR | Deslocamento lógico a direita | SHR D, contador |
Desloca (D) a direita pelo numero de posições de bit indicado pelo contador, preenchendo as posições livres a esquerda com zeros
|
OF, CF |
SAR | Deslocamento aritmético a direita | SAR D, contador |
Deslocar (D) a direita pelo número de posições de bit indicado pelo contador, preenchendo as posições a esquerda com o valor original do bit de maior peso(mais significativo).
|
OF, SF, ZF, AF, PF, CF |
MOV AX, 01001101B ;AX = 4Dh
SAL AX, 1 ;SAL ou SHR executado pela 1ª vez
MSB LSB
AX = 4Dh | 0 | 1 | 0 | 0 | 1 | 1 | 0 | 1 |
/ / / / / / / /
/ / / / / / / /
/ / / / / / / /
CF = | 0 | 1 | 0 | 0 | 1 | 1 | 0 | 1 | 0 |
AX = | 9 | A |
Observe que 9Ah = 2*4Dh
SAL AX, 1 ;SAL executado pela 2ª vez
MSB LSB
AX = 9Ah | 1 | 0 | 0 | 1 | 1 | 0 | 1 | 0 |
/ / / / / / / /
/ / / / / / / /
/ / / / / / / /
CF = | 1 | 0 | 0 | 1 | 1 | 0 | 1 | 0 | 0 |
AX = | 3 | 4 |
Observe que 134h = CF + 34h = 2*9Ah
SAL AX, 1 ;SAL executado pela 3ª vez
MSB LSB
AX = 9Ah | 0 | 0 | 1 | 1 | 0 | 1 | 0 | 0 |
/ / / / / / / /
/ / / / / / / /
/ / / / / / / /
CF = | 0 | 0 | 1 | 1 | 0 | 1 | 0 | 0 | 0 |
AX = | 6 | 8 |
Observe que 68h = 2*34h
SAL AX, 1 ;SAL executado pela 4ª vez
MSB LSB
AX = 9Ah | 0 | 1 | 1 | 0 | 1 | 0 | 0 | 0 |
/ / / / / / / /
/ / / / / / / /
/ / / / / / / /
CF = | 0 | 1 | 1 | 0 | 1 | 0 | 0 | 0 | 0 |
AX = | D | 0 |
Observe que 0D0h = 2*68h
Note que LSB significa bit menos significativo(de menor peso) e MSB bit mais significativo(de maior peso). Conforme visto, usando-se SAL ou SHL, os bits vagos a direita são preenchidos com zeros, enquanto o flag de carry(CF) assume o valor do bit MSB.
Depois de quatro "observe" deve ter percebido que o SAL ou SHL estavam multiplicando o valor do operando destino por 2, a cada vez que um bit zero ocupava uma posição a esquerda. Note agora um exemplo diferente:
MOV AX, 1010B ;AX = 0Ah
SAL AX, 1 ;SAL ou SHR executado pela 1ª vez
MSB LSB
AX = 4Dh | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 |
/ / / / / / / /
/ / / / / / / /
/ / / / / / / /
CF = | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 0 |
AX = | 1 | 4 |
Observe que 14h = 2*0Ah
MOV CL, 2
MOV AX, 1010B
SAL AX, CL ;SAL executado pela 2ª vez
MSB LSB
AX = 0Ah | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 |
/ / / / / / / /
/ / / / / / / /
/ / / / / / / /
CF = | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 0 |
/ / / / / / / /
/ / / / / / / /
/ / / / / / / /
CF = | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 0 |
AX = | 2 | 8 |
Observe que 28h = 4*0Ah
MOV CL, 3
MOV AX, 1010B
SAL AX, CL ;SAL executado pela 2ª vez
MSB LSB
AX = 0Ah | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 |
/ / / / / / / /
/ / / / / / / /
/ / / / / / / /
CF = | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 0 |
/ / / / / / / /
/ / / / / / / /
/ / / / / / / /
CF = | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 0 |
/ / / / / / / /
/ / / / / / / /
/ / / / / / / /
CF = | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 0 |
AX = | 5 | 0 |
Observe que 50h = 8*0Ah
Se fizer isso N vezes irá notar que:
AX = 2^N * AX -->
AX = 2^CL * AX
Onde CL, e apenas CL ou CX(sendo que CX <= 256), é o contador. AX representa, nesse exemplo o operando destino. A sintaxe correta para as instruções deslocamento é mostrada abaixo:
Destino | contador |
registro | 1 |
registro | CL |
memória | 1 |
memória | CL |
Resumindo tudo nós notamos o seguinte:
A dupla SAL / SHL realizam uma multiplicação do tipo: Destino = Destino * 2^CL
E SAR / SHR realizam uma divisão do tipo: Destino = Destino / (2^CL)
"E qual a diferença entre SAL e SHL ?" Nenhuma, ambos realizam a mesma função e com a mesma performance. A lógica de ambas é seguinte:
+----+
+---------+
¦ CF ¦ <-- ¦ Destino ¦ <-- 0
+----+ +---------+
Já a "dupla de dois" SAR e SHR são diferentes. Note a lógica de cada uma delas:
SAR:
+----+ +---------+ +----+
¦ SF ¦ --> ¦ DESTINO ¦ --> ¦ CF ¦
+----+ +---------+ +----+
SHR:
+---------+
+----+
0 --> ¦ Destino ¦ --> ¦ CF ¦
+---------+ +----+
Uma coisa é certa, as duas realizam uma instrução de divisão, mas a diferença está em como cada uma lida com números sinalizados. SAR realiza uma divisão do tipo Destino = Destino / (2^CL), mantendo o sinal do operando destino. Enquanto SHR, faz a divisão de números não sinalizados.
Se quer ver a prova, observe:
MOV NUM2, -10 ;-10 = 0FFF6h
SHR NUM2, 1 ;-10 / 2 = 5 = 7FFBh
;esse numero é positivo!!!
;
;NUM2 = 7FFBh ;lembre-se, isso é bem básico, o se o bit MSB for 0
; ;o número será POSITIVO.
MOV NUM2, -10 ;-10 = 0FFF6h
SAR NUM2, 1 ;-10 / 2 = -5 = 0FFFBh
;esse número é NEGATIVO
;
;NUM2 = FFFBh ;lembre-se, isso é bem básico, o se o bit MSB for 1
; ;o número será NEGATIVO.
Caso não esteja acreditando, acrescente um NEG no código veja se o que acontece:
MOV NUM2, -10 ;-10 = 0FFF6h
SHR NUM2, 1 ;-10 / 2 = 5 = 7FFBh
;esse numero é positivo!!!
NEG NUM2 ;NUM2 = 1000 0000 0000 0101b
;antes do NEG, era "0", portanto, era POSITIVO
;
;NUM2 = 8005h ;lembre-se, isso é bem básico, o se o bit MSB for 0
; ;o número será POSITIVO.
MOV NUM2, -10 ;-10 = 0FFF6h
SAR NUM2, 1 ;-10 / 2 = -5 = 0FFFBh
;esse número é NEGATIVO
NEG NUM2 ;NUM2 = 0000 0000 0000 0101b
;antes do NEG, era "1", portanto, era NEGATIVO
;
;NUM2 = 0005h ;lembre-se, isso é bem básico, o se o bit MSB for 1
; ;o número será NEGATIVO.
Quando tiver que multiplicar operandos por números que são potência de 2, é mais rápido fazê-lo usando SAL ou SHL. Para que tenha um idéia disso, o Norton Guide nos mostra quantos cloks são gastos usando-se cada instrução:
SAL ou SHR
MUL
Conforme visto, usar um SAL ou SHL para multiplicar um operando por um número que é potência de 2 é, no mímino, 35 vezes mais rápido que usar o MUL. O mesmo raciocínio é válido para SHR e SAR em comparação com DIV.
Para aprender a usar as instruções de deslocamento, baixe o asml_1.zip e modifique a linha 82 pela instrução que deseja estudar. Salve e compile, lembrando que este código faz uso das rotinas do AsmBR.
Instruções | Significado | Sintaxe | Operação | Flags Afetados |
ROL | Rotação a esquerda |
ROL D, contador |
Rotacionar (D) a esquerda bit a bit pelo número de vezes indicado pelo contador. O bit deslocado retorna a posição mais a direita. |
OF, CF |
ROR | Rotação a direita | ROR D, contador | Rotacionar (D) a direita bit a bit pelo número de vezes indicado pelo contador. O bit deslocado retorna a posição mais a esquerda | OF, CF |
RCL | Rotação a esquerda através do transporte(carray) | RCL D, contador | O mesmo que ROL, porém utilizando o bit de carry. | OF, CF |
RCR | Rotação a direita através do transporte(carray) | RCR D, contador | O mesmo que ROR, porém utilizando o bit de carry. | OF, CF |
Sintaxe das instruções
Destino | Contador |
Registro | 1 |
Registro | CL |
Memória | 1 |
Memória | CL |
Note agora os exemplos:
ROL
Sua lógica é a seguinte:
Perceba que o valor do bit mais significativo do "destino" é "jogado" no flag de carry e não é alterado, não importa quantas rotações tenham sido feitas.
A instrução ROL irá rotacionar todos os bits, começando pelo bit 0, para a esquerda. Neste exemplo vou rotacionar 2 bits. Note:
Observou que o número 9 foi "empurrado duas casas" para a frente(esquerda)? Agora execute novamente o programa e escolha o mesmo número 9 e rotacione agora 15. Percebeu o que está acontecendo? o bit de valor 1, menos significativo, foi empurrado dois bits para frente. Baixar asml_2.zip
RCL
A instrução RCL irá rotacionar todos os bits, começando pelo bit 0, para a esquerda, incluindo o bit presente no flag de carry. Sua lógica é a seguinte:
Perceba que o bit mais significativo do "destino" é jogado no flag de carry. Este, por sua vez, realimenta o "destino" pela esquerda.
Neste exemplo vou rotacionar 2 bits. Note:
Observou que o número 9 foi "empurrado duas casas" para a frente(esquerda), juntamente com o bit que havia no flag de carry? Se o bit do flag de carry fosse zero, o resultado seria o mesmo se usássemos ROL. Baixar asml_3.zip
ROR
Sua lógica é a seguinte:
Perceba que o valor do bit menos significativo do "destino" é "jogado" no flag de carry. E este não se altera, não importa quantas rotações tenham sido feitas.
A instrução ROR irá rotacionar todos os bits, começando pelo bit 0, para a direita Neste exemplo vou rotacionar 2 bits. Note:
Observou que o número 9 foi "empurrado duas casas" para a trás(direita)? Agora execute novamente o programa e escolha o mesmo número 9 e rotacione agora 5. Percebeu o que está acontecendo? o bit de valor 1, menos significativo, foi empurrado dois bits para frente. Baixar asml_4.zip
RCR
Sua lógica é a seguinte:
Perceba que o valor do bit menos significativo é "jogado" no flag de carry, este, por sua vez, é realimenta o "destino" pela direita.
A instrução RCR irá rotacionar todos os bits, começando pelo bit 0, para a direita, incluindo o valor do bit do flag de carry. Neste exemplo vou rotacionar 2 bits. Note:
Observou que o número 9 foi "empurrado duas casas" para a trás(direita), juntamente com o bit que havia no flag de carry? Se o bit do flag de carry fosse zero, o resultado seria o mesmo se usássemos ROR. Baixar asml_5.zip