No código fonte de assembly que acompanha este artigo, o endereço/ORG está construída de tal forma, que é carregada na primeira linha de BASIC, que deve ter um REM seguido de 58 caracteres. A rotina é carregada a seguir ao REM, se o BASIC estiver na posição normal.
Também partilhamos um .TAP já com a rotina carregada no REM.
O código assembly está escrito de tal forma que a rotina START:
- usa o registo BC para saber com que endereço foi invocada/onde está a ser executada;
- modifica a rotina HANDLER: para este bloco de código poder ser carregado em qualquer endereço;
- faz update do endereço apontado por ERR_SP para redireccionar a rotina de tratamento de erros do BASIC para HANDLER:
- volta ao BASIC
- verifica se o código de erro é BREAK - CONT ou BREAK into program;
- se não, salta para o endereço, que normalmente vai, sem este programa, para um ponto alternativo de entrada da rotina MAIN, o ciclo principal do interprete BASIC - MAIN_4;
- de outra forma, limpa o código de erro e o sinal de ter tecla(s) em buffer;
- Salta para uma entrada alternativa, da rotina da ROM onde chegam rotinas de BASIC sem erros, STMT_R_1.
; BASED IN YS/WOS ROUTINE
; RUI RIBEIRO/2019
ORG $5CD0 ; 1st Basic LINE after REM
START:
; HL,(HANDLER)
LD HL,HANDLER-START
ADD HL,BC ; HL=HANDLER
PUSH HL
POP IX ; LD IX,HANDLER
; self modifying code
; update handled address loaded
; in HL in HANDLER: line
; LD (HANDLER+1),HANDLER
LD (IX+1),L ; HANDLER+1
LD (IX+2),H ; HANDLER+2
; Update ERR_SP pointer
PUSH HL ; preserve handler address
; GET ADDRESS pointed by ERR_SP
; HL,(ERR_SP)
LD L,(IY+3) ; $5C3D ERR_SP
LD H,(IY+4) ; $5C3E ERR_SP
PUSH HL
POP IX ; LD IX,(ERR_SP)
POP HL
; LD (IX),HANDLER
LD (IX+0),L ;
LD (IX+1),H ;
RET
HANDLER:
LD HL,HANDLER ; value will be modified
LD A,(IY+0) ; ERR NR Sys Var 1 less than error code
CP $14 ; L BREAK into program
JR Z,label1 ; =
CP $0C ; D BREAK - CONT repeats
JP NZ,$1303 ; != GO MAIN_4
; usual value pushed in (ERR_SP)
label1:
PUSH HL ; PUSH HANDLER
LD (IY+0),$FF ; $5C3A ERR-NR
; 0-1 clear error
RES 5, (IY+1) ; $5C3B
; FLAGS - 5 Set when a new key has been pressed
; unset it
JP $1B7D ; STMT_R_1 - Continue here as the BREAK key was not pressed.
O TAP carrega uma linha 1 com um REM seguido da rotina em código máquina. A linha 2 é para calcular o endereço execução, já que o endereço de BASIC pode variar, notavelmente se estiver uma interface 1 ligada.
2 RANDOMIZE USR (PEEK 23635+PEEK 23636*256+5)
Se esta rotina for incluída num conjunto de protecção BASIC (pode ter outros usos, como usar à vontade BREAK como tecla de INPUT), para tornar a linha 1 em 0 e criar assim uma protecção ANTI-MERGE, fazer, depois de fazer load ao BASIC do TAP:
POKE (PEEK 23635+PEEK 23636*256+1),0
Nota: Um handler com um wrapper / rotina de tratamento pendurado em ERR_SP, é uma gateway possível, para ampliar o BASIC da ROM normal do ZX Spectrum 48K com mais comandos/funcionalidades.
O IY na ZX Spectrum ROM, aponta sempre para $5C3A.
Para clarificar o uso do registo BC nesta rotina, veja Devolver um número de uma rotina C/M
Temos conhecimento de POKEs anti-break, mas eles parecem ser derivados empiricamente e não são fiáveis, por exemplo, em GOSUBs, uma operação que mexe com o stack, deixam de trabalhar e tem que se fazer outra vez o POKE.
Sem comentários:
Enviar um comentário