Tutorial de Assembly

17
Tutorial de Assembly Aprenda Assembly (e não assembler) em 1 hora (pelo menos é o tempo que leva para ler este tutorial, ou 15 min. Com leitura dinâmica). Introdução: Assembly é uma linguagem que dá medo em muita gente, pois as instruções são completamente estranhas e diferentes de uma linguagem de alto nível, e mais ainda de uma linguagem visual. Nela você tem poucas funções básicas: mover, somar, subtrair, chamar interrupções etc. Neste tutorial, eu estou assumindo que você já saiba códigos binários e um pouco de eletrônica digital; eu irei abordar temas como programação VGA e um pouco de interface com as portas seriais e paralelas. Como este é o primeiro tutorial que estou escrevendo, será um texto para completos iniciantes no assunto, e depois, quem sabe eu escreva textos mais avançados. Mande-me e-mails com sugestões do que eu devo abordar nos próximos textos. Vamos ao que interessa: Em primeiro lugar, eu gostaria de esclarecer algumas coisas: Assembler é o compilador, montador, aquele que traduz para o código de máquina o seu código-fonte; Assembly é a linguagem de programação que todos vocês querem estudar. Assembly é uma linguagem muito eficiente, veloz e que gera executáveis menores que as outras linguagens, pois nela você fala diretamente com a máquina, as instruções usadas são as do processador, por isso é sempre importante conseguir o manual do processador, ou algum texto com todas as instruções e comandos dele, isso você pode encontrar geralmente no site do fabricante. Comparando com as linguagens de alto nível, no assembly você terá que digitar muito mais para resolver certos problemas e não terá a portabilidade que certas linguagens oferecem. Para resolver este último problema, sugiro sempre ter em mãos o manual de todos os processadores com o qual você quer que seu programa rode, assim como o dos Sistemas Operacionais, para converte-los. Mas, com tanta dificuldade, porque aprender assembly então? Simples, as empresas de Hardware preferem profissionais que saibam assembly, pois eles terão uma visão melhor da máquina em si e de como programá-la; algumas empresas de Software, como as de jogos, levam isso como bônus, pois algumas soluções de problemas só podem ser feitos no assembly, e estes programadores terão uma maior lógica computacional. Chega de papo furado: Que compilador eu uso? Neste tutorial eu irei utilizar o TASM, pois é mais conhecido e mais usado, mas sugiro que aprenda também a usar o NASM (não o MASM!!!) pois é de graça e também muito bom. Afinal, como funciona o Assembly? O Assembly simplesmente se comunica diretamente com a memória e as portas do computador usando registradores. Registradores são nada mais que flip-flops usados para armazenar os dados, e passá-los à memória, basicamente os registradores são: AX accumulator (acumulador): utilizado em operações aritméticas e de I/O (entrada e saída). BX base (base): utilizado como base ou ponteiro.

Transcript of Tutorial de Assembly

Page 1: Tutorial de Assembly

Tutorial de Assembly

Aprenda Assembly (e não assembler) em 1 hora (pelo menos é o tempo que leva para ler este tutorial, ou 15 min. Com leitura dinâmica).

Introdução:

Assembly é uma linguagem que dá medo em muita gente, pois as instruções são completamente estranhas e diferentes de uma linguagem de alto nível, e mais ainda de uma linguagem visual. Nela você tem poucas funções básicas: mover, somar, subtrair, chamar interrupções etc.

Neste tutorial, eu estou assumindo que você já saiba códigos binários e um pouco de eletrônica digital; eu irei abordar temas como programação VGA e um pouco de interface com as portas seriais e paralelas.

Como este é o primeiro tutorial que estou escrevendo, será um texto para completos iniciantes no assunto, e depois, quem sabe eu escreva textos mais avançados. Mande-me e-mails com sugestões do que eu devo abordar nos próximos textos.

Vamos ao que interessa:

Em primeiro lugar, eu gostaria de esclarecer algumas coisas: Assembler é o compilador, montador, aquele que traduz para o código de máquina o seu código-fonte; Assembly é a linguagem de programação que todos vocês querem estudar.

Assembly é uma linguagem muito eficiente, veloz e que gera executáveis menores que as outras linguagens, pois nela você fala diretamente com a máquina, as instruções usadas são as do processador, por isso é sempre importante conseguir o manual do processador, ou algum texto com todas as instruções e comandos dele, isso você pode encontrar geralmente no site do fabricante.

Comparando com as linguagens de alto nível, no assembly você terá que digitar muito mais para resolver certos problemas e não terá a portabilidade que certas linguagens oferecem. Para resolver este último problema, sugiro sempre ter em mãos o manual de todos os processadores com o qual você quer que seu programa rode, assim como o dos Sistemas Operacionais, para converte-los.

Mas, com tanta dificuldade, porque aprender assembly então? Simples, as empresas de Hardware preferem profissionais que saibam assembly, pois eles terão uma visão melhor da máquina em si e de como programá-la; algumas empresas de Software, como as de jogos, levam isso como bônus, pois algumas soluções de problemas só podem ser feitos no assembly, e estes programadores terão uma maior lógica computacional.

Chega de papo furado: Que compilador eu uso?

Neste tutorial eu irei utilizar o TASM, pois é mais conhecido e mais usado, mas sugiro que aprenda também a usar o NASM (não o MASM!!!) pois é de graça e também muito bom.

Afinal, como funciona o Assembly?

O Assembly simplesmente se comunica diretamente com a memória e as portas do computador usando registradores. Registradores são nada mais que flip-flops usados para armazenar os dados, e passá-los à memória, basicamente os registradores são:

AX – accumulator (acumulador): utilizado em operações aritméticas e de I/O (entrada e saída).

BX – base (base): utilizado como base ou ponteiro.

Page 2: Tutorial de Assembly

CX – counter (contador): utilizado como contador, e em loops de repetição.

DX – displacement (repositor): igual ao BX, é utilizado para propósitos gerais

Estes segmentos podem ser usados sem restrições pelo programador, são os chamados de propósitos gerais, eles tem 16 bits que podem ser acessados também em duas partes de 8 bits, a parte alta (H) e a baixa (L). Ex.: AH e AL.

À partir dos 386 estes segmentos passaram a ser de 32 bits, sendo acessados com EAX, EBX, ECX, EDX (o E é de Extended, estendido).

Existem também os registradores de segmentos, eles são:

CS – code segment (segmento de código): ele contém o endereço do código que está atualmente sendo executado (não mexa nele).

DS – data segment (segmento de data): contém o endereço dos dados do programa (não mexa nele).

ES – extra segment (segmento extra): este segmento aponta para onde você quer que ele aponte, use-o como você quiser.

SS – stack segment (segmento de pilha, e não o exército alemão): nele está o endereço da pilha, que contém valores retornados de instruções.

Destes segmentos, você só poderá modificar realmente o ES, pois ele não aponta para nada importante para a execução do programa. Existe também o FS, que é parecido com o ES, e dizem ser mais rápido.

Agora eu vos apresento os registradores de ponteiros:

SI e DI (source index e destiny index): eles são usados em comandos que movem blocos de bytes de um lugar(SI) para outro(DI), são a fonte e o destino.

BP – base pointer (ponteiro base): usado geralmente em conjunto com SS, ele nos servirá para, por exemplo, passar argumentos para uma função de um modo bem rápido (e complicado), quando fizer operações com pilhas, use-o, pois dificilmente você fará besteira com ele.

SP – stack pointer (ponteiro da pilha): Ele aponta para o topo da pilha, não mexa com ele, à não ser que queira que o seu programa trave.

Mas me diga....o que são pilhas?

Considere pilhas do jeito que o próprio nome diz, pilha!!! K ? Imagine uma pilha de livros, você começando a empilha-los, primeiro você põe o livro de Eletrônica Digital no chão, depois você põe o livro de Algoritmos em cima dele, e então põe o de cálculo, e em seguida o de Eletromagnetismo, no dia seguinte o professor de Algoritmos pede para trazer o livro na próxima aula, bem, você terá que tirar os livros de Eletromagnetismo e de Cálculo para poder pegá-lo.....em Assembly a pilha funciona desse jeito também, ou seja, o primeiro que entra é o último que sai (neste caso vale aquele ditado: Os últimos serão os primeiros). Os comandos para pôr e tirar um registrador da pilha são respectivamente:

PUSH reg

POP reg

Ex.:1) PUSH AX ;salva o valor de AX

...códigos, e mais códigos....

POP AX ;retorna o valor de AX

Page 3: Tutorial de Assembly

2) PUSH AX

PUSH BX

...mais códigos...

POP BX ;primeiro retorna o valor de BX e então...

POP AX ;...o de AX

Oh sim! Quase me esqueço, para fazer algum comentário use o ";" .

Segmentos de Memória, que diabo é isso?

A memória do computador é divida em segmentos para facilitar (?) o seu acesso, isso vem dos XTs que tinham pouca memória, tinham na verdade uma vaga lembrança....

A memória foi divida em segmentos e os segmentos em offsets.

4BC2 : 378F

seg. off.

Os registradores usados para representar os segmentos e offsets foram ditos acima. Ex.: DS:DI.

Você entenderá isso melhor ao longo do curso.

Pare com essa coisa chata, vamos partir logo para a parte legal (?), os comandos.

Bom, vamos começar com alguns comandos básicos, e ao longo deste texto eu irei mostrando novos comandos.

MOV dest, origem

Move um valor para um registrador. Pode-se fazer os seguintes tipos de MOVs:

registrador à registrador

registrador à memória

registrador à registrador de segmentos

valor à registrador

memória à registrador

Page 4: Tutorial de Assembly

OBS.: registrador são os registradores AX, BX, CX e DX.

ADD dest, origem

Soma a origem com o destino e põe o resultado no destino. Segue a mesma regra do MOV, citado acima.

ADC dest, origem

Mesma coisa que ADD, só que com "vai um", modificando o "Carry Flag".

INT interrupção

Chama uma interrupção de propósitos gerais.

JUMP label

Pula a execução do programa para a posição do código que se encontra label.

Label: pode ser qualquer palavra, desde que não seja reservada pelo compilador (algum comando, etc.) seguido ":".

Os números em assembly seguem as seguintes notações:

decimal: apenas escreva o número naturalmente;

binário, octal, hexadecimal: ponha uma letra b, o, h no final do número.

OBS.: no hexadecimal, se o número começar com A, B, C, D, E ou F, ponha um zero na frente, assim A000h vira 0A000h.

Bom, vamos ao código...

Como primeiro programa, vamos fazer o tradicional programa de iniciação em todas as linguagens.....o famoso: HELLO WORLD!!!!

Digite o texto abaixo em um editor (e não processador) de texto, como o EDIT ou o Bloco de Notas, e rode a seguinte linha de programa: TASM <nome-do-arquivo>, depois digite TLINK <nome-do-arquivo>. E execute-o.

Hellow.asm

.MODEL SMALL ;modelo de memória

.STACK 200h ;aloca espaço na pilha

.DATA ;aqui começam os dados e declaração de

;variáveis

HelloWorld DB "Hello World$" ;string sempre termina com $

.CODE ;aqui começa o código do programa

START: ;e aqui a função principal

Page 5: Tutorial de Assembly

MOV DX, OFFSET HelloWorld ;movendo o OFFSET de HelloWorld

MOV AX, SEG HelloWorld ;movendo o segmento de HelloWorld

MOV DS, AX ;e pondo ele no DS

MOV AH, 9h ;número da função do MS-DOS

INT 21h ;chamada de função

MOV AX, 4c00h ;função de saída do programa

INT 21h

END START ;fim do programa

Explicação:

.MODEL declara o modelo de memória usado no programa, ele pode ser:

TINY: código e dados cabem em 64kb de memória.

SMALL: código e dados são menores que 64kb, mas estão em segmentos diferentes.

MEDIUM: código é maior que 64kb mas os dados são menores.

COMPACT: código é menor que 64kb e os dados são maiores.

LARGE: códigos e dados são maiores que 64kb, mas arrays não são.

HUGE: tudo pode ser maior que 64kb.

.STACK aloca espaço na pilha.

.DATA indica o começo do bloco de dados.

.CODE indica o começo do bloco de código.

START e END START indica onde começa e termina o código principal.

Interrupção 21h: são as mais usadas, pois são as chamadas de funções do MS-DOS.

Função 9h do INT 21h: esta função escreve na tela um string apontada por DS:DX, perceba que a string sempre termina com $, e veja também como foi passado os valores do segmento e offset da string, e por último perceba que não podemos passar diretamente o segmento para DS, como foi explicado acima.

OBS.: Podemos mover o segmento DATA da seguinte forma: MOV AX, @DATA.

Função 4c00h do INT 21h: esta função retorna para o MS-DOS.

Repare que as funções dos INTs são escritas no registrador AX.

Na declaração da String, você reparou naquela palavra DB? Pois ela significa que estamos declarando um variável BYTE (8 bits), apesar do tamanho dela ser 1 BYTE, no caso das strings, ela amplia seu valor até o código $ subdividindo a string.

Page 6: Tutorial de Assembly

Também podemos declarar variáveis DW (Word – 16 bits), DD (Double Word – 32 bits).

O que são ‘flags’

Flags são quase como registradores, mas que servem para indicar certos acontecimentos, na verdade ele é um registrador de 8 bits onde cada bit indica uma coisa.

SF – Signal Flag: 0 – positivo, 1 – negativo;

ZF – Zero Flag: 0 – não zero, 1 – zero;

AF – Auxiliary Flag: carry (vai um) no fim do reg. ? 0 – não 1 – sim;

PF – Parity Flag: 0 – ímpar, 1 – par;

CF – Carry Flag: vai um;

OF – Overflow Flag: ocorreu overflow;

DF – Direction Flag: direção nos comandos de bloco, 0 – normal, 1 – reverso;

IF – Interrupt Flag: 0 – não executa interrupções, 1 – executa interrupções;

TF – Trap Flag: usado para debulhação (debug) do programa.

Como e para que eu uso isso?

Flags são importantes para verificar erros nos dados, estouro de pilha, e comandos parecidos com "se..então".

Eles são usados com os comandos CLx e STx, onde x é a inicial do flag que você usará.

Ou com comandos derivados do JUMP:

Jx ou JNx , onde x é a inicial do flag (Ex.: JC, pula se o carry flag está ativado). São usados depois de operações como ADD e MOV.

JUMPS condicionais:

Substituem o "se então" de outras linguagens. São usados geralmente após o comando CMP.

CMP reg1, reg2

Compara dois registradores, em relação ao seus valores.

Os Jumps condicionais são os seguintes:

Jumps levando em conta o sinal:

JG – pula se reg1 for maior que reg2;

Page 7: Tutorial de Assembly

JGE – pula se reg1 for maior ou igual à reg2;

JNG – pula se reg1 não for maior à reg2;

JL – pula se reg1 for menor que reg2;

JLE – pula se reg1 for menor que reg2;

JNL – pula se reg1 for menor ou igual à reg2;

JE – pula se reg1 for igual à reg2;

JNE – pula se reg1 não for igual à reg2;

OBS.: quando os registradores forem iguais o ZF será ativado, portanto dizer JE e JZ é a mesma coisa.

Jumps condicionais sem levar o sinal em consideração:

JA – pula se reg1 for maior que reg2;

JAE – pula se reg1 for maior ou igual à reg2;

JNA – pula se reg1 não for maior à reg2;

JB – pula se reg1 for menor que reg2;

JBE – pula se reg1 for menor que reg2;

JNB – pula se reg1 for menor ou igual à reg2;

JE – pula se reg1 for igual à reg2;

JNE – pula se reg1 não for igual à reg2;

Vamos agora exemplificar tudo isso com um programa que faz uma pergunta e pega a reposta do teclado.

Pergunte.asm

.MODEL SMALL

.STACK 200h

.DATA

Pergunta DB "Voce gosta de estudar Eletromagnetismo?$"

Sim DB "Isso e bom!$"

Nao DB "Deveria...$"

.CODE

START:

MOV AX, @DATA

Page 8: Tutorial de Assembly

MOV DS, AX ;primeiro façamos com que DS aponte para os dados

DeNovo:

MOV DX, OFFSET Pergunta

MOV AH, 9h

INT 21h

MOV AH, 0h ;função 0 do INT 16h: pega um caractere do teclado

INT 16h ;e coloca em AX.

CMP AX, "S" ;vê se sim foi pressionado

JNE MauAluno ; se não for, vai para o label "MauAluno"

MOV AH, 9h

MOV DX, OFFSET Sim

INT 21h

MOV AX, 4c00h

INT 21h

MauAluno:

MOV AH, 9h

MOV DX, OFFSET Nao

INT 21h

JUMP DeNovo ;repete ate dizer sim

END START

Espero que tenha entendido este exemplo, pois a coisa vai começar a pegar agora que vamos falar de......

PROGRAMAÇÃO DA PLACA VGA

MODO GRÁFICO: 320x200

Primeiramente iremos trabalhar com o modo gráfico 320x200, e possivelmente eu escreverei tutoriais sobre o famoso modo X e, quem sabe, sobre programação SVGA e VESA.

Como eu mudo do modo de texto para o modo VGA?

Simples, usa-se interrupções. A interrupção de funções VGA é a 10h.

Page 9: Tutorial de Assembly

Para passar para modo 320x200:

INT 10h

Função 00h – mudar modo de vídeo

13h – modo 320x200

00h – modo texto

Ex.:

MOV AH, 00h

MOV AL, 13h

INT 10h ;muda para 320x200

MOV AL, 00h

INT 10h ;muda para modo texto

Podemos simplesmente escrever:

MOV AX, 13h

INT 10h

Já que MOV AX, 13h vai mover 00 para AH e 13h para AL.

Legal, agora eu estou em 320x200, mas o que eu faço com isso?

Calma! Um passo de cada vez...vamos aprender a plotar um pixel.

Lembre-se que o modo VGA permite utilizar 256 cores de uma vez (0 – 255), ou seja, utilizaremos apenas 8bits de um registrador para colocar a cor.

Poderíamos simplesmente utilizar-se de funções do INT 10h para isso, mas isso deixaria o programa realmente muito lento se tivéssemos que pintar a tela inteira (precisaríamos repetir 64000 vezes).

Existe um jeito mais fácil de faze-lo: acessando a memória de vídeo diretamente.

O segmento de memória do VGA está no endereço 0A000h, mas e daí? E daí que assim nós podemos escrever um pixel na tela apenas usando comando MOV, isso torna o programa muito mais rápido, no final deste texto eu colocarei todas as instruções do assembler com seus respectivos ‘ticks’ (cada período do clock).

Para plotar um pixel faremos assim:

MOV AX, 0A000h ; o segmento do VGA vai para um registrador

MOV ES, AX ; de segmento (ES)

MOV BX, 32160 ; plota na posição (159,99)

MOV DI, BX

Page 10: Tutorial de Assembly

MOV AL, 54 ;cor a ser plotada

MOV ES:[DI], AL ;[ ] significa que estamos movendo para o

;local de memória indicado por DI, e não

;para o registrador DI.

Mas como eu sei que 32160 é a posição (159,99)?

A memória VGA é tratada linearmente (veja a figura abaixo), portanto o offset 0 representa (0,0) o 1 (1,0) o 319 (319,0) e o 320 (0,1), lembrando que se começa a contar do 0,0.

Como então calcular onde plotar? Basta usar esta simples fórmula: x + (320 * y), fácil não?

Então façamos a nossa função PlotPixel:

PlotPixel PROC

ARG x:WORD, y:WORD, cor:BYTE

MOV AX, 0A000h

MOV ES, AX

MOV BX, [x]

MOV DI, BX

MOV AX, [y]

MUL 320

ADD DI, AX

MOV AL, [cor]

MOV ES:[DI], AL

RET

PlotPixel ENDP

Basicamente, é isso, como PlotPixel é um procedimento e não a função principal ela é definida por:

<nome-da-função> PROC

Page 11: Tutorial de Assembly

ARG argumento1:tipo, argumento2:tipo, ...

...

RET

<nome-da-função> ENDP

ARG é usado para declarar os argumentos, RET diz para voltar à função principal, tipo pode ser DBYTE, DWORD, DDOUBLE (8 bits, 16 bits, 32 bits).

Antes de prosseguir vamos dar uma palavra sobre otimização. Bem essa função é bastante rápida, e se você tem um computador acima de um 486 você vai achar isso realmente muito rápido, mas quando você está trabalhando com animações, ou atualização de tela constante, isso se tornará excessivamente lento, então o que devemos fazer?

Em primeiro lugar, vamos lembrar que o processador trata tudo como número binário, ou seja 0s e 1s, nesse caso o processo de multiplicação se torna realmente lento, mas existe duas funções que podem nos ajudar no processo de multiplicação e divisão, os chamados ‘shifts’. Os shifts simplesmente arrastam os bits de um registrador para direita ou para a esquerda. Esse processo é realmente rápido para o computador, uma vez que ele apenas move os bits. Mas mover os bits de um número binário para a esquerda é a mesma coisa que multiplicar por uma potência de dois, e para a direita é dividir por um potência de dois:

SHL reg, num

Move os bits para a esquerda num casas.

SHR reg, num

Move os bits para a direita num casas.

Ex.: SHR AX, 1 (move os bits uma casa à direita = dividir por 2)

SHL AX, 3 (move os bits 3 casas à esquerda = multiplicar por 23 = 8)

Você irá notar que 320 não é uma potência de 2, certo, mas 256 e 64 são. Sim, e daí? E daí que 256 + 64 = 320....ou seja, 256 * y + 64 * y = 320 * y.

Agora o código ficará assim:

PlotPixel PROC

ARG x:WORD, y:WORD, cor:BYTE

MOV AX, 0A000h

MOV ES, AX

MOV BX, [y]

MOV DI, BX

SHL BX, 8

SHL DI, 6

Page 12: Tutorial de Assembly

ADD DI, BX

MOV DX, [x]

ADD DI, DX

MOV AL, [cor]

MOV ES:[DI], AL

RET

PlotPixel ENDP

Assim ele já está bom o suficiente, existe outros métodos para deixá-lo ainda mais rápido, mas isso eu deixarei para vocês, por enquanto...

Retas Horizontais, Verticais e Diagonais

Para desenhar um reta horizontal é bem simples, basta repetirmos um plot varias vezes sempre indo para a próxima coluna até o final da linha.

PlotHorizontal PROC

ARG x1:WORD, x2:WORD, y:WORD, cor:BYTE

MOV AX, 0A000h

MOV ES, AX

MOV AX, [x1]

MOV CX, [x2]

CMP AX, CX

JNA Desenha

MOV BX, CX

MOV CX, AX

MOV AX, BX

Desenha:

SUB CX, AX

MOV BX, [y]

MOV DI, BX

SHL BX, 8

SHL DI, 6

ADD DI, BX

Page 13: Tutorial de Assembly

ADD DI, AX

MOV AX, [cor]

REP STOSB

RET

PlotHorizontal ENDP

Oba! Mais duas funções novas à serem consideradas...

REP função

Repete a função o número de vezes indicado no registrador CX, no caso da nossa função ele vai repetir a diferença x2-x1, que é o comprimento da linha.

STOSB

Copia o conteúdo de AL para o segmento de memória apontado por ES:DI.

STOSW

Copia o conteúdo de AX para o segmento de memória apontado por ES:DI

MOVSB

Move um byte do conteúdo apontado por DS:SI para o conteúdo apontado em ES:DI.

MOVSW

Move uma word do conteúdo apontado por DS:SI para o conteúdo apontado em ES:DI.

Para desenhar um linha vertical, é fácil, mas tem-se que considerar certas coisas, tente fazer este por si só e também uma função geral para as linhas. Eu deixarei as respostas com os devidos comentários nas mesmas páginas que se encontra este tutorial. A resposta não é tão diferente do procedimento descrito acima, apenas lembre-se de que a cada STOSB o registrador DI é acrescido de mais 1.

Eu também deixarei um pequeno programa de demonstração, que mostra todas estas funções em uso.

Esta parte de VGA irá se encerrar aqui, existem bons materiais espalhados pela net sobre o assunto, eu também escreverei um tutorial mais específico sobre o assunto.

Vamos agora com a comunicação serial e paralela.

O processador se comunica com os diversos periféricos através de portas de comunicação, um PC tem 65535 portas, comunicar-se com estas portas é uma tarefa simples, o difícil é saber o que faz cada uma dessas portas.

Os comandos para entrada e saída de comunicação são:

IN AL, porta ou IN AL, DX ou IN AX, DX

Este comando obtém dados da porta e coloca-os em AL ou AX, dependendo se você quer bytes ou words, geralmente usa-se o registrador DX para dizer qual o no da porta, embora possa-se dizer diretamente, se o no da porta for até 255.

Page 14: Tutorial de Assembly

OUT DX, AL ou OUT DX, AX

Este comando envia dados para a porta especificada por DX.

Esta é a base do interfaceamento, dependendo do que você quer fazer, ou do que a máquina que você estará ligando ao computador foi feita, você usará esses comandos do jeito mais apropriado.

As portas seriais são:

Porta: COM1 COM2 COM3 COM4

Endereço: 3F8h 3E8h 2F8h 2E8h

A porta paralela geralmente é 378h (LPT1).

Apêndice I: Instruções Assembly

Aqui eu colocarei os comandos mais importantes da linguagem Assembly com uma breve explicação e quantos ticks (ciclos de máquina) ele leva (para o 486).

ADC dest, fonte

Realiza uma soma com carry (vai um).

ADD dest, fonte

Realiza uma soma.

AND dest, fonte

Realiza um "e" lógico.

CALL function/macro

Chama um procedimento ou uma macro.

CLx, onde x é o flag

Limpa o flag correspondente (zera).

CMC

Muda o valor do carry flag. Se for 1 vira 0, se for 0 vira 1.

CMP dest, fonte

Compara os dois valores mudando os flags correspondentes.

CMPSx, onde x é B (byte), W (word), ou D (double).

Compara o byte/word/double no endereço DS:[SI] com o ES:[DI].

DEC dest

Decrementa de um o registrador.

DIV num

Page 15: Tutorial de Assembly

Calcula o quociente (sem sinal) da divisão de dest por fonte. Se for uma divisão de bytes, o dividendo estará em AX e o quociente e resto em AH e AL respectivamente. Se for uma divisão de words, o dividendo estará em DX:AX e o quociente e o resto em AX e DX.

IDIV num

Calcula a divisão com sinal.

IMUL num

Calcula a multiplicação com sinal.

IN AL, porta/DX

Pega dados de alguma porta.

INC reg

Incrementa em um o registrador.

INT interrupt

Chama uma interrupção.

JUMP label

Pula para o label correspondente no código fonte.

Jx label, onde x é alguma condição descrita anteriormente no tutorial.

Pula para o label correspondente se a condição for satisfeita.

LAHF

Põe os valores dos bits mais baixos dos flags em AH.

LEA dest, fonte

Calcula o offset e põe no registrador.

LODSx, onde x é B, W ou D.

Põe o valor de DS:[SI] em Al, AX ou DX:AX, dependendo da escolha.

LOOP/LOOPE/LOOPNE label

Repete o código compreendido entre o label e a instrução o número de vezes armazenado em CX. LOOPE e LOOPNE são loops condicionais, eles repetem verificando também se o zero flag está setado ou zerado.

MOV dest, fonte

Move o valor de fonte para dest.

MOVSx, onde x é B, W, D.

Move o byte, word ou double de DS:[SI] para ES:[DI].

Page 16: Tutorial de Assembly

MUL num

Multiplica AX ou AL por num e o resultado armazenado em DX:AX ou AX.

NEG dest

Nega dest (0 – dest).

NOP

Não faz nada (no operation – sem operação).

(o Windows provavelmente tem muitas desta instrução em seu código...J ).

NOT dest

Faz um "não" lógico.

OR dest, fonte

Faz um "ou" lógico.

OUT porta/DX, AX/AL

Põe um dado na porta especificada.

POP reg

Põe o valor no topo da pilha em reg.

PUSH reg

Põe o valor de reg no topo da pilha.

POPF/PUSHF

Põe o valor da pilha no flag / Põe o valor do flag na pilha.

REP instrução

Repete a instrução CX vezes.

RET

Retorna de uma sub-rotina.

SHR / SHL dest, num

Move os bits de dest para direita / esquerda num posições.

STx, onde x é um flag.

Seta (põe o valor 1) no flag.

STOSx, onde x é B, W, D.

Põe o valor de AL, AX ou DX:AX em ES:[DI].

Page 17: Tutorial de Assembly

SUB dest, fonte

Subtrai fonte de dest e põe o valor em dest.

TEST dest, fonte

Faz um "e" lógico, só que não põe o resultado no registrador <dest>, ele apenas muda os flags.

XCHG dest, fonte

Troca os valores entre os registradores.

XOR dest, fonte

Faz um "ou exclusivo" entre os registradores.