terça-feira, 23 de maio de 2023

Relógio BCD para o TK85 no ZX Assembler da Artic

Um relógio BCD (binary-coded decimal) mostra os dígitos decimais em formato binário. Cada dígito decimal das horas, minutos e segundos está codificado em binário. Assim, cada coluna corresponde a um dígito do relógio (HH:MM:SS), mas em formato binário: quadrados preenchidos = 1, quadrados vazios = 0.

A leitura dos valores no caso do relógio que implementei se dá de baixo para cima. A primeira linha de bits tem valor 1, a segunda 2, a terceira 4 e a quarta 8. O valor resultante é a soma dos valores dos bits. Na figura abaixo, por exemplo, o bits da quinta coluna somam 5 e o da sexta coluna 9, indicando 59 segundos.

O relógio BCD com os valores de cada casa de bits e o horário: são 12h 46min e 59s.

Bom, foi isso que eu procurei implementar para a linha Sinclair ZX81. Já tinha feito um relógio BCD bem simples no BASIC do MSX numa manhã de domingo. Mas desta vez quis fazer algo na tela cheia, então fui de assembly para dar conta das limitações do TK85. Olha aí ele fornecendo as horas:



Para executar, digite RUN e entre com o horário. Confirme e pronto. Lá está o seu relógio BCD funcionado.

Durante o seu funcionamento, se você pressionar a tecla "D" (de decimal) as horas vão aparecer com dígitos normais no canto superior esquerdo da tecla. Tecle "D" novamente para que esse recurso desapareça. Pressionando a tecla "NEW LINE", o programa para e volta ao BASIC. É preciso de um pouco de paciência com esses comandos, já que a leitura do teclado só é feita na virada de cada segundo.

Segue o link para download do arquivo .p:

Download

Sobre o ZX Assembler da Artic

Para falar a verdade, a programação do relógio surgiu apenas como desculpa para  experimentar o ZX Assembler, da britânica Artic Computing Ltd. Queria ver como seria a programação em assembly utilizando uma ferramenta nativa. Eu procuro utilizar assemblers nativos em todas as máquinas que programo: GEN80 e Mega Assembler no MSX, Edtasm no TRS-80 e Edtasm+ para o TRS-Color. Mas no caso do ZX81, pensava que as limitações seriam torturantes demais e, por isso, estava utilizando o Pasmo para gerar o binário Z80 e o appmake (este do pacote z88dk) para gerar o arquivo ".p". Mais um pequeno bash script e o fluxo de trabalho fica simplesmente fantástico, gerando o arquivo .p no diretório do emulador e um arquivo texto (.lst) com a listagem dos endereços de montagem para referência, se necessário. E tudo no terminal, já que não uso ambiente gráfico para emulação no Raspberry Pi.

Mas sobre a impossibilidade prática de utilizar o micro real para programação assembly, eu estava enganado, pelo menos em parte. Para minha grata surpresa, depois de um "Hello World" no ZX Assembler, descobri que é sim possível trabalhar nativamente na máquina. Isto é, desde que não se utilize fita cassete como mídia (imagine carregar o ZX Assembler por 3:30 minutos, mais o  tempo de carregamento do programa fonte, toda vez que der um pau na execução do programa? Não dá). Então resolvi fazer algo para ver o quanto é viável utilizá-lo em projetos maiores. É verdade que, para isso, utilizei o emulador. Mas o fluxo de trabalho não seria muito diferente caso o usuário possua uma ZXpand ou um Blue Drive da vida. Eu aqui tenho um Blue Drive mas meu TK85, perfeitinho e original, não tem o mod de vídeo-composto que a ROM de 50Hz do Blue Drive exige, e a tela fica rolando no RF. Um dia eu resolvo essa história.

Obviamente, o ZX Assembler é bastante simples e limitado, mas ao mesmo tempo a forma que foi implementado é surpreendentemente inteligente. A primeira coisa que me chamou a atenção foi o editor: gostei muito por ser simples, limpo e direto. Diria é quase perfeito e que faltou apenas um par de comandos, page up e page down para navegar no texto mais rápido. Em lugar disso o programador pode lançar mão de uma busca por um rótulo para ir direto ao ponto do programa a ser editado. Mas no geral, excelente editor.

O montador em si é minimalista. Você dá o comando e se o montador não encontrar erros, não diz nada, apenas volta para o prompt. E como a montagem se dá na memória, é extremamente rápida. Se o programa encontrar um erro na montagem, sinaliza o tipo de erro e, se o usuário teclar "E" para voltar ao editor, a linha com erro já é mostrada. Simplicidade genial. 

A forma como o ZX Assembler contorna os problemas de design do ZX81 também é ótima. Pra quem não conhece, o código de máquina no ZX81 deve ficar guardado em uma linha REM, para poder ser salvo. Não há outra forma (simples) de salvar um programa em código de máquina. Assim, o ZX Assembler gera o código-objeto na linha 1 do BASIC, e o código-fonte assembly na linha 2. O programador pode então adicionar código em BASIC a partir da linha 3 em diante. Eventuais alterações nos códigos fonte e/ou objeto em assembly não afetam o conteúdo em BASIC já digitado, e vice-versa. E tudo pode ser salvo por um comando SAVE do BASIC. Ao finalizar, o código-fonte pode ser eliminado pela simples exclusão da linha 2, e lá vão estar a linha 1 REM com o código em linguagem de máquina e o código BASIC em seguida. Em compensação, por toda essa conveniência, não é possível montar o programa em endereço diferente de 16516.

Além do montador e do editor, há também algumas funções de monitor, como verificação e edição de endereços de memória, verificação e alteração de valores de registradores, cálculo de desvios relativos, etc; e a função de execução do programa com retorno ao monitor (o break-point é um JP específico que deve ser inserido manualmente no código-fonte).

Há ainda uma rotina utilitária de cópia de bloco de memória. Mas não há disassembler disponível no pacote. Sem problema. Seria exigir demais do programinha.

O montador é feito para ser minimista por boa razão:  a memória é um artigo de luxo para o ZX81. A configuração com expansão de memória mais comum, à época, era de 16kB. Assim, para deixar o maior espaço possível ao programador (códigos fonte e objeto + eventual código BASIC), o código do ZX Assembler deve ser o mais enxuto possível.

Isso reflete na falta de alguns recursos básicos que vemos em qualquer montador. Notadamente, o silêncio do montador ao gerar o código-objeto. Ele não lista o código-objeto com os respectivos endereços de montagem, não gera informações sobre o tamanho ocupado na memória nem sobre os endereços dos rótulos. Assim, o programador fica no escuro quanto a quantidade de memória utilizada e, principalmente, terá bastante dificuldade para calcular o endereço de uma eventual rotina no meio do código-objeto se quiser executá-la a partir do BASIC. O único endereço de execução fornecido é o do início do código-objeto, que consta no manual do ZX Assembler. Considero que o programa poderia pelo menos informar o endereço dos rótulos já que isso não demandaria grande espaço de memória.

Enfim, a conclusão é que o ZX Assembler pode ser usado tranquilamente para programas simples em lugar de ferramentas externas que estragam a experiência de imersão, ainda que seja por emulador. Mas como tudo está na memória (código-fonte, código-objeto, o assembler em si e mais, eventualmente, linhas em código BASIC), o espaço de memória fica bastante limitado.

Acrescento aqui informações que não constam do manual:

  • Os endereços 16514 e 16515 contêm o código 118 (76h), ou seja, NEW LINE. Provavelmente para evitar a listagem do código de máquina decodificado pelo comando LIST do BASIC, enchendo a tela com caracteres e comandos. É por isso que o programa em LM deve ser executado com RAND USR 16516;
  • O assembler reside acima da RAMTOP, setada em 25684. Em 30000 há um desvio (JP) para 30742, endereço efetivo do início de execução do programa. Mas o atalho RAND USR 3E4 (30000), fornecido no manual, é mais simples de lembrar e digitar;
  • Ao usuário fica disponível pouco menos de 9kB para código-objeto, código-fonte e linhas BASIC. O código-fonte é armazenado em modo texto, não há qualquer tipo de compressão ou pré-codificação dos mnemônicos.



Nenhum comentário:

Postar um comentário

Relógio BCD para o TK85 no ZX Assembler da Artic

Um relógio BCD (binary-coded decimal) mostra os dígitos decimais em formato binário. Cada dígito decimal das horas, minutos e segundos está ...