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.