Ao contrário dos computadores modernos, nos espectros o conceito de sistema de arquivos não era tal. Isso significa que o download de cada tipo de mídia exigia uma implementação separada e, na maioria dos casos, o programa não podia ser apenas copiado da fita para o disco. Nos casos em que o carregador de programa foi escrito em BASIC, ele pode ser adaptado ao TR-DOS com uma revisão bastante simples. No entanto, a situação foi complicada pelo fato de que em muitos jogos (de marca e invadidos), os carregadores foram escritos em códigos de máquina e, às vezes, continham proteção contra cópia.

Apesar da presença de um "botão mágico" que simplesmente fazia um despejo completo da memória do computador e possibilitava salvar o programa em um disquete, foi considerado por especialistas criar versões de disco dos jogos, preservando a imagem de inicialização original e outros atributos.
Neste artigo, mostrarei como realizar essa adaptação no exemplo do jogo Pac-Man , a saber, a imagem original do Pac-Man.tzx .
As ferramentas
Apesar do fato de que antigamente todo esse trabalho era feito diretamente no ZX Spectrum (na ausência de outras opções), adaptarei o jogo usando os utilitários de emulador e linha de comando. A principal razão é que, especialmente no início, o processo de adaptação consiste em um grande número de tentativas e erros e é muito menos doloroso se for automatizado. Tudo o mesmo pode ser feito diretamente no Spectrum.
Na primeira parte, usaremos as seguintes ferramentas:
- Emulador de fusível para depuração e teste.
- SkoolKit para desmontar.
Desativando a Inicialização no Carregador de Inicialização
Como o arquivo de imagem e dados é baixado sem um bloco de cabeçalho (17 bytes com o nome e o tipo do arquivo), isso significa que o carregador é gravado em códigos de máquina. Você precisa descobrir onde esses códigos estão localizados e de qual endereço eles foram lançados.
Existem várias maneiras de analisar o código do carregador de inicialização:
A maneira mais fácil é iniciar o download do programa, aguardar o início do gerenciador de inicialização e pará-lo pressionando a tecla Space
. Em muitos casos, isso funciona, mas no caso de Pacman, como em muitos outros, isso leva a uma redefinição.
A próxima maneira é carregar o programa usando MERGE ""
vez de LOAD ""
. Ao contrário de LOAD
, MERGE
ignora a execução automática do programa. No caso do Pac-Man, a inicialização através do MERGE
faz com que o computador congele com um deslocamento característico da tela esquerda. Isso ocorre porque, em vez de executar o programa linha por linha, o MERGE
tenta analisá-lo por inteiro e mesclá-lo com o programa já carregado. No entanto, se o programa tiver um bloco com códigos de máquina que viole a sintaxe do programa, isso causará um travamento.
Se você não deseja montar seu cérebro, pode converter a imagem da fita de TZX em TAP e usar o utilitário de lista que acompanha o Fuse:
$ tzx2tap Pac-Man.tzx $ listbasic Pac-Man.tap 1 RANDOMIZE USR (PEEK 23635+256*PEEK 23636+91)
O endereço 23635
( $5C53
) corresponde à variável de sistema PROG
, que contém o endereço inicial da área BASIC. Portanto, o ponto de entrada para o carregador de inicialização é compensado por 91 bytes em relação à área BASIC.
Outra maneira de examinar o gerenciador de inicialização é descrita no artigo Desativando uma autoexecução de um programa BASIC . No depurador do Fuse, você precisa definir um ponto de interrupção br 2053
, carregar o programa e, quando o download terminar e a execução do código parar, execute o set 23619 128
. Isso impedirá a inicialização do programa e permitirá que você vá para o básico.
Desmontagem do carregador de inicialização
Conhecendo a mudança do ponto de entrada em relação à área BASIC, você pode calcular seu endereço absoluto. No caso do ZX Spectrum 48K sem um TR-DOS carregado, a área BASIC começa em 23755
( $5CCB
). Consequentemente, o carregador de inicialização começará em 23755 + 91 = 23846
( $5D26
).
Para começar, basta colocar um ponto de interrupção no endereço de partida e ver os códigos da máquina. No Fuse, você pode criar br 23846
e começar a baixar o programa. Assim que o carregador de inicialização começar a executar, o emulador irá parar:

No caso em que o carregador é muito simples, basta olhar para o código desmontado no painel do meio e entender o que está sendo carregado. Normalmente, o código de download para um arquivo sem cabeçalho é mais ou menos assim:
LD IX, $8000 ; LD DE, $4000 ; LD A, $FF ; CALL $0556 ; LD-BYTES JP $8000 ;
Em um caso mais complexo com a execução de código, você precisa entender as etapas e fazer anotações. O pacote de utilitários do SkoolKit é adequado para isso. Se você definir uma meta, com sua ajuda, o jogo poderá ser analisado até o último parafuso (mensagem, sprite, som). Como isso é feito é descrito em detalhes na documentação .
Em resumo, faça o seguinte:
- Faça um instantâneo da memória do computador
Pac-Man.z80
usando os recursos tap2sna.py
ou emulador. - Crie um arquivo de controle
Pac-Man.ctl
com um conjunto inicial de instruções para desmontar:
i 16384 Ignore for now c $5D26 Loader
- Execute a desmontagem:
sna2skool.py -H -c Pac-Man.ctl Pac-Man.z80 > Pac-Man.skool
. - Ao estudar o código, adicione novas instruções e comentários ao arquivo de controle.
- Repita até ficar completamente iluminado.
Como resultado, após a primeira passagem, obtemos o seguinte (meus comentários, endereços são omitidos):
ORG $5D26 ; 23846, ; DI IM 1 ; LD D, IYh ; LD E, IYl ; LD B, $25 ; EX DE, HL ; LD DE, $0019 ; ADD HL, DE ; HL $5C53 ( PROG) LD E, (HL) ; PROG DE IX INC HL ; LD D, (HL) ; LD IXh, D ; LD IXl, E ; LD A, (IX+$7F) ; ( $7F- ; PROG) LD HL, $0035 ; ($35 PROG) ADD HL, DE ; PUSH HL ; XOR (HL) ; LD (HL), A ; INC HL ; DJNZ $5D43 ; AND (HL) ; RET NZ ; ; DEFB $77
Descriptografia do carregador de inicialização
Tudo o que é realmente importante é que o gerenciador de inicialização descriptografado esteja localizado em PROG + $35
. Isso significa que, se colocarmos um ponto de interrupção na br 23808
, nesse momento a descriptografia será concluída, veremos o gerenciador de inicialização descriptografado:

Este programa já é muito mais parecido com o caso típico mencionado acima. O valor $4000
( 16384
) é carregado nos registradores IX
e DE
, outra coisa é feita e o controle é transferido para a rotina ROM em $055A
(isto é, alguns bytes abaixo do ponto de entrada padrão no LD-BYTES
). Parece que essa abordagem implementa algum tipo de proteção contra cópia, porque o procedimento padrão não carrega esse arquivo e alguns copistas não o entendem.
Ponto de entrada do programa
Resta descobrir como o programa é chamado após o carregamento. Em vez do usual CALL LD-BYTES
e JP
, LD SP, XXXX
e JP LD-BYTES
são usados aqui. A primeira opção (usual) funciona da seguinte maneira:
CALL
envia o valor atual do contador de software ( PC
) para a pilha.- O controle é passado para a rotina chamada.
- Ao retornar de uma sub-rotina (
RET
), o valor é removido da pilha e ocorre uma transição para o programa de chamada.
Por que isso é feito de maneira diferente aqui? O fato é que o Pac-Man é compatível com o ZX Spectrum 16K e ocupa absolutamente toda a RAM (veja o tamanho do arquivo acima). Assim, ao carregar, o programa substitui a si próprio, tanto o carregador quanto a pilha, onde quer que estejam. Se quiséssemos mudar da ROM para o gerenciador de inicialização usando a pilha e depois chamar o programa baixado via JP
, no momento em que o download foi concluído, não haveria endereço de memória no qual o JP
estava localizado, nem a própria instrução.
Em vez disso, o ponteiro da pilha move-se para a área de memória onde, após o carregamento, o endereço do ponto de entrada do programa aparece e o processador, sem perceber a substituição, remove-o da pilha pelo novo ponteiro e vai para o endereço especificado.
O resultado completo da desmontagem pode ser visualizado no repositório do projeto no github.
Total
Como resultado do estudo do gerenciador de inicialização, descobrimos o seguinte:
- Um arquivo sem cabeçalho com um comprimento de 16384 bytes é baixado em 16384 (na área da tela, o que geralmente é óbvio durante o processo de download).
- No final do download, o ponteiro da pilha está localizado em
$5D7C
, para o qual o controle é transferido.
Nas partes a seguir, falarei sobre como preparar arquivos para gravar em disco e gravar um carregador de arquivos monobloco no assembler.
Links relacionados:
- Perfil "Espectrumista de TRUB . "
- Jogos de engenharia reversa ZX Spectrum (Z80) .
- Adaptação de jogos de fita para o Beta 48 .