domingo, 20 de abril de 2014

Keyler

Programinha simples para testar emuladores de teclado. Ele faz repetidas leituras na mesma linha do teclado, e deve imprimir um "#" toda vez que a uma das teclas (0-7) do teclado normal muda de estado.

Keyler rodando em emulador
Funcionou num Turbo R e num Expert (agradeço ao meu amigo Igor por ter testado, pois meus HotBits infelizmente estão meio parados).

Imagem de disco disponível neste link, ou somente o binário

Para carregar a partir do Basic:

bload "keyler.bin"
defusr=&Ha005:a=usr(0)




sábado, 5 de abril de 2014

Resposta a interrupção em menos de 690ns

Achei um artigo interessante sobre otimização de interrupções em C para o AVR

O autoru usou um AVR para implementar um emulador de joystick do Sega Genesis e precisava responder com prontidão ao sinal de seleção do multiplex. O tempo de resposta dele ficou entre 490 e 690ns

http://raphnet.net/programmation/snes2md/index_en.php

Isso pode ser usado por exemplo para ativar o /WAIT do Z80 quando o MSX vai ler ou escrever numa porta de I/O, emulando assim um periférico.




sexta-feira, 4 de abril de 2014

ROM do MSX e a leitura da matriz do teclado

O teclado do MSX é uma matriz de 11 linhas x 8 colunas de chaves entre as portas B e C da PPI.


Para ler o estado das teclas, o valor da linha deve ser escrito nos 4 bits menos significativos da porta C da PPI (0AAh), e então o estado das teclas deve ser lido na porta B (0A9H).

A ROM do MSX possui vários pontos onde a matriz é lida. Um ponto em comum em todos os trechos em assembly (listados abaixo) é que a instrução de leitura da porta acontece logo em seguida à instrução de seleção da coluna.

OUT (0AAh),A ; seleciona a linha a ser lida
IN A,(0A9h) ; lê o estado das teclas

Em termos de tempo, isso significa 3,7us como já foi bem explicado num post anterior.



  • Rotina BREAKX da BIOS

Esta rotina é lida em vários momentos quando se quer determinar o estado das teclas CONTROL+STOP


046Fh IN A,(0AAh)
0471h AND 0F0h
0473h OR 007h
0475h OUT (0AAh),A
0477h IN A,(0A9h)
0479h AND 010h
047Bh RET NZ

047Ch IN A,(0AAh)
047Eh DEC A
047Fh OUT (0AAh),A
0481h IN A,(0A9h)
0483h AND 002h
0485h RET NZ



  • Rotina GTSTCK da BIOS

A matriz do teclado é lida no endereço 1226H quando o argumento da rotina GTSTCK é '0', ou seja, as teclas de cursor

1226h DI
1227h IN A,(0AAh)
1229h AND 0F0h
122Bh ADD A,008h
122Dh OUT (0AAh),A
122Fh IN A,(0A9h)
1231h EI
1232h RET



  • Rotina GTTRIG da BIOS

Esta rotina chama o endereço 1226H caso o argumento seja '0' ou seja, a barra de espaço



  • Rotina SNSMAT da BIOS

A maioria dos jogos utiliza esta rotina para ler o teclado. O ponto de entrada desta rotina é o endereço 0141H, que chama o endereço 1452H

1452 ld C,A
1453 di
1454 in A,($AA)
1456 and $F0
1458 add A,C
1459 out ($AA),A ; seleciona a linha a ser lida
145B in A,($A9)  ; lê o estado das teclas
145D ei
145E ret


  • KEYINT da BIOS:

O MSX faz a varredura sequencial das linhas do teclado a cada três interrupções do VDP através da rotina localizada no endereço 0D12H.


0D12h IN A,(0AAh)
0D14h AND 0F0h
0D16h LD C,A ; Na primeira leitura o valor de C=0 (linha 0) 
0D17h LD B,11     
0D19h LD HL,0FBE5h
0D1Ch LD A,C  
0D1Dh OUT (0AAh),A ; seleciona a linha a ser lida
0D1Fh IN A,(0A9h) ; lê o estado das teclas
0D21h LD (HL),A
0D22h INC C ;  próxima linha  
0D23h INC HL
0D24h DJNZ 0F6h


Cabe notar que a seleção das linhas do teclado só ocorre de forma sequencial quando o MSX BASIC está executando.

A título de exemplo, ao se 'desassemblar' alguns jogos encontram-se apenas chamadas para a rotina SNSMAT (0141H).


Road Fighter: 2 chamadas com os valores 7 e 8

46D5h LD A,007h
46D7h CALL 0141H

46DFh LD A,008h
46E1h CALL 0141H

Galaga: 8 chamadas , com os valores 5, 6, 7 e 8

40D2h LD A,008h
40D4h CALL 0141H

40EEh LD A,005h
40F0h CALL 0141H

411Bh LD A,006h
411Dh CALL 0141H

4129h LD A,007h
412Bh CALL 0141H

60D2h LD A,008h
60D4h CALL 0141H

60EEh LD A,005h
60F0h CALL 0141H

611Bh LD A,006h
611Dh CALL 0141H

6129h LD A,007h
612Bh CALL 0141H


Ping Pong: 6 Chamadas com os valores 2, 3, 5, 6, 7 e 8

4817H: LD A,007h
4819H: CALL 0141H

4821H: LD A,008h
4823H: CALL 0141H

4857H: LD A,006h
4859H: CALL 0141H

485DH: LD A,003h
485FH: CALL 0141H

4868H: LD A,002h
486AH: CALL 0141H

4871H: LD A,005h
4873H: CALL 0141H

Knightmare: 6 Chamadas com os valores 3, 4, 5, 6, 7 e 8

44F1h LD A,007h
44F3h CALL 0141H

44FBh LD A,008h
44FDh CALL 0141H

56E8h LD A,006h
56EAh CALL 0141H

6F4Ch LD A,003h
6F4Eh CALL 0141H

6F58h LD A,004h
6F5Ah CALL 0141H

6F61h LD A,005h
6F63h CALL 0141H