|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Note : traduction par Denis Lechevalier. Prérequis
Eh oui, me voici de retour pour un autre tutoriel sur le déplombage MFM... Deliverance est un jeu sur deux disquettes avec un format de piste spécial de $18A0 octets sur chaque piste. La table de correspondance de fichiers qui contient toutes les informations à propos des positions des fichiers sur ces disquettes est stockée directement dans le bloc d'amorce à la position $200. Regardons vite fait la table de fichiers : on va lire la première piste de la disquette 1 en utilisant notre Action Replay bien-aimée... Tapez "rt 0 1 50000" et appuyez sur "Entrée"... Après que la piste ai été chargée, faites comme montré sur l'image ci-dessous pour voir la recopie du contenu en hexa de la table de fichiers. ![]() Bon, comment j'ai su où se trouvait la table de fichiers sur la disquette ?! Jetons un oeil dans le code de l'amorce ("bootcode") qui commence en $5000C. Tapez "d $5000C" et appuyez sur "Entrée". Faites défiler quelques lignes jusqu'à ce que vous voyez ceci : ![]() Mais si vous êtes l'heureux propriétaire d'une extension mémoire dépassant les 512 ko, le jeu allouera $1200 octets de mémoire pour le reste de la piste 0 ($400 octets du bloc d'amorce, $1200 octets d'autre code = $1600 octets de la longueur d'une piste DOS normale) et puis lire ces $1200 octets en utilisant le trackdisk.device. Vous pouvez voir l'appel AllocMem() en $50076 et l'appel DoIO() pour lire les $1200 octets en $50098. Enfin, en $5009C, il copie la table de fichiers depuis la position de l'amorce $200 jusqu'en mémoire haute. Si vous regardez de plus près à l'adresse $5007A, juste après l'appel AllocMem(), vous reconnaîtrez que le résultat de cet appel, qui est en fait l'adresse des $1200 octets du bloc mémoire, est poussé sur la pile ! En $500AC, après que la table de fichiers ai été copiée, l'instruction RTS qui suit amène la dernière adresse depuis la pile et continue l'exécution à cette position. Donc en fait, c'est notre JMP vers le bloc mémoire alloué ! Donc la partie importante de la piste 0 commencera sûrement à la position $400. Désassemblons cet endroit en tapant "d $50400", suivi de "Entrée"... ![]() Comme je l'ai découvert, le numéro de fichier #3 est une sorte de code de jeu principal qui inclut également un autre chargeur de piste qui marche de la même façon que celui-ci. Pour continuer le désassemblage du code où le "JMP $8(A4)" en $5044A nous emmènera alors, on va écraser cette instruction avec une boucle de branchement. Donc, si on démarre le jeu, le programme s'arrêtera à cet endroit, comme ça on peut trouver ou pointe a4+8... Insérez l'instruction branche et écrivez la piste 0 modifiée sur la disquette de jeu comme montré ci-dessous sur l'image : ![]() Réinitialisez votre machine maintenant et laissez le jeu démarrer jusqu'à ce que notre boucle de branchement soit lancée... vous remarquerez ceci si vraiment rien ne se passe ! ;-D Maintenant, activez votre Action Replay à nouveau et jetez un oeil sur les registres en tapant "r" puis "Entrée"... Si la configuration mémoire ci-dessus est celle utilisée, alors A4 pointera vers l'adresse $86800, ainsi notre saut continuera vers le code en $86808 ! Désassemblons le code avec "d $86808" suivi de "Entrée"... Vous devrez aller descendre quelques pages plus bas jusqu'à ce que vous voyez enfin ce code : ![]() Maintenant, pour choper le contenu des disquettes, on va regarder ce que fait le chargeur de pistes... désassemblons le code du chargeur de pistes avec "d $8D334". ![]() On va mettre un point d'arrêt ("breakpoint") de suite en $8D352, comme ça l'Action Replay s'active avant que le chargeur de piste soit appelé. Puis on va changer les paramètres du chargeur et avant de continuer l'exécution, on va mettre un autre point d'arrêt en $8D356, l'instruction juste après le retour du chargeur de piste. Ainsi, on est prévenu quand le chargeur de piste a terminé et on peut choper les pistes avant que le jeu les décompresse ! On ne sauvera aucun fichier sur disquette cette fois et on ne va même pas coder une nouvelle image de disquette aujourd'hui... ;). On va choper les pistes et les écrire directement depuis la mémoire sur nos disquettes fraîchement formatées ! Comme je l'ai dit quelques lignes auparavant, les deux disquettes de jeu sont complètement remplies avec des données, donc on devra utiliser une troisième disquette pour faire tenir toutes les données du jeu sur notre déplombage. Maintenant, réfléchissons à la façon dont on va répartir les données sur ces trois disquettes... Revenez à la table de fichiers, j'ai décidé de diviser les données comme suit : Disquette 1 : $000000 à $0B7976 Disquette 2 : $0B7976 à $182E7E Disquette 3 : $182E7E à $1EB7A4 ![]() Bon d'accord, commençons à créer la disquette déplombée #1. On ne peut pas sortir de l'Action Replay avec la commande "x" de suite parce qu'on est bloqué dans notre boucle. Pour continuer dans le code du jeu, on doit sauter à l'adresse stockée en a4 + 8 ! Étant donné que A4 pointe vers $86800, on va quitter l'Action Replay en faisant "g $86808" suivi de "Entrée"... Maintenant, le jeu commence à lire les pistes (ce qui se fait dans la foulée), entrez dans l'Action Replay à nouveau pour mettre notre point d'arrêt obligatoire comme ceci : "bs $8D352" suivi de "Entrée". Sortez de l'Action Replay à nouveau et attendez jusqu'à ce que l'Action Replay s'affiche... si cela se produit, regardons les "regs" pour voir que le chargeur de pistes veut faire... hum... charger. :-) ![]() La valeur stockée en D0 est la taille du fichier, $8BAC dans le cas de notre fichier #0. Maintenant, étant donné que l'on veut ripper plus que simplement le fichier #0, on va changer la valeur en D0 de manière à ce que le chargeur de piste lise tout les octets que l'on veut stocker sur notre disquette déplombée #1 ($B7976 octets). Pour faire en sorte que le chargeur lise tout depuis $18A0 à $B7976, on définit la valeur en D0 en $B7976-$18A0 (toutes les étapes sont montrées dans l'image ci-dessous). Enfin, on va changer l'adresse de chargement du fichier (stocké en A0) en $918A0... Maintenant, vous pouvez vous demander, mais pourquoi charger les données en $918A0 et pas en $90000 ? Comme on le sait, le fichier #0 commence sur la disquette de jeu à la position $18A0. Je vais donc sauver les pistes sur notre disquette déplombée à partir de $90000 plus tard pour être sûr que le fichier #0 a aussi la bonne position de départ sur notre disquette déplombée ! Donc... si vous changez les "regs" comme décrit, vous pouvez enfin définir le point d'arrêt à l'adresse juste après le renvoi du chargeur de piste avec bs $8D356, suivi par entrée... Quittez l'Action Replay maintenant et attendez que le chargeur de piste ait fini le boulot... vous serez prévenu par l'activation de l'Action Replay. ;-) ![]() Après ça, je continue en lisant la piste 0 en $90000 de manière à ce que l'on ait une recopie du contenu ("dump") complète de la disquette de jeu 1 allant de $0 à $B7976 en mémoire. Maintenant, avant de sauver cela sur notre disquette déplombée #1, on va devoir écraser notre boucle de branchement que l'on a mise sur la disquette originale parce qu'on ne veut pas que notre déplombage boucle ! Faites comme ce qui est montré dans l'image ci-dessous... Et enfin... insérez une disquette déplombée formatée #1 dans le lecteur df0: et sauvez tout ça en faisant : "wt 0 !134 90000". On sauve 134 pistes parce que... !134 * !5632 (taille de piste dos) = !754688 ($B8400). Ainsi, c'est OK pour notre plage allant de $0 à $B7976 ! A présent, la création des disquettes déplombées #2 et #3 est même encore plus facile... revenez dans la partie de ce tutoriel où l'on démarre la disquette de jeu originale #1 et suivez à nouveau toutes les étapes de manière à ce que votre Action Replay s'active juste avant que le chargeur de piste soit appelé... Pour créer la disquette déplombée #2, changez les paramètres de chargement comme ceci : ![]() Pour créer la disquette déplombée #3, changez les paramètres de chargement comme ceci : ![]() On est enfin arrivés au moment où les disquettes originales ne sont plus nécessaires. Maintenant, la seule chose qui reste à faire, c'est d'insérer notre propre chargeur de piste qui gère les pistes DOS normales. Pour faire cela, réinitialisez votre machine et démarrez votre assembleur favori, en espérant que ce soit ASM-One. ;-D Pour rendre la chose plus simple pour vous, j'ai inclus le code source tout entier dans l'archive Zip avec le binaire du chargement de piste (NDLR : vous devez être enregistré au site Flashtro pour pouvoir le télécharger). Donc... réservez quelques kilo-octets de mémoire Chip et lisez le source (en utilisant la commande "r") fourni avec ce tutoriel. Appuyez sur "Esc" pour basculer en mode éditeur, vous devriez vous quelque chose comme ceci : ![]() Maintenant, ce chargeur vérifie lui-même si le jeu veut charger le fichier #4. Si c'est le cas, le code principal du jeu inclut le second chargeur de piste (stocké dans le fichier #3) se trouve déjà décompressé en mémoire. Puis notre chargeur se copie lui-même en mémoire en $7FC00, une région mémoire qui n'est pas utilisée par le jeu et met un JMP $7FC00 sur la première instruction de la deuxième routine de chargement de piste. Comme ça, on n'a pas besoin de toucher le second chargeur compressé sur la disquette. Le code source avec les commentaires est ci-dessous :
Nouveauchargeur :
NumerO :
DISque3 : ; autrement il est sur le disque #3 ! ;-)
DISque3IN :
; pas d'explications supplémentaires pour la gestion du disque 1 et 2, tous pareil que pour le disque 3... DISque2 :
DISque2IN :
DISque1 :
Lecture :
FLASHe :
etatdisque :
Chargeurpiste :
Nouveauchargeurfin : piste0 :
Maintenant, faites comme dans l'image ci-dessous. Assemblez le tout en faisant "a", insérez votre disquette déplombée #1 et lisez la piste 0 en tapant "rt". Enfin, exécutez le source en utilisant "j" et écrivez la piste 0 avec "wt". ![]() ![]() Note : salutations spéciales à Musashi9 pour avoir mis en ligne le (presque) meilleur site Web dans le monde entier et bien sûr à Rob.
|