sábado, 25 de fevereiro de 2012

Medição dos tempos

Com o circuito ligado no MSX, mas ainda sem o sinal /Wait conectado ao barramento, fiz a medição dos tempos. O resultado encontra-se nas fotos abaixo.

A primeira foto está na escala de 500ns por divisão. O canal superior foi tomado no pino 5 do HCT139 e mostra a decodificação dos sinais [A0*/CS*/RD], ou seja o momento em que o MSX lê a porta B da PPI. O canal de baixo foi tomado na saída /Q do flip flop e mostra o tempo em que o sinal /WAIT fica acionado que corresponde ao tempo que o microcontrolador (ATMEGA8 @8MHz) leva para reconhecer a interrupção, ler os bits da porta C da PPI, colocar o dado correspondente na porta de saída e limpar o flip-flop para liberar o Z80. Tudo isso é feito em aproximadamente 4us.

500ns por divisão

A segunda foto foi tirada na escala de 50ns por divisão e mostra o "pulo do gato"...

Protótipo do adaptador de teclado

Comecei a montagem do adaptador de teclado. Testei estaticamente o mecanismo de wait, e encontrei um pequeno erro no inversor improvisado com o decodificador. O correto é ligar o sinal de clock do flip flop no pino 11 do HTC139 e não no pino 12.
Em seguida coloquei o microcontrolador (um ATMEGA8) com conector de programação e o fiz as conexões do microcontrolador ao conector de programação, ao conector que vai para o adaptador de teclado e os pinos /IRQ e /GO.

Pseudo Código para leitura de teclado

Apesar de existirem algumas bibliotecas para leitura de teclado PS/2 disponíveis, nenhuma que achei me serviu basicamente se utilizam de interrupções para ler o teclado e pela conversão de códigos para valores ASCII usando tabelas de estados com e sem shift, etc. Outras razões são o não processamento da teclas PAUSE/BREAK que pretendo utilizar STOP, e o excesso de 'orientação ao sucesso', por desconsiderar timeouts, bits errados, caracteres inesperados, etc.


Eis o primeiro passo, o pseudo codigo para leitura de scan codes, que apesar de ser por polling, pode ser facilmente adaptado para rodar por interrupçoes.


// pseudo codigo para comunicação // com teclado ps/2

quarta-feira, 22 de fevereiro de 2012

Overhead gasto nos ciclos de Wait para o adaptador de teclado.

A fim de calcular o overhead que os ciclos WAIT necessários para atender ao teclado representariam no MSX, fiz uma experiência usando linguagem C num AVR. O objetivo é calcular o tempo necessário
para:
- Atender a interrupção
- Decodificar a linha do teclado (ler porta C da PPI)
- colocar o valor das colunas (na porta B da PPI)
- Pulsar o sinal GO para liberar o Z80

Eis abaixo o código da rotina de interrupção:

terça-feira, 21 de fevereiro de 2012

Adaptador de teclado PS/2

Recapitulando o post anterior, para atender à temporização crítica da instrução IN do Z80 será necessário utilizar o Wait do Z80. A maneira mais simples de fazer isso é utilizar um decodificador dos sinais /CS, /RD e A0 diretamente na PPI e acionar um flip flop que segura a linha /Wait do Z80 em nível baixo e ao mesmo tempo  ativa a interrupção (/INT) do microcontrolador.
Mecanismo de Wait em Piggyback com a PPI

MSX + Arduino

A plataforma Arduino tem suas qualidades e seus defeitos, mas sem entrar nesse mérito, uma coisa é inegável: A plataforma que 'pegou'. É fácil de encontrar para comprar, e qualquer um pode programar facilmente plataforma, usando seu computador, seja ele um PC ou Mac, sem a necessidade de hardware de programação especial.

Sendo assim, eu resolvi refazer o adaptador de Nunchuck para MSX mas desta vez usando um Arduino como plataforma.

segunda-feira, 20 de fevereiro de 2012

Adaptador para teclado PS/2 - Problemas, considerações e idéias .

Antes de me aventurar num projeto de um adaptador de teclado PS/2 é importante estudar bem as particularidades do hardware do MSX.

O teclado do MSX é uma matriz de 11 linhas por 8 colunas. O MSX seleciona a linha através dos 4 bits menos significativos da porta C da PPI que vão a um decodificador BCD-Decimal (74LS145). A leitura das colunas referentes à linha selecionada é feita através da porta B da PPI.

Normalmente, uma leitura do teclado tem a seguinte estrutura:
A=linha selecionada
OUT (0AAh),A
IN A,(0A9H)
Considerando que as intruções OUT/IN executam em 12 ciclos de máquina (no MSX é inserido um 'wait' de um ciclo de clock cada ciclo M1), e que as instruções são normalmente consecutivas, dá pra se notar que o tempo disponível para a leitura de um teclado é bem estrito.

INSTRUCTION   BYTES   M1         M2        M3  
OUT (n),A     2       OCF(4+1)   OD(3)     PW(4)
IN A,(n)      2       OCF(4+1)   OD(3)     PR(4)


Para ser bem preciso, o tempo disponível entre a escrita na porta 0AAh e a leitura na porta 0A9H vai desde o meio segundo pulso de clock do ciclo M3 da instrução OUT (Port Write) até o meio do quarto pulso de clock do ciclo M3 da instrução IN, onde o Z80 efetivamente lê a porta.


Na ponta do lápis temos:
- 2,5 ciclos de clock restantes do ciclo M3 da instrução Write
- 5 ciclos de clock do 'Opcode Fetch' do ciclo M1 da instrução IN
- 3 ciclos de clock da leitura do operando da instrução IN (ciclo M2)
- 3 ciclos de clock da leitura da porta no ciclo M3 (no 3 1/2 o dado já deve estar pronto para ser lido)

Isso nos dá 13,5 ciclos de clock, o que equivale a 3,77 microssegundos numa máquina rodando a 3,58MHz .

Se quisermos ser mais estritos ainda, devemos considerar que nem todo programa precisa escrever na porta C da PPI antes de ler a porta B, pois basta escrever uma vez e ler quando necessário (por exemplo jogos que usem somente as setas cursoras e a barra de espaço).

Assim, considerando somente a leitura na porta B da PPI (0A9h) temos um tempo que vai desde o meio do segundo pulso ate o final do terceiro pulso de clock do ciclo M3 da instrução IN.
Isso equivale a 2,5 ciclos de clock ou 698 nanosegundos.

Penso em duas abordagens para o problema. A primeira é utilizar um CPLD e um microcontrolador. A CPLD é configurada como uma matriz de 10 linhas com 8 flip flops e mais um shift register capaz de endereçar a entrada de cada uma dessas 10 linhas. O microcontrolador lê o teclado PS/2 e cria internamente uma matriz de 11 bytes representando o estado de cada tecla (para o MSX). De tempos em tempos o microcontrolador desloca sequencialmente para o shift register interno cada um dos 10 bytes e apos transferir cada um dos bytes ele atualiza o estado dos flip flops da linha equivalente. A solução mais simples seria encadear todas as 11 linhas e fazer um shift register de 80 bits, mas isso poderia gerar falsos eventos caso o MSX estivesse lendo uma linha do teclado na hora em que o microcontrolador estivesse atualizando o shift register. Isso ia requerer pelo menos (11x8)+8 macrocélulas de uma CPLD, ou seja 98 macrocélulas. Uma abordagem parecida seria fazer um shift register de 88 bits com um latch de saída, mas isso ia requerer pelo menos 168 macro células.
Uma segunda abordagem utiliza somente o microcontrolador. Mas dados os tempos, qual microcontrolador utilizar? Um AVR rodando a 20MHz roda uma instrução a cada 50 nanossegundos, e pode rodar 14 instruções em 700 nanossegundos. Um PIC com mesmo clock teria uma 3 instruções apenas. Um 8051 a 12MHz nem teria como responder tão rápido. Embora seja possível utilizar microcontroladores mais rápidos, não creio que essa seja uma abordagem elegante, ainda mais que o tempo entre eventos de teclado normalmente é bem longo, da ordem de dezenas de milissegundos.

Pensando novamente, este problema de velocidade para atender a uma requisição do microprocessador não é novo, e a solução também não. O Z80 já tem um recurso para tratar esse problema que é a própria linha WAIT. Essa linha é amostrada no terceiro pulso de clock do ciclo M3 das instruções de I/O. Caso essa linha esteja em nível baixo, o Z80 vai fazendo novas amostragens até que a linha volte a nível alto (contudo deve-se tomar cuidado para não deixar o Z80 muito tempo neste estado, pois durante o "wait state" as memórias dinâmicas não sofrem refresh).

Essa segunda abordagem permite o uso de praticamente qualquer microcontrolador, basta adicionar um flip flop e um decodificador para os sinais /RD, /CS e A0 da própria PPI. O microcontrolador pode trabalhar por polling ou por interrupções, reconhecendo a mudança de estado da saída do flip flop (que vai a zero no momento em que /RD=0; /CS=0; A0=1). O microcontrolador então lê o estado dos bits 0-3 da porta C da PPI, determina qual a linha que o MSX deseja ler. Então o microcontrolador coloca na saída os bits correspondentes à coluna lida e reseta o flip flop, liberando a linha Wait. Se quisermos ser preciosistas, após liberar o Z80 basta aguardar por um tempo equivalente a um ciclo e meio de clock do Z80 e então desativar a porta de saída (bits da coluna).



sexta-feira, 3 de fevereiro de 2012

Interface MSX-Nunchuck


A interface é bem simples: Dois resistores de pull-up e alguns diodos e um capacitor para converter os +5V da porta de joystick nos +3,3V requeridos pelo Nunchuck.



O capacitor eletrolítico é soldado por baixo:


Interface encaixada no Hot Bit


quinta-feira, 2 de fevereiro de 2012

Road Fighter funcionando com Nunchuck

Finalmente tive um tempo para mexer na adaptação, e agora está funcionando.



Tive que mexer um pouquinho no código para mudar o limiar de sensibilidade em torno da posição central (era de +/- 32 e agora está +/- 20) e remapeei as direções UP DOWN LEFT RIGHT que estavam invertidas (tanto para os acelerômetros quanto para a manete analógica), e também inverti o mapeamento dos botões C e Z. O botão Z que é o maior ficou no trigger principal, ao passo em que o botão C ficou no trigger secundário.

Missão cumprida!!

Não sei quando eu vou poder me dedicar tão intensivamente ao MSX de novo, mas fico feliz de ter conseguido fazer essa adaptação.

Valeu Igor!!! Esse projetinho de final de ano nós começamos e terminamos. Acende aí a velinha pro Nosso Senhor do Bonfim e apaga a velinha do Nosso Senhor do Bom Começo, heheheh.