Curso Fudeba de ASM


Aula 1: Introduzindo a Introdução.

    Bem, começo de novo. Originalmente tinha planejado esse curso para algo bem nos moldes do que todo mundo está acostumado: ma introdução teórica e nada a ver com a programação em si, e depois um monte de comandos e suas sintaxes. Felizmente percebi a tempo que isso é uma perda de tempo para os que pouco sabem programar ou para os que não sabem nada.
    "Epa!" vão dizer... "Você quer ensinar Assembly para quem não sabe programar nada?" Bem, a idéia é essa mesmo. Assembly é, em essência, a linguagem mais fácil (e idiota) que tem para se compreender o que ela faz, e ao mesmo tempo desenvolve como nenhuma outra a habilidade de "dar soluções geniais" a problemas, devido a suas inerentes limitações.
    Como tornar Assembly algo simples? Bem, primeiramente esquecendo que é uma linguagem de programação, pensando que é mais uma seqüência de ordens que se dá as pecas do computador, quando então tudo começa a fazer muito mais sentido (obviamente porque é exatamente isso que estamos fazendo quando programamos Assembly: damos ordens aos microchips).
    Bem, esse deve ser um curso muito mais dinâmico que o outro. E mais rápido também, mas creio que muitas duvidas devem surgir, pois ele se baseia na técnica de ensino que estamos desenvolvendo na faculdade chamada VIAGRA (Viajamos e Introduzimos Aspectos GRAdualmente), ou seja, a gente vai falando de tudo um pouco e falando sobre os conceitos (aritméticos, lógicos, físicos, etc.) quando necessário.
Chega de papo e vamos ao que interessa...!
 

Nosso Primeiro Programa em Assembly (Já!)

    Bom, não tão já assim. Primeiro vamos parar um pouco e pensar. Vou propor a idéia, que é tão somente fazer um programa que escreva:

"Alo, Mundo"

    Na tela de nosso computador, mas isso é muito vago. Como e onde pretendo fazer isso? O que precisamos para começar? Bem, você não precisa de muita coisa. Um MSX com drive (vamos começar usando o MSX-DOS) e o Assembler/Linker M80/L80 (vou introduzir isso passo a passo na hora certa, por enquanto fica nisso mesmo). Mais pra frente vamos usar o BrMSX DOS para ajudar em algumas coisas.
Voltando ao nosso problema, que já é bem mais definido: Vamos escrever "Ola, Mundo" usando o MSX-DOS, em um computador MSX. Opa... primeira coisa sobre Assembly: ele varia de maquina para maquina, apesar de conceitualmente ser a mesma coisa. Imagine como se cada modelo de computador fosse gente de uma parte diferente do mundo. Os MSX falam português, os Amiga falam inglês, e os PCs falam russo, por exemplo. Assim, quando dizemos que vamos trabalhar no MSX, automaticamente dizemos que vamos trabalhar com uma linguagem que computadores MSX apenas entendem. Note que assim como conseguimos nos virar com o português na Argentina, o famoso portunhol, também o que escrevemos para MSX muitas vezes dá pra ser arranjado num ZX-Spectrum e vice-versa (daí já dá pra começar a entender porque tem tanto jogo de Spectrum no MSX).
    Mas isso tudo tá muito enrolado, não? Vamos com calma. Vamos por partes. Se tudo que queremos é escrever "Ola, Mundo" na tela, precisamos dar um jeito de dar ordens para o computador. Bem, sabemos que o MSX lê suas ordens de um lugar chamado MEMÓRIA. Assim, precisamos colocar essas ordens na MEMÓRIA. Como seria uma seqüência de instruções para fazer o computador escrever isso pra mim? Vamos ver isso com muita calma.

    Bem, a memória original do MSX é composta de 65536 "posições de memória" (os famosos 64K). O que isso quer dizer? Bem, imagine que você tenha uma folha onde você pode escrever exatamente 65536 letras. É mais ou menos isso. Você tem que organizar as letras de forma que elas signifiquem algo, e ao mesmo tempo tem que fazer com que elas caibam nesse espaço. Cada uma dessas "posições de memória" tem um nome. A numero zero tem o nome zero. A numero um tem o nome um. A numero dois tem o nome dois e assim por diante. Nada muito criativo, mas funciona, acredite.
    Assim, antes de mais nada precisamos colocar a nossa frase em algumas dessas posições de memória, cada letra em uma delas. Antes de descobrirmos COMO colocar isso lá, vamos escrever O QUE queremos colocar lá.
Assim, um bom primeiro passo é você abrir o seu NotePad e digitar lá, na primeira linha, o seguinte:

--- Cut Here ---
Alo, Mundo
--- Cut Here ---

    Legal. Só que se você colocar isso na memória do computador ele vai rir de você (ou seja, ele vai travar mesmo). Imagine um japonês tentando falar em russo com você, e você não sabe nem japonês nem russo. É mais ou menos assim que o computador se sente quando você coloca isso na memória para ele. Da mesma forma, isso que você escreveu aí não significa nada nem para uma pessoa (se você desse um papel com isso escrito para alguém, iam te perguntar se você não tá passando bem), porque você acha que para o computador faria algum sentido?
Para isso fazer algum sentido para uma pessoa você deveria escrever algo do tipo:

"Pegue a frase abaixo:
Alo, Mundo
e cole na tela do monitor"

    Com toda a certeza a pessoa ainda ia achar que você está passando mal se lhe desse essa ordem, mas com toda a certeza, se o salário dela depende de você, ela terá plenas condições de cumprir a tarefa, e pode ter certeza de que vai. Assim é o computador: ele faz o que você manda, desde que você mande direito. (pode-se dizer que ele faz exatamente o que você manda, o que não é necessariamente o que você quer...)
    Bem, e como vamos mandar ele colar a nossa frase na tela? Bem, como disse, estamos trabalhando no MSX, usando o sistema operacional MSX-DOS. Espantosamente, o MSX-DOS tem uma instrução perfeita para fazer exatamente isso que queremos. É a instrução numero 9 do MSX-DOS. Você vai me dizer, "Ah, tá, legal, e o que eu faço com isso?". Bem, vamos pensar um pouco. Se você fosse mandar alguém fazer, o que você faria? Como mandaria? Que tal a forma que eu propus logo acima? (reproduzida abaixo):

"Pegue a frase abaixo:
Alo, Mundo
e cole na tela do monitor"

    Bem, a função 9 do MSX-DOS é exatamente: "Pegue a frase x e cole na tela do monitor". Opa! É essa mesmo que a gente precisa... Agora a gente só precisa dar um jeito de informar essas coisas direitinho.

    Mas antes eu preciso passar uma informação a vocês... O Z80, esse paciente e trabalhador sujeito que fica recebendo ordens suas e obedecendo, apesar de ele ter uma folha com 65536 letras ele não pode carregar essa folha junto com ele, para onde ele precisa executar as tarefas, de modo que ele precisa ir até a folha, ler o que ele precisa fazer, ir até o local onde deve executar a tarefa, executa-la, voltar ao papel, e assim por diante. A memória dele é curtissima, e ele só consegue lembrar O QUE ele tem de fazer, mas nunca lembra COM O QUE ele tem que fazer isso. É como se numa prova de historia você soubesse que foi declarada a independência, mas não soubesse nem a data nem quem declarou. E o que você fazia nas provas de historia? Colava, né não? Pois é. O Z80 faz a mesma coisa. Só que você é que precisa preparar a cola para ele, pois ele tá sempre fazendo alguma coisa para alguém, e não tem tempo de preparar suas próprias colas. O Z80 tem vários papeizinhos de cola, mas eles não são muitos, assim você precisa reciclar. Agora, o mais legal é que ele usa colas especificas para tarefas especificas. Por exemplo, para executar a função 9 do MSX-DOS, ele sabe que a frase deve estar na memória (aquela folha de papel), apontada pelo endereço (lembra, o nome das posições de memória?) que está numa cola chamada DE.

    O que isso quer dizer?

    Isso quer dizer que, se por algum acaso do destino você colocar a frase desejada na memória do seu MSX da seguinte forma:
 

Nome da posição Conteúdo
   
10000 A
10001 l
10002 o
10003 ,
10004  
10005 M
10006 u
10007 n
10008 d
10009 o

    O numero que precisa estar na cola DE é 10000. Assim, quando o Z80 executar a ordem pra escrever na tela e olhar na cola DE, vai saber que o que ele precisa escrever esta na posição 10000 da folha de papel (ou da memória como vou começar a me referir daqui em diante) e tem condições de escrever o que tem lá na tela.
    Bem, então, a primeira coisa que temos que fazer após escrever a nossa frase:

--- Cut Here ---
Alo, Mundo
--- Cut Here ---

   É  preparar a "cola", preenchedo DE com o endereço certo. mas... bem, qual é o endereço onde essa frase vai estar? Você pode definir se quiser, mas por enquanto vamos deixar por conta do "assemblador", que é o programa que vai traduzir o que estamos escrevendo para os números que o computador é capaz de entender.) Ele escolhe. Nos só vamos dar um apelido para esta posição de memória (é como se você desse um apelido pra sua caixa do correio, como "suzana", e ao invés de dizer "vou até a caixa do correio ver se tem carta" dissesse "vou até a suzana ver se tem carta"). Um bom nome para essa posição de memória seria "FRASE".
    Assim, vamos indicar isso de forma que seja compreensível pelo M80/L80 (que é a dupla que vai traduzir o que a gente escrever para algo que o computador entenda)... poderíamos fazer isso da seguinte forma:

--- Cut Here ---
FRASE:          Alo, Mundo
--- Cut Here ---

    Mas isso seria horrível, porque o M80/L80 não tem como saber onde a frase começa nem onde termina. Assim, usamos um delimitador, no caso o apóstrofo. O nosso programa fica assim:

--- Cut Here ---
FRASE:          'Alo, Mundo'
--- Cut Here ---

    Bem, isso tá quase bom. O único problema é que tipo de coisa a que você está se referindo também precisa ser dito... Ou o M80 vai fazer caca. Como nos usamos uma seqüência de letrinhas (ou de bytes), vamos indicar ao M80 uma Definição de Byte (DB):

--- Cut Here ---
FRASE:          DB      'Alo, Mundo'
--- Cut Here ---

    Bem, com isso já temos que a frase 'Alo, Mundo' vai estar na memória, no endereço de apelido "FRASE". Agora vamos preparar a nossa cola. Para escrever na cola (ou no registrador, como vou chamar daqui por diante) temos um comandinho especifico. Este comando chama-se LoaD, ou LD para o M80. Como queremos escrever na cola DE, o comando será LD DE... e alguma coisa que diga a posição de memória que devo escrever nesse registrador (na cola). A forma como fazemos isso é:

        LD      DE,[dado]

    Onde [dado] é um numero qualquer, no nosso caso a posição de memória ou um apelido de uma dessas posições. Assim, nosso programa já fica assim:

--- Cut Here ---
FRASE:          DB      'Alo, Mundo'
        LD      DE,FRASE
--- Cut Here ---

    Bem, com isso já temos a frase na memória, na posição "FRASE" e a cola já está pronta. Agora falta mandar aparecer na tela. Bem, eu disse pra vocês que a função que faz isso do MSX-DOS é a função numero 9, certo? Bem, quando o Z80 vai executar uma função do MSX-DOS, o numero da função deve estar numa cola chamada C. O jeito de escrever nessa cola é o mesmo da anterior, ou seja:

        LD      C,[dado]

    Assim, para dizermos que precisamos da função 9, escrevemos da seguinte forma:

--- Cut Here ---
FRASE:          DB      'Alo, Mundo'
        LD      DE,FRASE
        LD      C,9
--- Cut Here ---

    E agora precisamos mandar o Z80 finalmente fazer o que deve ser feito, ou seja, ir até o DOS e ver o que essa "função 9" faz (que nos já sabemos, que é escrever na tela, mas ele só vai descobrir quando chegar lá). Ocorre que a função que manda o Z80 ver o que uma função especifica do MSX-DOS faz já está prontinha, na posição de memória 5. Precisamos apenas mandar o Z80 ir dar uma passadinha por lá e voltar assim que tiver descoberto o que a função 9 do MSX-DOS faz (e te-la cumprido, claro). Para dizer para o Z80 ir "dar uma olhadinha" num endereço e voltar em seguida, usamos o comando CALL:

        CALL    [endereço]

    Ou seja, nosso programa, para chamar a posição de memória 5, após preparar as colas (ops, carregar os registradores), fica assim:

--- Cut Here ---
FRASE:          DB      'Alo, Mundo'
        LD      DE,FRASE
        LD      C,9
        CALL    5
--- Cut Here ---

    Hummm! A coisa tá começando a fazer sentido... (mas não muito). Pra coisa fazer um pouco mais de sentido a gente pode dar alguns apelidos para esses números estranhos. Por exemplo, que tal chamar a função 9 do MSX-DOS de algo que lembre o que ela faz, como STROUT (STRing OUT, saída de texto)? O M80 permite que a gente faca isso usando o comando EQU (de EQUivalente), da seguinte forma:

        STROUT  EQU     9

E podemos fazer o mesmo com o endereço 5. Já que neste endereço 5 eu mando o meu programa falar com o BDOS (BIOS do MSX-DOS), eu vou chama-lo de BDOS. Dados os apelidos, sempre eu posso substituir os números pelos seus respectivos apelidos. O nosso programa fica, então, assim:

--- Cut Here ---
STROUT  EQU     9
BDOS    EQU     5

FRASE:          DB      'Alo, Mundo'

        LD      DE,FRASE
        LD      C,STROUT
        CALL    BDOS
--- Cut Here ---

    Bem, a coisa já está ficando mais legível, mas melhora se colocarmos alguns comentários, pelo menos agora que estamos iniciando:

--- Cut Here ---
STROUT  EQU     9
BDOS    EQU     5

FRASE:          DB      'Alo, Mundo'

        LD      DE,FRASE                ; Indica posição do texto
        LD      C,STROUT                ; Indica função a ser executada pelo BDOS
        CALL    BDOS                    ; Manda o BDOS executar.
--- Cut Here ---

   A coisa já está mais com cara de programa agora, mas, como diria o DalPoz, ainda não vai funcionar. Isso porque começamos o nosso programa com uma seqüência de dados que nada tem a ver com o programa, e o Z80 é meio burrinho, e ele vai pensar que esses dados são, na verdade, algumas ordens. Essa é a primeira grande lição sobre Assembly: Diferentemente de qualquer outra linguagem, não existem "dados e instruções" separadamente. Tudo vai depender de como eles são colocados na memória. Isso porque quando essas coisinhas são convertidas para a "Linguagem de Maquina", tudo vira numerozinho, um em cada posição de memória, e o que define se é um dado ou uma instrução é tão somente a ordem em que o processador os lê. Assim, ninguém te impedirá, em Assembly, de escrever:

        CALL    FRASE

    Só não espere que isso funcione. Esse tipo de coisa pode parecer um tanto estranha agora no principio, mas futuramente veremos aplicações disso. Assim, se você simplesmente tentar rodar esse programa, a primeira coisa que o Z80 vai fazer é pegar o numero referente `a letra "A" do "Alo, Mundo" e pensar que este é uma instrução, que só Deus sabe qual é... e o resultado pode ser o mais maluco do mundo, mas em geral só faz o seu computador travar, mesmo.
    Como não faz a menor diferença onde você colocou a definição da frase, a gente pode coloca-la no fim do programa, e aí o problema acaba:

--- Cut Here ---
STROUT  EQU     9
BDOS    EQU     5

        LD      DE,FRASE                ; Indica posição do texto
        LD      C,STROUT                ; Indica função a ser executada pelo BDOS
        CALL    BDOS                    ; Manda o BDOS executar.

FRASE:          DB      'Alo, Mundo'
--- Cut Here ---

    Pronto... ou nem tanto. Mas vamos ver isso mais adiante. Vamos ver o que essa geringonça toda que escrevemos faz. Antes de mais nada, vá até a pagina do Adriano e pegue o M80/L80 para PC. Descomprima num diretório chamado ASMMSX. Você deverá ter os seguintes arquivos nele:

        22nice.com
        _clerror.com
        cl80.bat
        l80.com
        l80.cpm
        m80.com
        m80.cpm

    Agora, digite o programa:

--- Cut Here ---
STROUT  EQU     9
BDOS    EQU     5

        LD      DE,FRASE                ; Indica posição do texto
        LD      C,STROUT                ; Indica função a ser executada pelo BDOS
        CALL    BDOS                    ; Manda o BDOS executar.

FRASE:          DB      'Alo, Mundo'
--- Cut Here ---

    No notepad e salve neste mesmo diretório ASMMSX com o nome de alomundo.mac (mac significa Macro Assembler Code, a extensão padrão do M80). Agora o diretório deve conter:

        22nice.com
        _clerror.com
        cl80.bat
        l80.com
        l80.cpm
        m80.com
        m80.cpm
        alomundo.mac

    Abra um prompt do DOS (no PC!) e execute o 22nice, entrando no diretório ASMMSX e entrando com 22NICE na linha de comando. O 22Nice vai dizer que foi instalado e isso e aquilo, e você pressiona espaço. A partir de então você está apto a usar o M80/L80 no MS-DOS!!! Uau! Obrigado ao Adriano. Mas chega de papo furado. Vamos ASSEMBLAR o seu programa. Para isso, digite o seguinte na linha de comando:

        CL80 ALOMUNDO

    (lembre-se, NÃO coloque a extensão .MAC com o comando CL80, ele não gosta!). A saída deverá ser algo do tipo:

C:\ASMMSX>cl80 test
M80/L80 Z80 Compiler - IBM PC
Ported by A&L Software
 
MSX.M-80  1.00  01-Apr-85  (c) 1981,1985 Microsoft
%No END statement
%No END statement

No Fatal error(s)

MSX.L-80  1.00  01-Apr-85  (c) 1981,1985 Microsoft

Data    0103    0115    <18>

49192 Bytes Free
[0000   0115        1]

C:\ASMMSX>

    O que significa que tudo correu como esperado. Se algum erro aconteceu, verifique se não digitou nada errado no código do programa (arquivo ALOMUNDO.MAC) e tente novamente.
    Se tudo correu bem, agora você deve ter um arquivo chamado ALOMUNDO.COM no seu diretório. Pronto, neste momento você já tem O QUE colocar na memória do MSX. A questão agora é COMO. Bem, ocorre que o MSX-DOS já faz isso sozinho por você. Como? Copie o arquivo ALOMUNDO.COM para um disquete com o MSX-DOS e leve-o feliz da vida pra aquele seu Expert que tá parado faz um século pegando poeira... dê o boot e quando o prompt do MSX-DOS aparecer, execute seu programa chamando-o simplesmente com:

        ALOMUNDO

    E você vai ver, surpreso, que alem do MSX-DOS carregar e executar o seu programa, muito rapidamente a frase "Alo, Mundo" VAI aparecer no seu vídeo, seguida por um monte de lixo e depois disso só Deus sabe o que acontece. O quem de errado aí?
    Bem, a culpa não é sua. Eu é que não falei direito. A função STROUT imprime uma frase terminada pelo símbolo "$". Sem isso, a função STROUT vai imprimindo tudo que encontrar na frente até achar um caractere desse (acredite, ela *não para* até achar!). Assim, experimente alterar o seu programa da seguinte forma:

--- Cut Here ---
STROUT  EQU     9
BDOS    EQU     5

        LD      DE,FRASE                ; Indica posição do texto
        LD      C,STROUT                ; Indica função a ser executada pelo BDOS
        CALL    BDOS                    ; Manda o BDOS executar.

FRASE:          DB      'Alo, Mundo$'
--- Cut Here ---

    Compile novamente no PC usando CL80 ALOMUNDO e envie para o MSX pelo disquete (vai se acostumando, é assim que sempre vai ser...)... Passando o boot execute novamente e... bem, veja que deu erro de novo, mas a coisa já melhorou. A saída deve ter sido algo como:

        Alo, MundoInvalid Time.
        Enter new time: 

    Aqui você pode perceber aquilo que eu falei sobre código e dado ser uma coisa só. Vamos ver porque isso aconteceu. Lembra que eu falei que o comando CALL servia para "ir até ali ver uma coisa e voltar"? Bem... é exatamente isso que acontece. Quando o CALL BDOS é executado, o Z80 realmente vai até lá, executa a operação de mostrar na tela (função 9, STROUT, do BDOS) e volta.. Mas o que ele acha a seguir? A sua frase!!! Ele acha o seguinte:

        Alo, Mundo$

    O que para ele não faz o menor sentido. Ou melhor, até faz, só que ... vamos ver por que raios ele pediu pra você acertar a hora (ou qualquer outra maluquice)? Para isso vamos ver como essa frase fica guardada na memória. Você já deve ter ouvido falar em código ASCII. Bem, esse é o código que o computador usa para traduzir as letras em números e os números em letras. Na tabela ASCII, temos os seguintes números para cada uma dessas letras:
 

Letra Decimal Hexadecimal
A 65 41h
l 108 6Ch
o 111 6Fh
, 44 2Ch
32 20h
M 77 4Dh
u 117 75h
n 110 6Eh
d 100 64h
o 111 6Fh
$ 36 24h

    Aproveito para introduzir os números hexadecimais (base 16 ao invés de base 10) para já ir acostumado vocês com isso. Mais tarde eu falo mais neles.
    Bem, então vamos ver... Quando o computador volta daquele "CALL BDOS", o que ele encontra é esta seqüência de bytes aí. Vamos brincar de "Disassembler" (papel inverso ao do Assembler) e vamos ver o que esses códigos querem dizer para o Z80... Não se preocupe muito com os comandos em Assembly ainda, veja apenas o comentário que diz o que cada uma dessas funções faz...

        Byte    Significado:
        41h     LD      B,C      ; Colocar o valor do registrador C em B
        6Ch     LD      L,H      ; Colocar o valor do reg. H em L
        6Fh     LD      L,A      ; Colocar o valor do reg. A em L
        2Ch     INC     L        ; Soma um em L
        .
        .
        .

    Note que é uma seqüência de instruções completamente sem sentido. E o Z80 vai segui-las `a risca, fazendo todo o tipo de maluquice com o seu computador. Assim, é de bom gosto, ao fim do programa você diga para o Z80 voltar ao MSX-DOS (aquele promptzinho bonitinho em que você estava antes de executar esse programa). Já existe uma função pronta para isso no MSX-DOS e ela está no endereço 0. Como você não pretende que essa função retorne ao seu programa (ele acabou!) você não usa o CALL. Ao invés disso, você usa a instrução JumP (JP), que fala para o Z80 "Vá embora e não volte nunca mais!". Assim, ao fim do seu programa acrescente a instrução JP 0 para voltar ao prompt do MSX-DOS. O seu programa deve estar com essa cara:

--- Cut Here ---
STROUT  EQU     9
BDOS    EQU     5

        LD      DE,FRASE                ; Indica posição do texto
        LD      C,STROUT                ; Indica função a ser executada pelo BDOS
        CALL    BDOS                    ; Manda o BDOS executar.
        JP      0                       ; Volta ao MSX-DOS

FRASE:          DB      'Alo, Mundo$'
--- Cut Here ---

    Se você assemblar com o M80/L80 e rodar no MSX, no já manjado processo, finalmente verá:

        A>alomundo
        Alo, Mundo
        A> 

    Voilá! Seu programa funcionou perfeitamente! Esse é o seu primeiro programa em Assembly. Antes de terminarmos, porem, queria comentar o seguinte. Você deve ter observado, quando usou o CL80, que os seguintes comentários apareceram:

MSX.M-80  1.00  01-Apr-85  (c) 1981,1985 Microsoft
%No END statement
%No END statement

    Bem, isso é devido ao fato que você não foi educado com o M80. O M80 gosta que você diga pra ele onde o programa começa e onde o programa termina. Para não deixar ele zangado, insira os indicadores START e END no programa, da seguinte forma:

--- Cut Here ---
STROUT  EQU     9
BDOS    EQU     5

START:
        LD      DE,FRASE                ; Indica posição do texto
        LD      C,STROUT                ; Indica função a ser executada pelo BDOS
        CALL    BDOS                    ; Manda o BDOS executar.
        JP      0                       ; Volta ao MSX-DOS

FRASE:          DB      'Alo, Mundo$'

        END
--- Cut Here ---

    E, ao compilar novamente, você verá feliz que o M80 não reclama mais de nada...


    É isso aí, negada. É muita informação, pra quem nunca programou nada, mas não tem nenhum bicho de sete cabeças aí. A idéia de se programar em Assembly é exatamente essa. Esse foi um programa "ridículo" para quem não sabe nada ir começando a se acostumar com o ambiente e ir, aos poucos, se acostumando com as tarefas de assemblar, debugar, etc. Nas próximas aulas vamos ver como estender o programa para fazer coisas mais interessantes, introduzindo já algumas técnicas típicas do Assembly, técnicas usando recursos do M80 e... muito importante, usando o BrMSX para debugar (tirar bugs) de nossos programas!
    Duvidas, basta enviar que eu e um monte de gente mais aqui na lista pode tirar.


    Gostaria de saber de todos (tanto dos que sabem programar - assembly ou outra coisa - como dos que não sabem) o que acharam... se é muito corrido, muito lento, o que precisa explicar melhor, o que está confuso, o que pode ser explicado mais por cima... A idéia é melhorar cada vez mais, mas preciso do Feedback.

    face="Comic Sans MS, Arial, Helvetica, Sans-Serif, MS Sans-Serif" size="2">Espero que tenham gostado. Quaisquer duvidas, enviem para a lista, eu ou qualquer um dos programadores da lista responderão tão breve quanto possível.

Abraços,

Daniel Caetano.

PS: Sugestões e comentários são bem-vindos. (^=