Contrairement aux ordinateurs modernes, sur le spectre, le concept d'un système de fichiers n'était pas en tant que tel. Cela signifie que le téléchargement à partir de chaque type de support nécessitait une implémentation distincte et, dans la plupart des cas, le programme ne pouvait pas simplement être copié d'une bande sur un disque. Dans les cas où le chargeur de programme a été écrit en BASIC, il pourrait être adapté à TR-DOS avec une révision assez simple. Cependant, la situation était compliquée par le fait que dans de nombreux jeux (à la fois de marque et piratés), les chargeurs étaient écrits dans des codes machine et contenaient parfois une protection contre la copie.

Malgré la présence d'un «bouton magique» qui faisait simplement un vidage complet de la mémoire de l'ordinateur et permettait de sauvegarder le programme sur une disquette, les experts ont envisagé de créer des versions de disque des jeux tout en préservant l'image de démarrage d'origine et d'autres attributs.
Dans cet article, je vais vous expliquer comment effectuer une telle adaptation sur l'exemple du jeu Pac-Man , à savoir l'image originale Pac-Man.tzx .
Les outils
Malgré le fait qu'auparavant tout ce travail était effectué directement sur le ZX Spectrum (en l'absence d'autres options), j'adapterai le jeu en utilisant l'émulateur et les utilitaires de ligne de commande. La raison principale est que, surtout au début, le processus d'adaptation consiste en un grand nombre d'essais et d'erreurs, et cela se passe beaucoup moins douloureusement s'il est automatisé. Tout de même peut se faire directement sur le Spectrum.
Dans la première partie, nous utiliserons les outils suivants:
- Émulateur de fusible pour le débogage et les tests.
- SkoolKit pour le démontage.
Désactiver le démarrage dans le chargeur de démarrage
Étant donné que le fichier image et données est téléchargé sans bloc d'en-tête (17 octets avec le nom et le type de fichier), cela signifie que le chargeur est écrit en codes machine. Vous devez trouver où se trouvent ces codes et à quelle adresse ils sont lancés.
Il existe plusieurs façons d'examiner le code du chargeur de démarrage:
Le moyen le plus simple consiste à démarrer le téléchargement du programme, à attendre le démarrage du chargeur de démarrage et à l'arrêter en appuyant sur la touche Space
. Dans de nombreux cas, cela fonctionne, mais dans le cas de Pacman, comme dans de nombreux autres, cela conduit à une réinitialisation.
La prochaine façon consiste à charger le programme en utilisant MERGE ""
au lieu de LOAD ""
. Contrairement à LOAD
, MERGE
ignore l'exécution automatique du programme. Dans le cas de Pac-Man, le démarrage via MERGE
provoque le gel de l'ordinateur avec un décalage d'écran gauche caractéristique. Cela est dû au fait qu'au lieu d'exécuter le programme ligne par ligne, MERGE
essaie de l'analyser dans son intégralité et de le fusionner avec le programme déjà chargé. Cependant, si le programme a un bloc avec des codes machine qui viole la syntaxe du programme, cela entraînera un plantage.
Si vous ne voulez pas vous listbasic
la listbasic
, vous pouvez convertir l'image de bande de TZX en TAP et utiliser l'utilitaire listbasic
fourni avec Fuse:
$ tzx2tap Pac-Man.tzx $ listbasic Pac-Man.tap 1 RANDOMIZE USR (PEEK 23635+256*PEEK 23636+91)
L'adresse 23635
( $5C53
) correspond à la variable système PROG
, qui contient l'adresse de départ de la zone BASIC. Ainsi, le point d'entrée du chargeur de démarrage est décalé de 91 octets par rapport à la zone BASIC.
Une autre façon de regarder le chargeur de démarrage est décrite dans l'article Desativando a autoexecução de um programa BASIC . Dans le débogueur Fuse, vous devez définir un point d'arrêt br 2053
, charger le programme, et lorsque le téléchargement se termine et que l'exécution du code s'arrête, exécutez set 23619 128
. Cela empêchera le démarrage du programme et vous permettra de quitter BASIC.
Démontage du chargeur de démarrage
Connaissant le décalage du point d'entrée par rapport à la zone BASIC, vous pouvez calculer son adresse absolue. Dans le cas du ZX Spectrum 48K sans TR-DOS chargé, la zone BASIC commence à 23755
( $5CCB
). Par conséquent, le chargeur de démarrage démarrera à 23755 + 91 = 23846
( $5D26
).
Pour commencer, il suffit de mettre un point d'arrêt à l'adresse de départ et de consulter les codes machine. Dans Fuse, vous pouvez créer br 23846
et commencer à télécharger le programme. Dès que le bootloader commence à s'exécuter, l'émulateur s'arrête:

Dans le cas où le chargeur est très simple, il suffit de regarder le code démonté dans le panneau du milieu et de comprendre ce qui est chargé. En règle générale, le code de téléchargement d'un fichier sans en-tête ressemble à ceci:
LD IX, $8000 ; LD DE, $4000 ; LD A, $FF ; CALL $0556 ; LD-BYTES JP $8000 ;
Dans un cas plus complexe avec l'exécution de code, vous devez comprendre les étapes et prendre des notes. La suite d'utilitaires SkoolKit est bien adaptée à cela. Si vous vous fixez un objectif, avec son aide, le jeu peut être analysé jusqu'à la dernière vis (message, sprite, son). La procédure à suivre est décrite en détail dans la documentation .
En bref, procédez comme suit:
- Faites un instantané de la mémoire de l'ordinateur
Pac-Man.z80
utilisant tap2sna.py
ou les fonctionnalités de l'émulateur. - Créez un fichier de contrôle
Pac-Man.ctl
avec un ensemble initial d'instructions pour le démontage:
i 16384 Ignore for now c $5D26 Loader
- Exécuter le démontage:
sna2skool.py -H -c Pac-Man.ctl Pac-Man.z80 > Pac-Man.skool
. - Pendant que vous étudiez le code, ajoutez de nouvelles instructions et de nouveaux commentaires au fichier de contrôle.
- Répétez jusqu'à ce que complètement éclairé.
En conséquence, après le premier passage, nous obtenons ce qui suit (mes commentaires, les adresses sont omises):
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
Déchiffrement du chargeur de démarrage
Tout ce qui est vraiment important, c'est que le chargeur de démarrage déchiffré se trouve à PROG + $35
. Cela signifie que si nous mettons un point d'arrêt sur le br 23808
, à ce moment le décryptage sera terminé, nous verrons le chargeur de démarrage décrypté:

Ce programme est déjà beaucoup plus similaire au cas typique mentionné ci-dessus. La valeur $4000
( 16384
) est chargée dans les registres IX
et DE
, quelque chose d'autre est fait et le contrôle est transféré à la routine ROM à $055A
(c'est quelques octets de moins que le point d'entrée standard dans LD-BYTES
). Il semble que cette approche implémente une sorte de protection contre la copie, car la procédure standard ne charge pas ce fichier et certains copistes ne le comprennent pas.
Point d'entrée du programme
Il reste à comprendre comment le programme est appelé après le chargement. Au lieu des CALL LD-BYTES
et JP
habituels, LD SP, XXXX
et JP LD-BYTES
sont utilisés ici. La première option (habituelle) fonctionne comme suit:
CALL
pousse la valeur actuelle du compteur logiciel ( PC
) sur la pile.- Le contrôle est passé à la routine appelée.
- Lors du retour d'un sous-programme (
RET
), la valeur est supprimée de la pile et une transition vers le programme appelant se produit.
Pourquoi est-ce fait différemment ici? Le fait est que Pac-Man est compatible avec le ZX Spectrum 16K et occupe absolument toute la RAM (voir la taille du fichier ci-dessus). Ainsi, lors du chargement, le programme écrase lui-même le chargeur et la pile, où qu'ils se trouvent. Si nous voulions passer de la ROM au chargeur de démarrage à l'aide de la pile, puis appeler le programme téléchargé via JP
, au moment où le téléchargement était terminé, il n'y aurait pas de mémoire dans l'adresse à laquelle se trouvait JP
.
Au lieu de cela, le pointeur de pile se déplace vers la zone de mémoire où, après le chargement, l'adresse du point d'entrée du programme apparaît et le processeur, sans remarquer l'usurpation d'identité, la supprime de la pile par le nouveau pointeur et va à l'adresse spécifiée.
Le résultat complet du désassemblage peut être consulté dans le référentiel du projet sur le github.
Total
À la suite de l'étude du chargeur de démarrage, nous avons découvert ce qui suit:
- Un fichier sans en-tête d'une longueur de 16384 octets est téléchargé à 16384 (dans la zone d'écran, ce qui est généralement évident pendant le processus de téléchargement).
- À la fin du téléchargement, le pointeur de pile est situé à
$5D7C
, où le contrôle est transféré.
Dans les parties suivantes, je parlerai de la façon de préparer les fichiers pour l'écriture sur le disque et d'écrire un chargeur de fichiers monobloc dans l'assembleur.
Liens connexes:
- Profil "Spectateur de TRUB . "
- Rétro-ingénierie des jeux ZX Spectrum (Z80) .
- Adaptação de jogos de fita para Beta 48 .