BlogCurso 2000: Assembly esse eterno desconhecido #2

Agora que sabemos fazer continhas básicas, vamos aprender sobre os outros registradores, e como usa-los, além das magias arcanas das repetições.

Voltando ao nosso código da aula passada, ele deve ter ficado assim:

ORG 0x100

MOV AX, 5
ADD AX, 10
SUB AX, 1

CALL videotxt_imprime_numero_em_ax

RET

; Rotinas de impressão na tela

videotxt_imprime_texto:
    push si
    push ax
    push bx
    mov ah, 0xe
    mov bx, 0x7
    .caractere:
        lodsb
        cmp al, 0
        je .fim
        int 0x10
        jmp .caractere
    .fim:
    pop bx
    pop ax
    pop si
    ret

videotxt_imprime_numero_em_ax:
    push ax
    push bx
    push cx
    push dx
    mov bx, 10
    xor dx, dx
    div bx
    cmp ax, 0
    je .fim
        call videotxt_imprime_numero_em_ax
    .fim:
    mov al, dl
    add al, '0'
    mov ah, 0xe
    int 0x10
    pop dx
    pop cx
    pop bx
    pop ax
    ret

Antes de mais nada, vamos aprender os últimos dois comandos, começando pelo CALL, ele serve para chamar uma rotina (um conjunto de comandos que são executados, e após rodarem volta para a linha de baixo do CALL, continuando de onde parou), neste exemplo acima, o CALL é utilizado para chamar a rotina que imprime o número que está em AX, futuramente entraremos no código desta rotina, mas antes aprenderemos mais, para sermos capazes de entende-la.

Abaixo do CALL, exite o comando RET, ele serve para encerrar a rotina atual, que no nosso caso vai da linha do MOV AX, 5 até a linha do CALL, este comando ou suas variações são usadas em todas as rotinas existentes para que se retorne a rotina que está chamando, apenas para exemplificar, o código acima é o equivalente em lógica ao código em Pseudo-Código abaixo:


algoritmo "Teste"

var ax: inteiro

inicio

    ax := 5+10-1
    escreva(ax)

fimalgoritmo

Antes de continuarmos, precisamos só aprender uma ultima coisinha, para conseguirmos colocar comentários em nossos códigos, usamos o caractere ‘;', e tudo escrito na mesma linha após ele será ignorado como um comando, abaixo vemos no arquivo da aula passada um exemplo disso:

CALL videotxt_imprime_numero_em_ax

RET

; Rotinas de impressão na tela

videotxt_imprime_texto:
    push si
    push ax
    push bx

Agora que aprendemos o significado dos ultimos comandos de nossa rotina e como funcionam os comentários, vamos aprender a fazer contas com mais registradores:

Já sabemos como usar o AX, inclusive temos uma rotina especialmente para imprimir ele na tela, mas e se quisermos usar os demais operadores?

Fácil, devemos sempre lembrar que grande parte dos comandos sempre funcionam na ordem abaixo:

COMANDO DESTINO, ORIGEM

Mas se colocarmos outro registrador no destino, podemos?

Claro que sim, podemos usar tranquilamente quaisquer um dos quatro registradores (AX, BX, CX, DX) como destino ou origem, tanto que dessa forma que fazemos contas mais complexas ou mesmo cópia de dados entre eles.

Abaixo dou um exemplo de como fazer vários cálculos usando os registradores, inclusive com comandos que vamos aprender agora: (Bastando substituir o primeiro trecho do arquivo da aula passada por este)

Ao lado de cada comando coloquei um comentário com a conta que ele vai fazer e o resultado dela

ORG 0x100

;Atribuição dos valores iniciais

MOV AX, 5
MOV BX, 10
MOV CX, 15
MOV DX, 20

;Contas que ja aprendemos

ADD BX, AX       ; BX = 10 + 5 = 15
SUB DX, CX       ; DX = 20 - 15 = 5
ADD BX, DX       ; BX = 15 + 5 = 20
MOV AX, BX       ; AX = 20
MOV BX, 5        ; BX = 5

;Contas novas
MUL DX           ; AX = 20 * 5 = 100    e   DX = 0
DIV BX           ; AX = 100 / 5         e    DX = 0

;Imprime conteudo de AX
CALL videotxt_imprime_numero_em_ax

RET

Se tudo deu certo, apareceu o resultado na tela igual o abaixo:

Resultado

Parabéns!! Mas e agora pra que servem esses comandos novos e porque são diferentes?

Mais continhas!!!

MUL é o comando que faz as multiplicações, para simplificar a implementação desse calculo, o comando sempre usa como destino o AX, deixando a origem livre para um outro registrador, não podendo usar números aqui.

Deve ter observado que no comentário coloquei que o DX ficou igual a 0, mas por que? como a multiplicação de dois numeros tem a tendencia a aumentar e muito o tamanho do número resultante, as veze nao podem caber no AX, ai se utiliza o DX para o restante do número que não couber no AX.

DIV é o comando que faz divisões, onde o resultado da divisão fica no AX e o DX guarda o resto da divisão.

Teste mudar os números e execute novamente, além de mudar a posição dos comandos e usos deles, lembrando de jamais fazer uma divisão por zero =D, senão travará o DOSBOX.

E agora o que fazer? Repita! E agora o que fazer? Repita! E ag….

Voltando a breve explicação da primeira aula, lembra que o CX era focado em contagens? Agora vamos usar esse truque na manga que tem associado ao CX.

Mas mas como? O que fazer para o CX contar?

Fácil, abaixo segue um código que vamos explicar linha a linha:

ORG 0x100

MOV CX, 10

REPETICAO:         ; Marcador do codigo

    MOV AX, CX     ; AX = Valor em CX

    ;Imprime conteudo de AX
    CALL videotxt_imprime_numero_em_ax

LOOP REPETICAO     ; Repete iniciando do marcador REPETICAO, subtraindo 1 do CX, até o CX for 0

RET
; CONTINUA COM O RESTANTE DO ARQUIVO ORIGINAL....

Iniciamos com a definição do CX como valor inicial de 10 na linha abaixo

MOV CX, 10

Ai marcamos o código usando o marcador abaixo, para marcar um local no código basta escolher uma palavra que não seja um comando e após ele sempre coloque o ‘:’ para indicar que é um marcador válido.

REPETICAO:         ; Marcador do codigo

Agora copiamos o valor do CX (Inicialmente 10) para o AX para podermos imprimi-lo asseguir.

    MOV AX, CX     ; AX = Valor em CX

    ;Imprime conteudo de AX
    CALL videotxt_imprime_numero_em_ax

Até ai imprimimos na tela “10”, mas agora a mágica acontece:

LOOP REPETICAO 

O comando LOOP serve para repetir um trecho de código, mas ele tem uma inteligência atrelada que vou explicar em passos abaixo:

  • Verifica se CX é 0, se for ignora o comando, seguindo a partir da linha de baixo do LOOP
  • Se CX for maior que 0, subtrai 1 do CX e pula para o marcador

O que quer dizer que com ele voce consegue fazer um contador que a cada rodada ele tira um do contador, o que em outras linguagens poderia ser feito com um loop FOR, agora, imagine, se ele imprime o conteudo de CX, subtrai um de CX, repete até CX ser zero, o que ele imprimiria na tela?

A mágica acontecendo a frente de seus olhos

Resultado

Ele colou vários valores do CX um ao lado do outro, como uma unica linha.

Agora como exercício tente mudar o valor de CX e ver o que acontece, e tente tambem adicionar dentro da repetição o comando abaixo acima da linha do LOOP e veja o que acontece:

SUB CX, 1

Experimente bastante mas fica uma dica, não adicione um comando que adicione 1 ao valor de CX, que senão você vai anular o efeito do LOOP, e ele vai rodar para sempre, o que se chama de LOOP INFINITO, e travaria o emulador DOSBOX =D

Agora divirta-se e até a próxima aula.

Inté =)