Instruções de Subtração
Nesse ponto será visto as instruções de Subtração do 8088, que são apresentadas nesta tabela*:
SUBTRAÇÃO | |
SUB | Subtrair byte ou palavra |
SBB | Subtrair byte ou palavra com empréstimo (Borrow) |
DEC | Decrementar byte ou palavra de 1 |
NEG | Negar byte ou palavra |
CMP | Comparar byte ou palavra |
AAS | Ajuste ASCII na subtração |
DAS | Ajuste decimal na subtração |
*Quando falo de "byte ou palavra", refiro-me a dados de 8 e 16 bits respectivamente.
++SUB++
No ASM1F não me lembrei de por as operações válidas para ADD e ADC, que são iguais as de SUB e SBB. A tabela abaixo resume isso:
Operando | Exemplo |
Registro, Registro | SUB BX,CX |
Registro, Imediato | SUB DX,255 |
Acumulador, Imediato | SUB AL,31H |
Memória, Registro | SUB SOMA, CX |
Registro, Memória | SUB AX,SUBTRAÇÃO |
Onde Acumulador, Memória e Imediato, referem-se respectivamente ao registrador AX, uma variável e uma constante. A sintaxe da instrução SUB é:
SUB Destino, Fonte
Exemplo:
MOV AX,38h ;AX=38h
SUB AX, 30h ;AX=AX-30h >>> AX=38h - 30h >>> AX=08h
Se sabe usar ADD é lógico que também saiba usar SUB. Antes que me esqueça, o exemplo acima acaba de fazer a conversão da tecla "8", do código ASCII, para o número 08h em hexa (é o que se conhece por conversão ASCII em Binário) ou decimal se assim desejar. Digo isso por que entre 0 e 9 em hexadecimal equivale aos números decimais de 0 a 9.
Antes de prosseguir, é bom lembrar da aritmética do "complemento de 2". Para entende-la veja este exemplo:
5 = 0101 ;No ASM1F era para lembrar sobre a adição de números
+3 = 0011 ;binários mas acabei me esquecendo :) Vou atualiza-lo
_________________ ; em breve! Bem, na adição com números binários
8 = 1000 ;seguimos a seguinte regra: 1+1=0, que vai 1
Vamos dar um "zoom" na soma de 3 com 5 em binário:
3 2 1 0 <<< bit
1 1 1 <<< "vai um"
5 = 0 1 0 1 <<< número
+3 = 0 0 1 1
___________________
8 = 1 0 0 0 <<< resultado
-Somando o bit 0 do número 5 com o bit 0 do número 3 temos:
1+1=0, que vai 1
resultado: bit 0 = 0
-Somando o bit 1 de 5 com bit 1 de 3 temos:
0+1=1
1(foi "1" do bit 0 para o bit 1) + 1=0, que vai 1
resultado: bit 1 = 0
-Somando o bit 2 de 5 com o bit 2 de 3 temos:
1+0=1
1(foi "1" do bit 1 para o bit 2) + 1=0, que vai 1
resultado: bit 2 = 0
-Somando o bit 3 de 5 com o bit 3 de 3 temos:
0+0=0
1(foi "1" do bit 1 para o bit 2) + 0 = 1
resultado: bit 3 = 1
E como visto: 1+0=1, 0+1=1 e 0+0=0. Se conseguiu entender a soma, a subtração fica fácil. lembrando que: 0 - 1 = 1, que vai 1
3 2 1 0 <<< bit
-1 &nbssp; <<< "vai um"
5 = 0 1 0 1 <<< número
- 3 = 0 0 1 1
___________________
2 = 0 0 1 0 <<< resultado
-Subtraindo o bit 0 do número 5 com o bit 0 do número 3 temos:
1 - 1 = 0
resultado: bit 0 = 0
-Subtraindo o bit 1 de 5 com bit 1 de 3 temos:
0 - 1 = 1, que vai "-1"
>resultado: bit 1 = 1
-Subtraindo o bit 2 de 5 com o bit 2 de 3 temos:
1 - 0 = 1
-1(foi "-1" do bit 1 para o bit 2) + 1=0 ; -1+1=0
resultado: bit 2 = 0
-Subtraindo o bit 3 de 5 com o bit 3 de 3 temos:
0 - 0 = 0
resultado: bit 3 = 0
Mais um exemplo e basta:
-1 &nbssp; <<< "vai um"
13 = 1 1 0 1 <<< número
- 11 = 1 0 1 1
___________________
2 = 0 0 1 0 <<< resultado
-Subtraindo o bit 0 do número 13 com o bit 0 do número 11 temos:
1 - 1 = 0
resultado: bit 0 = 0
-Subtraindo o bit 1 de 13 com bit 1 de 11 temos:
0 - 1 = 1, que vai "-1"
>resultado: bit 1 = 1
-Subtraindo o bit 2 de 13 com o bit 2 de 11 temos:
1 - 0 = 1
-1(foi "-1" do bit 1 para o bit 2) + 1=0 ; -1+1=0
resultado: bit 2 = 0
-Subtraindo o bit 3 de 13 com o bit 3 de 11 temos:
1 - 1 = 0
resultado: bit 3 = 0
E como visto: 1 - 0=1, 1 - 1=0 e 0 - 0=0. Se conseguiu entender a subtração , o "complemento de 2" fica fácil. Veja:
3 2 1 0 <<< bit
-1 &nbssp; <<< "vai um"
3 = 0 0 1 1 <<< número
- 5 = 0 1 0 1
_______________________
-2 = 11 1 1 1 0 <<< resultado
Este valor 11110B=48D representa o complemento do número 2, ou seja o número "2" negativo.
Agora a questão é: "Como representar números negativos ?" Em ASM quando o bit mais significativo dum número for "1", ele será negativo. Como nossos registros têm apenas 16 bits, ou 65536, temos que representar os números negativos e positivos na faixa de -32.768 a +32.767.
Veja estes exemplos:
0000 0000 0011 0101B = positivo
1000 0000 0011 0101B = negativo
1000h = negativo
0FFFFh = negativo
0FFFh=positivo
Acontece que os números negativos estão na forma de complemento de 2.
"E se eu quiser transformar o número -2 em +2, ou vice-versa, como eu faço ?"
Note que: 3 - 5 = -2 = 1 1100B
Para efetuar a conversão segue-se a seguinte lógica:
1- Efetuamos a operação NOT, bit-a-bit, no número desejado;
2- Somamos "1" ao número que acaba de ser negado.
Observe este exemplo:
-2 = 1 1110B > complemento de 2 do número "-2"
0 0001B > inverso de "-2"
0 0001B + 1 = 0010B > Somando-se "+1" ao inverso de "-2", temos "+2"
Caso eu queira transformar "+9" em "-9" eu faria:
+9 = 0 1001B > número "+9"
1 0110B > inverso de "+9"
1 0110B + 1 = 1 0111B > Somando-se "+1" ao inverso de "+9", temos "-9"
Outra alternativa seria subtrair o módulo do número desejado por zero. Note:
1 111
0 = 0 0000B
2 = - 0 0010B
______________
-2 = 1 1110B
0 = 0 0000B
9 = - 0 1001B
______________
-9 = 1 0111B
Bem, chega de revisão. Veja este código e tire suas conclusões:
MOV AL, 32h ; AL = 32h
SUB AL, 38h ; AL = 32h - 38h = - 6h
Qual o valor de "- 6h" em binário ? Para saber faça o seguinte:
NOT(6h) + 1 = -6h
NOT(0110B) + 1 = -6h
1001B + 1 = -6h
1010B = -6h
Sacou ? Basta pegarmos o "módulo" do número, nega-lo e somar com "1".
++SBB++
Atua da mesma forma que ADC. Só que SBB leva em conta o flag CF quando este é setado (CF=1). Veja isso:
MOV AL, -90
SUB AL, 200 ; AL=-290 = -34 CF=0
;"Por que '-290' = '-34' ?" veja a instrução ADC, em ASM1F
;Mas lembre-se: podemos ir até '-255'. Se esse valor for menor
;que '-255' o flag de CF será setado. A conversão de '-290' para
;'-34' segue o mesmo raciocínio usado no ASM1F, quando se
;falou de ADC.
SUB AL, 10 ; AL = -44 isso é falso, pois houve empréstimo (CF=1).
;o correto é usar SBB que leva o flag CF em conta.
MOV AL, -90
SUB AL, 200 ; AL=-290 = -34 CF=1
SBB AL, 10 ; AL= -45
++NEG++
A instrução NEG tem como função realizar o complemento de dois em um operando. Sua sintaxe é:
NEG registro ou variável
Exemplo:
MOV AL, 32h ;AL = 32h = "2"
SUB AL, 38h ;AL = 32h - 38h = "2" - "8" = -6h = 1 1010B
NEG AL ;AL = +6h
A instrução NEG fez o seguinte:
NOT (-6h) + 1 = +6h
NOT (1 1010B) + 1 = +6h
0 0101B + 1 = +6h
0 0110B = +6h
++DEC++
O que DEC (Decrement) faz é decrementar 1 ao conteúdo de um registrador ou variável, trabalhando com operandos de 8 e 16 bits. A instrução DEC atualiza os flags AF, OF, PF, SF e ZF. O flag CF não é afetado. A lógica de DEC é:
contador = contador - 1
Sintaxe:
DEC registrador ou variável
Antes dos exemplos vejamos a instrução CMP.
++CMP++
Apesar de tê-lo visto no ASM1E, onde falamos das instruções condicionais, vamos nos aprofundar um pouco nesta instrução. CMP está aqui por que na sua lógica é feita a subtração do operando destino do valor do operando fonte, para que os flags possam ser atualizados. Mas o CMP não põem o resultado final no operando destino. Os flags afetados são: AF, CF, OF, PF, SF e ZF.
A sua lógica:
Estado dos Flags = Destino - Fonte
Sintaxe:
CMP registro, registro
CMP registro, variável
CMP variável, registro
CMP acumulador, constante ;acumulador = AX ou AL ou AH
CMP variável, constante
Note este exemplo:
LEA SI, novo
CMP [SI], 2 ;2=02h (byte) ou 2=0002h (word) ?
Ao fazer isso e compilar com MASM, será mostrado um erro. Mas por quê ? Sempre que comparamos uma localização de memória com um imediato, ou constante, temos que especificar de que tipo é este imediato. Para isso usa-se a pseudo-instrução PTR. O modo correto de escrever o exemplo acima é o seguinte:
LEA SI, novo
CMP [SI], BYTE PTR 2 ;estamos dizendo que 2=02h (byte)
Se a constante do "vetor novo" fosse do tipo word, escreveríamos WORD no lugar de byte.
Antes das instruções de ajuste veja estes exemplos:
sum
segment
assume cs:sum
org 100h
inicio proc near
mov ax,0003h ;limpa tela e define modo
int 10h
;texto 80 colunas por 25 linhas
;-------------------------------
mov lin,0
mov col,0
lea si,titulo
leia_titulo:
cmp [si],byte ptr "$"
je subtraia
mov ah,9
mov al,[si]
mov bl,00001110b
;veja o Norton Guide, em tables
mov bh,0
;as outras opcoes de cores.
mov cx,1
int 10h
inc si
inc col
call xy
jmp leia_titulo
;-------------------------------
subtraia:
mov col,40
mov lin,1
call xy
mov ah,1
int 21h
mov cl,al
mov ah,1
int 21h
cmp al,"-"
je subtracao
jmp inicio
subtracao:
mov ah,1
int 21h
cmp al,cl
jg sub_correta
jmp inicio
;--------------------------------
sub_correta:
sub cl,al
mov _al,cl
mov col,0
mov lin,2
call xy
mov ah,9
lea dx,frase
int 21h
mov col,33
mov lin,2
call xy
mov ah,2
mov dl,_al
int 21h
;----------------------------------
;----------------------------------
mov col,0
mov lin,4
call xy
mov ah,9
lea dx,frase2
int 21h
mov col,22
mov lin,4
call xy
mov ah,2
mov dl,_al
NOT dl
int 21h
;----------------------------------
;----------------------------------
mov col,0
mov lin,6
call xy
mov ah,9
lea dx,frase3
int 21h
mov col,24
mov lin,6
call xy
mov ah,2
mov dl,_al
NOT dl
add dl,30h
int 21h
;----------------------------------
;----------------------------------
mov col,0
mov lin,8
call xy
mov ah,9
lea dx,frase4
int 21h
mov col,45
mov lin,8
call xy
mov ah,2
mov dl,_al
NOT dl
add dl,31h
int 21h
;----------------------------------
;----------------------------------
mov col,0
mov lin,10
call xy
mov ah,9
lea dx,frase5
int 21h
mov col,62
mov lin,10
call xy
mov ah,2
mov dl,_al
mov cl,00h
sub cl,dl
mov dl,cl
int 21h
;----------------------------------
;----------------------------------
mov col,0
mov lin,12
call xy
mov ah,9
lea dx,frase6
int 21h
mov col,55
mov lin,12
call xy
mov ah,2
mov dl,_al
mov cl,00h
sub cl,dl
mov dl,cl
add dl,30h
int 21h
;----------------------------------
fim:
mov ah,4ch
;fecha programa e retorna para o DOS
int 21h
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++
; AREA DE DADOS
;
frase db 'Subtra‡Æo com resultado negativo:','$'
frase2 db 'Mas ao usar NOT temos:','$'
frase3 db 'Covertendo para decimal:','$'
frase4 db 'Somando-se com "1", temos o complemento de 2:','$'
frase5 db 'Mas poder¡amos fazer o mesmo, subtraindo o resultado por ZERO:','$'
frase6 db 'Agora basta somar com 30h e ter o resultado em decimal:','$'
titulo db 'Enter com 2 n£meros de tal modo que o resulatdo seja sempre negativo.','$'
col db ?
lin db ?
_al db ?
cont db ?
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++
inicio endp
;----------------------------------------------------
;Procedimento para ajustar coluna e linha
;do cursor
;
xy proc near
mov ah,2
mov dl,col
mov dh,lin
mov bx,0
int 10h
ret
xy endp
;----------------------------------------------------
sum ends
end inicio
Para usar o SUM.COM basta compila-lo e realizar uma subtração de modo que o resultado seja sempre negativo. Assim que o programa for carregado faça:
2 - 5
Ao digitar "2", "-" e depois "5" será realizada a subtração e várias observações sobre a subtração serão mostradas na tela.
++AAS e DAS++
AAS (ASCII adjust subtraction), corrige o resultado da subtração de dois números no formato decimal não-compactado. Sua lógica é esta:
SE (AL and 0F) > 9 ou AF=1 então:
AL = AL - 6
AH = AH - 1
AF = 1
CF = AF
Como o uso de AAS e AAA são semelhantes não mostrarei exemplos. Mas se quiser aprender a usar AAS basta ir no ASM1F e adaptar os exemplos mostrados.
Para DAS o mesmo raciocínio é válido. sua lógica é:
SE (AL AND 0Fh) > 9 ou AF=1 então
AL=AL- 6
AF=1
SE AL > 153 ou CF=1 então
AL=AL- 102
CF=1
Para exemplos consulte o ASM1F e veja a instrução DAA. Mas se quiser aprender a usar DAS basta ir no ASM1F e adaptar os exemplos mostrados.
Quanto aos exercícios, serão os mesmos apresentados no ASM1F.