Bugs
O exame da ROM do MC1000 revela algumas características que foram programadas, mas que não funcionam devido a erros de lógica.
Para cada erro apresenta-se um "patch", um "remendo", que poderia consertar o erro numa versão melhorada da ROM.
Caracter de controle FF (CHR$(12))
Pela programação na ROM, o caracter de controle FF deveria avançar o cursor, isto é, movê-lo uma coluna à direita; se estivesse no fim de uma linha, iria para o início da linha seguinte; e se estivesse no fim da tela, continuaria no mesmo lugar e um bip soaria para avisar da impossibilidade do cursor avançar.
Mas há um erro na rotina de verificação de fim de tela. A posição do cursor é subtraída em um (equivalendo a um movimento para a esquerda), e quando finalmente se soma um para fazê-lo mover-se à direita... o resultado é que o cursor não sai do lugar!
pc ← POSIÇÃO_DO_CURSOR ft ← FIM_DA_TELA + 1 pc ← pc - 1 (deveria ser: ft ← ft - 1) se pc = ft então produz bip senão pc ← pc + 1 POSIÇÃO_DO_CURSOR ← pc fim se
Como efeito colateral, este bug inutilizou o uso das teclas H, J, K e L associadas a <CTRL> para mover o cursor enquanto se digita uma linha. A lógica está toda implementada, e quando se pressiona <CTRL>+<L> a posição do cursor é até avançada no buffer de linha, mas não se move na tela.
Patch
CA69 2B DEC HL
CA69 1B DEC DE
Caracter de controle DEL (CHR$(127))
DEL deveria mover o cursor para a esquerda, apagando (isto é, substituindo por espaço) o caracter que estivesse na posição do cursor. Mas uma verificação mal feita faz com que a porção de código que interpreta DEL como um caracter de controle nunca seja executada. Por isso ele acaba sendo interpretado como um caracter comum.
c ← CARACTER_A_IMPRIMIR se c < 32 então (deveria ser: se c < 32 ou c = 127 então) (interpreta caracteres de controle) se c = 7 então produz bip fim se (...) se c = 127 então (...) fim se senão imprime c como um caracter comum fim se
Patch
C8BE C2F9C8 JP NZ,$C8F9
C8BE C2F4C8 JP NZ,$C8F4
Posicionamento de cursor (CHR$(27))
Usando CHR$(27) (ESC) é possível posicionar o cursor no MC1000. Para programar o cursor em modo de 32 colunas, dever-se-ia usar CHR$(27);"=";CHR$(linha);CHR$(coluna). E em modo de 80 colunas, CHR$(27);"=";CHR$(linha);CHR$(32+coluna).
Um erro faz com que o posicionamento de cursor para 32 colunas não funcione corretamente: o cursor é posicionado uma linha abaixo de onde deveria ficar.
li ← NÚMERO_DA_LINHA co ← NÚMERO_DA_COLUNA se co < 32 então (para 32 colunas) co ← co + 32 (esta soma não deveria ser feita!) senão (para 80 colunas) co ← co - 32 fim se posiciona o cursor nas coordenadas (li,co)
Como contornar
Use o posicionamento para 80 colunas (CHR$(27);"=";CHR$(linha);CHR$(32+coluna)). Ele funciona mesmo quando o vídeo está em 32 colunas.
Patch
C994 C620 ADD A,$20
C994 00 NOP C995 00 NOP
Instrução SLOW
O MC1000 tem um par de instruções não documentadas no manual de BASIC: FAST e SLOW. FAST ("rápido") é o modo normal de execução do MC1000. O SLOW ("lento") faz com que o computador adicione uma brevíssima pausa entre os comandos. Mas, por um erro de lógica, o comando não funciona. Primeiro ele verifica (corretamente) se não há nenhum parâmetro a seguir (se houver, ele produz erro de sintaxe, "?SN ERRO"); depois disso, ele "invade" a programação do comando SET, produzindo um erro de acordo com o modo de vídeo. Em modo TEXT ele produz erro de tipo incompatível ("?TI ERRO"); em modo gráfico (GR ou HGR) ele produz erro de falta de operando ("?FO ERRO").
FAST: x ← 0 FAST_SLOW: endereço de memória(864) ← x retorna SLOW: x ← 1 (faltou: desvia para FAST_SLOW) SET: (...)
Como contornar
É possível entrar em modo SLOW por meio da instrução POKE 864,1.
Patch
Este patch exige alguns bytes do espaço não utilizado no fim da ROM.
D74D 22D2 DB $D222 F563 FFFFFF DB $FF,$FF,$FF ; (Lixo no fim da ROM) F566 FFFFFF DB $FF,$FF,$FF
D74D 63F5 DB $F563 F563 C0 RET NZ F564 3E01 LD A,$01 F566 C31ED2 JP $D21E
Cláusula VTAB
VTAB é uma cláusula da instrução PRINT não documentada no Manual do BASIC.
Deveria servir para posicionar o cursor verticalmente, mas não funciona por uma sucessão de erros na lógica que calcula a nova posição do cursor.
Tenta isto e vê o cursor desaparecer... :-(
PRINT VTAB(12);
Para recuperar o cursor, digita (às cegas mesmo) o comando HOME seguido da tecla <RETURN>, ou então pressiona <CTRL>+<↑>.
Como contornar
Pode-se usar a sequência de escape para posicionamento do cursor, obtendo-se a coluna atual do cursor da variável de sistema LCNT: PRINT CHR$(27);"=";CHR$(linha);CHR$(32+PEEK(349));
Patch
E141 210080 LD HL,$8000 E144 ED52 SBC HL,DE E146 13 INC DE E147 01 DB $01 ; "LD BC,..." (oculta as duas instruções seguintes) E148 7B LD A,E E149 3D DEC A E14A 2803 JR Z,$E14F E14C 09 ADD HL,BC E14D 18FA JR $E149
E141 2A6301 LD HL,($0163) ; SNAM = início da VRAM. E144 ED5B1301 LD DE,($0113) ; DLNG = largura da linha. E148 04 INC B ; parâmetro de VTAB() + 1. E149 1801 JR $E14C E14B 19 ADD HL,DE E14C 10FD DJNZ $E14B E14E 00 NOP
Rotina JSTICK
Esta é uma rotina da ROM do MC1000 (no endereço $CC2C) voltada a permitir que um ou dois jogadores joguem compartilhando o teclado. O jogador da esquerda utilizaria as teclas <A> (esquerda), <S> (cima), <D> (baixo), <F> (direita) e <Q>,<W>,<E>,<R>,<T> (tiro). O jogador da direita utilizaria as teclas <K> (esquerda), <L> (cima), <;> (baixo), <:> (direita) e <I>,<O>,<P>,<↑>,<RETURN> para tiro. A rotina traduz um código de tecla para um byte cujos bits indicam a qual dos controles ela corresponde, se algum.
A listagem desta rotina na ROM está no Manual de Referência, e vemos claramente que o erro surgiu por erro de digitação de um dos rótulos de desvio internos da rotina. Foi digitado "K6" em vez de "J6", e por azar o rótulo "K6" existia em outro lugar da listagem, então o erro não foi detectado durante a compilação. O resultado foi um desvio para fora da rotina (para o endereço $C3FB em vez de $CC83), inutilizando-a. Eis a listagem original (em assembly 8080) na página 96:
LOC OBJ LINE SOURCE STATEMENT [...] CC59 FE41 2175 CPI 'A' CC5B C260CC 2176 JNZ J1 CC5E 0604 2177 MVI B,4 2178 J1: CC60 FE46 2179 CPI 'F' CC62 C267CC 2180 JNZ J2 CC65 0608 2181 MVI B,8 2182 J2: CC67 FE53 2183 CPI 'S' CC69 C26ECC 2184 JNZ J3 CC6C 0610 2185 MVI B,10H 2186 J3: CC6E FE43 2187 CPI 'C' CC70 C275CC 2188 JNZ J4 CC73 0610 2189 MVI B,10H 2190 J4: CC75 FE44 2191 CPI 'D' CC77 C27CCC 2192 JNZ J5 CC7A 0620 2193 MVI B,20H 2194 J5: CC7C FE4B 2195 CPI 'K' CC7E C2FBC3 2196 JNZ K6 (rótulo errado, seria J6!) CC81 0605 2197 MVI B,5 2198 J6: CC83 FE3A 2199 CPI ':' [...]
(No assembly do Z80, CPI é CP, JNZ é JP NZ e MVI é LD.)
Patch
CC7E C2FBC3 JP NZ,$C3FB
CC7E C283CC JP NZ,$CC83
Instruções PLOT, UNPLOT, DRAW, UNDRAW
No modo HGR, quando as instruções de desenho tentam desenhar/apagar uma linha em 45° com uma extremidade na coordenada horizontal 255, as instruções não conseguem terminar de desenhar a linha e o computador trava.
Por exemplo, executar HGR : PLOT 255-7,0 TO 255,7 deveria produzir apenas um pequeno traço diagonal no canto superior direito da tela, mas a linha continua sendo desenhada tela abaixo:
O problema ocorre porque nas rotinas específicas que tratam as linhas em 45°, identifica-se a chegada ao fim da linha quando, após somar 1 ao registrador contendo a coordenada horizontal do pixel recém desenhado, seu valor é superior ao da coordenada final. Mas como o em 8 bits 255 + 1 = 0, seu valor NUNCA é maior do que 255!
x ← MENOR_COORDENADA_X y ← COORDENADA_Y_CORRESPONDENTE faça desenha ponto nas coordenadas (x,y) x ← x + 1 (em 8 bits, 256 é automaticamente transformado em 0) y ← y + 1 se LINHA_ASCENDENTE y ← y - 2 fim se até que x > MAIOR_COORDENADA_X (esta condição nunca é satisfeita quando a MAIOR_COORDENADA_X é 255!)
Patch
A solução é comparar a coordenada atual com a coordenada final antes de somar 1.
D2B6 7C LD A,H D2B7 24 INC H D2B8 45 LD B,L D2B9 2C INC L D2BA CDDAD3 CALL $D3DA ; PLOTAB D2BD F1 POP AF D2BE F5 PUSH AF D2BF 3802 JR C,$D2C3 D2C1 2D DEC L D2C2 2D DEC L D2C3 7C LD A,H D2C4 B9 CP C D2C5 28EF JR Z,$D2B6 D2C7 38ED JR C,$D2B6
D2B6 7C LD A,H D2B7 45 LD B,L D2B8 CDDAD3 CALL $D3DA ; PLOTAB D2BB 7C LD A,H D2BC B9 CP C D2BD 280A JR Z,$D2C9 D2BF 24 INC H D2C0 2C INC L D2C1 F1 POP AF D2C2 F5 PUSH AF D2C3 38F1 JR C,$D2B6 D2C5 2D DEC L D2C6 2D DEC L D2C7 18ED JR $D2B6