Sunteți pe pagina 1din 93

CURSO FUDEBA DE ASSEMBLER Z80

Daniel Jorge Caetano


Preparado por Ni vardo Caval cante
Aula I - Introduzindo a Introduo
Bem, comeo de novo. Originalmente tinha planejado esse curso para algo bem
nos moldes do que todo mundo est acostumado: ma introduo terica e nada a ver
com a programao 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 no sabem nada.
"Epa!" vo dizer... "Voc quer ensinar Assembly para quem no sabe programar
nada?" Bem, a idia essa mesmo. Assembly , em essncia, a linguagem mais
fcil (e idiota) que tem para se compreender o que ela faz, e ao mesmo tempo
desenvolve como nenhuma outra a habilidade de "dar solues geniais" a
problemas, devido a suas inerentes limitaes.
Como tornar Assembly algo simples? Bem, primeiramente esquecendo que uma
linguagem de programao, pensando que mais uma seqncia de ordens que se d
as pecas do computador, quando ento tudo comea 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 dinmico que o outro. E mais rpido
tambm, mas creio que muitas duvidas devem surgir, pois ele se baseia na tcnica
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 (aritmticos, lgicos, fsicos, etc.) quando
necessrio.
Chega de papo e vamos ao que interessa...!

Nosso Primeiro Programa em Assembly (J!)
Bom, no to j assim. Primeiro vamos parar um pouco e pensar. Vou propor a
idia, que to 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 comear? Bem, voc no precisa de muita coisa.
Um MSX com drive (vamos comear 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 portugus, os Amiga falam ingls, 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 portugus
na Argentina, o famoso portunhol, tambm o que escrevemos para MSX muitas vezes
d pra ser arranjado num ZX-Spectrum e vice-versa (da j d pra comear a
entender porque tem tanto jogo de Spectrum no MSX).
Mas isso tudo t muito enrolado, no? 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 MEMRIA. Assim, precisamos colocar essas ordens na MEMRIA. Como seria
uma seqncia de instrues para fazer o computador escrever isso pra mim? Vamos
ver isso com muita calma.
Bem, a memria original do MSX composta de 65536 "posies de memria" (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 espao. Cada uma dessas "posies de memria"
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:1/92
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
posies de memria, 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:
Alo, Mundo
Legal. S que se voc colocar isso na memria do computador ele vai rir de
voc (ou seja, ele vai travar mesmo). Imagine um japons tentando falar em russo
com voc, e voc no sabe nem japons nem russo. mais ou menos assim que o
computador se sente quando voc coloca isso na memria para ele. Da mesma forma,
isso que voc escreveu a no significa nada nem para uma pessoa (se voc desse
um papel com isso escrito para algum, iam te perguntar se voc no 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 salrio dela depende de voc, ela
ter plenas condies 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 no 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 instruo perfeita para fazer exatamente isso
que queremos. a instruo numero 9 do MSX-DOS. Voc vai me dizer, "Ah, t,
legal, e o que eu fao com isso?". Bem, vamos pensar um pouco. Se voc fosse
mandar algum 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 funo 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 informao a vocs... O Z80, esse paciente e
trabalhador sujeito que fica recebendo ordens suas e obedecendo, apesar de ele
ter uma folha com 65536 letras ele no 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 memria 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 independncia, mas no soubesse nem a data nem quem declarou. E o
que voc fazia nas provas de historia? Colava, n no? 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 algum, e no tem tempo de preparar suas prprias
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:2/92
colas. O Z80 tem vrios papeizinhos de cola, mas eles no so muitos, assim voc
precisa reciclar. Agora, o mais legal que ele usa colas especificas para
tarefas especificas. Por exemplo, para executar a funo 9 do MSX-DOS, ele sabe
que a frase deve estar na memria (aquela folha de papel), apontada pelo
endereo (lembra, o nome das posies de memria?) 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 memria do seu MSX da seguinte forma:
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 posio 10000 da folha de papel (ou da memria como vou comear
a me referir daqui em diante) e tem condies de escrever o que tem l na tela.
Bem, ento, a primeira coisa que temos que fazer aps escrever a nossa
frase:
Alo, Mundo
preparar a "cola", preenchedo DE com o endereo certo. mas... bem, qual
o endereo 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 nmeros que o computador capaz de
entender.) Ele escolhe. Nos s vamos dar um apelido para esta posio de memria
( como se voc desse um apelido pra sua caixa do correio, como "suzana", e ao
invs 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 posio de memria seria
"FRASE".
Assim, vamos indicar isso de forma que seja compreensvel pelo M80/L80
(que a dupla que vai traduzir o que a gente escrever para algo que o
computador entenda)... poderamos fazer isso da seguinte forma:
FRASE: Alo, Mundo

Mas isso seria horrvel, porque o M80/L80 no tem como saber onde a frase
comea nem onde termina. Assim, usamos um delimitador, no caso o apstrofo. O
nosso programa fica assim:
FRASE: Alo, Mundo
Bem, isso t quase bom. O nico problema que tipo de coisa a que voc est
se referindo tambm precisa ser dito... Ou o M80 vai fazer caca. Como nos usamos
uma seqncia de letrinhas (ou de bytes), vamos indicar ao M80 uma Definio de
Byte (DB):

FRASE: DB Alo, Mundo

Bem, com isso j temos que a frase 'Alo, Mundo' vai estar na memria, no
endereo 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 posio de memria
que devo escrever nesse registrador (na cola). A forma como fazemos isso :
LD DE,[dado]
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:3/92
Onde [dado] um numero qualquer, no nosso caso a posio de memria ou um
apelido de uma dessas posies. Assim, nosso programa j fica assim:
FRASE: DB Alo, Mundo
LD DE,FRASE
Bem, com isso j temos a frase na memria, na posio "FRASE" e a cola j
est pronta. Agora falta mandar aparecer na tela. Bem, eu disse pra vocs que a
funo que faz isso do MSX-DOS a funo numero 9, certo? Bem, quando o Z80 vai
executar uma funo do MSX-DOS, o numero da funo 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 funo 9, escrevemos da seguinte
forma:
FRASE: DB Alo, Mundo
LD DE,FRASE
LD C,9
E agora precisamos mandar o Z80 finalmente fazer o que deve ser feito, ou
seja, ir at o DOS e ver o que essa "funo 9" faz (que nos j sabemos, que
escrever na tela, mas ele s vai descobrir quando chegar l). Ocorre que a
funo que manda o Z80 ver o que uma funo especifica do MSX-DOS faz j est
prontinha, na posio de memria 5. Precisamos apenas mandar o Z80 ir dar uma
passadinha por l e voltar assim que tiver descoberto o que a funo 9 do MSX-
DOS faz (e te-la cumprido, claro). Para dizer para o Z80 ir "dar uma olhadinha"
num endereo e voltar em seguida, usamos o comando
CALL:
CALL [endereco]
Ou seja, nosso programa, para chamar a posio de memria 5, aps preparar
as colas (ops, carregar os registradores), fica assim:
FRASE: DB Alo, Mundo
LD DE,FRASE
LD C,9
CALL 5
Hummm! A coisa t comeando a fazer sentido... (mas no muito). Pra coisa
fazer um pouco mais de sentido a gente pode dar alguns apelidos para esses
nmeros estranhos. Por exemplo, que tal chamar a funo 9 do MSX-DOS de algo que
lembre o que ela faz, como STROUT (STRing OUT, sada 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 endereo 5. J que neste endereo 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 nmeros pelos seus respectivos
apelidos. O nosso programa fica, ento, assim:
STROUT EQU 9
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:4/92
BDOS EQU 5
FRASE: DB Alo, Mundo
LD DE,FRASE
LD C,STROUT
CALL BDOS
Bem, a coisa j est ficando mais legvel, mas melhora se colocarmos alguns
comentrios, pelo menos agora que estamos iniciando:
STROUT EQU 9
BDOS EQU 5
FRASE: DB Alo, Mundo
LD DE,FRASE ; Indica posicao do texto
LD C,STROUT ; Indica funcao a ser executada pelo BDOS
CALL BDOS ; Manda o BDOS executar.
A coisa j est mais com cara de programa agora, mas, como diria o DalPoz,
ainda no vai funcionar. Isso porque comeamos o nosso programa com uma
seqncia de dados que nada tem a ver com o programa, e o Z80 meio burrinho, e
ele vai pensar que esses dados so, na verdade, algumas ordens. Essa a
primeira grande lio sobre Assembly: Diferentemente de qualquer outra
linguagem, no existem "dados e instrues" separadamente. Tudo vai depender de
como eles so colocados na memria. Isso porque quando essas coisinhas so
convertidas para a "Linguagem de Maquina", tudo vira numerozinho, um em cada
posio de memria, e o que define se um dado ou uma instruo to somente a
ordem em que o processador os l. Assim, ningum te impedir, em Assembly, de
escrever:
CALL FRASE
S no espere que isso funcione. Esse tipo de coisa pode parecer um tanto
estranha agora no principio, mas futuramente veremos aplicaes 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 instruo, 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 no faz a menor diferena onde voc colocou a definio da frase, a
gente pode coloca-la no fim do programa, e a o problema acaba:
STROUT EQU 9
BDOS EQU 5
LD DE,FRASE ; Indica posicao do texto
LD C,STROUT ; Indica funcao a ser executada pelo BDOS
CALL BDOS ; Manda o BDOS executar.
FRASE: DB Alo, Mundo
Pronto... ou nem tanto. Mas vamos ver isso mais adiante. Vamos ver o que
essa geringona toda que escrevemos faz. Antes de mais nada, v at a pagina do
Adriano e pegue o M80/L80 para PC. Descomprima num diretrio chamado ASMMSX.
Voc dever ter os seguintes arquivos nele:
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:5/92
22nice.com
_clerror.com
cl80.bat
l80.com
l80.cpm
m80.com
m80.cpm
Agora, digite o programa:
STROUT EQU 9
BDOS EQU 5
LD DE,FRASE ; Indica posicao do texto
LD C,STROUT ; Indica funcao a ser executada pelo BDOS
CALL BDOS ; Manda o BDOS executar.
FRASE: DB Alo, Mundo
No notepad e salve neste mesmo diretrio ASMMSX com o nome de alomundo.mac
(mac significa Macro Assembler Code, a extenso padro do M80). Agora o
diretrio 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 diretrio
ASMMSX e entrando com 22NICE na linha de comando. O 22Nice vai dizer que foi
instalado e isso e aquilo, e voc pressiona espao. A partir de ento 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, NO coloque a extenso .MAC com o comando CL80, ele no gosta!).
A sada 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
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:6/92
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 no digitou nada errado no cdigo do programa (arquivo
ALOMUNDO.MAC) e tente novamente.
Se tudo correu bem, agora voc deve ter um arquivo chamado ALOMUNDO.COM no
seu diretrio. Pronto, neste momento voc j tem O QUE colocar na memria do
MSX. A questo 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 sculo 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 vdeo,
seguida por um monte de lixo e depois disso s Deus sabe o que acontece. O quem
de errado a?
Bem, a culpa no sua. Eu que no falei direito. A funo STROUT imprime
uma frase terminada pelo smbolo "$". Sem isso, a funo STROUT vai imprimindo
tudo que encontrar na frente at achar um caractere desse (acredite, ela *no
para* at achar!). Assim, experimente alterar o seu programa da seguinte forma:
STROUT EQU 9
BDOS EQU 5
LD DE,FRASE ; Indica posicao do texto
LD C,STROUT ; Indica funcao a ser executada pelo BDOS
CALL BDOS ; Manda o BDOS executar.
FRASE: DB Alo, Mundo$
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 sada deve ter sido algo como:
Alo, Mundo
Invalid Time.
Enter new time:
Aqui voc pode perceber aquilo que eu falei sobre cdigo 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 operao de mostrar na tela (funo 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 no 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
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:7/92
maluquice)? Para isso vamos ver como essa frase fica guardada na memria. Voc
j deve ter ouvido falar em cdigo ASCII. Bem, esse o cdigo que o computador
usa para traduzir as letras em nmeros e os nmeros em letras. Na tabela ASCII,
temos os seguintes nmeros para cada uma dessas letras:

Aproveito para introduzir os nmeros hexadecimais (base 16 ao invs de base
10) para j ir acostumado vocs com isso. Mais tarde eu falo mais neles.
Bem, ento vamos ver... Quando o computador volta daquele "CALL BDOS", o que
ele encontra esta seqncia de bytes a. Vamos brincar de
"Disassembler" (papel inverso ao do Assembler) e vamos ver o que esses cdigos
querem dizer para o Z80... No se preocupe muito com os comandos em Assembly
ainda, veja apenas o comentrio que diz o que cada uma dessas funes 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 seqncia de instrues 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 funo pronta para isso no MSX-DOS e ela est no
endereo 0. Como voc no pretende que essa funo retorne ao seu programa (ele
acabou!) voc no usa o CALL. Ao invs disso, voc usa a instruo JumP (JP),
que fala para o Z80 "V embora e no volte nunca mais!". Assim, ao fim do seu
programa acrescente a instruo JP 0 para voltar ao prompt do MSX-DOS. O seu
programa deve estar com essa cara:
STROUT EQU 9
BDOS EQU 5
LD DE,FRASE ; Indica posicao do texto
LD C,STROUT ; Indica funcao a ser executada pelo BDOS
CALL BDOS ; Manda o BDOS executar.
JP 0 ; Volta ao MSX-DOS
FRASE: DB Alo, Mundo$
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 comentrios apareceram:
MSX.M-80 1.00 01-Apr-85 (c) 1981,1985 Microsoft
%No END statement
%No END statement
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:8/92
Bem, isso devido ao fato que voc no foi educado com o M80. O M80 gosta
que voc diga pra ele onde o programa comea e onde o programa termina. Para no
deixar ele zangado, insira os indicadores START e END no programa, da seguinte
forma:
STROUT EQU 9
BDOS EQU 5
START:
LD DE,FRASE ; Indica posicao do texto
LD C,STROUT ; Indica funcao a ser executada pelo BDOS
CALL BDOS ; Manda o BDOS executar.
JP 0 ; Volta ao MSX-DOS
FRASE: DB Alo, Mundo$
END
E, ao compilar novamente, voc ver feliz que o M80 no reclama mais de
nada...
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:9/92
Aula II - Algumas tcnicas iniciais
Antes de continuar com o curso, vamos a uma breve reviso do que foi visto na
aula passada. A idia era escrever um programa, ou seja, uma seqncia de ordens
para "o mais loiro dos seres" (o seu computador) que escrevesse na tela a frase
"Ola Mundo".
Bem, para fazer isso, estamos usando o NotePad como editor (tem no seu Windows)
e o Microsoft Macro Assembler (M80/L80 que pode ser obtido aqui:
http://www.crosswinds.net/~adrianpage/m80l80pc.zip
Vimos algumas coisas sobre o nosso ambiente: temos 64K posies de memria,
que o processador (Z80) trabalhador, mas de memria muito curta e temos de
colocar tudo que ele precisa em seus registradores (colas) antes de mandarmos
ele fazer alguma coisa, e que usamos para isso o comando LoaD (LD). Vimos tambm
como fazemos para informar o Z80 para executar uma funo do DOS (STROUT),
indicando para ele o numero da funo (LD C,STROUT) e mandando ele ir procurar o
que essa maledeta funo significa no endereo BDOS (que seria o endereo do
"Altavista" do MSX-DOS), pedindo para que ele voltasse e continuasse com o nosso
programa quando tivesse descoberto (e executado) o que a funo STROUT faz,
usando o comando CALL (CALL BDOS). Finalmente vimos como voltar ao prompt do
MSX-DOS, usando o comando JumP para o endereo 0 da RAM (JP 0).
Alem disso, vimos como escrever tudo isso de forma que o M80/L80 entendam o
que estamos dizendo, como colocar dados na memria (APELIDO: DB 'dado') e como
dar apelidos a endereos de memria (APELIDO EQU endereo). Vimos tambm que o
Z80 to "loiro" que se voc mandar ele executar um dado (JP FRASE ou CALL
FRASE) ele realmente vai tentar (e vai fazer caca) e por isso temos de evitar
que ele chegue at estes dados (ele como um lemingue: se voc no disser para
ele para onde ele tem que ir, ele vai sempre em frente, se matando no buraco, ou
seja, travando o seu micro, quando for o caso... mas no sem antes jogar um
monte de lixo na tela e outras coisas mais bizarras).
Finalmente vimos como "assemblar" o programa com o M80/L80, ou seja, como
tornar o que escrevemos algo legvel para o computador.
Seria interessante se o leitor pudesse adquirir o livro "MSX TopSecret" de
Edison Antnio Pires de Moraes (ele andou oferecendo copias pela MSXBr-L) pois
este livro contem muitas especificaes que sero teis (pra no dizer vitais)
mais pra frente no curso. Programar assembly "no existe" sem informaes
tcnicas sobre a maquina em que estamos trabalhando.
Caso o leitor saiba ingls, pode adquirir gratuitamente o MSX2 Technical
Handbook, digitado por Nestor Soriano, que contem grande parte das informaes
que existem no MSX TopSecret (mas nem metade delas), mas j algum comeo. Este
voc pode obter na pagina do KonamiMan:
http://www.geocities.com/SiliconValley/Bay/9797/msx2.htm#MSX2TH
Ou pegue direto:
http://www.geocities.com/SiliconValley/Bay/9797/th.bin
(renomeie para th.lzh e descomprima com o LHA)
Nesta segunda aula veremos como estender o programa que j tnhamos para
fazer alguma coisa a mais, como perguntar coisas ao usurio e interpretar as
respostas... vamos l!
Conversando com o usurio...
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:10/92
Bem, para "principiar" tomemos o programa final da aula anterior.
STROUT EQU 9
BDOS EQU 5
START:
LD DE,FRASE ; Indica posicao do texto
LD C,STROUT ; Indica funcao a ser executada pelo BDOS
CALL BDOS ; Manda o BDOS executar.
JP 0 ; Volta ao MSX-DOS
FRASE: DB Alo, Mundo$
END
Antes de mais nada, salve este arquivo como PROG2.MAC, e ento vamos fazer
uma alterao substituindo o apelido FRASE pelo apelido NOMEDOPRG e substituir a
frase "Alo, Mundo" por "Programa 2 - Conversando com o usurio":
STROUT EQU 9
BDOS EQU 5
START:
LD DE,NOMEDOPRG ; Indica texto do nome do programa
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
JP 0 ; Volta ao MSX-DOS
NOMEDOPRG: DB Programa 2 - Conversando com o usuario$
END
Isso acabou de se tornar o "nome" do nosso programa. Isso vai aparecer
escrito sempre que nosso programa for executado. Aconselho, inclusive, que a
cada "alterao" voc "assemble" o programa usando o comando CL80 PROG2 no seu
PC, e leve at o MSX para verificar o que acontece, ver se funciona, o que
mudou, para voc perceber efetivamente o que a alterao que voc fez causou.
No vou ficar escrevendo a cada instante "assemble, leve para o MSX e veja o que
deu" para no aumentar ainda mais o tamanho do curso, e tambm para no ficar
"enchendo lingia" com informao j conhecida.
Bem, vamos escrever mais alguma coisa na tela, adicionando uma segunda frase
chamada AUTOR, de modo que voc possa colocar que foi voc quem fez o programa.
Isso fica assim:
STROUT EQU 9
BDOS EQU 5
START:
LD DE,NOMEDOPRG ; Indica texto do nome do programa
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
JP 0 ; Volta ao MSX-DOS
NOMEDOPRG: DB Programa 2 - Conversando com o usuario$
AUTOR: DB Por Daniel Caetano$ ; coloque seu nome ao inves do meu.
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:11/92
END
Bem, mas isso no vai fazer com que a frase aparea na tela. Precisamos
mandar o Z80 mostra-la para nos. Onde mandar ento? Bem, queremos que ela
aparea depois dele ter mandado aparecer o nome do programa, mas antes do
programa retornar ao prompt do MSX-DOS. Assim, a posio certa para inserir isso
entre o CALL BDOS e o JP 0. Nosso programa, com as alteraes fica assim:
STROUT EQU 9
BDOS EQU 5
START:
LD DE,NOMEDOPRG ; Indica texto do nome do programa
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
LD DE,AUTOR ; Indica texto do nome do autor
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
JP 0 ; Volta ao MSX-DOS
NOMEDOPRG: DB Programa 2 - Conversando com o usuario$
AUTOR: DB Por Daniel Caetano$ ; coloque seu nome ao inves do meu.
END
Se voc observar bem, a coisa j comeou a ficar meio bagunada. Assim bom
inserir alguns comentrios chamados "comentrios de blocos", que so comentrios
que descrevem no o que um comando faz, mas o que um conjunto de comandos, logo
abaixo deste comentrio, fazem. Nos temos atualmente dois conjuntos bsicos de
comandos: um que escreve o nome do programa e outro que escreve o nome do autor.
Vamos inserir esses comentrios: face="Comic Sans MS, Arial, Helvetica, Sans-
Serif" size="2">
STROUT EQU 9
BDOS EQU 5
START:
; Mostra nome do programa
LD DE,NOMEDOPRG ; Indica texto do nome do programa
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
; Mostra nome do programador
LD DE,AUTOR ; Indica texto do nome do autor
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
JP 0 ; Volta ao MSX-DOS
NOMEDOPRG: DB Programa 2 - Conversando com o usuario$
AUTOR: DB Por Daniel Caetano$ ; coloque seu nome ao inves do meu.
END
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:12/92
Agora isso no parece to interessante, mas no futuro voc ver que isso o
que torna os programas "legveis" depois de muito tempo que voc no os v. Se
voc executar esse programa, vai ver que algo "indesejado" aconteceu: o MSX-DOS
*no* pulou linha entre uma frase e outra. Bem, pois , voc precisa dizer pra
ele fazer isso. Pra isso voc precisa dizer para ele retornar para a primeira
posio da linha (CR, de Carriage Return) e pular uma linha (LF, de Line Feed).
O CR representado pelo numero 13, e o LF pelo numero 10. Assim, se voc quiser
pular linha, basta adicionar, no fim da frase, esses nmeros, da seguinte forma:
NOMEDOPRG: DB Programa 2 - Conversando com o usuario$,13,10
MAS, se voc fizer isso ver que no adiantou nada. O programa continua *no*
pulando a linha. Uai... E por que no? Simples... Se voc observar, tem um "$"
antes do 13 e do 10, sendo que o $ diz para a funo STROUT que o texto ACABOU.
Ento, meu amigo, esse 13 e esse 10 que voc colocou ai' no esto nem sendo
lidos. Voc precisa coloca-los ANTES do $, o que pode ser feito assim:
NOMEDOPRG: DB Programa 2 - Conversando com o usuario,13,10,$
E agora sim ele vai pular as linhas direitinho. Nosso programa, j corrigido,
fica assim:
STROUT EQU 9
BDOS EQU 5
START:
; Mostra nome do programa
LD DE,NOMEDOPRG ; Indica texto do nome do programa
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
; Mostra nome do programador
LD DE,AUTOR ; Indica texto do nome do autor
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
JP 0 ; Volta ao MSX-DOS
NOMEDOPRG: DB Programa 2 - Conversando com o usuario,13,10,$
AUTOR: DB Por Daniel Caetano,13,10,$
END
Agora vamos pedir ao usurio que pressione uma tecla, receber a resposta e
fazer alguma coisa com essa resposta.
O primeiro passo colocar a pergunta na tela, para que o usurio tome
conhecimento de que precisa entrar com alguma informao. Isso pode ser feito da
mesma forma com que fizemos antes com o nome do programa e nome do autor,
inserindo a frase PERGU1:
STROUT EQU 9
BDOS EQU 5
START:
; Mostra nome do programa
LD DE,NOMEDOPRG ; Indica texto do nome do programa
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:13/92
CALL BDOS ; Manda o BDOS executar.
; Mostra nome do programador
LD DE,AUTOR ; Indica texto do nome do autor
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
; Mostra a pergunta
LD DE,PERGU1 ; Indica texto da pergunta
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
JP 0 ; Volta ao MSX-DOS
NOMEDOPRG: DB Programa 2 - Conversando com o usuario,13,10,$
AUTOR: DB Por Daniel Caetano,13,10,$
PERGU1: DB Pressione alguma tecla: $
END
Legal, nosso programa, ento, j mostra suas informaes e faz uma pergunta.
Bem, voc deve ter notado que a sada do programa foi algo mais ou menos assim:
A>PROG2
Programa 2 - Conversando com o usuario
Por Daniel Caetano
Pressione alguma tecla:
A>
Mas seria mais interessante se a sada fosse:
A>PROG2
Programa 2 - Conversando com o usuario
Por Daniel Caetano
Pressione alguma tecla:
A>
Ficaria mais legal, no? Pois . Isso simples. Basta mandar pular mais uma
linha, acrescentando um 10 adicional na frase:
AUTOR: DB Por Daniel Caetano,13,10,10,$
Com isso alteramos o programa assim:
STROUT EQU 9
BDOS EQU 5
START:
; Mostra nome do programa
LD DE,NOMEDOPRG ; Indica texto do nome do programa
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
; Mostra nome do programador
LD DE,AUTOR ; Indica texto do nome do autor
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:14/92
CALL BDOS ; Manda o BDOS executar.
; Mostra a pergunta
LD DE,PERGU1 ; Indica texto da pergunta
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
JP 0 ; Volta ao MSX-DOS
NOMEDOPRG: DB Programa 2 - Conversando com o usuario,13,10,$
AUTOR: DB Por Daniel Caetano,13,10,10,$
PERGU1: DB Pressione alguma tecla: $
END
Mas e agora? O programa j mostra tudo como a gente quer, mas como informar o
Z80 para ele receber uma informao? Bem, existe uma funo do MSX-DOS
especifica para que possamos esperar que uma tecla seja pressionada. Essa funo
chama-se CONIN (CONsole IN, entrada de console, o que o mesmo que entrada pelo
teclado), e a funo de numero 1 do BDOS. Para chama-la, basta indicar a
funo, uma vez que nada mais necessrio para que o Z80 possa executar a
operao. Isso pode ser feito assim:
LD C,1 ; Indica a funcao que pega uma tecla
CALL 5 ; Chama BDOS
Ou, usando os apelidos,
CONIN EQU 1
BDOS EQU 5
LD C,CONIN ; Indica a funcao que pega uma tecla
CALL BDOS ; Chama BDOS
Bem, podemos inserir isso logo abaixo da pergunta, em nosso programa:
BDOS EQU 5
CONIN EQU 1
STROUT EQU 9
START:
; Mostra nome do programa
LD DE,NOMEDOPRG ; Indica texto do nome do programa
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
; Mostra nome do programador
LD DE,AUTOR ; Indica texto do nome do autor
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
; Mostra a pergunta
LD DE,PERGU1 ; Indica texto da pergunta
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
; Espera tecla ser pressionada
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:15/92
LD C,CONIN ; Indica a funcao que pega uma tecla
CALL BDOS ; Chama BDOS
JP 0 ; Volta ao MSX-DOS
NOMEDOPRG: DB Programa 2 - Conversando com o usuario,13,10,$
AUTOR: DB Por Daniel Caetano,13,10,10,$
PERGU1: DB Pressione alguma tecla: $
END
Bem, tudo jia, mas quando executei isso tudo que aconteceu foi que o
programa esperou eu pressionar uma tecla, mostrou a tecla que eu pressionei e
voltou para o prompt. Note inclusive que o prompt apareceu exatamente na frente
da pergunta... Se voc observar no programa, isso ocorreu porque *no* mandamos
pular linha nem voltar ao inicio da linha na frase PERGU1. Legal, mas como fao
para saber, dentro do meu programa, qual foi a tecla que foi pressionada?
O Z80 um cara legal. Tem memria curta, mas legal. Ele compartilha as
colas dele com a gente. Existe uma cola especial que normalmente onde ele
coloca as respostas das coisas que perguntamos. Esse registrador (essa cola) o
chamado A. Por exemplo, usando a funo CONIN do BDOS, perguntamos a ele que
espere por uma tecla ser pressionada, e quando ela for, que nos informe qual
foi. Assim, ele coloca o numero dessa tecla (aquele mesmo numero "ASCII" que eu
citei na aula anterior) no registrador A. Ento, j temos a resposta. A tecla
digitada est prontinha para usarmos, no registrador A.
Interessante, mas isso parece ainda no ajudar muito, no? Bem, antes de ver
como podemos usar essa informao dada pelo Z80, vamos preparar uma resposta ao
usurio. Vamos inserir a seguinte frase:
RESP1: DB 13,10,10, A tecla pressionada foi: $
Note que antes da frase eu devidamente adicionei o retorno do cursor (13 =
CR) e pulei duas linhas (10 = LF). Alem disso, no pulei linha nem retornei o
cursor ao fim da frase, pois vou querer colocar a resposta (a tecla pressionada)
DEPOIS dela, sem pular linha ou qualquer outra coisa. Adicionamos essa frase
depois do ponto em que mandamos o Z80 ir pegar uma tecla pra gente:
BDOS EQU 5
CONIN EQU 1
STROUT EQU 9
START:
; Mostra nome do programa 111
LD DE,NOMEDOPRG ; Indica texto do nome do programa
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
; Mostra nome do programador
LD DE,AUTOR ; Indica texto do nome do autor
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
; Mostra a pergunta
LD DE,PERGU1 ; Indica texto da pergunta
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:16/92
; Espera tecla ser pressionada
LD C,CONIN ; Indica a funcao que pega uma tecla
CALL BDOS ; Chama BDOS
; Mostra a resposta
LD DE,RESP1 ; Indica texto da resposta
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
JP 0 ; Volta ao MSX-DOS
NOMEDOPRG: DB Programa 2 - Conversando com o usuario,13,10,$
AUTOR: DB Por Daniel Caetano,13,10,10,$
PERGU1: DB Pressione alguma tecla: $
RESP1: DB 13,10,10, A tecla pressionada foi: $
END
Bom, o programa j quase faz o que a gente quer, mas ainda no faz. Eu tenho
o valor da tecla, mas no sei como mostrar isso na tela. Ou sei? Sei sim. Existe
no BDOS uma funo que faz exatamente o contrario do que a CONIN faz. No, essa
funo no escreve um caractere no teclado. Essa funo escreve um caractere na
tela, de acordo com o numero fornecido. Essa funo chama-se CONOUT (CONsole
OUT, ou sada para o console, ou sada para a tela - entenda, o console um
negocio que tem uma entrada (o teclado) e uma sada (a tela). Assim, sempre que
voc pedir uma ENTRADA (IN) do console, o computador l o teclado. Sempre que
voc pedir uma SAIDA (OUT) para o console, o computador escreve na tela).
Essa funo chamada normalmente, da mesma forma que a CONIN, pois tambm
uma funo do MSX-DOS. A funo CONOUT a funo de numero 2 do MSX-DOS. H um
porem... Ela requer que o numero do caractere a ser escrito esteja em uma outra
cola... No registrador chamado E. Bem, temos o numero do caractere no
registrador A, e precisamos que ele esteja no E. Existem diversas maneiras de
copiar o valor de um registrador para outro, mas o mais fcil usando o LoaD
(LD). Se voc fosse mandar algum copiar a cola, voc talvez dissesse:
Copie na cola E o que estiver na cola A
Para o Z80 a mesma coisa:
LD E,A
E pronto... aps isso, o valor do caractere vai estar onde queremos, no
registrador E. Note que o comando LoaD (LD) COPIA o valor de um registrador para
outro, portanto, o que quer que estivesse no registrador E foi SUBSTITUIDO pelo
valor do registrador A. Alem disso, como se trata de uma COPIA, o valor que
estava no registrador A (o numero do caractere) CONTINUA l.
Inserindo essa nova informao no nosso programa, temos:
BDOS EQU 5
CONIN EQU 1
STROUT EQU 9
START:
; Mostra nome do programa
LD DE,NOMEDOPRG ; Indica texto do nome do programa
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:17/92
; Mostra nome do programador
LD DE,AUTOR ; Indica texto do nome do autor
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
; Mostra a pergunta
LD DE,PERGU1 ; Indica texto da pergunta
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
; Espera tecla ser pressionada e coloca seu valor em A
LD C,CONIN ; Indica a funcao que pega uma tecla
CALL BDOS ; Chama BDOS
; Mostra a resposta
LD DE,RESP1 ; Indica texto da resposta
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
LD E,A ; Copia valor do caractere para E
JP 0 ; Volta ao MSX-DOS
NOMEDOPRG: DB Programa 2 - Conversando com o usuario,13,10,$
AUTOR: DB Por Daniel Caetano,13,10,10,$
PERGU1: DB Pressione alguma tecla: $
RESP1: DB 13,10,10, A tecla pressionada foi: $
END
Mas s isso no adianta, n? Precisamos, alem disso, usar nosso conhecimento
da funo CONOUT para mostrar o caractere. Para tanto vamos inserir mais isso no
programa:
CONOUT EQU 2
LD C,CONOUT ; Indica a funcao exibe um caractere na tela
CALL BDOS ; Chama BDOS
Ficando nosso programa assim:
BDOS EQU 5
CONIN EQU 1
CONOUT EQU 2
STROUT EQU 9
START:
; Mostra nome do programa
LD DE,NOMEDOPRG ; Indica texto do nome do programa
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
; Mostra nome do programador
LD DE,AUTOR ; Indica texto do nome do autor
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:18/92
CALL BDOS ; Manda o BDOS executar.
; Mostra a pergunta
LD DE,PERGU1 ; Indica texto da pergunta
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
; Espera tecla ser pressionada e coloca seu valor em A
LD C,CONIN ; Indica a funcao que pega uma tecla
CALL BDOS ; Chama BDOS
; Mostra a resposta
LD DE,RESP1 ; Indica texto da resposta
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
LD E,A ; Copia valor do caractere para E
LD C,CONOUT ; Indica a funcao exibe um caractere na tela
CALL BDOS ; Chama BDOS
JP 0 ; Volta ao MSX-DOS
NOMEDOPRG: DB Programa 2 - Conversando com o usuario,13,10,$
AUTOR: DB Por Daniel Caetano,13,10,10,$
PERGU1: DB Pressione alguma tecla: $
RESP1: DB 13,10,10, A tecla pressionada foi: $
END
Beleza? Bem, se voc perdeu tempo para executar esse programa, voc vai ver
que, sinistramente, algo deu errado. Esse programa sempre vai dizer que a tecla
pressionada foi a tecla $. E porque isso acontece?
Ser que tem um bug...? COM CERTEZA, e um bug conceitual, daqueles mais
difceis de se encontrar. Como vamos encontra-lo? Bem, fizemos algumas coisas
entre o momento em que obtivemos o valor do caractere em A e o momento em que
copiamos ele para E. Vamos ver se, eliminando esse monte de coisa, a sada do
programa acontece normalmente. Vamos "comentar" as linhas adicionando um ";" na
frente delas, ficando nosso programa assim:
BDOS EQU 5
CONIN EQU 1
CONOUT EQU 2
STROUT EQU 9
START:
; Mostra nome do programa
LD DE,NOMEDOPRG ; Indica texto do nome do programa
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
; Mostra nome do programador
LD DE,AUTOR ; Indica texto do nome do autor
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:19/92
; Mostra a pergunta
LD DE,PERGU1 ; Indica texto da pergunta
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
; Espera tecla ser pressionada e coloca seu valor em A
LD C,CONIN ; Indica a funcao que pega uma tecla
CALL BDOS ; Chama BDOS
; Mostra a resposta
; LD DE,RESP1 ; Indica texto da resposta
; LD C,STROUT ; Indica funcao de mostrar texto do BDOS
; CALL BDOS ; Manda o BDOS executar.
LD E,A ; Copia valor do caractere para E
LD C,CONOUT ; Indica a funcao exibe um caractere na tela
CALL BDOS ; Chama BDOS
JP 0 ; Volta ao MSX-DOS
NOMEDOPRG: DB Programa 2 - Conversando com o usuario,13,10,$
AUTOR: DB Por Daniel Caetano,13,10,10,$
PERGU1: DB Pressione alguma tecla: $
RESP1: DB 13,10,10, A tecla pressionada foi: $
END
Ou seja, eliminamos tudo que acontece entre o momento em que pegamos o numero
do caractere e o momento em que mandamos ele ser mostrado na tela. Rodemos o
programa e ... veja que funciona! Note que agora o caractere aparece repetido
duas vezes na tela (uma vez o "retorno" normal da funo CONIN e a outra a
sada da funo CONOUT). Ento podemos presumir que estamos pegando e mostrando
o caractere corretamente. O que pode ter dado errado ento? Bem, se voc
observar, ver que entre pegarmos o valor da tecla pressionada e tentarmos
imprimir ele na tela, imprimimos um texto: " A tecla pressionada foi: "... O
problema deve estar ai'.
Lembra-se de que na primeira aula eu falei que o Z80 tinha poucos papeis de
cola e que portanto ele precisava reciclar esses papeis? Provavelmente o que
est acontecendo. Em algum momento, quando o MSX-DOS est imprimindo a sua
frase, ele usa o registrador A para guardar o numero do caractere a ser impresso
na tela. Um indicio de que isso verdade que, se voc observar, o valor que
era sempre impresso como sendo "a tecla que voc digitou" era o "$", que
exatamente o ultimo caractere da frase RESP1!
Bem, ento como fazemos? Ser que a gente no pode nunca fazer nada entre
pegar um dado e usa-lo? Claro que podemos. Se no pudssemos, seria impossvel
trabalhar em Assembly. O que precisamos guardar erra valor na MEMORIA, em um
lugar seguro, antes de fazermos qualquer outra coisa. Existem muitos jeitos de
guardar este dado na memria. Um dizendo exatamente onde queremos que este
dado seja guardado. Outro deixando que o Z80 escolha para a gente. Neste
momento vamos escolher a primeira opo. Ento, primeiro vamos definir um lugar
para esse valor ser colocado. Um bom lugar para isso depois das frases. E como
guardamos lugar para esse caractere? Simples, definimos uma "frase" para ele, de
um caractere s. Isso pode ser feito assim:
VAR1: DB 0
Isso define uma posio de memria apelidada de VAR1 (VARiavel 1) com o valor
0 dentro. neste lugar que vamos mandar o Z80 colocar o valor que a gente
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:20/92
recebe. E como vamos fazer isso? Exatamente com o comando LoaD. Ele tambm serve
para copiar coisas da MEMORIA para um REGISTRADOR, ou de um REGISTRADOR para a
MEMORIA. Se queremos colocar o dado em VAR1 e este dado est no registrador A,
nada mais natural do que um comando:
LD VAR1,A
Mas isso no vai funcionar, como diria o DalPoz. E porque? Bem, lembre-se que
VAR1 apenas uma apelido para um NOME de posio de memria. O Z80 iria ler
isso ai' como "De um jeito de o nome 0 ser igual a 2", por exemplo. claro que
teremos problemas. Temos que dar um jeito de dizer a ele que coloque o valor de
A DENTRO da posio de memria chamada VAR1. Para isso usamos os parnteses:
LD (VAR1),A
Isso diz ao Z80 "Copie DENTRO da posio de memria chamada VAR1 o valor de
A". Ai' sim obteremos sucesso, pois ele vai entender direitinho o que queremos
dizer... o que em nosso programa fica:
BDOS EQU 5
CONIN EQU 1
CONOUT EQU 2
STROUT EQU 9
START:
; Mostra nome do programa
LD DE,NOMEDOPRG ; Indica texto do nome do programa
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
; Mostra nome do programador
LD DE,AUTOR ; Indica texto do nome do autor
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
; Mostra a pergunta
LD DE,PERGU1 ; Indica texto da pergunta
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
; Espera tecla ser pressionada e coloca seu valor em A
LD C,CONIN ; Indica a funcao que pega uma tecla
CALL BDOS ; Chama BDOS
LD (VAR1),A ; Grava o valor da tecla na MEMORIA.
; Mostra a resposta
; LD DE,RESP1 ; Indica texto da resposta
; LD C,STROUT ; Indica funcao de mostrar texto do BDOS
; CALL BDOS ; Manda o BDOS executar.
LD E,A ; Copia valor do caractere para E
LD C,CONOUT ; Indica a funcao exibe um caractere na tela
CALL BDOS ; Chama BDOS
JP 0 ; Volta ao MSX-DOS
NOMEDOPRG: DB Programa 2 - Conversando com o usuario,13,10,$
AUTOR: DB Por Daniel Caetano,13,10,10,$
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:21/92
PERGU1: DB Pressione alguma tecla: $
RESP1: DB 13,10,10, A tecla pressionada foi: $
VAR1: DB 0
END
timo, o dado j est na memria. Agora temos que, antes de chamar a funo
que nos mostra o caractere na tela, colocar no registrador E esse valor que est
na posio de memria VAR1. O jeito mais natural de fazer isso :
LD E,(VAR1)
Ou seja, "Copie em E o que estiver DENTRO da posio de memria chamada
VAR1". Substituindo a antiga instruo LD E,A (que tinha exatamente a funo
disso que estamos fazendo) por essa nova instruo LD E,(VAR1) e retirando os
";" das linhas que mostram o texto da resposta, teremos:
BDOS EQU 5
CONIN EQU 1
CONOUT EQU 2
STROUT EQU 9
START:
; Mostra nome do programa
LD DE,NOMEDOPRG ; Indica texto do nome do programa
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
; Mostra nome do programador
LD DE,AUTOR ; Indica texto do nome do autor
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
; Mostra a pergunta
LD DE,PERGU1 ; Indica texto da pergunta
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
; Espera tecla ser pressionada e coloca seu valor em A
LD C,CONIN ; Indica a funcao que pega uma tecla
CALL BDOS ; Chama BDOS
LD (VAR1),A ; Grava o valor da tecla na MEMORIA.
; Mostra a resposta
LD DE,RESP1 ; Indica texto da resposta
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
LD E,(VAR1) ; Copia para E o conteudo de VAR1.
LD C,CONOUT ; Indica a funcao exibe um caractere na tela
CALL BDOS ; Chama BDOS
JP 0 ; Volta ao MSX-DOS
NOMEDOPRG: DB Programa 2 - Conversando com o usuario,13,10,$
AUTOR: DB Por Daniel Caetano,13,10,10,$
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:22/92
PERGU1: DB Pressione alguma tecla: $
RESP1: DB 13,10,10, A tecla pressionada foi: $
VAR1: DB 0
END
Parece que agora vai, no? Bem, ao tentar compilar voc seguramente vai
receber a seguinte mensagem:
C:\ASMMSX>cl80 prog2
M80/L80 Z80 Compiler - IBM PC
Ported by A&L Software
MSX.M-80 1.00 01-Apr-85 (c) 1981,1985 Microsoft
A 0028 3A 00AE LD E,(VAR1) ; Copia para E o
conteudo de VAR1.
1 Fatal error(s)
C:\ASMMSX>
E o seu programa no ter nem sido assemblado. O que esse cdigo de erro
significa? Significa que na linha apresentada ai' houve um erro. E no caso O
erro que esse comando LD E,(VAR1) no existe para o Z80!
Caramba, voc me pergunta, mas to lgico! Como assim, no existe? Simples,
no existindo. E essa a parte mais chata do Assembly. Lembra que eu disse que
existiam colas especificas para algumas coisas? Pois . Em um outro momento eu
disse que o Z80 gostava de colocar repostas no registrador A. Pois aqui
exatamente um desses casos. Voc s pode ler o contedo de UM BYTE da MEMORIA,
ou seja, o valor de UMA nica posio de memria *se* coloca-lo dentro do
registrador A.
Voc vai dizer... poxa, mas eu preciso dele dentro do registrador E, e no
dentro do registrador A. Felizmente voc ainda pode usar o LoaD para copiar o
valor de A para E. Assim, o comando:
LD E,(VAR1) ; Copia para E o conteudo de VAR1.
Deve ser substitudo por dois outros comandos, que tem um resultado final
equivalente:
LD A,(VAR1) ; Copia para A o conteudo de VAR1
LD E,A ; Copia para E o conteudo de A
E o nosso programa finalmente fica assim:
BDOS EQU 5
CONIN EQU 1
CONOUT EQU 2
STROUT EQU 9
START:
; Mostra nome do programa
LD DE,NOMEDOPRG ; Indica texto do nome do programa
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
; Mostra nome do programador
LD DE,AUTOR ; Indica texto do nome do autor
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:23/92
CALL BDOS ; Manda o BDOS executar.
; Mostra a pergunta
LD DE,PERGU1 ; Indica texto da pergunta
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
; Espera tecla ser pressionada e coloca seu valor em A
LD C,CONIN ; Indica a funcao que pega uma tecla
CALL BDOS ; Chama BDOS
LD (VAR1),A ; Grava o valor da tecla na MEMORIA.
; Mostra a resposta
LD DE,RESP1 ; Indica texto da resposta
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
LD A,(VAR1) ; Copia para A o conteudo de VAR1
LD E,A ; Copia para E o conteudo de A
LD C,CONOUT ; Indica a funcao exibe um caractere na tela
CALL BDOS ; Chama BDOS
JP 0 ; Volta ao MSX-DOS
NOMEDOPRG: DB Programa 2 - Conversando com o usuario,13,10,$
AUTOR: DB Por Daniel Caetano,13,10,10,$
PERGU1: DB Pressione alguma tecla: $
RESP1: DB 13,10,10, A tecla pressionada foi: $
VAR1: DB 0
END
Finalmente nosso programa est pronto e faz o que queremos. Nesta aula
aprendemos novos comandos, e vimos como algumas limitaes do Assembly do Z80
nos "enchem a pacincia", mas teremos de conviver com elas se quisermos
programas nesta linguagem. Adianto que isso que parece uma irritao agora no
futuro no lhes incomodar mais, passando a ser algo "natural".
Tambm vimos algumas novas funes, como a de pegar um caractere do teclado e
a de mostrar um caractere na tela.
Na prxima aula veremos como "otimizar" este programa e tambm como usar o
BrMSX para verificar o resultado da programao, para evitar termos de ficar
copiando as coisas em disquete e levando at o MSX toda hora... Vocs vero que
isso de grande auxilio e acelera muito a velocidade do desenvolvimento.
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:24/92
Aula III - Trabalhando com o que temos

Nesta aula vamos fazer algumas coisas diferentes... Primeiramente vamos dar
uma olhada em como podemos tornar a nossa vida mais simples na programao
Assembly para o MSX (que, convenhamos, algo muito mais til que uma
programao Assembly Z80 pura) com o material que temos, que o M80/L80 para PC
e o BrMSX.
Tambm vamos aprender algumas brincadeiras novas com o nosso j bem estudado
programinha, e no vamos acrescentar nenhuma nova funcionalidade a ele por
enquanto: vamos apenas melhorar sua estrutura, tornando-o mais "adequado",
digamos assim.
Antes disso, vamos dar uma olhadinha no que vimos na ultima aula, que j faz
um tempinho, visto que tive uns probleminhas de sade a no meio do caminho que
me deixaram mais de 15 dias de cama.
Na aula passada estendemos o nosso programa para apresentar informaes na
tela de uma forma um pouco mais padronizada, como feito pela maioria dos
programas para MSX-DOS (CP/M). Para isso, usamos sucessivas chamadas funo
STROUT do BDOS. Como isso comeou a tornar o programa 'meio confuso', foi
introduzida a tcnica de comentrios por blocos, de forma a deixar o programa um
pouco mais 'legvel'.
Ao colocar mais informaes na tela, aprendemos a lidar com alguns caracteres
de controle como o Carriage Return (CR, 13) e o Line Feed (LF, 10), que nos
permite escolher um pouco melhor qual o posicionamento que queremos dar ao texto
na tela. Depois desse processo, aprendemos como usar a funo CONIN para receber
uma entrada do usurio, aprendemos como guarda-la na memria e como usar a
funo CONOUT para colocar o caractere desta tecla novamente na tela. No meio do
caminho deste aprendizado topamos com um imprevisto, que foi o fato de a funo
STROUT sumariamente sumir com o resultado que havamos obtido com a funo
CONIN, problema que foi resolvido guardando-se a informao na memria logo aps
usarmos a funo CONIN e antes de usar a funo STROUT. Ao recuperarmos o valor
da memria, topamos novamente com um problema: precisvamos do valor no
registrador E devido a uma limitao do Z80 (que a de s podermos usar o
registrador A como 'cola' para escrever ou ler dados que esto na memria)
acabamos tendo que descobrir uma das formas de se lidar com isso, trocando dados
entre os registradores A e E, aprendendo neste processo todo ainda algumas
pequenas tcnicas de debug (knock-out, o processo de sair removendo partes do
programa e ver se o que foi removido sumiu com o que deveria sumir e se o
problema sumiu junto).
Bem, vamos aos tpicos da aula de hoje...
Usando o BrMSX para acelerar o desenvolvimento

Com as duas primeiras aulas vocs devem ter observado que, realmente, o
Assembly no um bicho de sete cabeas, apesar de ser meio chatinho, por ser
detalhista. No entanto, uma coisa que deve ter incomodado bastante a vocs (a
mim incomodou) foi o fato de termos de assemblar-no-PC,-copiarmos-no-disquete-e-
levar-para-o-MSX. Isso aborrecedor! Contra isso teramos a alternativa de
assemblar direto no MSX, usando a verso M80/L80 do MSX, mas contra isso temos
que o MSX muito mais lento para assemblar, e os editores de texto do MSX
conseguem, em sua maioria, ser piores (ou mais lentos ou com menos recursos) que
o prprio Notepad.
O que fazer ento? Porque no podemos fazer exatamente como no Basic, que
escrevemos e rodamos?
Bem, se voc escrevessem em linguagem de maquina (aquele monte de
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:25/92
numerozinhos em base hexadecimal) voc efetivamente teria como executar o
programa diretamente, mas adianto a voc que isso extremamente pouco pratico,
principalmente no que se refere variveis e alguns outros detalhes. Ento...
no podemos escapar muito da rotina de assemblar antes de testar o programa
(vocs vo ver que o Assemblador traz algumas vantagens extras nas prximas
aulas), mas a gente pode, se no eliminar a peregrinao ao MSX, diminui-la. Mas
como? Com o BrMSX.
Antes de mais nada, v no seu diretrio "\ASMMSX" e crie dentro dele o
seguinte diretrio: BRMSX. Voc dever ter ento:
\ASMMSX
[arquivos das aulas anteriores]
\ASMMSX\BRMSX
E dentro deste \ASMMSX\BRMSX descomprima o BrMSX, que voc encontra na pagina
do Ricardo Bittencourt ( http://www.lsi.usp.br/~ricardo/brmsx.htm ou http://
www.lsi.usp.br/~ricardo/brmsx206.zip diretamente ) e tambm crie, dentro deste
diretrio \ASMMSX\BRMSX o diretrio: TESTE (\ASMMSX\BRMSX\TESTE ).
Voc vai precisar de dois arquivos do MSXDOS: MSXDOS.SYS e COMMAND.COM.
Coloque-os dentro deste diretrio ( \ASMMSX\BRMSX\TESTE ).
Mude para o diretrio das aulas anteriores com
CD\ASMMSX [enter]
e depois copie o arquivo da aula anterior para este novo diretrio:
COPY PROG2.COM .\BRMSX\TESTE
Com isso, tudo que voc precisa para rodar o seu programa j est no
diretrio \ASMMSX\BRMSX\TESTE . Agora vamos aprender a executar isso usando o
BrMSX, o que muito simples... mude para o diretrio do BrMSX:
CD BRMSX
e comande:
BRMSX -mount teste
E voc observar milagrosamente que o BrMSX j entrou com um MSX-DOS, e se
voc digitar DIR ver que os arquivos existentes neste "disquete virtual" so
exatamente os arquivos que estavam no diretrio:
\ASMMSX\BRMSX\TESTE
Para executar seu programa no BrMSX, a partir deste prompt do MSXDOS, basta voc
digitar:
PROG2 [enter]
Garanto que funciona. Para sair e voltar ao MS-DOS (ou ao seu Windows),
digite F10 e depois pressione Q. Quando voc pressionar F10 ver uma tela cheia
de nmeros e uns dados em Assembly e outros.
Essa tela chamada FuDebug e a melhor coisa que existe no BrMSX para quem
quer programar Assembly. Daqui algumas aulas nos vamos utilizar extensivamente o
BrMSX exatamente para tirarmos proveito do FuDebug... assim, bom que voc j
v se acostumando a executar seus programas no BrMSX.
Voc pode automatizar esse procedimento todo criando arquivos de lote no MS-
DOS/Windows, e tudo ficar bem automtico, mas lembre-se que importante
executar seu programa no MSX real e testa-lo com alguma freqncia...
simplesmente para conferir se as coisas esto andando como deviam. Em geral
estaro, mas no custa nada dar uma verificada (jamais libere uma verso nova do
seu software para MSX sem te-lo executado antes no MSX. Voc pode ter alguma
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:26/92
surpresa bem desagradvel).
Aprenda bem esse procedimento de executar os programas no BrMSX.
Futuramente irei comentar sobre utilizao de funes do BrMSX mais
aprofundadas, e importante que voc j esteja familiarizado com a execuo do
seu software dentro do ambiente do BrMSX, de forma que voc possa se preocupar
somente com a explicao da nova funo, e no com o procedimento de como
carregar o software pelo BrMSX.
Otimizando nosso programa
Bem, agora j nos livramos de ter que, a cada compilao, jogar num disquete,
levar at o MSX e executar para ento ver que no funciona etc. e tal... Agora
j podemos trabalhar um pouco mais confortavelmente no PC, usando o BrMSX.
Vamos ver como podemos dar uma otimizada no nosso programa da aula passada...
que no fim, ficou da seguinte forma:
BDOS EQU 5
CONIN EQU 1
CONOUT EQU 2
STROUT EQU 9
START:
; Mostra nome do programa
LD DE,NOMEDOPRG ; Indica texto do nome do programa
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
; Mostra nome do programador
LD DE,AUTOR ; Indica texto do nome do autor
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
; Mostra a pergunta
LD DE,PERGU1 ; Indica texto da pergunta
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
; Espera tecla ser pressionada e coloca seu valor em A
LD C,CONIN ; Indica a funcao que pega uma tecla
CALL BDOS ; Chama BDOS
LD (VAR1),A ; Grava o valor da tecla na MEMORIA.
; Mostra a resposta
LD DE,RESP1 ; Indica texto da resposta
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
LD A,(VAR1) ; Copia para A o conteudo de VAR1
LD E,A ; Copia para E o conteudo de A
LD C,CONOUT ; Indica a funcao exibe um caractere na tela
CALL BDOS ; Chama BDOS
JP 0 ; Volta ao MSX-DOS
NOMEDOPRG: DB Programa 2 - Conversando com o usuario,13,10,$
AUTOR: DB Por Daniel Caetano,13,10,10,$
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:27/92
PERGU1: DB Pressione alguma tecla: $
RESP1: DB 13,10,10, A tecla pressionada foi: $
VAR1: DB 0
END
Vocs devem ter reparado uma certa repetio, ao menos na parte de mostrar
algum texto:
; Mostra nome do programa
LD DE,NOMEDOPRG ; Indica texto do nome do programa
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
; Mostra nome do programador
LD DE,AUTOR ; Indica texto do nome do autor
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
; Mostra a pergunta
LD DE,PERGU1 ; Indica texto da pergunta
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
; Mostra a resposta
LD DE,RESP1 ; Indica texto da resposta
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
Preste ateno na padronizao. Podemos dizer que em todas essas chamadas,
tem uma parte que no muda jamais:
; Comentario
LD DE,xxxx ; Indica texto
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
Como d pra observar, apenas UM parmetro muda numa seqncia inteira de
instrues. Esse parmetro justamente o endereo do texto. Bem, e se a gente
transformasse esse bloco todo em algo que pudesse ser chamado com apenas um
comando?
o que nos vamos aprender a fazer agora... vamos criar uma funo NOSSA,
nossa primeira funo. A primeira coisa que precisamos definir em uma funo o
seu nome. Essa funo faz exatamente o que? Mostra um texto, no ? Que tal
darmos o nome MOSTRATXT para ela? Numa primeira etapa nossa funo fica assim:
MOSTRATXT
Mas... isso vai dar erro, seguramente, no nosso assemblador. Precisamos dar
um jeito de dizer a ele que raios significa esse "MOSTRATXT". E como fazemos
isso? Dizendo a ele que ele que este um ponto de entrada, ou, de forma mais
simples, que esta uma funo. E como dizemos isso a ele?
Usando o caractere ":" na frente do nome da funo:
MOSTRATXT:
Isso j vai passar, ao menos, no nosso assemblador. Bem, tambm conveniente
colocar alguns comentrios no inicio da funo, dizendo o que esta funo faz:
;------
; MOSTRATXT - Funcao que mostra um texto cuja sequencia eh terminada por $.
;------
MOSTRATXT:
J comeou a ficar com uma aparncia melhor, no? Bem, agora a gente pega e
joga o nosso cdigo dentro:
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:28/92
;------
; MOSTRATXT - Funcao que mostra um texto cuja sequencia eh terminada por $.
;------
MOSTRATXT:
; Comentario
LD DE,xxxx ; Indica texto
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
Bem, esse primeiro comentrio pode ser suprimido, j que no acrescenta nada
neste lugar (a funo dele j feita pela descrio da funo).
;------
; MOSTRATXT - Funcao que mostra um texto cuja sequencia eh terminada por $.
;------
MOSTRATXT:
LD DE,xxxx ; Indica texto
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
Alem disso, o LD DE,xxxx algo que muda sempre, ento tambm deve ser
retirado da, e um valor que j deve vir pronto de fora. Ao suprimirmos essa
linha, devemos acrescentar um comentrio na descrio da funo, dizendo que o
texto deve estar indicado em DE, e teremos como resultado:
;------
; MOSTRATXT - Funcao que mostra um texto cuja sequencia eh terminada por $.
; Entrada: DE - Aponta para sequencia a ser mostrada, terminada por $
;------
MOSTRATXT:
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
E pronto, nossa funo est pronta. A questo : onde vamos colocar isso em
nosso programa? Um bom lugar entre o fim do nosso programa (JP 0) e as
variveis.
Vamos fazer isso?
BDOS EQU 5
CONIN EQU 1
CONOUT EQU 2
STROUT EQU 9
START:
; Mostra nome do programa
LD DE,NOMEDOPRG ; Indica texto do nome do programa
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
; Mostra nome do programador
LD DE,AUTOR ; Indica texto do nome do autor
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
; Mostra a pergunta
LD DE,PERGU1 ; Indica texto da pergunta
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:29/92
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
; Espera tecla ser pressionada e coloca seu valor em A
LD C,CONIN ; Indica a funcao que pega uma tecla
CALL BDOS ; Chama BDOS
LD (VAR1),A ; Grava o valor da tecla na MEMORIA.
; Mostra a resposta
LD DE,RESP1 ; Indica texto da resposta
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
LD A,(VAR1) ; Copia para A o conteudo de VAR1
LD E,A ; Copia para E o conteudo de A
LD C,CONOUT ; Indica a funcao exibe um caractere na tela
CALL BDOS ; Chama BDOS
JP 0 ; Volta ao MSX-DOS
;------
; MOSTRATXT - Funcao que mostra um texto cuja sequencia eh terminada por $.
; Entrada: DE - Aponta para sequencia a ser mostrada, terminada por $
;------
MOSTRATXT:
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
NOMEDOPRG: DB Programa 3 - Otimizando a estrutura,13,10,$
AUTOR: DB Por Daniel Caetano,13,10,10,$
PERGU1: DB Pressione alguma tecla: $
RESP1: DB 13,10,10, A tecla pressionada foi: $
VAR1: DB 0
END
Pronto! Nosso programa j tem uma funo agora. Experimente salvar esse texto
como PROG3.MAC e assembla-lo com o j manjado CL80 PROG3 e depois executa-lo no
BrMSX como explicado no inicio desta aula. Funcionou, no? Claro que sim, mas se
voc observar, no ganhamos nada com isso. Na verdade, perdemos. Nosso programa
ficou maior e mais confuso de ler.
Mas isso s aconteceu devido ao fato de que no acrescentamos a funo em nosso
programa, mas ainda no a utilizamos! Para que nosso programa ganhe benefcios
desta funo, precisamos modificar as partes dele para que estas se utilizem da
funo. E como fazemos isso? Bem, peguemos cada parte do programa que se
assemelhe a:
; Mostra nome do programa
LD DE,NOMEDOPRG ; Indica texto do nome do programa
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
E faca com que fique na forma:
; Mostra nome do programa
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:30/92
LD DE,NOMEDOPRG ; Indica texto do nome do programa
CALL MOSTRATXT ; Mostra texto
O que indica que usamos a instruo CALL para chamar a nossa funo.
Quando o Z80 for executar esses comandos, o que ele vai fazer? Ele vai
carregar DE com NOMEDOPRG:
LD DE,NOMEDOPRG
Depois ele vai pular para a funo MOSTRATXT, onde ele vai encontrar uma
instruo dizendo para ele carregar C com STROUT:
LD C,STROUT
E finalmente vai mandar o BDOS executar a nossa funo:
CALL BDOS
Ou seja, no fim das contar, para o Z80 o programa continuou o mesmo, a menos
do fato as instrues agora esto 'espalhadas' pelo programa. Se mudarmos todas
as partes que esto na forma:
; Comentario
LD DE,xxxx ; Indica texto
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
para
; Comentario
LD DE,xxxx ; Indica texto
CALL MOSTRATXT ; Mostra texto
Ficaremos com o programa assim:
BDOS EQU 5
CONIN EQU 1
CONOUT EQU 2
STROUT EQU 9
START:
; Mostra nome do programa
LD DE,NOMEDOPRG ; Indica texto do nome do programa
CALL MOSTRATXT ; Mostra texto
; Mostra nome do programador
LD DE,AUTOR ; Indica texto do nome do autor
CALL MOSTRATXT ; Mostra texto
; Mostra a pergunta
LD DE,PERGU1 ; Indica texto da pergunta
CALL MOSTRATXT ; Mostra texto
; Espera tecla ser pressionada e coloca seu valor em A
LD C,CONIN ; Indica a funcao que pega uma tecla
CALL BDOS ; Chama BDOS
LD (VAR1),A ; Grava o valor da tecla na MEMORIA.
; Mostra a resposta
LD DE,RESP1 ; Indica texto da resposta
CALL MOSTRATXT ; Mostra texto
LD A,(VAR1) ; Copia para A o conteudo de VAR1
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:31/92
LD E,A ; Copia para E o conteudo de A
LD C,CONOUT ; Indica a funcao exibe um caractere na tela
CALL BDOS ; Chama BDOS
JP 0 ; Volta ao MSX-DOS
;------
; MOSTRATXT - Funcao que mostra um texto cuja sequencia eh terminada por $.
; Entrada: DE - Aponta para sequencia a ser mostrada, terminada por $
;------
MOSTRATXT:
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
NOMEDOPRG: DB Programa 3 - Otimizando a estrutura,13,10,$
AUTOR: DB Por Daniel Caetano,13,10,10,$
PERGU1: DB Pressione alguma tecla: $
RESP1: DB 13,10,10, A tecla pressionada foi: $
VAR1: DB 0
END
E o programa j ficou mais limpo. No entanto, percebemos que aqueles
comentrios de blocos to pertinentes anteriormente agora esto mais poluindo o
nosso programa do que ajudando. Podemos modifica-los de forma que continuem
explicando o que est acontecendo, sem que fiquem poluindo tudo. Isso pode ser
conseguido assim:
BDOS EQU 5
CONIN EQU 1
CONOUT EQU 2
STROUT EQU 9
START:
; Mostra informacoes do programa e faz pergunta
LD DE,NOMEDOPRG ; Indica texto do nome do programa
CALL MOSTRATXT ; Mostra texto
LD DE,AUTOR ; Indica texto do nome do autor
CALL MOSTRATXT ; Mostra texto
LD DE,PERGU1 ; Indica texto da pergunta
CALL MOSTRATXT ; Mostra texto
; Espera tecla ser pressionada e coloca seu valor em A
LD C,CONIN ; Indica a funcao que pega uma tecla
CALL BDOS ; Chama BDOS
LD (VAR1),A ; Grava o valor da tecla na MEMORIA.
; Mostra a resposta
LD DE,RESP1 ; Indica texto da resposta
CALL MOSTRATXT ; Mostra texto
LD A,(VAR1) ; Copia para A o conteudo de VAR1
LD E,A ; Copia para E o conteudo de A
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:32/92
LD C,CONOUT ; Indica a funcao exibe um caractere na tela
CALL BDOS ; Chama BDOS
JP 0 ; Volta ao MSX-DOS
;------
; MOSTRATXT - Funcao que mostra um texto cuja sequencia eh terminada por $.
; Entrada: DE - Aponta para sequencia a ser mostrada, terminada por $
;------
MOSTRATXT:
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
NOMEDOPRG: DB Programa 3 - Otimizando a estrutur!,13,10,$
AUTOR: DB Por Daniel Caetano,13,10,10,$
PERGU1: DB Pressione alguma tecla: $
RESP1: DB 13,10,10, A tecla pressionada foi: $
VAR1: DB 0
END
Uau! Bem mais limpo, no? Sim. Experimente assemblar esse programa e executa-
lo, tanto no BrMSX quanto no MSX real. No funcionou?
Bem, em ambos os casos ele deve ter mostrado o nome do programa, uma
seqncia de lixo e o computador deve ter travado ou voltado ao MSX-DOS. Por que
isso aconteceu? Vamos seguir o programa passo a passo e ver onde est o erro?
Bem, o programa comea com:
START:
; Mostra informacoes do programa e faz pergunta
LD DE,NOMEDOPRG ; Indica texto do nome do programa
Jia... at aqui o programa carregou a posio do texto em DE.
CALL MOSTRATXT ; Mostra texto
Agora ele chama a nossa funo... vamos at l?
MOSTRATXT:
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
Carregou o valor de STROUT em C...
CALL BDOS ; Manda o BDOS executar.
Chamou o BDOS... e ao voltar...
NOMEDOPRG: DB Programa 3 - Otimizando a estrutura,13,10,$
Epa! Tem alguma coisa errada a. No era para ele seguir por esse caminho, e
sim voltar l para cima e continuar com:
LD DE,AUTOR ; Indica texto do nome do autor
No mesmo? Sim, ... mas a gente precisa avisar o Z80 quando pra voltar de
um CALL. O comando que usamos para isso o RET (RETurn, de retorne). Assim,
precisamos, sempre que fazemos uma funo, criar a instruo RET no fim da
funo. Nossa funo deve ento ser modificada para ficar assim:
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:33/92
;------
; MOSTRATXT - Funcao que mostra um texto cuja sequencia eh terminada por $.
; Entrada: DE - Aponta para sequencia a ser mostrada, terminada por $
;------
MOSTRATXT:
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
RET ; Retorna
E o nosso programa fica assim:
BDOS EQU 5
CONIN EQU 1
CONOUT EQU 2
STROUT EQU 9
START:
; Mostra informacoes do programa e faz pergunta
LD DE,NOMEDOPRG ; Indica texto do nome do programa
CALL MOSTRATXT ; Mostra texto
LD DE,AUTOR ; Indica texto do nome do autor
CALL MOSTRATXT ; Mostra texto
LD DE,PERGU1 ; Indica texto da pergunta
CALL MOSTRATXT ; Mostra texto
; Espera tecla ser pressionada e coloca seu valor em A
LD C,CONIN ; Indica a funcao que pega uma tecla
CALL BDOS ; Chama BDOS
LD (VAR1),A ; Grava o valor da tecla na MEMORIA.
; Mostra a resposta
LD DE,RESP1 ; Indica texto da resposta
CALL MOSTRATXT ; Mostra texto
LD A,(VAR1) ; Copia para A o conteudo de VAR1
LD E,A ; Copia para E o conteudo de A
LD C,CONOUT ; Indica a funcao exibe um caractere na tela
CALL BDOS ; Chama BDOS
JP 0 ; Volta ao MSX-DOS
;------
; MOSTRATXT - Funcao que mostra um texto cuja sequencia eh terminada por $.
; Entrada: DE - Aponta para sequencia a ser mostrada, terminada por $
;------
MOSTRATXT:
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
RET ; Retorna
NOMEDOPRG: DB Programa 3 - Otimizando a estrutura,13,10,$
AUTOR: DB Por Daniel Caetano,13,10,10,$
PERGU1: DB Pressione alguma tecla: $
RESP1: DB 13,10,10, A tecla pressionada foi: $
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:34/92
VAR1: DB 0
END
Assemblando esse cdigo e executando-o no MSX real ou no BrMSX, voc ver que
agora ele funciona bem, ficou menor e mais fcil de ler. O ganho maior quanto
mais vezes a repetio aparecer e maior for o trecho repetido.
Neste exemplo o ganho at pequeno, mas este tipo de otimizao, em um
programa complexo, pode ser a diferena entre ele ter um tamanho ou ser muito
maior, podendo chegar a ser seis, sete, n vezes maior.
Na aula que vem vamos aprender a usar o BrMSX para achar falhas como essa
falta do "RET" ao invs de ficar lendo o cdigo at encontra-la por nos mesmos,
e tambm vamos aprender algo um pouco mais complicado, que como otimizar ainda
mais o programa, transformando isso:
LD DE,NOMEDOPRG ; Indica texto do nome do programa
CALL MOSTRATXT ; Mostra texto
LD DE,AUTOR ; Indica texto do nome do autor
CALL MOSTRATXT ; Mostra texto
LD DE,PERGU1 ; Indica texto da pergunta
CALL MOSTRATXT ; Mostra texto
Em algo mais otimizado, visto que voc deve ter observado que isso segue uma
lgica bem explicita, principalmente se voc observar que os valores variveis
(NOMEDOPRG, AUTOR e PERGU1) esto assim na memria:
NOMEDOPRG: DB Programa 3 - Otimizando a estrutura,13,10,$
AUTOR: DB Por Daniel Caetano,13,10,10,$
PERGU1: DB Pressione alguma tecla: $
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:35/92
Aula IV - Comeando a pensar em ASM.
Bem, chegou a hora do desapego. Esta aula apenas uma parte do que
originalmente havia sido previsto para a Aula 4, pois achei que estava muito
pesada. Nesta aula vamos comear a tomar algum contato com uma forma um pouco
mais "rudimentar" de raciocnio: vamos brincar de pensar igual ao computador.
Pode parecer bobeira, mas tudo que parece muito difcil de programar pensando
como "gente" fica mais simples quando pensado como se fossemos o computador.
Nesta aula que os programadores de BASIC comearam a sentir alguma diferena
mais fundamental com o que esto habituados, mas hey, continua no sendo um
bicho nem de duas cabeas.
Primeiramente veremos como trabalhar com repetio de instrues e nas
prximas aulas usaremos isso para imprimir varias mensagens diferentes usando
apenas um loop. Nesta aula vamos aprender tambm a usar o FuDebug para ajudar a
resolver os paus de nossos programas.
Brincando de repetir uma tarefa
Voc deve ter reparado que nos programas anteriores escrevemos uma seqncia
de frases, no ? Bem, mas e se ao invs de imprimirmos varias frases,
quisssemos repetir varias vezes, digamos, 5 vezes, a mesma frase? Bem, nosso
programa ficaria mais ou menos assim...
BDOS EQU 5
STROUT EQU 9
START:
; Mostra informacoes do programa e faz pergunta
LD DE,NOMEDOPRG ; Indica texto do nome do programa
CALL MOSTRATXT ; Mostra texto
LD DE,AUTOR ; Indica texto do nome do autor
CALL MOSTRATXT ; Mostra texto
LD DE,FUDEBA ; Indica texto fudeba
CALL MOSTRATXT ; Mostra texto
LD DE,FUDEBA ; Indica texto fudeba
CALL MOSTRATXT ; Mostra texto
LD DE,FUDEBA ; Indica texto fudeba
CALL MOSTRATXT ; Mostra texto
LD DE,FUDEBA ; Indica texto fudeba
CALL MOSTRATXT ; Mostra texto
LD DE,FUDEBA ; Indica texto fudeba
CALL MOSTRATXT ; Mostra texto
JP 0 ; Volta ao MSX-DOS
;------
; MOSTRATXT - Funcao que mostra um texto cuja sequencia eh terminada por $.
; Entrada: DE - Aponta para sequencia a ser mostrada, terminada por $
;------
MOSTRATXT:
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:36/92
RET ; Retorna
NOMEDOPRG: DB Programa 4 - Brincando com loops,13,10,$
AUTOR: DB Por Daniel Caetano,13,10,10,$
FUDEBA: DB O DalPoz eh um fudeba!,13,10,$
END
Simples, melzinho na chupeta agora que estamos todos craques em ASM. Mas
vocs concordam que isso ficou com uma aparncia meio "burra"? Estamos repetindo
5 vezes a mesma coisa! Uma alternativa seria fazer o seguinte:
BDOS EQU 5
STROUT EQU 9
START:
; Mostra informacoes do programa e faz pergunta
LD DE,NOMEDOPRG ; Indica texto do nome do programa
CALL MOSTRATXT ; Mostra texto
LD DE,AUTOR ; Indica texto do nome do autor
CALL MOSTRATXT ; Mostra texto
CALL TXTFUDEBA ; Imprime texto fudeba
CALL TXTFUDEBA ; Imprime texto fudeba
CALL TXTFUDEBA ; Imprime texto fudeba
CALL TXTFUDEBA ; Imprime texto fudeba
CALL TXTFUDEBA ; Imprime texto fudeba
JP 0 ; Volta ao MSX-DOS
;------
; TXTFUDEBA - Imprime texto fudeba na tela
;------
MOSTRATXT:
LD DE,FUDEBA ; Indica texto fudeba
CALL MOSTRATXT ; Mostra texto
RET
;------
; MOSTRATXT - Funcao que mostra um texto cuja sequencia eh terminada por $.
; Entrada: DE - Aponta para sequencia a ser mostrada, terminada por $
;------
MOSTRATXT:
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
RET ; Retorna
NOMEDOPRG: DB Programa 4 - Brincando com loops,13,10,$
AUTOR: DB Por Daniel Caetano,13,10,10,$
FUDEBA: DB O DalPoz eh um fudeba!,13,10,$
END
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:37/92
J ficou melhor, no? De fato, essa segunda soluo melhor em termos de
tamanho, mas na verdade, se voc pensar com carinho, ver que ela ficou mais
lenta, porque agora o processador tem que pular de um lado para outro muito mais
vezes do que antes. Assim, aqui aparece um conceito importante: se voc precisa
de velocidade em um determinado trecho do programa, s o subdivida em funes
se:
For impossvel fazer diferente
A parte que se repete (ou seja, a funo) grande o suficiente para o tempo
gasto a mais "pulando" pra l e pra c no importe tanto. (em geral, funes com
5 ou mais linhas de assembly j valem a pena de serem criadas, SE a funo no
for critica em termos de velocidade.)
Voc tenha serias restries de espao, e cada byte economizado vale ouro.
Se a parte nem se repete tanto numa dado lugar, mas aparece centenas de vezes
durante todo o programa.
Fora essas situaes, evite simplesmente sair dividindo tudo. E o caso de
nosso programa um desses em que ficar enchendo de funo no t melhorando
muito. T diminuindo o tamanho de uma quantia nfima e t deixando ele mais
lento, alem de deixando ele mais difcil de ler, pois ele t cada vez mais
espalhado, com funes que fazem tarefas cada vez menores e mais especializadas.
Alem disso, *existe* um jeito diferente de fazer isso. Um jeito que nos d
mais maleabilidade como veremos posteriormente, alem de trazer um ganho de
desempenho e economizar ainda MAIS espao. COMO?!? simples! Dizendo pro Z80
repetir os comandos! Ele sabe fazer isso muito bem!
O comando que faz isso o DJNZ, um tipo especial de Jump. O que ele
significa eu entro em mais detalhes depois. Mas a idia mais ou menos essa:
LOOP: ASM1
ASM2
ASM3 ...
DJNZ LOOP
Ou seja, o DJNZ vai fazer ele repetir tudo que est entre o DJNZ e a
definio LOOP. Epa, mas ento o LOOP uma funo tambm? Afinal, eu defini ele
com os 2 pontinhos na frente! Bem, digamos que no. Eu menti pra vocs. Colocar
esses dois pontinhos na frente no significa que uma funo, mas sim significa
que isso uma ETIQUETA (Label, em ingls). Ora, se voc pensar que uma
etiqueta, na vida real, serve para a gente identificar as coisas, pro
assemblador a mesma coisa. Ou seja, essa "etiqueta" indica pro assemblador
onde esto as coisas. Assim, quando voc usa:
CALL FUNCAO
Ele vai procurar pela etiqueta
FUNCAO:
E vai executar a partir de ento. E por isso, ento, que toda a funo
comea com uma etiqueta (pra que seja possvel voc mandar o Z80 pular pra l!).
No entanto, voc pode colocar etiquetas onde quiser, mesmo no meio de funes.
Isso til em diversos casos, como neste do DJNZ. O DJNZ diz mais ou menos
assim pro processador: "Repete tudo que estiver entre esta etiqueta e eu". E o
Z80, como muito obediente, vai l e faz, sem questionar.
Assim, como ficaria nosso programa? Bem, o que queremos repetir o seguinte:
LD DE,FUDEBA ; Indica texto fudeba
CALL MOSTRATXT ; Mostra texto

Que havamos at separado em uma funo (mas vamos voltar atras). Ento, se
queremos repetir isso, devemos usar um trecho mais ou menos assim:
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:38/92
LOOP: LD DE,FUDEBA ; Indica texto fudeba
CALL MOSTRATXT ; Mostra texto
DJNZ LOOP ; Repete os comandos LD DE,FUDEBA e CALL
MOSTRATXT

No ? Sim! ! Vamos inserir isso no programa, que fica agora assim:
BDOS EQU 5
STROUT EQU 9
START:
; Mostra informacoes do programa e faz pergunta
LD DE,NOMEDOPRG ; Indica texto do nome do programa
CALL MOSTRATXT ; Mostra texto
LD DE,AUTOR ; Indica texto do nome do autor
CALL MOSTRATXT ; Mostra texto
LOOP: LD DE,FUDEBA ; Indica texto fudeba
CALL MOSTRATXT ; Mostra texto
DJNZ LOOP ; Repete os comandos LD DE,FUDEBA e CALL
MOSTRATXT
JP 0 ; Volta ao MSX-DOS
;------
; MOSTRATXT - Funcao que mostra um texto cuja sequencia eh terminada por $.
; Entrada: DE - Aponta para sequencia a ser mostrada, terminada por $
;------
MOSTRATXT:
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
RET ; Retorna
NOMEDOPRG: DB Programa 4 - Brincando com loops,13,10,$
AUTOR: DB Por Daniel Caetano,13,10,10,$
FUDEBA: DB O DalPoz eh um fudeba!,13,10,$
END
E vejam como ficou mais limpo! Notem que continua existindo um pulo, como no
caso da funo. No entanto, quando transformamos em funo tivemos que gastar
espao com 5 chamadas funo (agora esse espao foi economizado) e, ainda no
caso da funo, havia um pulo adicional: se fomos, tivemos que voltar (com o
RET). Ou seja, para cada chamada funo tnhamos DOIS pulos, que agora virou
apenas 1 (ele pula da posio do DJNZ para a posio da etiqueta LOOP).
Assemblem isso com o M80/L80, usando o CL80 e rodem no BrMSX. E o que vocs
viram? Creio que funcionou, em parte. (^= Vocs devem ter notado que, ao invs
de repetir 5 vezes a frase, esta ficou se repetindo milhares de vezes...
infinitas, na verdade. Bem, o que est faltando? Dissemos ao Z80 para REPETIR um
trecho de cdigo, mas no dissemos para ele QUANTAS vezes repetir.
O comando DJNZ significa "Decrement and Jump if Not Zero" ou, em portugus,
subtraia 1 e pule pra etiqueta indicada se o resultado no for zero. At ai',
tudo bem.... Mas subtrai 1 de ONDE? Eu fui maldoso e no contei pra vocs que
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:39/92
essa informao precisa ser colocada no registrador B. Quando chegar no DJNZ,
ele vai fazer o seguinte:
B = B - 1
(subtraiu 1 de B)
B = 0?
Se NO, ele pula para a etiqueta (Decrement and Jump if Not Zero). Se B era
igual a zero, no entanto, a instruo simplesmente ignorada e o programa segue
adiante. Assim, devemos colocar no registrador B o numero de vezes que queremos
que a coisa se repita. Vamos, ento, mudar o programa, acrescentando um
LD B,5
Pra indicar isso. O programa fica ento assim:
BDOS EQU 5
STROUT EQU 9
START:
; Mostra informacoes do programa e faz pergunta
LD DE,NOMEDOPRG ; Indica texto do nome do programa
CALL MOSTRATXT ; Mostra texto
LD DE,AUTOR ; Indica texto do nome do autor
CALL MOSTRATXT ; Mostra texto
LOOP: LD B,5 ; Indica repeticao de 5 vezes.
LD DE,FUDEBA ; Indica texto fudeba
CALL MOSTRATXT ; Mostra texto
DJNZ LOOP ; Repete os comandos LD DE,FUDEBA e CALL
MOSTRATXT
JP 0 ; Volta ao MSX-DOS
;------
; MOSTRATXT - Funcao que mostra um texto cuja sequencia eh terminada por $.
; Entrada: DE - Aponta para sequencia a ser mostrada, terminada por $
;------
MOSTRATXT:
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
RET ; Retorna
NOMEDOPRG: DB Programa 4 - Brincando com loops,13,10,$
AUTOR: DB Por Daniel Caetano,13,10,10,$
FUDEBA: DB O DalPoz eh um fudeba!,13,10,$
END
Assemble novamente e rode.
O QUE?!? Continuou dando problema? Bem, vamos passo a passo ver o que est
acontecendo. Assim que voc executa o programa ele vai executar:
LD DE,NOMEDOPRG ; Indica texto do nome do programa
CALL MOSTRATXT ; Mostra texto
LD DE,AUTOR ; Indica texto do nome do autor
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:40/92
CALL MOSTRATXT ; Mostra texto
At aqui nada de anormal. Em seguida, ele executa:
LOOP: LD B,5 ; Indica repeticao de 5 vezes.
Na linha acima indica numero de vezes igual a 5. Portanto, B indica 5 neste
momento.
LD DE,FUDEBA ; Indica texto fudeba CALL MOSTRATXT ; Mostra texto
Aqui ele aponta o texto e mostra o texto. B ainda indica 5.
DJNZ LOOP ; Repete os comandos LD DE,FUDEBA e CALL MOSTRATXT
No DJNZ, o valor de B decrementado (subtrado de uma unidade). Ou seja, com
a execuo deste comando, B passa a conter o valor 4. Ainda no DJNZ verificado
se 4 = 0? Como no, ele pula para o label LOOP, e temos em seguida:
LOOP: LD B,5 ; Indica repeticao de 5 vezes.
Que faz B = 5 de novo! Epa, isso est errado! Assim o B nunca vai chegar a
zero! E porque isso t ocorrendo? Porque colocamos o LD B,5 dentro do loop, e
isso est, logicamente, errado! A soluo mudar o loop para:
LD B,5 ; Indica repeticao de 5 vezes.
LOOP: LD DE,FUDEBA ; Indica texto fudeba
CALL MOSTRATXT ; Mostra texto
DJNZ LOOP ; Repete os comandos LD DE,FUDEBA e CALL
MOSTRATXT
Ou seja, com o B FORA do loop. Se voc fizer a "emulao de cabea" que eu
fiz h pouco ver que agora sim o valor de B vai decrescendo... O programa deve
estar assim agora:
BDOS EQU 5
STROUT EQU 9
START:
; Mostra informacoes do programa e faz pergunta
LD DE,NOMEDOPRG ; Indica texto do nome do programa
CALL MOSTRATXT ; Mostra texto
LD DE,AUTOR ; Indica texto do nome do autor
CALL MOSTRATXT ; Mostra texto
LD B,5 ; Indica repeticao de 5 vezes.
LOOP: LD DE,FUDEBA ; Indica texto fudeba
CALL MOSTRATXT ; Mostra texto
DJNZ LOOP ; Repete os comandos LD DE,FUDEBA e CALL
MOSTRATXT
JP 0 ; Volta ao MSX-DOS
;------
; MOSTRATXT - Funcao que mostra um texto cuja sequencia eh terminada por $.
; Entrada: DE - Aponta para sequencia a ser mostrada, terminada por $
;------
MOSTRATXT:
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
RET ; Retorna
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:41/92
NOMEDOPRG: DB Programa 4 - Brincando com loops,13,10,$
AUTOR: DB Por Daniel Caetano,13,10,10,$
FUDEBA: DB O DalPoz eh um fudeba!,13,10,$
END
Assemble seu programinha e rode no BrMSX e veja que agora o programa roda
perfeitamente!
O QUE!?! No rodou? Poxa, mas no tem nenhum erro de lgica! hummm... Como
fazemos para diagnosticar esse problema? De repente at fazendo a "emulao de
cabea" a gente ache o problema, mas... poxa, isso d trabalho pra caramba! No
tem uma ferramenta que faca isso pra gente? UAI, e no tem? Claro que tem! E
vocs j a esto usando. o BrMSX. Pra que usar um "emulador de cabea" se
temos um eletrnico, prontinho?
Vamos usar o BrMSX ento pra descobrir porque nosso programa no est
funcionando, mesmo que aparentemente deveria estar.
Aprendendo a usar o FuDebug
Entre no BrMSX normalmente at ele entrar no MSX-DOS, mas ainda NO rode o
programa. Antes precisamos tomar algumas precaues e conhecer alguns detalhes.
Antes de mais nada pressione F10. Isso vai entrar na tela 1 do FuDebug. Tem
um monte de numero a, no? Tem, pois . Esta tela mais ou menos assim:
BrMSX debugger Z80 VDP PSG
AF=0042 AF=01A8 Reg0 00 55
10DC> 28 FB JR Z,10D9 BC=00FF BC=0019 Reg1 F0 00
10DE CD 27 0A CALL 0A27 DE=007C DE=0000 Reg2 00 00
10E1 21 9B FC LD HL,FC9B HL=0304 HL=E0AB Reg3 00 00
10E4 7E LD A,(HL) IX=009F Reg4 01 00
10E5 FE 04 CP 04 IY=BB80 SZ5H3VNC Reg5 00 00
10E7 20 02 JR NZ,10EB PC=10DC 01000010 Reg6 00 00
10E9 36 00 LD (HL),00 SP=EAEF Reg7 F1 B8
10EB 2A FA F3 LD HL,(F3FA) I=00 EI IM1 R=63 Reg8 00 00
10EE 4E LD C,(HL) PPI MegaROM Reg9 00 00
10EF CD C2 10 CALL 10C2 0000 00 RegA 00 00
10F2 22 FA F3 LD (F3FA),HL A=A8 2000 00 RegB 00 0B
C=5A 4000 00 RegC 00 00
Memory 6000 01 RegD 00 00
0000 F3 C3 D7 02 BF 1B 98 98 ........ Page0=0 8000 02 RegE 00 00
0008 C3 83 26 00 C3 B6 01 00 ..&..... Page1=2 A000 03 RegF 00 CF
0010 C3 86 26 00 C3 D1 01 00 ..&..... Page2=2 C000 00
0018 C3 45 1B 00 C3 17 02 00 .E...... Page3=2 E000 00 PSG addr 0E
BrMSX settings
Resolution: 320x200 Frame skipping: 0001 Bar Graph: OFF Emulation: NORMAL
Joy: - Sound: ON VSync: OFF Session: SINGLE COM: 1 Video Cache: ON
Command: SCC: OFF

E pode ser dividida basicamente em trs partes:
A da esquerda, que engloba as regies "BrMSX debugger" e "Memory" que
representam informaes da memria principal do MSX.
A da direita, que possui informaes sobre diversos processadores do MSX,
incluindo VDP, PSG, PPI e Z80, alem da MegaROM.
A parte inferior, contendo informaes sobre a configurao do emulador.
nesse lugar que a maioria da atividade de debug acontece. Acostume-se com a
cara dele. Aperte S para voltar emulao. Rode o seu programa. Ele vai comear
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:42/92
a mostrar infinitamente a frase "DalPoz fudeba", como fazia antes. Agora,
pressione F10.
Voc deve aparecer na tela do FuDebug... mas... e a? Onde t o meu programa
no meio desse lixo todo? Hummm... Voc pode tentar procurar usando as teclas pra
cima e para baixo. Voc vai ver que a seo "BrMSX debugger" mexe. Nesta seo,
todos os valores esto em hexadecimal. Voc encontra, da esquerda para a
direita, o endereo da memria, os bytes que compem a instruo, e mais `a
direita da seo o MNEMONICO ASSEMBLY da instruo. Mas isso demorado. Pra
pular para uma posio de memria especifica voc pode usar o comando U
(Unassemble) do FuDebug. Digite:
U 0100
E veja! Ele pulou direto para a posio 0100 da memria. Melhorou bastante,
n? Mas onde est o meu programa? Difcil dizer. Na verdade sabemos que ele est
em um lugar especifico (j conto pra vocs), mas ele pode no estar visvel no
momento (como em geral no vai estar). Em 99,99% dos casos o MSX estar
processando algumas informaes que nada tem a ver com o seu programa. Essa
informaes esto, em geral, na BIOS do seu MSX. A BIOS contem programas, como o
seu, dentro, mas ela fica escondida em um lugar. Se voc observar na Janela PPI,
notar que existem as seguintes indicaes:
Page 0
Page 1
Page 2
Page 3
Certo? Mas o que significa isso? Bem, vamos com calma. Lembra-se que na
primeira aula eu disse que a folha de papel do MSX tinha 65536 lugares para
escrever letrinhas? Ento, eu menti de novo. Na verdade, no uma folha, mas
sim duas, frente e verso. Ou seja, temos 4 paginas, cada uma podendo ter at
16384 letrinhas. Uau! Mas pra que isso serve? Pra muita coisa como vamos ver j.
Antes gostaria de fazer um parntese: apesar de PAGINA ser a nomenclatura
padronizada para isso no MSX1, devido a mudanas na estruturao do MSX2 a
palavra PAGINA foi usada para OUTRA coisa. Vamos chamar essas 4 "coisas" de
FRAMES (molduras) como ficou padronizado no MSX2 e superiores pelo MSX2
Technical Handbook. Assim, o MSX tem 4 frames, cada um podendo ter at 16386
bytes, ou seja, cada frame tem 16384 posies de memria, ou 16Kb. Alem disso,
voc deve ter notado que os MSX em geral possuem vrios conectores de cartuchos
(chamados SLOTS). Apesar de voc s ver 2, na verdade existem 4 (dois deles
costumam ser usados internamente, e nos j veremos com o que). Bem, pense agora
que voc pode ter expanses de memria conectados nesses slots, sejam elas RAM
(mais memria pra voc brincar) ou ROM (funes pre-prontas, como as do MSX-DOS,
que ficam no chamado BDOS, ou as da prpria BIOS). Agora, eu te digo que seu MSX
*realmente* tem um monte de expanses ligadas. Em geral os slots que aparecem
pra fora so o slot 1 e o 2. Mas que fim levaram os slots 0 e 3? Bem, a que
entra a manha: o slot 0 tem ligado nele de fabrica a BIOS e o BASIC, enquanto o
slot 3 costuma vir ligado com a RAM. Note que, tirando a necessidade da BIOS
estar no slot 0, essa configurao no totalmente obrigatrio (embora seja
seguida pela maioria das maquinas). E... tanto essa configurao no 100%
padro que existem computadores que vem com a BIOS no slot 0, RAM no Slot 2 e
os slots 1 e 3 aparecem para fora no micro. E o Expert, emulado pelo BrMSX, um
deles.
Bem, em algum lugar a gente precisa dizer pro MSX em que slot est a RAM/ROM
que queremos usar... E pra isso que temos a memria do MSX dividida em 4
FRAMES de 16Kb: para que cada um deles possa conter dados de diferentes slots,
sem que o Z80 precise se preocupar com "onde estou lendo esse dado?" Essa
configurao feita pela PPI, um processador externo ao Z80, que quem faz
essa gambiarra pra podermos ter essa facilidade de ter cada frame da memria do
Z80 mostrando dado de um slot diferente.
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:43/92
E o que isso tudo tem a ver com o FuDebug? Bem, se voc olhar, na seo PPI,
os valores que esto em frente
Page 0
Page 1
Page 2
Page 3
Se voc estiver executando o programa, ver que em 99,99% dos casos a
configurao esta:
Page 0=0
Page 1=2
Page 2=2
Page 3=2
(se no estiver, aperte S pra voltar pra emulao e depois aperte F10 de novo
pra voltar ao FuDebug. Voc tinha sido um felizardo dos 0,01%!)
Essa a configurao do momento, para cada Frame (ou Page, com o emulador
chama) qual slot que est sendo usado. Assim, de 0 a 3FFFh (0 a 16383) temos
informaes do slot 0 (BIOS), e nos outros 3 frames, de 4000h a FFFFh (16384 a
65535) temos informaes do Slot 2 (no caso do Expert e BrMSX, a RAM).
Assim, se o seu programa estivesse em qualquer rea da RAM entre 16384 e
65535 voc o encontraria simplesmente procurando com as setar ou usando U XXXX
no FuDebug.
No entanto, existe uma peculiaridade no MSX-DOS: ele sempre carrega um
programa a partir do endereo 0100h da RAM. Ora, mas se de 0000h a 3FFFh temos a
BIOS, como vamos ver o nosso programa?
Bem, existe um jeito para fazer isso. O BrMSX tem um comando B (de Break) em
que voc escolhe uma posio de memria na qual o BrMSX automaticamente abrir o
FuDebug quando ela for executada.
Vamos fazer exatamente isso agora: Aperte S para voltar ao programa. Ele vai
continuar imprimindo "DalPoz fudeba" na tela. Pressione CTRL+C para parar com
isso. Agora, ANTES de executar novamente seu programa, aperte F10 para entrar no
FuDebug. No FuDebug, comande:
B 0100
O emulador automaticamente voltar para o MSX-DOS. Esse comando que voc
passou far com que o FuDebug entre em ao exatamente quando a posio de
memria 0100 (o seu programa!) for executada. ( Caso voc se pergunte o que
aconteceria se alguma coisa na ROM fosse executada no endereo 0100h, leia at o
fim da aula, onde eu falo um pouco mais sobre isso. )
Manda o MSX-DOS executar o seu programa. Instantaneamente o FuDebug vai te
mostrar algo mais ou menos assim:
BrMSX debugger Z80 VDP PSG
AF=0044 AF=0082 Reg0 00 55
0100> 00 NOP BC=00FF BC=3CF6 Reg1 F0 00
0101 00 NOP DE=DDFF DE=3CF6 Reg2 00 00
0102 00 NOP HL=0000 HL=3CFB Reg3 00 00
0103 11 22 01 LD DE,0122 IX=3EFD Reg4 01 00
0106 CD 1C 01 CALL 011C IY=3FDB SZ5H3VNC Reg5 00 00
0109 11 45 01 LD DE,0145 PC=0100 01000100 Reg6 00 00
010C CD 1C 01 CALL 011C SP=D6FE Reg7 F1 B8
010F 06 05 LD B,05 I=00 EI IM1 R=5A Reg8 00 00
0111 11 5D 01 LD DE,015D PPI MegaROM Reg9 00 00
0114 CD 1C 01 CALL 011C 0000 00 RegA 00 00
0117 10 F8 DJNZ 0111 A=AA 2000 00 RegB 00 0B
C=5A 4000 00 RegC 00 00
Memory 6000 01 RegD 00 00
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:44/92
0000 C3 03 DE 00 00 C3 06 D7 ........ Page0=2 8000 02 RegE 00 00
0008 00 00 00 00 C3 E8 F1 00 ........ Page1=2 A000 03 RegF 00 CF
0010 00 00 00 00 C3 EB F1 00 ........ Page2=2 C000 00
0018 00 00 00 00 C3 EE F1 00 ........ Page3=2 E000 00 PSG addr 0E
BrMSX settings
Resolution: 320x200 Frame skipping: 0001 Bar Graph: OFF Emulation: NORMAL
Joy: - Sound: ON VSync: OFF Session: SINGLE COM: 1 Video Cache: ON
Command: SCC: OFF
Como voc pode notar, todos os frames esto no Slot2 agora (RAM). E o
ponteiro do BrMSX ( o ">" do lado direito do endereo na seo BrMSX debugger)
indica a instruo que ser executada em seqncia. E ele est exatamente sobre
a posio 0100h, que o inicio do seu programa! Vamos acompanhar... Existem 3
NOPs a no comeo que so acrescentados pelo assemblador, vamos ver futuramente
para que eles servem. A seguir, vem
LD DE,0122h
E voc vai pensar... "Poxa isso no tem nada a ver com o
LD DE,NOMEDOPRG ; Indica texto do nome do programa
Que tinha logo no inicio do meu programa!". Ser que no mesmo? O que o
FuDebug est mostrando que estamos "apontando" DE para a posio de memria
0122h. Vamos ver o que tem l? Digite
D 0122
No fudebug. Este comando vai fazer um "Dump" da memria a partir de 0120h, na
seo "Memory" do fudebug. Se voc fizer isso, vai ver a seguinte tela:
BrMSX debugger Z80 VDP PSG
AF=0044 AF=0082 Reg0 00 55
0100> 00 NOP BC=00FF BC=3CF6 Reg1 F0 00
0101 00 NOP DE=DDFF DE=3CF6 Reg2 00 00
0102 00 NOP HL=0000 HL=3CFB Reg3 00 00
0103 11 22 01 LD DE,0122 IX=3EFD Reg4 01 00
0106 CD 1C 01 CALL 011C IY=3FDB SZ5H3VNC Reg5 00 00
0109 11 45 01 LD DE,0145 PC=0100 01000100 Reg6 00 00
010C CD 1C 01 CALL 011C SP=D6FE Reg7 F1 B8
010F 06 05 LD B,05 I=00 EI IM1 R=5A Reg8 00 00
0111 11 5D 01 LD DE,015D PPI MegaROM Reg9 00 00
0114 CD 1C 01 CALL 011C 0000 00 RegA 00 00
0117 10 F8 DJNZ 0111 A=AA 2000 00 RegB 00 0B
C=5A 4000 00 RegC 00 00
Memory 6000 01 RegD 00 00
0122 50 72 6F 67 72 61 6D 61 Programa Page0=2 8000 02 RegE 00 00
012A 20 34 20 2D 20 42 72 69 4 - Bri Page1=2 A000 03 RegF 00 CF
0132 6E 63 61 6E 64 6F 20 63 ncando c Page2=2 C000 00
013A 6F 6D 20 6C 6F 6F 70 73 om loops Page3=2 E000 00 PSG addr 0E
BrMSX settings
Resolution: 320x200 Frame skipping: 0001 Bar Graph: OFF Emulation: NORMAL
Joy: - Sound: ON VSync: OFF Session: SINGLE COM: 1 Video Cache: ON
Command: SCC: OFF

Olhe l, na posio 0122h... "Programa 4 - Brincando com loops" ou seja, LD
DE,0122h a codificao exata que o assemblador gerou do seu LD DE,NOMEDOPROG.
Uma das principais vantagens do assemblador e de se usar labels (etiquetas) em
Assembly que voc no precisa se preocupar mais com "em que endereo isso vai
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:45/92
ficar?", porque o assemblador cuida de tudo pra voc. Mas voc vai precisar
ficar esperto ao usar o FuDebug, pois eles vo aparecer com os nomes j trocados
para nmeros durante a execuo de seu programa. Seguindo essa idia, o CALL
011Ch deve ser o mesmo que o "CALL MOSTRATXT" de nosso programa. E de fato ! Se
voc usar:
U 011C
(Unassemble 011C) vai notar que o seguinte vai aparecer na tela:
BrMSX debugger Z80 VDP PSG
AF=0044 AF=0082 Reg0 00 55
011C 0E 09 LD C,09 BC=00FF BC=3CF6 Reg1 F0 00
011E CD 05 00 CALL 0005 DE=DDFF DE=3CF6 Reg2 00 00
0121 C9 RET HL=0000 HL=3CFB Reg3 00 00
0122 50 LD D,B IX=3EFD Reg4 01 00
0123 72 LD (HL),D IY=3FDB SZ5H3VNC Reg5 00 00
0124 6F LD L,A PC=0100 01000100 Reg6 00 00
0125 67 LD H,A SP=D6FE Reg7 F1 B8
0126 72 LD (HL),D I=00 EI IM1 R=5A Reg8 00 00
0127 61 LD H,C PPI MegaROM Reg9 00 00
0128 6D LD L,L 0000 00 RegA 00 00
0129 61 LD H,C A=AA 2000 00 RegB 00 0B
C=5A 4000 00 RegC 00 00
Memory 6000 01 RegD 00 00
0122 50 72 6F 67 72 61 6D 61 Programa Page0=2 8000 02 RegE 00 00
012A 20 34 20 2D 20 42 72 69 4 - Bri Page1=2 A000 03 RegF 00 CF
0132 6E 63 61 6E 64 6F 20 63 ncando c Page2=2 C000 00
013A 6F 6D 20 6C 6F 6F 70 73 om loops Page3=2 E000 00 PSG addr 0E
BrMSX settings
Resolution: 320x200 Frame skipping: 0001 Bar Graph: OFF Emulation: NORMAL
Joy: - Sound: ON VSync: OFF Session: SINGLE COM: 1 Video Cache: ON
Command: SCC: OFF

Ora, LD C,09 (STROUT), CALL 0005 (BDOS) e RET exatamente sua funo
MOSTRATXT! Ento isso mesmo! Ih, mas e agora pra voltar onde estvamos? Em que
posio estava mesmo o marcador do BrMSX?
Bem, o marcador do BrMSX apenas emula o marcador do prprio Z80. E claro, o
Z80 real tem um marcador, afinal, isso til pra ele tambm. Esse marcador um
registrador especial, e chama-se PC (de Program Counter, ou contador de
programa) e voc pode olhar o valor atual dele na seo Z80, onde voc vai
encontrar:
PC=0100
"Ah, ! Era a posio 0100h!"
Bem, ento digite U 0100h pra voltar pra l... E pumba!
BrMSX debugger Z80 VDP PSG
AF=0044 AF=0082 Reg0 00 55
0100> 00 NOP BC=00FF BC=3CF6 Reg1 F0 00
0101 00 NOP DE=DDFF DE=3CF6 Reg2 00 00
0102 00 NOP HL=0000 HL=3CFB Reg3 00 00
0103 11 22 01 LD DE,0122 IX=3EFD Reg4 01 00
0106 CD 1C 01 CALL 011C IY=3FDB SZ5H3VNC Reg5 00 00
0109 11 45 01 LD DE,0145 PC=0100 01000100 Reg6 00 00
010C CD 1C 01 CALL 011C SP=D6FE Reg7 F1 B8
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:46/92
010F 06 05 LD B,05 I=00 EI IM1 R=5A Reg8 00 00
0111 11 5D 01 LD DE,015D PPI MegaROM Reg9 00 00
0114 CD 1C 01 CALL 011C 0000 00 RegA 00 00
0117 10 F8 DJNZ 0111 A=AA 2000 00 RegB 00 0B
C=5A 4000 00 RegC 00 00
Memory 6000 01 RegD 00 00
0122 50 72 6F 67 72 61 6D 61 Programa Page0=2 8000 02 RegE 00 00
012A 20 34 20 2D 20 42 72 69 4 - Bri Page1=2 A000 03 RegF 00 CF
0132 6E 63 61 6E 64 6F 20 63 ncando c Page2=2 C000 00
013A 6F 6D 20 6C 6F 6F 70 73 om loops Page3=2 E000 00 PSG addr 0E
BrMSX settings
Resolution: 320x200 Frame skipping: 0001 Bar Graph: OFF Emulation: NORMAL
Joy: - Sound: ON VSync: OFF Session: SINGLE COM: 1 Video Cache: ON
Command: SCC: OFF

Voltamos. T, tudo bem, mas em que isso ajuda a gente? Simples. Experimente
pressionar a tecla F8. Ah! O ponteiro andou pra prxima posio de memria! Sim,
mas no s isso. Ele de fato executou a operao (no caso, NOP). Apertando F8
voc pode ir passando comando por comando (Step Over). Para acompanhar o que
est acontecendo na tela, pressione a tecla 0 que ele vai te mostrar a tela (sem
descongelar a emulao). No momento em que a tela de emulao congelada estiver
sendo mostrada, qualquer tecla faz voltar ao FuDebug. Assim, pressione 0 para
ver que a tela do MSX-DOS continua l, sem nenhuma alterao. Pressione alguma
outra tecla pra voltar ao FuDebug. Pressione F8 at o marcador ficar em frente
`a posio de memria 0103h. Nesta posio tem o comando LD DE,0122h. O ponteiro
nessa linha indica que ela a prxima a ser executada. Observe o valor que DE
contem atualmente, na seo Z80. No meu caso DDFFh, mas poderia ser qualquer
valor. Pressione F8, executando a instruo LD DE,0122h (e agora o marcador vai
apontar para a posio de memria 0106h). Agora voc pode olhar que o valor do
registrador DE foi mudado para... Exatamente 0122h! Uau! Pressione o F8
novamente para executar o CALL 011Ch. Isso deve ter colocado a mensagem que
comea na posio 0122h da RAM na tela... Mas como vemos isso sem descongelar a
emulao? Simples... pressione 0. Isso vai te mostrar a imagem com a emulao
ainda congelada. Pressione qualquer tecla para voltar. sempre a mesma coisa.
(^= Agora pressione F8 algumas vezes, at que o ponteiro de execuo ficar em
frente posio de memria 010Fh. A segunda mensagem j deve estar na tela
(voc pode conferir com a tecla 0). Da prxima vez que voc apertar F8, o
emulador vai executar a o comando:
LD B,005h
Que justamente onde voc inicializava o numero de vezes que queria a
mensagem. Opa! T chegando o lugar onde deve estar o pepino! Pressione F8. B foi
carregado com o valor 5. At aqui tudo dentro do esperado. Pressione F8
novamente. DE deve ter sido carregado com 015Dh, que o endereo da mensagem
fudeba. Pressione F8 novamente. Verifique que a mensagem apareceu na tela, pois
o CALL foi executado (use 0 para verificar a tela). Mas ... ei, se voc notar
por algum motivo estranho B t valendo 00h! Onde foi parar o meu 5? Bem, agora
ento no vamos mais usar o F8, e sim o F7. A diferena do F8 para o F7 que o
F8 no entra dentro das funes (por exemplo, usando o F8 voc no viu o que
acontecia dentro do CALL. Usando o F7 vai poder ver). Assim, aperte F7 e voc
vai ver que a execuo do DJNZ vai fazer tudo aquilo que j tinha dito: subtrair
1 do B (que de 00 passa a FFh, pois em Assembly os nmeros "giram" assim mesmo)
e pulou de volta para 0111h! Pressione F7 mais uma vez, e novamente DE ser
carregado com o valor 015Dh, o endereo da mensagem fudeba. Quando voc apertar
F7 novamente, vai ver que a execuo pula agora para o endereo 011C, ou seja,
com o F7 voc entrou dentro da funo. E o que voc acha no endereo 011C? A sua
funo MOSTRATXT! Que :
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:47/92
BrMSX debugger Z80 VDP PSG
AF=0044 AF=0082 Reg0 00 55
011C> 0E 09 LD C,09 BC=FF02 BC=3CF6 Reg1 F0 00
011E CD 05 00 CALL 0005 DE=015D DE=3CF6 Reg2 00 00
0121 C9 RET HL=0000 HL=3CFB Reg3 00 00
0122 50 LD D,B IX=3EFD Reg4 01 00
0123 72 LD (HL),D IY=3FDB SZ5H3VNC Reg5 00 00
0124 6F LD L,A PC=011C 01000100 Reg6 00 00
0125 67 LD H,A SP=D6FC Reg7 F1 B8
0126 72 LD (HL),D I=00 EI IM1 R=71 Reg8 00 00
0127 61 LD H,C PPI MegaROM Reg9 00 00
0128 6D LD L,L 0000 00 RegA 00 00
0129 61 LD H,C A=AA 2000 00 RegB 00 0B
C=5A 4000 00 RegC 00 00
Memory 6000 01 RegD 00 00
0122 50 72 6F 67 72 61 6D 61 Programa Page0=2 8000 02 RegE 00 00
012A 20 34 20 2D 20 42 72 69 4 - Bri Page1=2 A000 03 RegF 00 CF
0132 6E 63 61 6E 64 6F 20 63 ncando c Page2=2 C000 00
013A 6F 6D 20 6C 6F 6F 70 73 om loops Page3=2 E000 00 PSG addr 0E
BrMSX settings
Resolution: 320x200 Frame skipping: 0001 Bar Graph: OFF Emulation: NORMAL
Joy: - Sound: ON VSync: OFF Session: SINGLE COM: 1 Video Cache: ON
Command: SCC: OFF

Note que B continua com o valor FF. Pressione F7 para executar o LD D,009h, e
veja que C efetivamente cai conter esse valor, agora. ATENO: NO USE F7 AGORA!
Sempre que houver uma chamada ao BDOS assim (CALL 0005) USE F8! Caso contrario
voc vai entrar dentro do BDOS e vai ficar maluquinho pra entender o que t
rolando. Antes de apertar F8 e executar o CALL, no entanto, note que B *ainda*
vale FFh. Pressione F8. Agora o ponteiro deve estar indicando a posio de
memria 0121, pois o CALL j foi executado... porem, note o valor de B agora...
BrMSX debugger Z80 VDP PSG
AF=0044 AF=0082 Reg0 00 55
0121> C9 RET BC=0002 BC=3CF6 Reg1 F0 00
0122 50 LD D,B DE=0175 DE=3CF6 Reg2 00 00
0123 72 LD (HL),D HL=0000 HL=3CFB Reg3 00 00
0124 6F LD L,A IX=3EFD Reg4 01 00
0125 67 LD H,A IY=3FDB SZ5H3VNC Reg5 00 00
0126 72 LD (HL),D PC=0121 01000100 Reg6 00 00
0127 61 LD H,C SP=D6FC Reg7 F1 B8
0128 6D LD L,L I=00 EI IM1 R=6D Reg8 00 00
0129 61 LD H,C PPI MegaROM Reg9 00 00
012A 20 34 JR NZ,0160 0000 00 RegA 00 00
012C 20 2D JR NZ,015B A=AA 2000 00 RegB 00 0B
C=5A 4000 00 RegC 00 00
Memory 6000 01 RegD 00 00
0122 50 72 6F 67 72 61 6D 61 Programa Page0=2 8000 02 RegE 00 00
012A 20 34 20 2D 20 42 72 69 4 - Bri Page1=2 A000 03 RegF 00 CF
0132 6E 63 61 6E 64 6F 20 63 ncando c Page2=2 C000 00
013A 6F 6D 20 6C 6F 6F 70 73 om loops Page3=2 E000 00 PSG addr 0E
BrMSX settings
Resolution: 320x200 Frame skipping: 0001 Bar Graph: OFF Emulation: NORMAL
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:48/92
Joy: - Sound: ON VSync: OFF Session: SINGLE COM: 1 Video Cache: ON
Command: SCC: OFF

Voltou para zero! Uau! Ento o vilo da nossa historia esse "CALL BDOS"?!?
Sim, mais ou menos isso. A chamada da funo STROUT (9) do BDOS no preserva o
valor do registrador B. Isso faz com que nosso contador fique zoado!
Bem, agora j achamos o Bug... voltemos programao normal para tentar
corrigi-lo...
Corrigindo o Bug
Bem, ento o problema que precisamos "guardar" o contador em algum lugar
seguro antes de chamar a funo do BDOS. Poderamos colocar o valor em um outro
registrador, mas quem sabe qual deles seguro? Como essa aula pesada, no vou
introduzir novos conceitos. Vamos corrigir essa falha da mesma forma que
corrigimos quando descobrimos que perdamos o valor de E aps coletarmos o mesmo
com o CONIN, numa das aula anteriores: salvando na memria.
Assim, a nossa funozinha:
LD B,5 ; Indica repeticao de 5 vezes.
LOOP: LD DE,FUDEBA ; Indica texto fudeba
CALL MOSTRATXT ; Mostra texto
DJNZ LOOP ; Repete os comandos LD DE,FUDEBA e CALL MOSTRATXT
Fica:
LD B,5 ; Indica repeticao de 5 vezes.
LOOP: LD DE,FUDEBA ; Indica texto fudeba
LD A,B ; Copia em A o contador
LD (VAR1),A ; Grava o valor do contador na MEMORIA.
CALL MOSTRATXT ; Mostra texto
LD A,(VAR1) ; Copia para A o conteudo de VAR1
LD B,A ; Coloca de volta no contador
DJNZ LOOP ; Repete os comandos LD DE,FUDEBA e CALL MOSTRATXT
; Decrementando B ate ele ser zero.
Lembrando de acrescentar a VAR1 de volta na lista de variveis, no fim do
programa com:
VAR1: DB 000h
O programa final fica:
BDOS EQU 5
STROUT EQU 9
START:
; Mostra informacoes do programa e faz pergunta
LD DE,NOMEDOPRG ; Indica texto do nome do programa
CALL MOSTRATXT ; Mostra texto
LD DE,AUTOR ; Indica texto do nome do autor
CALL MOSTRATXT ; Mostra texto
LD B,5 ; Indica repeticao de 5 vezes.
LOOP: LD DE,FUDEBA ; Indica texto fudeba
LD A,B ; Copia em A o contador
LD (VAR1),A ; Grava o valor do contador na MEMORIA.
CALL MOSTRATXT ; Mostra texto
LD A,(VAR1) ; Copia para A o conteudo de VAR1
LD B,A ; Coloca de volta no contador
DJNZ LOOP ; Repete os comandos LD DE,FUDEBA e CALL
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:49/92
MOSTRATXT
JP 0 ; Volta ao MSX-DOS
;------
; MOSTRATXT - Funcao que mostra um texto cuja sequencia eh terminada por $.
; Entrada: DE - Aponta para sequencia a ser mostrada, terminada por $
;------
MOSTRATXT:
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
RET ; Retorna
NOMEDOPRG: DB Programa 4 - Brincando com loops,13,10,$
AUTOR: DB Por Daniel Caetano,13,10,10,$
FUDEBA: DB O DalPoz eh um fudeba!,13,10,$
VAR1: DB 000h
END
Que ao ser compilado e executado mostrar direitinho a mensagem 5 vezes.
Na prxima aula aprenderemos a mexer com alguns outros recursos do Z80, como
a PILHA, e tambm introduziremos alguns novos conceitos... Aguardem.
Um pouco mais sobre o FuDebug
Se voc ficou curioso l em cima, com o fato de ter usado o comando B 0100 e
o MSX-DOS continuar funcionando normalmente, inclusive com seus comandos, e o
BrMSX s' entrou quando o programinha foi executado, saiba que isso no magica
no. Na verdade, isso s ocorre porque o MSX-DOS no tem NADA de sua estrutura
na regio 0100h. E tambm no chama nenhuma funo de BIOS no endereo 0100h.
Caso essas duas condies no se verificassem, talvez ele pudesse parar num
endereo 0100h que no fosse o seu programa (fosse a posio 0100h de algum
outro slot que no o da memria). Principalmente no futuro, quando voc muitas
vezes usara o comando B (break) com endereos totalmente diferentes de 0100h
(para parar direto na posio 0109h, por exemplo). Bem voc precisa ficar
esperto para perceber isso. Um bom indicador so os valores dos "PAGE0" a
"PAGE3" da seo da PPI. Como seu programa est na RAM, se o endereo que voc
mandou parar estiver indicado como sendo um frame que no da RAM (0 ou 1, por
exemplo) com toda a certeza do mundo isso no ser um trecho do seu programa.
Conhecer bem seu programa tambm ajuda nessas horas. Assim, se parar no endereo
que voc queria, mas o contedo no o que voc esperava, aja simples:
pressione F7 para ele pular para o prximo endereo e use novamente o comando B
(break) indicando o mesmo endereo que havia dado anteriormente. Em geral isso
resolve.
Algumas palavras finais...
Povo,
Sei que esta aula pesada, e que o FuDebug pode parecer meio confuso no
comeo. Por ser poderoso, acaba sendo um pouco complexo mexer com ele tambm. No
entanto, com ele a programao fica centenas de vezes mais simples...! Eu no
mostrei nem 5% da capacidade dele. Com o tempo vamos conhecendo mais.
essencial que vocs "percam tempo" mexendo com ele, e fiquem craques. "defeitos"
como esse que mostrei no ultimo programa acontecem aos montes em programas
assembly mais complicados, e identificar na mo muitas vezes no possvel,
como nesse caso! Essa aula foi dividida em varias partes, e todas elas ficaram
enormes (ainda no preparei as outras, mas imagino o que vou colocar nelas) mas
agora que a coisa comea a andar, e coisas teis comeam a ser construdas.
Espero que o tempo que gastei bolando muita coisa que est aqui (meses) e o
tempo que gastei escrevendo essa aula (muitas e muitas horas, mesmo!). E o que
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:50/92
posso dizer que estou tentando fazer a minha parte, mas consultar outros
livros essencial a aprender a programar ASM. Com o pouco que eu passei, j
possvel pegar a lgica de como o assemblador funciona e, lendo um bom livro de
Assembly Z80 e tendo mo um MSX2 Technical Handbook j d at pra ir embora
sozinho... de modo que eu at pretendo dar continuidade no curso, mas adianto
que com preguia no se vai a lugar algum em ASM, porque os cdigos so,
costumeiramente, enormes e muito complexos, e demandam um bom tempo de tentativa
e erro para aprender a lidar com as dificuldades mais comuns.
O meu desafio : quero ver algum que consiga fazer algo interessante com o
que eu j passei at essa aula. Estou a disposio para responder duvidas e
ajudar com alguma coisa, mas assembly o tipo da coisa que s' praticando pra
aprender. Ningum aprende s lendo.
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:51/92
Aula V - Truques Matemticos I | Imprimindo Nmeros.
Originalmente eu havia pensado em dar um direcionamento este curso, mas ao
longo do ltimo ano (j faz mais de um ano desde a ltima aula) resolvi mudar
algumas coisas.
Percebi que a lgica principal do ASM j foi indicada nas 4 primeiras aulas e
que, se eu ficasse introduzindo comandos para otimizar apenas, grande parte do
interesse no curso seria prejudicado... j que a maioria das pessoas pretende
fazer coisas mais "divertidas" do que simplesmente otimizando um programa que
imprime textos na tela.
Desta forma, preparei um novo direcionamento que vai explicando como usar
caractersticas do VDP, PSG, FM, Z80 e PPI para obter coisas interessantes, ao
mesmo tempo em que vou introduzindo outros comandos do prprio Z80, bem como
mais detalhes de sua estrutura e da estrutura do MSX em si.
Quem ficar muito curioso com os registradores e comandos existentes do Z80,
indico o livro do Rossini e Figueredo que pode ser encontrado na pgina do MSX
Land ( http://www.geocities.com/msxland/msxlivros.html ), que a minha
principal fonte de referncia para as intrues do Z80.
Para esta aula estava previsto falar de duas coisas interessantes, contornando
as limitaes matemticas do Z80: vamos aprender a multiplicar e dividir com o
Z80.
Entretanto, para conseguir trabalhar com nmeros, precisamos primeiramente
aprender a imprimir nmeros, e posteriormente operar com eles... Assim, resolvi
falar primeiramente em como imprimir nmeros, para que numa aula posterior
possamos fazer conta com eles e ver os resultados destas contas.

Imprimindo Nmeros em Hexadecimal

Sabemos que o Z80 trabalha e faz contas com nmeros em binrio. Entretanto,
uma forma mais simples de ns, humanos, trabalharmos com esses nmeros, que tm
correspondncia direta com o binrio, usando a notao hexadecimal (base 16).
Alm disso, o jeito mais fcil de mostrar respostas numricas exatamente em
hexadecimal.
Vamos criar uma funo chamada HEX que converte um numero de 8 bits em uma
string terminada por $ do nmero, e HEXW que faz o mesmo, mas com um numero de
16 bits.
A entrada para estas funces devem ser:
1) o nmero
2) o endereo onde a string ser colocada
Vamos trabalhar primeiro com a HEX, j que como veremos em seguida, a HEXW
usar a funo HEX.
Quando pensamos em converter formatos, a primeira coisa que precisamos ter em
mente que temos de conhecer muito bem tanto a organizao inicial como a
organizao de sada, para que no faamos bobagem com os dados. Assim, pensemos
no que de fato um nmero de 8 bits...
Um nmero de 8 bits um nmero composto por 8 casas binrias, o que significa
que ele pode variar de 00000000b a 11111111b. Essa progresso se d da seguinte
forma:
00000000b = 000d = 00h
00000001b = 001d = 01h
00000010b = 002d = 02h
00000011b = 003d = 03h
00000100b = 004d = 04h
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:52/92
00000101b = 005d = 05h
...
11111010b = 250d = FAh
11111011b = 251d = FBh
11111100b = 252d = FCh
11111101b = 253d = FDh
11111110b = 254d = FEh
11111111b = 255d = FFh
Acima possvel ver alguns nmeros em binrio e sua representao binria,
decimal e hexadecimal. Deixemos de lado os nmeros decimais (no nos interessam
por enquanto) e trabalhemos apenas com os nmeros binrios e hexadecimais.
Como os nmeros hexadecimais tem unidades de 0 a F, podemos dizer que cada
unidade hexadecimal pode ser escrita com apenas 4 bits, segundo a
correspondncia abaixo:
0000b = 0h
0001b = 1h
0010b = 2h
0011b = 3h
0100b = 4h
0101b = 5h
0110b = 6h
0111b = 7h
1000b = 8h
1001b = 9h
1010b = Ah
1011b = Bh
1100b = Ch
1101b = Dh
1110b = Eh
1111b = Fh
Podemos reescrever a seqncia original de uma forma mais adequada
visualizao do processo de transformao de binrio para hexadecimal:
0000:0000b = 00h
0000:0001b = 01h
0000:0010b = 02h
0000:0011b = 03h
0000:0100b = 04h
0000:0101b = 05h
...
1111:1010b = FAh
1111:1011b = FBh
1111:1100b = FCh
1111:1101b = FDh
1111:1110b = FEh
1111:1111b = FFh

Esses "blocos" de 4 bits foi dado o nome de "nibble". Assim, um nmero de
8 bits composto de dois nibbles, um nibble alto (o mais da esquerda), e um
nibble baixo (o mais da direita). Assim, dizemos que existe uma correspondncia
direta entre o binrio e o hexadecimal, pois o nibble alto (esquerdo) pode ser
facilmente traduzido para o dgito hexadecimal correspondente (o da esquerda) e
o mesmo valendo para o nibble baixo (direito) correspondendo ao dgito direito
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:53/92
do hexadecimal.
Assim, a estratgia de converso de um nmero de 8 bits em um "texto"
hexadecimal separar o nmero de 8 bits em dois nibbles e usar o valor do
nibble para encontrar o dgito hexadecimal que ele representa.
Vamos tentar fazer isso com um cdigo... inicialmente um cdigo que no faz
nada disso, ser apenas o programa base que se utilizar de nossa funo.
BDOS EQU 5
STROUT EQU 9
START:
; Mostra informacoes do programa
LD DE,NOMEDOPRG ; Indica texto do nome do programa
CALL MOSTRATXT ; Mostra texto
LD DE,AUTOR ; Indica texto do nome do autor
CALL MOSTRATXT ; Mostra texto
JP 0 ; Volta ao MSX-DOS
;------
; MOSTRATXT - Funcao que mostra um texto cuja sequencia e terminada por $.
; Entrada: DE - Aponta para sequencia a ser mostrada, terminada por $
;------
MOSTRATXT:
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
RET ; Retorna
NOMEDOPRG: DB Programa 5a - Mostrando Numeros em Hexadecimal,13,10,$
AUTOR: DB Por Daniel Caetano,13,10,10,$
END
A primeira coisa criar uma funo deste tipo:
;------
; HEX - Converte um numero na RAM para um texto hex terminado por $.
; Entrada: DE - Posicao de memoria onde o texto sera colocado (3 bytes)
; A - Valor a ser "convertido"
;------
HEX:
RET
Vamos passo a passo agora. Como primeiro valor do texto deve ser o esquerdo
(pois escrevemos os nmeros da esquerda para a direita), o nibble mais alto deve
ser o primeiro a ser considerado.
Isso pode ser facilmente obtido, usando uma instruo do Z80 chamada SRL
(Shift Right and cLear), que faz exatamente deslocar todos os bits do
registrador e limpar o bit mais significativo. Aplicando quatro vezes seguidas
SRL no registrador A, teremos o efeito de obter diretamente o valor do nibble
superior. Vamos ver como isso funciona... com o nmero 111d, por exemplo, que
pode ser escrito como 01101111b ou 6Fh. Assim, o nibble alto que queremos isolar
o valor 0110b, ou seja, 6h
Instrucao Registrador A (binario) Registrador A (Hexa)
LD A,111d 01101111b 6Fh
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:54/92
SRL A 00110111b 37h
SRL A 00011011b 1Bh
SRL A 00001101b 0Dh
SRL A 00000110b 06h
Opa! Ento, aps quatro chamadas instruo SRL A, o valor do registrador A
ir nos indicar o valor correto do valor esquerdo do nmero em hexadecimal!
Queremos colocar isso em DE, certo? Ento a nossa funo fica assim:
;------
; HEX - Converte um numero na RAM para um texto hex terminado por $.
; Entrada: DE - Posicao de memoria onde o texto sera colocado (3 bytes)
; A - Valor a ser "convertido"
;------
HEX: SRL A ; Pega valor do nibble superior
SRL A
SRL A
SRL A
LD DE,A
RET
Correto? Bem, na verdade no. Primeiramente porque a instruo LD DE,A
ilegal, e fcil entender o porqu. O Z80 no sabe como atribuir o valor de um
registrador de 8 bits (A) a um registrador de 16 bits (DE), mesmo sabendo que DE
a unio de dois registradores de 8 bits (D e E).
O jeito "correto" de fazer isso seria:
LD D,0
LD E,A
Entretanto, observe que fazendo isso no estamos colocando o valor de A na
memria, e sim escrevendo ele no registrador DE (e por conseqncia apagando o
valor original, que era exatamente o endereo de memria onde
queramos registrar a resposta).
Para indicar para o Z80 que queremos colocar o valor de A na posio de
memria que nos foi indicada por DE, devemos mais uma vez recorrer
ao parntesis. Assim, a forma correta da instruo :
LD (DE),A
Que uma forma perfeitamente legal, j que ele coloca um nmero de 8 bits
numa posio de memria (a que tem o nome indicado por DE), que tambm de 8
bits. Nossa funo ento fica assim:
;------
; HEX - Converte um numero na RAM para um texto hex terminado por $.
; Entrada: DE - Posicao de memoria onde o texto sera colocado (3 bytes)
; A - Valor a ser "convertido"
;------
HEX: SRL A ; Pega valor do nibble superior
SRL A
SRL A
SRL A
LD (DE),A ; Guarda na memoria
RET

Estaria tima, SE no fosse um pequeno problema: ns jogamos fora o nibble
inferior (direito) de nosso nmero, e precisamos dele agora! A soluo para isso
guardar o valor de entrada, temporariamente, em algum outro lugar... no
registrador B, por exemplo, e depois recuperando-o em A. A funo fica assim:
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:55/92
;------
; HEX - Converte um numero na RAM para um texto hex terminado por $.
; Entrada: DE - Posicao de memoria onde o texto sera colocado (3 bytes)
; A - Valor a ser "convertido"
;------
HEX: LD B,A ; Salva valor original
SRL A ; Pega valor do nibble superior
SRL A
SRL A
SRL A
LD (DE),A ; Guarda na memoria
LD A,B ; Recupera valor numerico original
RET
E novamente temos o valor no registrador A... mas ele est novamente com o
nmero original... de onde precisamos tirar o dgito "direito" do nosso nmero
em hexadecimal. Isso mais fcil, pois basta mandarmos o Z80 zerar os dgitos
superiores, aplicando uma mscara lgica.
Mas que raios uma mscara lgica? Uma mscara lgica uma operao em
que podemos indicar quais so os bits que desejamos que sejam mantidos e todos
os outros sero zerados. A instruo que usamos para aplicar mscaras lgicas
a instruo AND. A instruo AND opera sobre o Acumulador (registrador A), sendo
que o parmetro passado para ela indica quais so os bits do registrador A que
sero preservados.
Vejamos isso numericamente:
Operacao Registrador A (binario):
LD A,01101110b 01101110b
AND 11000011b 01000010b
Onde o valor de A (01101110b) o valor original, e o parmetro do AND
(11000011b) a mscara.
Nossa... que coisa bizarra, no entendi o que aconteceu... \^= Vamos ento ver
por um outro ngulo:
Bit 76543210
A 01101110
AND 11000011
----------
01000010
A instruo AND opera da seguinte forma, bit a bit: se ambos os bits (do
nmero original e o da mscara) de uma dada posio forem 1, o resultado 1. Em
qualquer outro caso, a sada zero. Trata-se da operao "E" booleana, onde a
sada ser "verdadeiro" apenas se a primeira *E* a segunda entrada forem
verdadeiras:
1 AND 1 = 1
1 AND 0 = 0
0 AND 1 = 0
0 AND 0 = 0
Assim, a operao acima pode ser escrita como:
Bit 7 6 5 4 3 2 1 0
--------------------------------------------------------------------
0 1 1 0 1 1 1 0
AND 1 1 0 0 0 0 1 1
--- --- --- --- --- --- --- ---
0 1 0 0 0 0 1 0
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:56/92
Assim, fica fcil perceber que se queremos preservar os quatro bits da direita
(nibble inferior), devemos usar uma mscara do tipo 00001111b.
Ou seja, se j possumos o valor correto em A, basta usar a instruo
AND 00001111b
Para isolar o valor que desejamos no registrador A.
Instrucao Registrador A (binario) Registrador A (Hexa)
LD A,111d 01101111b 6Fh
AND 00001111b 00001111b 0Fh
E pronto! J temos o segundo byte do nosso texto em hexadecimal! Incorporando
isso na funo, teremos:
;------
; HEX - Converte um numero na RAM para um texto hex terminado por $.
; Entrada: DE - Posicao de memoria onde o texto sera colocado (3 bytes)
; A - Valor a ser "convertido"
;------
HEX: LD B,A ; Salva valor original
SRL A ; Pega valor do nibble superior
SRL A
SRL A
SRL A
LD (DE),A ; Guarda na memoria
LD A,B ; Recupera valor numerico original
AND 00001111b ; Aplica mascara (isola nibble inferior)
RET
Falta agora apenas coloc-lo na memria...
;------
; HEX - Converte um numero na RAM para um texto hex terminado por $.
; Entrada: DE - Posicao de memoria onde o texto sera colocado (3 bytes)
; A - Valor a ser "convertido"
;------
HEX: LD B,A ; Salva valor original
SRL A ; Pega valor do nibble superior
SRL A
SRL A
SRL A
LD (DE),A ; Guarda na memoria
LD A,B ; Recupera valor numerico original
AND 00001111b ; Aplica mascara (isola nibble inferior)
LD (DE),A
RET
E indicar o fim do texto, colocando o '$' na memria, o que pode ser
facilmente feito da seguinte forma:
LD A,$
LD (DE),A
Que inserido na funo d:
;------
; HEX - Converte um numero na RAM para um texto hex terminado por $.
; Entrada: DE - Posicao de memoria onde o texto sera colocado (3 bytes)
; A - Valor a ser "convertido"
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:57/92
;------
HEX: LD B,A ; Salva valor original
SRL A ; Pega valor do nibble superior
SRL A
SRL A
SRL A
LD (DE),A ; Guarda na memoria
LD A,B ; Recupera valor numerico original
AND 00001111b ; Aplica mascara (isola nibble inferior)
LD (DE),A
LD A,$
LD (DE),A
RET
E a funo est pronta. Podemos inser-la no nosso programa, para imprimir o
nmero 188d (BCh) na tela, ficando o programa assim:
BDOS EQU 5
STROUT EQU 9
START:
; Mostra informacoes do programa
LD DE,NOMEDOPRG ; Indica texto do nome do programa
CALL MOSTRATXT ; Mostra texto
LD DE,AUTOR ; Indica texto do nome do autor
CALL MOSTRATXT ; Mostra texto
; Converte numero
LD DE,NUMERO ; Indica posicao de memoria para resposta
LD A,188 ; Carrega Registrador A com o valor
CALL HEX ; Converte o valor para uma string
; Mostra numero
CALL MOSTRATXT ; Imprime o numero na tela
JP 0 ; Volta ao MSX-DOS
NOMEDOPRG: DB Programa 5a - Mostrando Numeros em Hexadecimal,13,10,$
AUTOR: DB Por Daniel Caetano,13,10,10,$
NUMERO: DB 0,0,0
;------
; MOSTRATXT - Funcao que mostra um texto cuja sequencia e terminada por $.
; Entrada: DE - Aponta para sequencia a ser mostrada, terminada por $
;------
MOSTRATXT:
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
RET ; Retorna
;------
; HEX - Converte um numero na RAM para um texto hex terminado por $.
; Entrada: DE - Posicao de memoria onde o texto sera colocado (3 bytes)
; A - Valor a ser "convertido"
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:58/92
;------
HEX: LD B,A ; Salva valor original
SRL A ; Pega valor do nibble superior
SRL A
SRL A
SRL A
LD (DE),A ; Guarda na memoria
LD A,B ; Recupera valor numerico original
AND 00001111b ; Aplica mascara (isola nibble inferior)
LD (DE),A
LD A,$
LD (DE),A
RET
END
Entretanto, ao executar vemos que... nada foi impresso! Por que isso acontece?
Voc pode analisar isso com o FuDebug, e vai descobrir que o problema est em
nossa funo HEX. Suponhamos que DE aponte para a posio de memria 1000h.
Ento, digamos que as posies 1000h, 1001h e 1002h esto disponveis para
colocarmos o primeiro e o segundo byte do nmero, MAIS o $ final. Ou seja:
Posicao O que deve conter
1000h Valor do Nibble Alto
1001h Valor do Nibble Baixo
1002h $
Mas quando observamos o que a nossa funo faz, vemos que ela coloca os trs
valores exatamente na mesma posio de memria! Ou seja, no fim de nossa rotina,
as posies de memria deveriam conter:
Posicao Valor
1000h Bh
1001h Ch
1002h $

Mas no isso que est acontecendo. O resultado est sendo:
Posicao Valor
1000h $
1001h 0
1002h 0
E, obviamente, quando mandarmos isso ser impresso, nada aparecer! O problema
est em que esquecemos de atualizar a posio de memria apontada por DE, de
forma que a cada valor que escrevemos na RAM, devemos indicar a
posio seguinte, para que o valor seguinte no sobreponha o anterior. Isso pode
ser feito usando-se a instruo:
INC DE
Onde INC significa INCremente, ou seja, INC DE significa adicione uma unidade
ao valor de DE. Como DE aponta um endereo de memria, INC DE pode ser traduzido
como "Aponte o prximo endereo de memria". Assim, sempre que escrevermos um
dado na posio de memria DE, devemos increment-la. O cdigo corrigido da
funo ser:
;------
; HEX - Converte um numero na RAM para um texto hex terminado por $.
; Entrada: DE - Posicao de memoria onde o texto sera colocado (3 bytes)
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:59/92
; A - Valor a ser "convertido"
;------
HEX: LD B,A ; Salva valor original
SRL A ; Pega valor do nibble superior
SRL A
SRL A
SRL A
LD (DE),A ; Guarda na memoria
INC DE ; Aponta proxima posicao de memoria
LD A,B ; Recupera valor numerico original
AND 00001111b ; Aplica mascara (isola nibble inferior)
LD (DE),A
INC DE ; Aponta proxima posicao de memoria
LD A,$
LD (DE),A
RET
Note que aps escrever '$' em DE eu no adicionei um INC DE, visto que no
previa escrever mais nada ali. Quando voltar dessa funo, portanto, DE vai
estar apontando para o '$'.
O programa final fica:
BDOS EQU 5
STROUT EQU 9
START:
; Mostra informacoes do programa
LD DE,NOMEDOPRG ; Indica texto do nome do programa
CALL MOSTRATXT ; Mostra texto
LD DE,AUTOR ; Indica texto do nome do autor
CALL MOSTRATXT ; Mostra texto
; Converte numero
LD DE,NUMERO ; Indica posicao de memoria para resposta
LD A,188 ; Carrega Registrador A com o valor
CALL HEX ; Converte o valor para uma string
; Mostra numero
CALL MOSTRATXT ; Imprime o numero na tela
JP 0 ; Volta ao MSX-DOS
NOMEDOPRG: DB Programa 5a - Mostrando Numeros em Hexadecimal,13,10,$
AUTOR: DB Por Daniel Caetano,13,10,10,$
NUMERO: DB 0,0,0
;------
; MOSTRATXT - Funcao que mostra um texto cuja sequencia e terminada por $.
; Entrada: DE - Aponta para sequencia a ser mostrada, terminada por $
;------
MOSTRATXT:
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
RET ; Retorna
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:60/92
;------
; HEX - Converte um numero na RAM para um texto hex terminado por $.
; Entrada: DE - Posicao de memoria onde o texto sera colocado (3 bytes)
; A - Valor a ser "convertido"
;------
HEX: LD B,A ; Salva valor original
SRL A ; Pega valor do nibble superior
SRL A
SRL A
SRL A
LD (DE),A ; Guarda na memoria
INC DE ; Aponta proxima posicao de memoria
LD A,B ; Recupera valor numerico original
AND 00001111b ; Aplica macara (isola nibble inferior)
LD (DE),A
INC DE ; Aponta proxima posicao de memoria
LD A,$
LD (DE),A
RET
END
E... ao executar... Ora pois! O problema continuou! Sim, o problema continuou,
mas por um motivo diferente. Lembra-se que eu disse que, na saida da funo HEX
o valor apontado por DE era o '$'? Pois ento.
Observe este trecho no programa principal:
; Converte numero
LD DE,NUMERO ; Indica posicao de memoria para resposta
LD A,188 ; Carrega Registrador A com o valor
CALL HEX ; Converte o valor para uma string
; Mostra numero
CALL MOSTRATXT ; Imprime o numero na tela
Como MOSTRATXT usa o valor apontado por DE para comear a imprimir, e
este valor o '$', que indica fim de impresso... Fica claro que *nada*
ser impresso. Isso pode ser corrigindo RECARREGANDO o endero do nmero a ser
mostrado, assim:
; Converte numero
LD DE,NUMERO ; Indica posicao de memoria para resposta
LD A,188 ; Carrega Registrador A com o valor
CALL HEX ; Converte o valor para uma string
; Mostra numero
LD DE,NUMERO ; Indica posicao de memoria com o numero
CALL MOSTRATXT ; Imprime o numero na tela
E o programa final fica:
BDOS EQU 5
STROUT EQU 9
START:
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:61/92
; Mostra informacoes do programa
LD DE,NOMEDOPRG ; Indica texto do nome do programa
CALL MOSTRATXT ; Mostra texto
LD DE,AUTOR ; Indica texto do nome do autor
CALL MOSTRATXT ; Mostra texto
; Converte numero
LD DE,NUMERO ; Indica posicao de memoria para resposta
LD A,188 ; Carrega Registrador A com o valor
CALL HEX ; Converte o valor para uma string
; Mostra numero
LD DE,NUMERO ; Indica posicao de memoria com o numero
CALL MOSTRATXT ; Imprime o numero na tela
JP 0 ; Volta ao MSX-DOS
NOMEDOPRG: DB Programa 5a - Mostrando Numeros em Hexadecimal,13,10,$
AUTOR: DB Por Daniel Caetano,13,10,10,$
NUMERO: DB 0,0,0
;------
; MOSTRATXT - Funcao que mostra um texto cuja sequencia e terminada por $.
; Entrada: DE - Aponta para sequencia a ser mostrada, terminada por $
;------
MOSTRATXT:
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
RET ; Retorna
;------
; HEX - Converte um numero na RAM para um texto hex terminado por $.
; Entrada: DE - Posicao de memoria onde o texto sera colocado (3 bytes)
; A - Valor a ser "convertido"
;------
HEX: LD B,A ; Salva valor original
SRL A ; Pega valor do nibble superior
SRL A
SRL A
SRL A
LD (DE),A ; Guarda na memaria
INC DE ; Aponta proxima posicao de memoria
LD A,B ; Recupera valor numerico original
AND 00001111b ; Aplica mascara (isola nibble inferior)
LD (DE),A
INC DE ; Aponta proxima posicao de memoria
LD A,$
LD (DE),A
RET
END
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:62/92
Ao executar esse cdigo... algo inesperado acontece. Lixo na tela e a tela se
limpa. O que tem de errado agora? Qual o erro?
Bem, o fato que realmente as posies de memria que mandamos o programa
escrever continham os nmeros em hexadecimal de 0 a 15 tanto do nibble alto
quanto do nibble baixo, mas no podemos nos esquecer que esses nmeros precisam
estar na *notao ASCII*. Ou seja, nao podemos ter um nmero de 0 a 15, mas sim
um nmero de 30h (valor ASCII de 0) a 39h (valor ASCII de 9) ou um valor de 41h
(valor ASCII de A) a 46h (valor ASCII de F). Ento precisamos criar uma funo
que converta um valor de 0 a 15 no valor ASCII correspondente.
Vou chamar essa funcao de DIG2ASCII (converte DIGito para ASCII). A idia
somar o valor 30h ao nmero, caso ele seja inferior a 10d (ou seja, de 0 a 9),
criando o valor 30h a 39h (ASCIIs de 0 a 9). Se o nmero for superior a 10d, a
idia subtrair 10d (Ah) e somar 41h (obtendo o valor 41 a 46h, que so os
valores ASCII de A a F).
A primeira coisa a fazer ser uma comparao para verificar se o valor do
registrador A menor que 10d (0Ah). Uma forma simples de fazer isso seria
subtrair 0Ah do registrador A (usando a instruo SUB) e verificar se o
resultado deu um "underflow". Um underflow significaria que eu subtra do
registrador um valor maior do que aquele que ele continha.
Mas como verificaramos se ocorreu um underflow? Bem, o Z80 tem um registrador
chamado F (Flags), em que cada bit representa uma coisa, dependendo da instruo
que se acabou de executar. Um destes bits chamado C (Carry) e serve para uma
poro de coisas. Uma delas indicar um underflow... (ou, se estivssemos
tratando em termos de nmeros positivos e negativos, que o nmero do acumulador
se tornou negativo).
A idia , ento, usar o valor do Carry para decidir qual parte do cdigo
executar. Para isso vamos recorrer instruo JP (JumP) novamente, que j vimos
na primeira aula... Mas agora com uma leve diferena:
JP C,endereo
Que significa: "Se o Carry estiver marcado, pule para o endereo". Ou seja,
podemos comear nossa funo assim:
;------
; DIG2ASCII - Converte um valor de 0 a 15 para seu correspondente ASCII
; Entrada: A - Valor a ser convertido
; Saida: A - Valor convertido
;------
DIG2ASCII:
SUB 10 ; Subtrai 10 do acumulador
JP C,D2ASC2 ; Se ficou negativo, era um numero de 0 a 9...
; Vai para rotina la pra frente
; Esta parte eh se o numero era maior ou igual a 10
ADD A,A ; Soma A com o valor ASCII de A
RET
D2ASC2: ; Parte que lida com numeros de 0 a 9
ADD A,0+10 ; Soma A com o valor ASCII de 0, MAIS o 10
; que tiramos no inicio da funcao
RET
Note que a instruo SUB 10 opera sobre o Acumulador (registrador A). No
existe SUB A,10 (no me pergunte o porqu, j que para ADD temos, por exemplo,
ADD A,10).
Essa funo pode ser inserida no nosso programa, usada para corrigir o valor
no registrador A antes dele ser armazenado na memria:
BDOS EQU 5
STROUT EQU 9
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:63/92
START:
; Mostra informacoes do programa
LD DE,NOMEDOPRG ; Indica texto do nome do programa
CALL MOSTRATXT ; Mostra texto
LD DE,AUTOR ; Indica texto do nome do autor
CALL MOSTRATXT ; Mostra texto
; Converte numero
LD DE,NUMERO ; Indica posicao de memoria para resposta
LD A,188 ; Carrega Registrador A com o valor
CALL HEX ; Converte o valor para uma string
; Mostra numero
LD DE,NUMERO ; Indica posicao de memoria com o numero
CALL MOSTRATXT ; Imprime o numero na tela
JP 0 ; Volta ao MSX-DOS
NOMEDOPRG: DB Programa 5a - Mostrando Numeros em Hexadecimal,13,10,$
AUTOR: DB Por Daniel Caetano,13,10,10,$
NUMERO: DB 0,0,0
;------
; MOSTRATXT - Funcao que mostra um texto cuja sequencia e terminada por $.
; Entrada: DE - Aponta para sequencia a ser mostrada, terminada por $
;------
MOSTRATXT:
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
RET ; Retorna
;------
; HEX - Converte um numero na RAM para um texto hex terminado por $.
; Entrada: DE - Posicao de memoria onde o texto sera colocado (3 bytes)
; A - Valor a ser "convertido"
;------
HEX: LD B,A ; Salva valor original
SRL A ; Pega valor do nibble superior
SRL A
SRL A
SRL A
CALL DIG2ASCII ; Converte valor de A para ASCII
LD (DE),A ; Guarda na memoria
INC DE ; Aponta proxima posicao de memoria
LD A,B ; Recupera valor numerico original
AND 00001111b ; Aplica mascara (isola nibble inferior)
CALL DIG2ASCII ; Converte valor de A para ASCII
LD (DE),A
INC DE ; Aponta proxima posicao de memoria
LD A,$
LD (DE),A
RET
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:64/92
;------
; DIG2ASCII - Converte um valor de 0 a 15 para seu correspondente ASCII
; Entrada: A - Valor a ser convertido
; Saida: A - Valor convertido
;------
DIG2ASCII:
SUB 10 ; Subtrai 10 do acumulador
JP C,D2ASC2 ; Se ficou negativo, era um numero de 0 a 9...
; Vai para rotina la pra frente
; Esta parte ehe se o numero era maior ou igual a 10
ADD A,A ; Soma A com o valor ASCII de A
RET
D2ASC2: ; Parte que lida com numeros de 0 a 9
ADD A,0+10 ; Soma A com o valor ASCII de 0, MAIS o 10
; que tiramos no inicio da funcao
RET
END
E finalmente nosso programa j responde corretamente. Podemos ainda mudar um
pouco a funo DIG2ASCII, aproveitando para introduzir o comando CP (ComPare). O
Compare faz EXATAMENTE o que fizemos com o SUB, mas sem afetar o valor do
registrador A. Ou seja, como se ele fizesse um SUB, preenchesse os flags (no
caso o flag C que nos interessa), mas recuperasse o valor original de A no fim
da operao. Embora isso no traga um ganho sensvel de performance (e, em
alguns casos, talvez o uso do SUB seja mais eficiente), o uso do CP torna o
cdigo mais legvel, pois ele diz exatamente o que se est fazendo.
O cdigo da funo DIG2ASCII usando CP seria:
;------
; DIG2ASCII - Converte um valor de 0 a 15 para seu correspondente ASCII
; Entrada: A - Valor a ser convertido
; Saida: A - Valor convertido
;------
DIG2ASCII:
CP 10 ; Compara A com 10
JP C,D2ASC2 ; Se A era menor que 10, pula pro fim
; Vai para rotina la pra frente
; Esta parte eh se o numero era maior ou igual a 10
ADD A,A-10 ; Soma A com o valor ASCII de A, subtraindo
; 10 (jaque nao foi subtraido no inicio).
RET
D2ASC2: ; Parte que lida com numeros de 0 a 9
ADD A,0 ; Soma A com o valor ASCII de 0
RET
Uma forma de "otimizar" um pouco essa funo seria torn-la serial. Desta
forma, aceleraramos o processamento para numeros de 0 a 9, em contrapartida
tornaramos mais lento o processo para nmeros de A a F.
Entretanto, eliminaremos o JP do processo, o que usualmente significa um ganho
de performance:
;------
; DIG2ASCII - Converte um valor de 0 a 15 para seu correspondente ASCII
; Entrada: A - Valor a ser convertido
; Saida: A - Valor convertido
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:65/92
;------
DIG2ASCII:
ADD A,0 ; Soma o valor ASCII de 0 indepentende do
; valor original de A
CP 9+1 ; Verifica se o valor em A eh menor que o
; valor de 9 + 1 (ou seja, se eh menor ou
; igual a 9)
RET C ; Se sim, vai embora...!
; Aqui eh caso o valor seja maior... ou seja, A a F
ADD A,A-(0+10) ; Corrige para um valor de A a F
RET
Observe o uso do valor do flag C (Carry) em outra instruo: a instruo RET.
A instruo RET tambm pode utiliz-lo. Neste caso ela significa:
"RETorne se o flag C estiver marcado".
Finalmente, nosso programa de imprimir um nmero de 8 bits est pronto.
BDOS EQU 5
STROUT EQU 9
START:
; Mostra informacoes do programa
LD DE,NOMEDOPRG ; Indica texto do nome do programa
CALL MOSTRATXT ; Mostra texto
LD DE,AUTOR ; Indica texto do nome do autor
CALL MOSTRATXT ; Mostra texto
; Converte numero
LD DE,NUMERO ; Indica posicao de memoria para resposta
LD A,188 ; Carrega Registrador A com o valor
CALL HEX ; Converte o valor para uma string
; Mostra numero
LD DE,NUMERO ; Indica posicao de memoria com o numero
CALL MOSTRATXT ; Imprime o numero na tela
JP 0 ; Volta ao MSX-DOS
NOMEDOPRG: DB Programa 5a - Mostrando Numeros em Hexadecimal,13,10,$
AUTOR: DB Por Daniel Caetano,13,10,10,$
NUMERO: DB 0,0,0
;------
; MOSTRATXT - Funcao que mostra um texto cuja sequencia e terminada por $.
; Entrada: DE - Aponta para sequencia a ser mostrada, terminada por $
;------
MOSTRATXT:
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
RET ; Retorna
;------
; HEX - Converte um numero na RAM para um texto hex terminado por $.
; Entrada: DE - Posicao de memoria onde o texto sera colocado (3 bytes)
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:66/92
; A - Valor a ser "convertido"
;------
HEX: LD B,A ; Salva valor original
SRL A ; Pega valor do nibble superior
SRL A
SRL A
SRL A
CALL DIG2ASCII ; Converte valor de A para ASCII
LD (DE),A ; Guarda na memoria
INC DE ; Aponta proxima posicao de memoria
LD A,B ; Recupera valor numerico original
AND 00001111b ; Aplica mascara (isola nibble inferior)
CALL DIG2ASCII ; Converte valor de A para ASCII
LD (DE),A
INC DE ; Aponta proxima posicao de memoria
LD A,$
LD (DE),A
RET
;------
; DIG2ASCII - Converte um valor de 0 a 15 para seu correspondente ASCII
; Entrada: A - Valor a ser convertido
; Saida: A - Valor convertido
;------
DIG2ASCII:
ADD A,0 ; Soma o valor ASCII de 0 indepentende do
; valor original de A
CP 9+1 ; Verifica se o valor em A eh menor que o
; valor de 9 + 1 (ou seja, se eh menor ou
; igual a 9)
RET C ; Se sim, vai embora...!
; Aqui eh caso o valor seja maior... ou seja, A a F
ADD A,A-(0+10) ; Corrige para um valor de A a F
RET
END
--- Cortar Aqui ---
Agora vamos adicionar nele a rotina HEXW, que converte um nmero de 16 bits
para uma string. A idia a mesma, mas veja... um nmero de 16 bits pode ser
entendido assim:
Binario Hexadecimal
0000:1101:0110:1111 = 0D6F
Ou seja, a idia de que cada dgito do nmero hexadecimal um nible do nmero
binrio permanece. Podemos dizer que um nmero de 16 bits e' composto por dois
bytes: o byte alto e o byte baixo. Assim, podemos decompor o nmero acima em:
Binario Hexadecimal
0000:1101 0110:1111 = 0D 6F
Assim, podemos usar a nossa funo HEX j pronta como parte da funo HEXW.
Podemos criar a base da funo HEXW assim:
;------
; HEXW - Converte um numero na RAM para um texto hex terminado por $.
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:67/92
; Entrada: DE - Posicao de memoria onde o texto sera colocado (5 bytes)
; HL - Valor a ser "convertido"
;------
HEXW:
RET
Sabendo que H o byte alto do nmero de 16 bits (tamanho tambm conhecido
como PALAVRA ou WORD... da o nome HEXW, ou o HEX para Words), ele ser o que
ficar mais esquerda do nmero, ento deve ser colocado na string antes. A
funo fica assim:
;------
; HEXW - Converte um numero na RAM para um texto hex terminado por $.
; Entrada: DE - Posicao de memoria onde o texto sera colocado (5 bytes)
; HL - Valor a ser "convertido"
; Modifica: A, DE
;------
HEXW: LD A,H
CALL HEX
RET
Note que, como o valor de DE j vem pronto, no precisamos mexer nele. Note
tambm que o fato da funo HEX deixar DE apontando sobre o '$' vai nos ajudar
agora... vejamos o porqu:
Suponhamos que DE apontasse para 1000h. Teramos 1000h, 1001h, 1002h, 1003h e
1004h para colocarmos o nosso numero de 16 bits. Ou seja:
Posicao Valor
1000h Nibble alto do byte alto
1001h Nibble baixo do byte alto
1002h Nibble alto do byte alto
1003h Nibble baixo do bayte alto
1004h $
Ora, aps a primeira chamada de HEX, temos:
Posicao Valor
1000h Nibble alto do byte alto
1001h Nibble baixo do byte alto
1002h $
1003h 0
1004h 0
Com DE apontando para 1002h, que exatamente onde queremos comear a
impresso do byte baixo! Assim, nem precisamos corrigir o valor de DE, basta
corrigir o valor de A com o valor do byte baixo e novamente chamar a rotina HEX.
Assim, a nossa verso final de HEXW ser:
;------
; HEXW - Converte um numero na RAM para um texto hex terminado por $.
; Entrada: DE - Posicao de memoria onde o texto sera colocado (5 bytes)
; HL - Valor a ser "convertido"
; Modifica: A, DE
;------
HEXW: LD A,H
CALL HEX
LD A,L
CALL HEX
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:68/92
RET
E pronto. Vamos inser-la em nosso programa, e cham-la na rotina principal:
--- Cortar Aqui ---
BDOS EQU 5
STROUT EQU 9
START:
; Mostra informacoes do programa
LD DE,NOMEDOPRG ; Indica texto do nome do programa
CALL MOSTRATXT ; Mostra texto
LD DE,AUTOR ; Indica texto do nome do autor
CALL MOSTRATXT ; Mostra texto
; Mostra numero de 8 bits
LD DE,NUMERO ; Indica posicao de memoria para resposta
LD A,188 ; Carrega Registrador A com o valor
CALL HEX ; Converte o valor para uma string
LD DE,NUMERO ; Indica posicao de memoria com o numero
CALL MOSTRATXT ; Imprime o numero na tela
; Pula uma linha
LD DE,PULALINHA ; Indica "texto"
CALL MOSTRATXT ; Imprime
; Mostra numero de 16 bits
LD DE,NUMERO16 ; Indica posicao de memoria para resposta
LD HL,04DC2h ; Carrega Registrador HL com o valor
CALL HEXW ; Converte o valor para uma string
LD DE,NUMERO16 ; Indica posicao de memoria com o numero
CALL MOSTRATXT ; Imprime o numero na tela
JP 0 ; Volta ao MSX-DOS
NOMEDOPRG: DB Programa 5a - Mostrando Numeros em Hexadecimal,13,10,$
AUTOR: DB Por Daniel Caetano,13,10,10,$
NUMERO: DB 0,0,0
PULALINHA: DB 13,10,$
NUMERO16: DB 0,0,0,0,0
;------
; MOSTRATXT - Funcao que mostra um texto cuja sequencia e terminada por $.
; Entrada: DE - Aponta para sequencia a ser mostrada, terminada por $
;------
MOSTRATXT:
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
RET ; Retorna
;------
; HEX - Converte um numero na RAM para um texto hex terminado por $.
; Entrada: DE - Posicao de memoria onde o texto sera colocado (3 bytes)
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:69/92
; A - Valor a ser "convertido"
;------
HEX: LD B,A ; Salva valor original
SRL A ; Pega valor do nibble superior
SRL A
SRL A
SRL A
CALL DIG2ASCII ; Converte valor de A para ASCII
LD (DE),A ; Guarda na memoria
INC DE ; Aponta proxima posicao de memoria
LD A,B ; Recupera valor numerico original
AND 00001111b ; Aplica mascara (isola nibble inferior)
CALL DIG2ASCII ; Converte valor de A para ASCII
LD (DE),A
INC DE ; Aponta proxima posicao de memoria
LD A,$
LD (DE),A
RET
;------
; DIG2ASCII - Converte um valor de 0 a 15 para seu correspondente ASCII
; Entrada: A - Valor a ser convertido
; Saida: A - Valor convertido
;------
DIG2ASCII:
ADD A,0 ; Soma o valor ASCII de 0 indepentende do
; valor original de A
CP 9+1 ; Verifica se o valor em A eh menor que o
; valor de 9 + 1 (ou seja, se eh menor ou
; igual a 9)
RET C ; Se sim, vai embora...!
; Aqui eh caso o valor seja maior... ou seja, A a F
ADD A,A-(0+10) ; Corrige para um valor de A a F
RET
;------
; HEXW - Converte um numero na RAM para um texto hex terminado por $.
; Entrada: DE - Posicao de memoria onde o texto sera colocado (5 bytes)
; HL - Valor a ser "convertido"
; Modifica: A, DE
;------
HEXW: LD A,H
CALL HEX
LD A,L
CALL HEX
RET
END
Bem, chegamos aqui ao fim desta aula... Espero que a despeito do "peso" dessa
aula todos tenham conseguido acompanhar. No nada de outro mundo, mas
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:70/92
certamente parece um monstro quando pensamos que em Basic, C ou pascal
conseguimos imprimir esses valores com um nico "PRINT". Entretanto, por trs
deste "PRINT" tem tudo isso que acabamos de ver aqui.
Fica como proposta de pensamento analisar o porque seria mais complicado
imprimir os nmeros em decimal - algo que o Z80 ajuda a fazer atravs de algumas
instrues que, possivelmente, veremos no futuro.
Mais uma vez estou a berto a sugestes... mas no me perguntem quando a
prxima aula sai. S a ttulo de curiosidade, estou h quase 6 horas preparando
esta "msera" aula, um tempo que certamente no tenho com
freqncia.
Espero que apreciem, pois esta aqui amplia bastante os horizontes,
introduzindo no s uma rotina importante como a impresso de nmeros, mas
tambm comandos condicionais por flags, como CALL, RET e JP, alm da instruo
CP.
Detalhes sobre instrues que afetam e so afetadas por flags podem ser, mais
uma vez, encontradas no livro do Rossini e Figueredo, sendo que a explicao
detalhada de cada flag, instruo e operao do Z80 foge completamente ao escopo
deste curso.
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:71/92
Aula VI
Truques Matemticos II - Muliplicaes com o Z80
Na aula passada vimos de maneira detalhada a forma de imprimir nmeros em
hexadecinal. Juntamente com isso, vimos alguns conceitos importantes sobre
valores binrios, deslocamentos de bits e coisas deste tipo.
Como foi possvel ver, existiu uma converso razoavelmente complexa entre a
forma que o computador trabalha com os nmeros para que pudssemos ver o
resultado na tela. Isso indica uma coisa: o computador lida com os nmeros de
uma forma bem diferente da nossa, e melhor fugir dos nmeros decimais na hora
de implementar funes matemticas no computador.
Fundamentalmente, na maioria das vezes iremos implementar usando exatamente a
mesma idia que usamos nas contas decimais que fazemos mo, mas sempre tomando
o cuidado de adapt-las para que funcionem em base binria... Evitando assim
muita perda de tempo de processamento.
Nesta aula vamos criar uma funo interessante: MULUU. Esta funo deve
multiplicar um numero de 8 bits por outro de 8 bits, gerando um nmero de 16
bits.
Deixaremos a diviso para uma aula posterior, caso contrrio essa aula seria
literalmente interminvel.
Multiplicando 2 Nmeros
Como era de se esperar, o nosso programa base desta aula ser baseado no
programa final da aula 5. O esqueleto est reproduzido abaixo:
BDOS EQU 5
STROUT EQU 9
START:
; Mostra informacoes do programa
LD DE,NOMEDOPRG ; Indica texto do nome do programa
CALL MOSTRATXT ; Mostra texto
LD DE,AUTOR ; Indica texto do nome do autor
CALL MOSTRATXT ; Mostra texto
JP 0 ; Volta ao MSX-DOS
NOMEDOPRG: DB Programa 6a - Multiplicando Numeros.,13,10,$
AUTOR: DB Por Daniel Caetano,13,10,10,$
PULALINHA: DB 13,10,$
;------
; MOSTRATXT - Funcao que mostra um texto cuja sequencia e terminada por $.
; Entrada: DE - Aponta para sequencia a ser mostrada, terminada por $
;------
MOSTRATXT:
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
RET ; Retorna
;------
; HEX - Converte um numero na RAM para um texto hex terminado por $.
; Entrada: DE - Posicao de memoria onde o texto ser! colocado (3 bytes)
; A - Valor a ser "convertido"
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:72/92
;------
HEX: LD B,A ; Salva valor original
SRL A ; Pega valor do nibble superior
SRL A
SRL A
SRL A
CALL DIG2ASCII ; Converte valor de A para ASCII
LD (DE),A ; Guarda na memoria
INC DE ; Aponta proxima posicao de memoria
LD A,B ; Recupera valor numerico original
AND 00001111b ; Aplica mascara (isola nibble inferior)
CALL DIG2ASCII ; Converte valor de A para ASCII
LD (DE),A
INC DE ; Aponta proxima posicao de memoria
LD A,$
LD (DE),A
RET
;------
; DIG2ASCII - Converte um valor de 0 a 15 para seu correspondente ASCII
; Entrada: A - Valor a ser convertido
; Sa"da: A - Valor convertido
;------
DIG2ASCII:
ADD A,0 ; Soma o valor ASCII de 0 indepentende do
; valor original de A
CP 9+1 ; Verifica se o valor em A eh menor que o
; valor de 9 + 1 (ou seja, se ehmenor ou
; igual a 9)
RET C ; Se sim, vai embora...!
; Aqui eh caso o valor seja maior... ou seja, A a F
ADD A,A-(0+10) ; Corrige para um valor de A a F
RET
;------
; HEXW - Converte um numero na RAM para um texto hex terminado por $.
; Entrada: DE - Posiaco de memoria onde o texto sera colocado (5 bytes)
; HL - Valor a ser "convertido"
; Modifica: A, DE
;------
HEXW: LD A,H
CALL HEX
LD A,L
CALL HEX
RET
END
A primeira coisa que podemos definir que a nossa nova funo ter a seguinte
cara:
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:73/92
;------
; MULUU - Multiplica um numero de 8 bits por outro de 8 bits (sem sinal)
; Entrada: L - Multiplicando
; A - Multiplicador
; Saida: A - Produto
;------
MULUU:
RET
Bem, pensemos um pouco. Como fazer um processador que s faz soma e subtrao
realizar uma multiplicao? A forma mais simples, baseada naquela que aprendemos
quando crianas na escola, fazer um monte de somas... Afinal, correto
afirmar que:
5 * 1 = 1 + 1 + 1 + 1 + 1 = 5
7 * 3 = 7 + 7 + 7 = 21
Opa! Isso parece uma tarefa para aquela instruo bizarra da aula 4... o DJNZ!
Para quem j se esqueceu, o DJNZ uma instruo que significa "Decrement B and
Jump if Not Zero". Se fizermos uma construo do tipo:
LD B,n
LOOP: ; Operacoes
DJNZ LOOP
As operaes sero realizadas "n" vezes! Ora... se 7*3 = somar 7 por 3
vezes... Hum! Interessante. Implementando essa idia, temos que colocar o valor
de A em B, e ir somando L vrias vezes... O que resulta em:
;------
; MULUU - Multiplica um numero de 8 bits por outro de 8 bits (sem sinal)
; Entrada: L - Multiplicando
; A - Multiplicador
; Saida: A - Produto
;------
MULUU:
LD B,A
MUUL: ADD A,L
DJNZ MUUL
RET
E pronto! No nosso programa teramos:
BDOS EQU 5
STROUT EQU 9
START:
; Mostra informacoes do programa
LD DE,NOMEDOPRG ; Indica texto do nome do programa
CALL MOSTRATXT ; Mostra texto
LD DE,AUTOR ; Indica texto do nome do autor
CALL MOSTRATXT ; Mostra texto
LD L,010h ; Multiplicando
LD A,005h ; Multiplicador
CALL MULUU ; Chama multiplicacao (resultado em A)
LD DE,NUMERO ; Indica posicao do texto
CALL HEX ; Converte para ASCII
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:74/92

LD DE,NUMERO ; Aponta numero
CALL MOSTRATXT ; Imprime
JP 0 ; Volta ao MSX-DOS
NOMEDOPRG: DB Programa 6a - Multiplicando Numeros.,13,10,$
AUTOR: DB Por Daniel Caetano,13,10,10,$
NUMERO: DB 0,0,0
PULALINHA: DB 13,10,$
;------
; MULUU - Multiplica um numero de 8 bits por outro de 8 bits (sem sinal)
; Entrada: L - Multiplicando
; A - Multiplicador
; Saida: A - Produto
;------
MULUU:
LD B,A
MUUL: ADD A,L
DJNZ MUUL
RET
;------
; MOSTRATXT - Funcao que mostra um texto cuja sequencia e terminada por $.
; Entrada: DE - Aponta para sequencia a ser mostrada, terminada por $
;------
MOSTRATXT:
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
RET ; Retorna
;------
; HEX - Converte um numero na RAM para um texto hex terminado por $.
; Entrada: DE - Posicao de memoria onde o texto sera colocado (3 bytes)
; A - Valor a ser "convertido"
;------
HEX: LD B,A ; Salva valor original
SRL A ; Pega valor do nibble superior
SRL A
SRL A
SRL A
CALL DIG2ASCII ; Converte valor de A para ASCII
LD (DE),A ; Guarda na memoria
INC DE ; Aponta proxima posicao de memoria
LD A,B ; Recupera valor numerico original
AND 00001111b ; Aplica mascara (isola nibble inferior)
CALL DIG2ASCII ; Converte valor de A para ASCII
LD (DE),A
INC DE ; Aponta proxima posicao de memoria
LD A,$
LD (DE),A
RET
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:75/92
;------
; DIG2ASCII - Converte um valor de 0 a 15 para seu correspondente ASCII
; Entrada: A - Valor a ser convertido
; Saida: A - Valor convertido
;------
DIG2ASCII:
ADD A,0 ; Soma o valor ASCII de 0 indepentende do
; valor original de A
CP 9+1 ; Verifica se o valor em A eh menor que o
; valor de 9 + 1 (ou seja, se eh menor ou
; igual a 9)
RET C ; Se sim, vai embora...!
; Aqui eh caso o valor seja maior... ou seja, A a F
ADD A,A-(0+10) ; Corrige para um valor de A a F
RET
;------
; HEXW - Converte um numero na RAM para um texto hex terminado por $.
; Entrada: DE - Posicao de memoria onde o texto sera colocado (5 bytes)
; HL - Valor a ser "convertido"
; Modifica: A, DE
;------
HEXW: LD A,H
CALL HEX
LD A,L
CALL HEX
RET
END
Entretanto, ao rodar esse programa... Algo estranho aconteceu. O nmero
impresso nada tem a ver com a resposta esperada. O programa nos retornou o valor
55h, quando bem sabemos que 5h * 10h = 50h! O que est errado?!
Analisemos com calma aquilo que a funo est fazendo: Colocamos o nmero de
repeties em B e somamos B vezes L em A... opa! Estamos somando o valor em A,
antes de ter zerado o valor de A... ento, na realidade, fizemos 5h * 10h + 5h =
55h! Isso pode ser corrigido ento, usando a seguinte modificao:
;------
; MULUU - Multiplica um numero de 8 bits por outro de 8 bits (sem sinal)
; Entrada: L - Multiplicando
; A - Multiplicador
; Saida: A - Produto
;------
MULUU:
LD B,A
LD A,0
MUUL: ADD A,L
DJNZ MUUL
RET
E pronto! A vai conter o resultado da multiplicao na sada da funo, e o
programa imprime corretamente o valor 50h. Entretanto, basta substituir:
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:76/92
LD L,010h ; Multiplicando
LD A,005h ; Multiplicador
Por algo como:
LD L,082h ; Multiplicando
LD A,005h ; Multiplicador
Que a nossa alegria vai para o vinagre. O programa passa a responder 8A,
quando deveria responder 28A. O que est errado? Certamente a nossa concepo do
problema. Observe que o valor mximo possvel de se guardar em um registrador de
8 bits FFh. 28Ah um nmero bem superior a FFh.
A soluo ento para isso usar um registrador de mais bits. Quantos? Bem, se
estamos multiplicando dois nmeros de 8 bits... temos, por uma regra matemtica
simples, que:
(2^8 * 2^8) = 2^(8+8) = 2^16
Ou seja, basta um nmero de 16 bits que conseguiremos, com sucesso, armazenar
qualquer resultado de uma multiplicao entre dois nmeros de 8 bits. Uma outra
forma de ver isso seria pensar assim: qual o maior nmero de 8 bits possvel?
FFh. Quanto vale FFh * FFh ? FE01. Assim, um nmero capaz de armazenar FE01 ser
suficiente para guardar resultado de uma multiplicao de 8 bits por 8 bits.
Assim, iremos usar o registrador HL, o que implica que precisamos inicializar,
antes de mais nada, o valor de H:
------
; MULUU - Multiplica um numero de 8 bits por outro de 8 bits (sem sinal)
; Entrada: L - Multiplicando
; A - Multiplicador
; Saida: HL - Produto
;------
MULUU:
LD H,0 ; Zera H...
LD B,A ; Indica numero de vezes
LD A,0 ; Zera acumulador
MUUL: ADD A,L ; Soma B vezes o valor de L
DJNZ MUUL
LD L,A ; Copia pro destino
RET
Ao inserir essa funo no programa principal, algumas mudanas precisam ser
realizadas no corpo do cdigo. O programa completo fica:
BDOS EQU 5
STROUT EQU 9
START:
; Mostra informacoes do programa
LD DE,NOMEDOPRG ; Indica texto do nome do programa
CALL MOSTRATXT ; Mostra texto
LD DE,AUTOR ; Indica texto do nome do autor
CALL MOSTRATXT ; Mostra texto
LD L,082h ; Multiplicando
LD A,005h ; Multiplicador
CALL MULUU ; Chama multiplicacao
; HL j! vem com o valor da reposta
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:77/92
LD DE,NUMERO ; Indica posicao do texto
CALL HEXW ; Converte para ASCII

LD DE,NUMERO ; Aponta numero
CALL MOSTRATXT ; Imprime
JP 0 ; Volta ao MSX-DOS
NOMEDOPRG: DB Programa 6a - Multiplicando Numeros.,13,10,$
AUTOR: DB Por Daniel Caetano,13,10,10,$
NUMERO: DB 0,0,0,0,0
PULALINHA: DB 13,10,$
;------
; MULUU - Multiplica um numero de 8 bits por outro de 8 bits (sem sinal)
; Entrada: L - Multiplicando
; A - Multiplicador
; Saida: HL - Produto
;------
MULUU:
LD H,0 ; Zera H...
LD B,A ; Indica numero de vezes
LD A,0 ; Zera acumulador
MUUL: ADD A,L ; Soma B vezes o valor de L
DJNZ MUUL
LD L,A ; Copia pro destino
RET
;------
; MOSTRATXT - Funcao que mostra um texto cuja sequencia e terminada por $.
; Entrada: DE - Aponta para sequencia a ser mostrada, terminada por $
;------
MOSTRATXT:
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
RET ; Retorna
;------
; HEX - Converte um numero na RAM para um texto hex terminado por $.
; Entrada: DE - Posicao de memoria onde o texto sera colocado (3 bytes)
; A - Valor a ser "convertido"
;------
HEX: LD B,A ; Salva valor original
SRL A ; Pega valor do nibble superior
SRL A
SRL A
SRL A
CALL DIG2ASCII ; Converte valor de A para ASCII
LD (DE),A ; Guarda na memoria
INC DE ; Aponta proxima posicao de memoria
LD A,B ; Recupera valor numurico original
AND 00001111b ; Aplica mascara (isola nibble inferior)
CALL DIG2ASCII ; Converte valor de A para ASCII
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:78/92
LD (DE),A
INC DE ; Aponta proxima posicao de memoria
LD A,$
LD (DE),A
RET
;------
; DIG2ASCII - Converte um valor de 0 a 15 para seu correspondente ASCII
; Entrada: A - Valor a ser convertido
; Saida: A - Valor convertido
;------
DIG2ASCII:
ADD A,0 ; Soma o valor ASCII de 0 indepentende do
; valor original de A
CP 9+1 ; Verifica se o valor em A eh menor que o
; valor de 9 + 1 (ou seja, se eh menor ou
; igual a 9)
RET C ; Se sim, vai embora...!
; Aqui eh caso o valor seja maior... ou seja, A a F
ADD A,A-(0+10) ; Corrige para um valor de A a F
RET
;------
; HEXW - Converte um numero na RAM para um texto hex terminado por $.
; Entrada: DE - Posicao de memoria onde o texto sera colocado (5 bytes)
; HL - Valor a ser "convertido"
; Modifica: A, DE
;------
HEXW: LD A,H
CALL HEX
LD A,L
CALL HEX
RET
END
Entretanto... mais uma vez, ao rodar o programa, a decepo: O programa
responde 008A, quando deveria responder 028A. O que ainda est errado?
Analisemos, mais uma vez, com calma.
;------
; MULUU - Multiplica um numero de 8 bits por outro de 8 bits (sem sinal)
; Entrada: L - Multiplicando
; A - Multiplicador
; Saida: HL - Produto
;------
MULUU:
LD H,0 ; Zera H...
LD B,A ; Indica numero de vezes
LD A,0 ; Zera acumulador
MUUL: ADD A,L ; Soma B vezes o valor de L
DJNZ MUUL
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:79/92
LD L,A ; Copia pro destino
RET
Se pensarmos bem, estamos ainda fazendo a conta s com 8 bits, pois estamos
usando o registrador A para realizar o clculo. E, com efeito, devemos realizar
com o registrador HL! Assim, a funcao deve ser modificada da seguinte forma:
;------
; MULUU - Multiplica um numero de 8 bits por outro de 8 bits (sem sinal)
; Entrada: L - Multiplicando
; A - Multiplicador
; Saida: HL - Produto
;------
MULUU:
LD H,0 ; Zera H... HL agora contem o numero a ser multiplicado
LD D,H ; Zera DE
LD E,H
EX DE,HL ; Troca o conteudo de DE com HL (HL fica 0000 e DE fica o multiplicando)
LD B,A ; Indica numero de vezes
MUUL: ADD HL,DE ; Soma B vezes o valor de DE em HL
DJNZ MUUL
RET
Isso corrige o problema dos 8 bits para 16 bits. Entretanto, se percebermos
bem... Caso o multiplicador seja ZERO teremos uma reposta errada: a
multiplicao ocorrer, mas ser uma multiplicao por 256!
Ora, e por que isso acontece? Por uma peculiaridade do DJNZ. O DJNZ decrementa
o valor de B antes de test-lo. Desta forma, se enviarmos um valor ZERO como
multiplicador, este valor ser colocado em B e, ao ser decrementado, se tornar
FFh. Desta forma, a multiplicao no ser finalizada e o resultado ser
incorreto.
Para corrigir isso, basta que verifiquemos, no incio, se o valor do
multiplicador zero e, se for, iremos embora. Para isso, utilizaremos um CP 0 e
um RET Z (RETurn if Zero). Note que colocamos isso em um local que HL tem um
valor zero, assim o valor da soluo estar correto (0*n = 0):
;------
; MULUU - Multiplica um numero de 8 bits por outro de 8 bits (sem sinal)
; Entrada: L - Multiplicando
; A - Multiplicador
; Saida: HL - Produto
;------
MULUU:
LD H,0 ; Zera H... HL agora contem o numero a ser multiplicado
LD D,H ; Zera DE
LD E,H
EX DE,HL ; Troca o conteudo de DE com HL (HL fica 0000 e DE fica o multiplicando)
CP 0 ; Verifica se A eh zero
RET Z ; Vai embora se for
LD B,A ; Indica numero de vezes
MUUL: ADD HL,DE ; Soma B vezes o valor de DE em HL
DJNZ MUUL
RET
Com essas correes, nossa funo de multiplicar est pronta! O programa final
completo tem este aspecto:
BDOS EQU 5
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:80/92
STROUT EQU 9
START:
; Mostra informacoes do programa
LD DE,NOMEDOPRG ; Indica texto do nome do programa
CALL MOSTRATXT ; Mostra texto
LD DE,AUTOR ; Indica texto do nome do autor
CALL MOSTRATXT ; Mostra texto
LD L,082h ; Multiplicando
LD A,005h ; Multiplicador
CALL MULUU ; Chama multiplicacao
; HL javem com o valor da reposta
LD DE,NUMERO ; Indica posicao do texto
CALL HEXW ; Converte para ASCII

LD DE,NUMERO ; Aponta numero
CALL MOSTRATXT ; Imprime
JP 0 ; Volta ao MSX-DOS
NOMEDOPRG: DB Programa 6a - Multiplicando Numeros.,13,10,$
AUTOR: DB Por Daniel Caetano,13,10,10,$
NUMERO: DB 0,0,0,0,0
PULALINHA: DB 13,10,$
;------
; MULUU - Multiplica um numero de 8 bits por outro de 8 bits (sem sinal)
; Entrada: L - Multiplicando
; A - Multiplicador
; Saida: HL - Produto
;------
MULUU:
LD H,0 ; Zera H... HL agora contem o numero a ser multiplicado
LD D,H ; Zera DE
LD E,H
EX DE,HL ; Troca o conteudo de DE com HL (HL fica 0000 e DE fica o multiplicando)
CP 0 ; Verifica se A eh zero
RET Z ; Vai embora se for
LD B,A ; Indica numero de vezes
MUUL: ADD HL,DE ; Soma B vezes o valor de DE em HL
DJNZ MUUL
RET
;------
; MOSTRATXT - Funcao que mostra um texto cuja sequencia e terminada por $.
; Entrada: DE - Aponta para sequencia a ser mostrada, terminada por $
;------
MOSTRATXT:
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
RET ; Retorna
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:81/92
;------
; HEX - Converte um numero na RAM para um texto hex terminado por $.
; Entrada: DE - Posicao de memoria onde o texto sera colocado (3 bytes)
; A - Valor a ser "convertido"
;------
HEX: LD B,A ; Salva valor original
SRL A ; Pega valor do nibble superior
SRL A
SRL A
SRL A
CALL DIG2ASCII ; Converte valor de A para ASCII
LD (DE),A ; Guarda na memoria
INC DE ; Aponta proxima posicao de memoria
LD A,B ; Recupera valor numerico original
AND 00001111b ; Aplica mascara (isola nibble inferior)
CALL DIG2ASCII ; Converte valor de A para ASCII
LD (DE),A
INC DE ; Aponta proxima posicao de memoria
LD A,$
LD (DE),A
RET
;------
; DIG2ASCII - Converte um valor de 0 a 15 para seu correspondente ASCII
; Entrada: A - Valor a ser convertido
; SaIda: A - Valor convertido
;------
DIG2ASCII:
ADD A,0 ; Soma o valor ASCII de 0 indepentende do
; valor original de A
CP 9+1 ; Verifica se o valor em A eh menor que o
; valor de 9 + 1 (ou seja, se eh menor ou
; igual a 9)
RET C ; Se sim, vai embora...!
; Aqui eh caso o valor seja maior... ou seja, A a F
ADD A,A-(0+10) ; Corrige para um valor de A a F
RET
;------
; HEXW - Converte um numero na RAM para um texto hex terminado por $.
; Entrada: DE - Posicao de memoria onde o texto sera colocado (5 bytes)
; HL - Valor a ser "convertido"
; Modifica: A, DE
;------
HEXW: LD A,H
CALL HEX
LD A,L
CALL HEX
RET
END
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:82/92
Entretanto, vocs devem ter percebido que essa funo um tanto quanto lenta.
Se precisarmos realizar muitas dessas operaes por segundo, podemos ter um
problema realmente srio. Em especial se substituirmos isso:
LD L,082h ; Multiplicando
LD A,005h ; Multiplicador
Por uma operao deste tipo:
LD L,082h ; Multiplicando
LD A,0FFh ; Multiplicador
Uma forma de acelerar neste caso, seria escolher o menor valor como sendo o
multiplicador... Entretanto essa soluo no resolve todos os problemas. Por
exemplo, se a operao a ser realizada for:
LD L,0FFh ; Multiplicando
LD A,0FFh ; Multiplicador
No h muita alternativa... no ? Sim, claro que h. (^=
Vamos voltar um pouco teoria e pensar: Como fazemos contas de multiplicar?
Obviamente ninguem fica contando nos dedos o nmero de vezes... Nem usa
palitinho. E, de certa forma, foi isso que ensinamos o computador fazer.
Ns no fazemos isso manualmente porque lento e desajeitado. No h muita
razo para imaginar que seria diferente para o computador. Pensemos ento: como
fazmos conta de multiplicao no papel?
A idia da multiplicao no papel a seguinte:
134 x 7 reproduzida na seguinte operao:
7*4 = 28. Fica 8 e vai dois.
7*3 = 21 mais dois = 23. Fica 3, vai 2.
7*1 = 7 mais 2 = 9. Fica 9.
Com isso construmos a primeira operao: multiplicamos o multiplicando pelo
primeiro dgito do multiplicador. Costumamos desenhar isso da seguinte forma:
134
x7
---
938
Ora, podemos escrever tambm essa operao de forma inversa:
7
x134
----
938
Embora seja anti-natural, ela facilita um pouco a explicao do que est por
vir. Como realizaramos essa conta, agora?
4*7 = 28.
Reescreveramos isso assim:
7
x134
----
28
+
3*7 = 21.
Compondo a segunda etapa:
7
x134
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:83/92
----
28
21+
++
1*7 = 7.

Sendo finalmente:
7
x134
----
28
21+
7++
----
938
Mas esses "+" no parecem ajudar muito na explicao matemtica, certo? Uma
outra forma de realizar este mesmo clculo, mais elucidativa matematicamente,
seria:
7
x134
----
938
4*7 = 28.
...
7
x134
----
28

30*7 = 210.
...
7
x134
----
28
210
100*7 = 700.
Sendo finalmente:
7
x134
----
28
+ 210
+ 700
----
938
Pode-se dizer ento que fizemos foi o seguinte:
134 * 7 = 1*4*7 + 10*3*7 + 100*1*7
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:84/92
= (10^0)*4*7 + (10^1)*3*7 + (10^2)*1*7
O que fizemos aqui foi transformar uma multiplicao de um nmero complicado
em uma sequncias de multiplicaes por nmeros entre 0 e 9 (nmeros da base
decimal, em cada uma das etapas), multiplicaes por potncias de 10, ou seja,
da base (entre cada etapa) e finalmente em um nmero de somas que igual ao
nmero de dgitos do multiplicador (no caso, 3).
O que aconteceria se transformssemos essa lgica para uma multiplicao de
lgica binria? Poderamos escrever, por exemplo, que:
4 * 3
00000100b * 00000011b
Seria como? Vamos tentar aplicar a mesma lgica: Multiplicar o primeiro dgito
do nultiplicador pelo multiplicando, multiplicado pela base elevada a zero; o
segundo dgito do multiplicador pelo multiplicando, multiplicado pela base
elevada a um; o terceiro dgido to multiplicador pelo multiplicando,
multiplicado pela base elevada a dois... e assim por diante:
00000100b * 00000011b
1o. Digito do Multiplicador:
0 * 00000011b * 2^0 = 0
2o. Digito do Multiplicador:
0 * 00000011b * 2^1 = 0
3o. Digito do Multiplicador:
1 * 00000011b * 2^2 = 00000011b * 4 = 00001100b
... (todos os outros dgitos do multiplicador so zero)
Somando todos estes resultados:
00000000b + 00000000b + 00001100b = 00001100b = 12
E 12 exatamente o valor do clculo 4*3!
Qual a vantagem de se fazer isso? Se observarmos bem, podemos reescrever
assim:
1o. Digito do Multiplicador:
0 * 00000011b * 2^0 = 0 * 00000011b * 1 = 0 * 00000011b
2o. Digito do Multiplicador:
0 * 00000011b * 2^1 = 0 * 00000011b * 2 = 0 * 00000110b
3o. Digito do Multiplicador:
1 * 00000011b * 2^2 = 1 * 00000011b * 4 = 1 * 00001100b
...
Observem os valores mais da direita... Eles significam que podemos transformar
uma multiplicacao em uma sequncia de somas de valores... e esses valores, vo
sendo deslocados uma casa esquerda em cada iterao!
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:85/92
Parece estranho, mas... exatamente ESSA a funo daquele "+", "++", "+++" ...
que colocamos numa operao como essa:
7
x134
----
28
21+
7++
----
938
Podemos dizer que "escrever esse +" uma boa forma de realizar potncias da
base utilizada sem ter de pensar muito a respeito!
Assim, um bom algoritmo de multiplicao pode se utilizar dessa "manha" para
reduzir seu loop. Uma multiplicacao de dois nmeros de 8 bits se reduzir de 255
somas (no pior caso) para 8 somas e 8 deslocamentos esquerda!
Um bom algoritmo para realizar isso, em binrio, seria:
0- Zera-se resultado.
1- Primeira casa do multiplicador um?
No? Pula pro passo 2.
Sim? Soma ao resultado o multiplicando
2- Rotaciona-se o multiplicando esquerda
Segunda casa do multiplicador um?
No? Pula pro passo 3.
Sim? Soma ao resultado o multiplicando.
3- Rotaciona-se o multiplicando esquerda
Terceira casa do multiplicador um?
No? Pula pro passo 4.
Sim? Soma ao resultado o multiplicando.
... e assim por diante at serem verificadas as 8 casas do multiplicador.
Nesta primeira implementao usaremos algumas instrues de rotao novas:
RRCA, SLA e RL. O que essas instrues fazem?
RRCA - Rotate Right (with Copy) Accumulator. Em lngua de gente, a RRCA
rotaciona o acumulador pra direita, jogando o bit 7 pro bit 6, o bit 6 pro bit 5
e assim por diante... at o bit 0, que jogado no bit 7. Alm disso, uma cpia
do bit 0 sempre jogada no carry. Desta forma, depois de aplicada 8 vezes esta
instruo faz o Acumulador (registrador A) voltar a ter exatamente o mesmo valor
original. Usaremos essa instruo para poder testar bit por bit do acumulador,
usando-se do flag Carry para isso (o qual podemos usar facilmente em instrues
JP (JumP) e JR (Jump Relative).
SLA - Shift Left And clear. Apesar do nome bizarro o que esta rotina faz
simples. Ela desloca para a esquerda os bits de um registrador qualquer, jogando
bit 7 no flag Carry, o bit 6 no bit 7, o bit 5 no bit 6... at o bit 0 no bit 1.
E no lugar no bit 0 um bit de valor "0" inserido. Trocando em midos,
multiplica um registrador por 2 e indica no carry se "foi um". Usaremos essa
para multiplicar o byte menos significativo do multiplicando.
RL - Rotate Left. Essa aqui a mais simples de rodas. Simplesmente rotaciona
um registrador pra esquerda, jogando o contedo do flag Carry no bit 0, o bit 0
no bit 1, o bit 2 no bit 2... at o bit 7, que vai parar no carry. Como temos um
possvel "vai um" no byte menos significativo, essa instruo vai fazer no byte
mais significativo uma multiplicao por 2 caso o valor do Carry for zero (no
houve "vai um") ou ento far uma multiplicao por 2 e em seguida somar 1,
caso o valor do Carry seja zero.
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:86/92
Com essas instrues, podemos implementar a multiplicao da seguinte forma:
;------
; MULUU - Multiplica um numero de 8 bits por outro de 8 bits (sem sinal)
; Entrada: L - Multiplicando
; A - Multiplicador
; Saida: HL - Produto
;------
MULUU:
LD H,0 ; Zera H... HL agora contem o numero a ser multiplicado
LD D,H ; Zera DE
LD E,H
EX DE,HL ; Troca o conteudo de DE com HL (HL fica 0000 e DE fica o multiplicando)
LD B,8 ; Repetir 8 vezes, uma vez pra cada bit
MUUL: ; Verifica o bit mais baixo de A
RRCA ; Joga bit mais baixo de A no flag Carry
JR NC,MUUL2 ; Se era zero, nao soma nada ao HL.
; Aqui se bit valia 1, entao vai somar...
ADD HL,DE
MUUL2: ; Faz o Shift pra esquerda em DE (multiplica DE por 2)
SLA E ; Shifta E pra direita, jogando bit mais significativo no Carry
RL D ; Rotaciona D, colocando o bit do carry no bit 0
DJNZ MUUL ; Repete 8 vezes
RET
Apesar da rotina ser bem maior, ela seguramente, no caso mdio, bem mais
rpida que a de somas simples, que fazia todas as somas. Essa rotina sempre vai
fazer 24 shifts e de 0 a 8 somas. A rotina de somas simples podia, em alguns
casos, realizar apenas algumas poucas somas. Mas para qualquer nmero maior que
32, por exemplo, esta rotina ser mais eficiente.
Esta forma de raciocnio extensvel e permite realizar operaes com bem
mais de 16 e 8 bits (quantos for desejado). Obviamente nestes casos necessrio
um pouco mais de controle sobre alguns flags, mas a idia basicamente a mesma.
Vale ressaltar que para alguns casos especiais, pode no ser interessante usar
essa rotina. Por exemplo, se voce sempre vai multiplicar por nmeros entre 1 e
15, por exemplo, pode considerar uma rotina que conte s at o quarto bit,
mudando a
linha:
LD B,8 ; Repetir 8 vezes, uma vez pra cada bit
para:
LD B,4 ; Repetir 4 vezes, uma vez pra cada bit
Se a maioria das vezes a multiplicao por nmeros pequenos, mas s vezes o
nmero grande, talvez seja interessante trocar o DJNZ por algo um pouco
diferente:
;------
; MULUU - Multiplica um numero de 8 bits por outro de 8 bits (sem sinal)
; Entrada: L - Multiplicando
; A - Multiplicador
; Saida: HL - Produto
;------
MULUU:
LD H,0 ; Zera H... HL agora contem o numero a ser multiplicado
LD D,H ; Zera DE
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:87/92
LD E,H
EX DE,HL ; Troca o conteudo de DE com HL (HL fica 0000 e DE fica o multiplicando)
MUUL: ; Verifica o bit mais baixo de A
SRL A ; Joga bit mais baixo no flag Carry
JR NC,MUUL2 ; Se era zero, nao soma nada ao HL.
; Aqui se bit valia 1, entao vai somar...
ADD HL,DE
MUUL2: ; Faz o Shift pra esquerda em DE (multiplica DE por 2)
SLA E ; Shifta E pra direita, jogando bit mais significativo no Carry
RL D ; Rotaciona D, colocando o bit do carry no bit 0
CP 0 ; Verifica se A virou zero
JR NZ,MUUL ; Se A ainda nao eh zero, continua o loop
RET
Note as diferenas importantes: primeiramente trocamos o RRCA pelo SRL. Por
que isso? Bem, a idia desta segunda implementao ir "limpando" o
multiplicador medida que testamos seus bits, de forma que quando ele for zero
a rotina ser finalizada, mesmo que nem todos os 8 bits tenham sido testados um
a um (se o multiplicador virou zero, significa que todos os bits restantes so
zero, e portanto no h mais nada a somar).
Ora, como eu disse, o RRCA deixa o Acumulador intocado (e ainda por cima faz o
favor de "suj-lo" com o valor desconhecido do Carry durante as 8 rotaes).
Obviamente esta instruo no serve para o nosso propsito. Precisamos de uma
instruo que v jogando os bits do registrador no Carry, deslocando-os para a
direita, e inserindo um zero no bit 7. Pois exatamente isso que a instruo
SRL faz:
SRL - Shift Right and cLear the most significant bit. Ou seja, desloca todos
os bits pra direita (bit 0 vai pro Carry, bit 1 vai pro bit 0... e assim por
diante... e o bit 7 ganha um bit de valor "0" nele). Assim, na pior hiptese,
aps 8 instrues destas seguidas... o registrador sempre valer zero.
Ora, mas ento ... porqu eu no propus essa forma originalmente? Bem, vamos
analisar qual o "overhead" adicionado com as instrues extras, por etapa da
operao:
Saiu TStates Entrou TStates
RRCA 4+1 = 5 SRL 8+2 = 10
DJNZ 13+1 = 14 CP 0 + JR NZ 4+1 + 12+1 = 18
Ora, acrescentamos um overhead de (10-5)+(18-14) = 9 TStates em cada rodada do
Loop. preciso que esses 9 TStates por loop sejam compensados pela reduo de
rodadas. De fato, no melhor caso do loop "original" (quando o bit sendo testado
zero), o tempo de uma rodada do loop SRL + JR NC (verdadeiro) + SLA + RL +
DJNZ. O tempo disso 10 + 13 + 10 + 10 + 18 = 61 T States. Como na verso
modificada temos apenas 9 TStates a mais por loop, vejamos a tabela:
Bit mais alto TStates TStates Variacao
No multiplicador economizados gastos a mais
5 61*2 = 122 9*6 = 54 -68
6 61*1 = 61 9*7 = 63 2
7 61*0 = 0 9*8 = 72 72
Por essa conta simples fica fcil de ver que, quando tivermos um nmero de at
6 bits, (multiplicadores de 0 a 63) no vale a pena usar a verso "original" da
rotina, melhor usar a verso extendida (o ganho tanto maior quanto menor for
o multiplicador, pois h uma economia de tempo cada vez maior). Para nmeros
entre 64 e 127 o desempenho praticamente o mesmo, sendo ligeiramente mais
rpido na verso original.
Para nmeros maiores (de 128 a 255), a verso original claramente mais
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:88/92
rpida, e portanto a verso "mexida" perde o sentido. Assim, importante fazer
uma anlise de qual o problema que se est resolvendo e usar uma ou outra
rotina. Veja que embora a maior parte dos nmeros (64 a 255) seja resolvido mais
rapidamente pela verso "original", os ganhos so brutais para multiplicadores
entre 0 e 63 na verso extendida.
Na dvida de qual o escopo de solues, talvez seja mais interessante ficar
com a verso original.
O programa desta aula, com a verso "original" (que sempre executa os 8 passos
do loop) da funo tem a seguinte cara:
BDOS EQU 5
STROUT EQU 9
START:
; Mostra informacoes do programa
LD DE,NOMEDOPRG ; Indica texto do nome do programa
CALL MOSTRATXT ; Mostra texto
LD DE,AUTOR ; Indica texto do nome do autor
CALL MOSTRATXT ; Mostra texto
LD L,082h ; Multiplicando
LD A,005h ; Multiplicador
CALL MULUU ; Chama multiplicacao
; HL j! vem com o valor da reposta
LD DE,NUMERO ; Indica posicao do texto
CALL HEXW ; Converte para ASCII

LD DE,NUMERO ; Aponta numero
CALL MOSTRATXT ; Imprime
JP 0 ; Volta ao MSX-DOS
NOMEDOPRG: DB Programa 6a - Multiplicando Numeros.,13,10,$
AUTOR: DB Por Daniel Caetano,13,10,10,$
NUMERO: DB 0,0,0,0,0
PULALINHA: DB 13,10,$
;------
; MULUU - Multiplica um numero de 8 bits por outro de 8 bits (sem sinal)
; Entrada: L - Multiplicando
; A - Multiplicador
; Saida: HL - Produto
;------
MULUU:
LD H,0 ; Zera H... HL agora contem o numero a ser multiplicado
LD D,H ; Zera DE
LD E,H
EX DE,HL ; Troca o conteudo de DE com HL (HL fica 0000 e DE fica o multiplicando)
LD B,8 ; Repetir 8 vezes, uma vez pra cada bit
MUUL: ; Verifica o bit mais baixo de A
RRCA ; Joga bit mais baixo de A no flag Carry
JR NC,MUUL2 ; Se era zero, nao soma nada ao HL.
; Aqui se bit valia 1, entao vai somar...
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:89/92
ADD HL,DE
MUUL2: ; Faz o Shift pra esquerda em DE (multiplica DE por 2)
SLA E ; Shifta E pra direita, jogando bit mais significativo no Carry
RL D ; Rotaciona D, colocando o bit do carry no bit 0
DJNZ MUUL ; Repete 8 vezes
RET
;------
; MOSTRATXT - Funcao que mostra um texto cuja sequencia e terminada por $.
; Entrada: DE - Aponta para sequencia a ser mostrada, terminada por $
;------
MOSTRATXT:
LD C,STROUT ; Indica funcao de mostrar texto do BDOS
CALL BDOS ; Manda o BDOS executar.
RET ; Retorna
;------
; HEX - Converte um numero na RAM para um texto hex terminado por $.
; Entrada: DE - Posicao de memoria onde o texto sera colocado (3 bytes)
; A - Valor a ser "convertido"
;------
HEX: LD B,A ; Salva valor original
SRL A ; Pega valor do nibble superior
SRL A
SRL A
SRL A
CALL DIG2ASCII ; Converte valor de A para ASCII
LD (DE),A ; Guarda na memoria
INC DE ; Aponta proxima posicao de memoria
LD A,B ; Recupera valor numerico original
AND 00001111b ; Aplica mascara (isola nibble inferior)
CALL DIG2ASCII ; Converte valor de A para ASCII
LD (DE),A
INC DE ; Aponta proxima posicao de memoria
LD A,$
LD (DE),A
RET
;------
; DIG2ASCII - Converte um valor de 0 a 15 para seu correspondente ASCII
; Entrada: A - Valor a ser convertido
; Saida: A - Valor convertido
;------
DIG2ASCII:
ADD A,0 ; Soma o valor ASCII de 0 indepentende do
; valor original de A
CP 9+1 ; Verifica se o valor em A eh menor que o
; valor de 9 + 1 (ou seja, se eh menor ou
; igual a 9)
RET C ; Se sim, vai embora...!
; Aqui eh caso o valor seja maior... ou seja, A a F
ADD A,A-(0+10) ; Corrige para um valor de A a F
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:90/92
RET
;------
; HEXW - Converte um numero na RAM para um texto hex terminado por $.
; Entrada: DE - Posicao de memoria onde o texto sera colocado (5 bytes)
; HL - Valor a ser "convertido"
; Modifica: A, DE
;------
HEXW: LD A,H
CALL HEX
LD A,L
CALL HEX
RET
END
Entretanto, essas so sempre as melhores solues? De forma alguma. Essas so
timas solues para clculos mais "genricos", por assim dizer... quando de
antemo voc no sabe exatamente o tipo de multiplicao que vai realizar.
Por exemplo: tem um jeito muito mais rpido e eficiente de realizar
multiplicaes quando se tratam de potncias de dois, que simplesmente fazer o
nmero de shifts adequados, sem loops, sem toda essa parafernalha. Alis, uma
boa idia, quando a velocidade algo realmente fundamental, abrir esses
loops, ou seja: tirar fora o DJNZ ou o JR NZ... e simplesmente copiar 8 vezes a
rotina. Com isso o ganho razovel, j que cada um desses DJNZs ou CP 0 + JR NZ
levam respectivamente 14 T States e 18 T States para serem executados. (^=
Uma outra aproximao usar uma tabela pr-fixada, mas essa soluo s
vivel quando a multiplicao sempre por um nmero fixo. Cria-se uma tabela
com as respostas na seguinte forma:
MULTTBL:
DW RESULTADO0 ; N*0
DW RESULTADO1 ; N*1
DW RESULTADO2 ; N*2
(...)
DW RESULTADO255 ; N*255
E para o clculo da multiplicao a nossa funo fica:
;------
; MULNU - Multiplica N por um numero de 8 bits
; Entrada: A - Multiplicador
; Saida: HL - Produto
;------
MULNU: LD L,A ; Coloca multiplicador em HL
LD H,0
ADD HL,HL ; Multiplica por 2 (offset da tabela)
LD DE,MULTTBL ; Coloca endereco base da tabela em DE
ADD HL,DE ; Calcula posicao da memoria que contem a solucao, em HL
LD A,(HL) ; Pega solucao em HL
INC HL
LD H,(HL)
LD L,A
RET
MULTTBL:
DW RESULTADO0 ; N*0
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:91/92
DW RESULTADO1 ; N*1
DW RESULTADO2 ; N*2
(...)
DW RESULTADO255 ; N*255
Essa uma soluo de alto desempenho, mas gasta uma grande quantidade de
memria. Essa , alis, uma das grandes dicotomias do ASM. Muitas vezes para
acelerar voc obrigado a gastar mais espao, e muitas vezes para economizar
espao voc deixa as coisas mais lentas.
Note, entretanto, que isso no uma regra sem exceo. Cdigos mal planejados
tornam-se maiores e mais lentos do que seria necessrio. Nem sempre um cdigo
enorme sinnimo de rpido e nem sempre um cdigo pequeno sinnimo de lento.
Como sempre... h casos e casos.
Curso Fudeba de Assembler Z80 MSX Computers Jan/2014
Autor:DanielCaetano(http://www.amusementfactory.com.br/main/?p=casm) Pagina:92/92

S-ar putea să vă placă și