sexta-feira, 29 de novembro de 2019

A cassete do ZX Spectrum (II) - headers + blocos

Já vimos no artigo anterior, como carregar e gravar blocos de dados. No entanto, ter bloco de dados sem cabeçalhos em cassete, embora seja usado para carregar rotinas C/M de jogos, quer por protecção, quer por serem rotinas mais fáceis de usar desde C/M, não identifica o que estamos a carregar na tape.

Nas rotinas da ROM dos comandos BASIC LOAD e SAVE, é primeiro gravado em tape um header / cabeçalho, que define o nome do bloco e tipo de dados.


Imediatamente em seguida é gravado um bloco com os dados.


A consequência prática de gravar com um header, é que enquanto as rotinas de LD_BYTES carregam o primeiro bloco que "vêem", as rotinas de carregamento com headers podem ser instruídas para esperar pelo bloco com o nome pretendido.

Bloco header

O cabeçalho tem 17 bytes, e os campos têm valores definidos:

Byte (decimal) Length Descrição
010 - programa BASIC
1 - variáveis de números
2 - variáveis de caracteres
3 - CODE (C/M / dados )
110Nome (espaços em branco até 10)
$FF no primeiro byte indica qualquer nome.
112Tamanho do bloco de dados
132Parâmetro 1
BASIC: linha auto-arranque (>=32768 não arranca)
CODE: início de posição de memória
152Parâmetro 2
BASIC: VARS - PROG
CODE: 32768 ???

O SCREEN$ é uma caso especial de CODE com início em 16384 e tamanho 6912 decimal.

Para gravar o bloco com headers, similar ao BASIC, e com a mensagem "Press any key", usa-se a rotina  $0970 SA-CONTRL.

LD HL,500000
LD  IX,HEADER
CALL $0970 ; SA-CONTRL
HEADER: DEFB $03
                  DEFM "Programa  "
                  DEFW 1000
                  DEFW 50000
                  DEFW 0

Dessa forma, tendo o header, pode-se carregar este bloco gravado em C/M, com LOAD "" CODE, a partir do BASIC.

E para carregar LOAD "" CODE com header de uma cassete, ajustando o assembly para invocar a rotina SA_ALL:

T_ADDR equ 5c74h
SA_ALL equ 075Ah

ORG 25000
LD A,(T_ADDR)
LD (T_ADDR2),A
LD  IX,ExpectedHeader
LD HL,0
LD  A,1 ; LOAD nesta rotina de ROM é 1
LD (T_ADDR),A
CALL SA_ALL ;command multiplexor
LD A,(T_ADDR2)
LD (T_ADDR),A
RET

ExpectedHeader:
DB 3 ;expected type (Bytes)
DB 0ffh ;name = "" for any name
DS 9
DW 0 ; size = 0 (use tamanho do header em cassete)
DW 0 ; start = 0 (usar começo do header em cassete)
DW 0 ;
DS 17 ; espaço em RAM para carregar header da cassete
T_ADDR2:
;DB 0
END 25000

(nota: se for para incluir noutra rotina, descomentar o ultimo db 0; é um hack intencional para dar para testar a rotina com ela própria)

Exemplo ASM como gravar e carregar ecrã com header + bloco de dados

A titulo de exemplo, para carregarmos um header em memória usando a rotina LD_BYTES que vimos na parte (I) deste artigo:

LOAD_HEADER:
SCF
LD A,$00 ; HEADER BLOCK
LD IX,Header
LD DE,17 ; 17 bytes
CALL $0556 ; call LD_BYTES
RET

Para terminar, temos aqui um programa em assembly, como exemplo, que lista cabeçalhos de blocos que passem na cassete:

Exemplo ASM como listar cabeçalhos

Para mais informações, fica o link:

Sem comentários:

Enviar um comentário