quinta-feira, novembro 21, 2024

Simulador de K7 para o ZX81/TK82C - Parte 1

Esta é uma ideia antiga, que foi mudando um pouco com o tempo e entrou na "Maratona de Projetos de 2024". É ainda um projeto em curso, no momento atingi o primeiro resultado positivo.


Um Pouco de História

Lançado em 81, o ZX81 tinha como objetivo o baixo custo. Uma formas de atingir isso era usar fitas K7 (ou cassete?) para armazenar programas. O ZX81 tem dois conectores, marcados como EAR e MIC para serem ligados, respectivamente, à saída de fone de ouvido e à entrada de microfone de um gravador de fitas mono.

Junto com meu TK82C (um clone nacional do ZX81) eu comprei um gravador National e uma TV Philips, branco e preta, de 12". Durante o período que ele esteve com o meu pai, ele comprou um gravador da Gradiente, "específico" para uso com computadores.

O processo de leitura e gravação em fita é bastante lento (e este projeto não pretende resolver isso). Para complicar, a leitura é bastante caprichosa, sendo comum ter um micro travado após aguardar vários minutos pela carga.

Uma outra fonte de redução de custo foi colocar todo o circuito lógico em um chip semi-custom (a ULA). Em tenho dois TK82C, o primeiro tem um clone da ULA e o segundo quase duas dúzias de chips e um emaranhado de fios (a placa principal corresponde ao modelo anterior da Sinclair, o ZX80, e uma segunda placa com as adaptações necessárias para ficar compatível com o ZX81). Não que isso seja relevante para o projeto, mas ajuda a entender as fotos. Nas fotos aparecem também duas gambiarras adaptações técnicas que eu fiz: uma expansão de 16k e a geração de vídeo composto.

Como ZX81 Lê e Grava Fitas

O ZX81 se notabiliza pela engenhosidade e simplicidade. O circuito é quase que inteiramente digital, acrescentando apenas alguns resistores e capacitores. No caso da interface de fita, a saída usa o sinal de vídeo (que normalmente indica se um ponto está aceso ou apagado), reduzido para um nível compatível com a entrada de microfone e filtrado para transformar a onda quadrada de entrada em algo próximo a uma senoide. No lado da entrada, o que nos interessa é que tem um capacitor na entrada, o que nos permite ligar diretamente um sinal digital.

No lado do software, o processamento é feito por laços curtos (escritos em assembly, como todo o código na ROM), portanto os tempos são definidos pelo número de ciclos e a frequência do cristal.

O comando para gravar um programa é SAVE "NOME".  Para carregar um programa você pode usar LOAD "NOME" ou simplesmente LOAD ""; no primeiro caso ele vai querer carregar o programa com um nome específico, no segundo carrega o primeiro programa que ler. Detalhe: o ZX81 usa um conjunto de caracteres próprio, que só tem as letras maiúsculas. Se você forçar o bit mais significativo de um caracter para 1, o caracter é apresentado invertido (branco com fundo preto).

O que é gravado em fita? O nome do programa, com o último caracter com o bit mais significativo ligado, seguido de um "dump" de quase toda a parte da memória RAM em uso. A memória RAM começa no endereço 0x4000 e tem as seguintes regiões: variáveis de sistema, programa BASIC, imagem da tela e variáveis do programa BASIC. A gravação começa no endereço 0x4009 (pegando a maior parte das variáveis de sistema) e vai até o primeiro byte depois das variáveis do programa BASIC (salvando portanto a tela e as variáveis BASIC).

A área de sistema inclui ponteiros para a imagem da tela (D_FILE em 0x400C), as variáveis do programa BASIC (VARS em 0x4010) e o fim da área salva (E_LINE em 0x4014). O início do programa BASIC é sempre no endereço 0x407D.

Note que o fim da área salva (e portanto o seu tamanho), só é descoberto após ler o ponteiro E_LINE. Para uma conferência básica, a primeira posição salva contém sempre 0 e a última sempre 0x80.

Um formato padrão para armazenar programas em emuladores do ZX81 (arquivos .P) é gravar em um arquivo diretamente os bytes da área salva, sem o nome do programa na frente. Obs: devido a emuladores buggentos, o CPM/80 e a transferência via XModem. alguns arquivos possuem lixo acrescido ao final.

Do ponto de vista elétrico, os bytes são gravados sem intervalo na fita. Cada bit de cada byte é convertido em uma sequência de pulsos, seguida de um silêncio, do bit mais significativo para o menos. Se o bit é 0 são 4 pulsos, se é 1 são 9 pulsos. Cada pulso fica 150us em nível alto e 150us em nível baixo; o silêncio entre os bits é de 1300us. 

Algumas Ideias de Projeto e a Meta Atual

Da descrição acima dá para imaginar projetos como:

  • Converter a saída do gravador em um arquivo .P, para recuperar os muitos programas que eu tenho salvo em fita.
  • Capturar a saída do ZX81 e salvar o programa em um arquivo .P
  • Enviar a um ZX81 os pulsos equivalentes a um arquivo .P.  Existe na Internet uma quantidade absurda de programas para o ZX81 neste formato.
A diferença entre os dois primeiros é o nível do sinal. Em particular, as minhas tentativas de observar o sinal de saída do ZX81 com o osciloscópio não foram bem sucedidas, o nível do sinal é alguns milivolts. Uma grande dificuldade é que o sinal a ser analisado está mais para uma onda senoidal do que quadrada (fora o problema do ruído).

Foi por esse motivos que resolvi me limitar ao último projeto. Como hardware uma placa baseada no RP2040 ligada a um adaptador para cartão micro SD, um diplay e um encoder (para selecionar o arquivo e informar o andamento da transmissão).

O Primeiro Passo

Como "prova de conceito", resolvi tentar enviar um programa .P fixo no código para o ZX81.Um programa em C# lê o arquivo .P e exporta os bytes na forma de um arquivo .h que declara uma matriz com os bytes correspondentes. Como brinde, esse programa lista o programa BASIC.

O programa para a placa (no caso um Pi Pico) gera os pulsos "na raça", usando delays para gerar as temporizações. O código pode ser visto em https://github.com/dquadros/PicoK7.

Do lado do hardware a questão era como compatibilizar o sinal digital do microcontrolador com a entrada do ZX81, a solução foi usar um simples transistor NPN para converter o sinal de 3,3V para 5V (neste processo o sinal é invertido, o que é compensado no software). O ZX81 aceitou alegremente este sinal.

Próximos Passos

Uma ideia mais ambiciosa é gerar os pulsos usando a PIO do RP2040, isto eliminará os delays no software e facilitará apresentar o andamento da transmissão no display.

Depois tem a ligação do cartão SD e a listagem e leitura dos arquivos. Por último tem a interface com o operador. Uma caixa bonita será um "plus a mais", que não deve sair este ano.


Nenhum comentário: