0 evaluări0% au considerat acest document util (0 voturi)
86 vizualizări93 pagini
Este documento apresenta uma introdução ao curso de assembler Z80 para computadores MSX. Nele, o autor explica como escrever o primeiro programa em assembler que imprime "Alo, Mundo" na tela do computador MSX usando a função 9 do MSX-DOS. Ele descreve como colocar a string de texto na memória do computador e definir o endereço de memória na "cola" DE para que a função 9 possa acessar a string e imprimi-la.
Este documento apresenta uma introdução ao curso de assembler Z80 para computadores MSX. Nele, o autor explica como escrever o primeiro programa em assembler que imprime "Alo, Mundo" na tela do computador MSX usando a função 9 do MSX-DOS. Ele descreve como colocar a string de texto na memória do computador e definir o endereço de memória na "cola" DE para que a função 9 possa acessar a string e imprimi-la.
Este documento apresenta uma introdução ao curso de assembler Z80 para computadores MSX. Nele, o autor explica como escrever o primeiro programa em assembler que imprime "Alo, Mundo" na tela do computador MSX usando a função 9 do MSX-DOS. Ele descreve como colocar a string de texto na memória do computador e definir o endereço de memória na "cola" DE para que a função 9 possa acessar a string e imprimi-la.
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