quinta-feira, 27 de novembro de 2014

Incompatibilidades do Megalomania

Na reconversão do Megalomania, eu tinha prometido contar sobre as incompatibilidades deste demo no TK90X. Nesta postagem estou cumprindo a promessa.


Parte 1

Já na 1ª parte o demo trava na tela abaixo, esperando entrada pelo teclado.


Este é o sintoma de uma incompatibilidade já conhecida na porta 254, que espera um valor que nunca será fornecido pelo TK90X e alguns modelos de ZX Spectrum ou clones. A listagem assembly do trecho da leitura do teclado é:

58216   LD BC,#F7FE     ;Seleciona fileira das teclas 1-5. 
58221   IN A,(C)        ;Leitura da porta 254. 
        CP #BF          ;Se nenhuma tecla for pressionada 
        JR Z,58221      ;
(%10111111), volta para o laço.
        LD (65502),A    ;Guarda valor em variável do programa. 
        CP #BE          ;Tecla 1 (%10111110).
        JR NZ,58238
        LD B,1
        JR 58268
58238   CP #BD          ;Tecla 2 (%10111101). 
        JR NZ,58246
        LD B,2
        JR 58268
58246   CP #BB          ;Tecla 3 (%10111011). 
        JR NZ,58254
        LD B,3
        JR 58268
58254   CP #B7          ;Tecla 4 (%10110111). 
        JR NZ,58262
        LD B,4
        JR 58268
58262   CP #AF          ;Tecla 5 (%10101111). 
        JR NZ,58221
58266   LD B,5
58268   LD HL,22711


A leitura da porta 254 deveria ser tratada bit a bit, não feita uma comparação com o byte inteiro. Felizmente como a rotina não é otimizada, há espaço de sobra para ser modificada:

loop
58221   IN A,(C)
58223   OR %11100000
58225   CP %11111111
58227   JR Z,58221
58229   RES 6,A
58231   LD (65502),A
58234   LD B,1
58236   RRA
58237   JR NC,skip1
58239   INC B
58240   RRA
58241   JR NC,skip1
58243   INC B
58244   RRA
58245   JR NC,skip1
58247   INC B
58248   RRA
58249   JR NC,skip1
58251   INC B
58252   RRA
58253   JR C,loop
skip1
58255   JP 58268

Com o remendo (patch) acima, o demo roda sem problemas no TK90X.

Parte 3

Logo depois de iniciar esta parte, o computador fica paralisado.


Examinando com a Multiface 1, encontrou-se a pilha do Z80 em SP=#7516, que aponta para o endereço 51952. O disassembly deste trecho é:

51949   EI
51950   NOP
51951   HALT
 
51952   DI

Vi que IFF2=0, isto é, aparentemente ocorre um HALT com interrupções desabilitadas, o que explicaria o travamento do computador.

Logo após retornar da M1, o programa destrava e continua funcionando por um tempo. Porém novamente acaba travando após certo tempo. Este fato reforça a hipótese de um HALT com interrupções desabilitadas, pois o NMI da M1 aparentemente faz com que o Z80 saia do estado de HALT.  

Segundo Sean Young, em "The Undocumented Z80 Documented" (disponível em www.z80.info), a instrução logo a seguir de EI não aceitará interrupções. Portanto do jeito que está, não se aceita requisição de interrupção entre 51949 e 51950, porém é perfeitamente possível haver uma requisição entre 51950 e 51951. 

Se houver uma requisição de interrupção antes de HALT, as interrupções são desabilitadas e executa-se a rotina em 65535, que simplesmente é RET. O problema está no retorno da rotina de interrupção, que deixa a interrupção desabilitada; ao encontrar HALT, o Z80 fica paralisado para sempre. O correto era: 1) a rotina de interrupção deve ativar as interrupções antes do retorno; ou 2) colocar a instrução EI imediatamente antes de HALT. 

O motivo do bug só se manifestar no TK90X não está claro. Uma possibilidade é que, por ser de 60Hz a frequência do sinal INT do Z80, diferente de 50 Hz do ZX Spectrum, acaba fazendo com que em algum momento ocorra a infeliz coincidência da interrupção ser executada entre 51950 e 51951. Talvez do modo que o programa está escrito, com o sinal INT à 50 Hz não há possibilidade de ocorrer tal coincidência. Qualquer hora preciso testar no TK90X chaveado para 50 Hz.

O diagnóstico não é fácil, mas a solução é bastante simples. Basta subsitituir a instrução em 51950 de NOP para EI, para impedir que uma interrupção seja aceita entre 51950 a 51951. Para isso basta fazer POKE 51950,251 (251 é opcode de EI). Este é o único programa com  problema com 60 Hz que encontrei uma solução que não seja o chaveamento na ULA.

Nenhum comentário:

Postar um comentário

Seu comentário é bem vindo, mas peço que use este espaço adequadamente.