Curso Fudeba de ASM |
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...!
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. (^=