domingo, 12 de abril de 2020

Representação numérica em BASIC - inteiros positivos

O BASIC para armazenar número, normalmente armazena a parte ASCII seguida de 0x0E e uma representação numérica de 5 bytes, que é usada directamente pela rotina da calculadora de stack de vírgula flutuante do Spectrum.

Esta representação existe, para acelerar o interprete de BASIC. Aquando da edição ou LIST de uma linha BASIC, apenas se lida com a representação ASCII, mas fazendo ENTER para introdução a linha, esta é introduzida em RAM com a representação ASCII seguida de 0x0E mais a representação numérica.

Ou seja, em runtime, a representação ASCII é ignorada quando a representação numérica existe, e é usada a representação numérica para lidar com números. (excepção feita a um VAL "número").

Portanto, um número inteiro em 5 bytes menor que 65536, é representado por:

     Exemplo: 45000 (AFC8)

      00 00 C8 AF 00

Note-se que o primeiro byte a $00 denota um inteiro, e o segundo byte a $FF um número negativo. No entanto, em listagens BASIC e variáveis, a ROM parece preferir usar o sinal - (ASCII $2D ) seguido da representação do número positiva.

Se em variáveis, apenas os 5 bytes são usados, em BASIC na prática são 6 bytes, já que a representação numérica é sempre precedida por 0x0E.

10 PRINT 45000            [int:45000,$AFC8]

5CCB 00 0A 0D 00 F5 34 35 30 30 30 0E 00 00 C8 AF 00 ....?45000...ȯ. 
5CDB 0D

20 PRINT -5454            [int:5454,$154E]

5CDC 00 14 0D 00 F5 2D 35 34 35 34 0E 00 00 4E 15 00 ....?-5454...N.. 
5CEC 0D

30 PRINT VAL "50"


5CED 00 1E 07 00 F5 B0 22 35 30 22 0D  ....??"50".

Zona de variáveis BASIC

5CF7 61 00 00 28 00 00               (a=40)

Como método de protecção,  pode-se alterar a representação numérica. No entanto, estas modificações perdem-se editando as linhas em questão. Estes artifícios eram usados em software comercial.

Por exemplo,  no Pheenix:

- B
(PROG) 5CCB (VARS) 5DA0 (NXTLIN) 5DA0
1 CLEAR 24500
2 INK 0 : PAPER 0 : BORDER 0 :CLS 
3 PRINT AT 8,7;"....PHEENIX is loading";AT 10,9;"........ Please Wait ......"
4 POKE 23659,0

[mem:$5D75]
5 LOAD ""CODE 24576[int:24532,$5FD4]

5D75 00 05 10 00 EF 22 22 AF 32 34 35 37 36 0E 00 00 ....?""?24576... 
5D85 D4 5F 00 0D

[mem:$5D89]
6 LOAD ""CODE :RANDOMIZE USR 30121[int:30105,$7599]

5D89 00 06 13 00 EF 22 22 AF 3A F9 C0 33 30 31 32 31 ....?""?:??30121 
5D99 0E 00 00 99 75 00 0D

Exemplo:

No programa, vamos adulterar o 0 para apontar para uma rotina RET em ROM (retornar ao BASIC em vez de fazer RESET).

10 PRINT USR 0

Temos então a linha em RAM:

5CCB 00 0A 0A 00 F5 C0 30 0E 00 00 00 00 00 0D

Que vamos alterar para apontar para $171D em vez de 0.

Para tal fazemos: 

POKE 23765,29                ; $5CD5 = $1D
POKE 23766,23                ; $5CD6 = $17

Ficando:

[mem:$5CCB]
10 PRINT USR 0[int:5917,$171D]

Ou em RAM:

5CCB 00 0A 0A 00 F5 C0 30 0E 00 00 1D 17 00 0D

1 comentário:

  1. Parabéns Rui pelo excelente trabalho. Estou aqui recordando meus primeiros passos com o TK85, mas agora na linha Spectrum! SHOW! ;-)

    ResponderEliminar