Sorti en février 1979 (et faisant suite, je vous le donne en mille, au DOS 3.1 sorti quelques mois plus tôt), le DOS 3.2 aura eu lui aussi une durée de vie relativement courte puisque dès août 80, il laissera la place au DOS 3.3. Un malheur n'arrivant jamais seul, il fallait carrément changer les PROM 5 et 6 des cartes contrôleur DISK II de l'époque pour passer au DOS 3.3, les deux systèmes ne pouvant booter sur les mêmes PROM. Ajouté à cela une capacité de stockage accrue, et il n'en fallut pas plus au DOS 3.3 pour envoyer définitivement le 3.2 aux oubliettes ! Au début des années 80 toutefois, plusieurs éditeurs firent en sorte que leurs programmes puissent booter à la fois avec les nouvelles mais aussi les anciennes PROM. Leurs disques contenaient un Boot Sector type 13 secteurs et un Boot Sector type 16 secteurs, chacun étant reconnu comme le premier secteur du disque suivant la PROM qui le lisait. Astucieux et classe si vous voulez mon avis...
L'objectif aujourd'hui n'est pas de refaire l'historique du DOS, on trouve sur le Net d'excellents sites pour cela. Ce qui m'a interpellé en fait quand j'ai été confronté au format 13 secteurs pour la première fois (c'est à dire presque 32 ans après sa sortie...), c'est le fait que le codage bien qu'en 5-3 n'était pas le même pour le Boot Sector et pour le reste du disque ! Et cette info, sauf erreur, je ne l'ai retrouvée nulle part. Il faut dire que la documentation sur le DOS 3.2 reste relativement pauvre comparé à ce que l'on peut trouver sur le DOS 3.3 et ProDOS.
Pour mettre en évidence cette observation, rien de plus simple : on va utiliser Copy II+ 5.x. On reconnaîtra sur la capture d'écran la version issue de Ze Enfoirés Copy Disk (comme d'habitude me direz-vous...) mais vous pouvez utiliser celle que vous voulez. On retrouvait Copy II+ 5.x sur à peu près tous les Copy Disk de l'époque. Attention toutefois à ne pas prendre une version 6 (ou supérieure), sinon vous n'aurez plus du tout les mêmes fonctions (Copy II+ étant alors passé sous ProDOS). Avec votre 5.x donc, configurez votre lecteur en mode DOS 3.2 (menu New Disk Info qui permet de changer le Slot, le Drive et surtout le type de DOS attendu pour chaque Disk). Utilisez ensuite l'éditeur de secteur intégré (menu Sector Editor) sur une image disque DOS 3.2 (voir à la fin de l'article pour en récupérer si vous n'en avez pas).
Lisez alors le premier secteur de la première piste (le fameux Boot Sector). Vous devriez obtenir ce que l'on voit ci-contre.
Si ce n'est pas le cas ou que vous obtenez une "I/O Error", vérifez que vous avez bien configuré Copy II+ en mode DOS 3.2 et que vous lisez bien une image disque DOS 3.2 dans le lecteur concerné...
Appuyez alors sur "L" pour avoir le listing. Et... tada ! Garbage ! Circulez, y'a rien à voir !
Effectivement le code désassemblé ne donne rien de cohérent.
Passez alors au secteur suivant (Sector 01 / Track 00), désassemblez-le (toujours par la touche "L") et là miracle, le code est parfaitement compréhensible. Vous contemplez en fait ici le début de la RWTS du DOS 3.2 du disque. Vous pouvez continuer à passer aux secteurs suivants, plus de problème : le contenu est affiché correctement...
Que se passe-t'il donc ? Tout ceci n'est-il que diableries ? Pourquoi le Boot Sector censé être lisible ne l'est point ?
Avant de pouvoir répondre à ces questions, ô combien existentielles, nous allons d'abord devoir nous occuper de notre émulateur fétiche : AppleWin !
En effet, par défaut, AppleWin est incapable d'amorcer un disque au format DOS 3.2. L’émulateur utilise le code d'une PROM P5A (la version 16 secteurs) qui ne peut reconnaître les headers d'un disque 13 secteurs ni même en décoder le contenu.
Il est pourtant tout à fait possible de modifier AppleWin pour qu'il puisse booter ce type de disque. Comment ? Et bien c'est très simple, on l'a déjà vu plusieurs fois ici, tout ce qui est firmware ou ROM est sous forme de ressources dans l'exécutable d'AppleWin. Il suffit donc de remplacer la ressource FIRMWARE/133 (qui contient en fait le code de la PROM P5A d'une carte contrôleur 16 secteurs) par le contenu d'une PROM P5 originelle (13 secteurs).
Il nous faudra ensuite utiliser des images au format .nib (nibble) d'une disquette 13 secteurs. AppleWin ne reconnaît pas le format D13 (équivalent 13 secteurs du .DSK). Cela tombe bien, on n'en trouve quasiment plus... S'il vous reste toutefois quelques images D13, vous pouvez les convertir au format .nib grâce à Ciderpress.
Comme d'habitude, pour éditer notre Exe, on utilisera Resource Hacker. Démonstration :
Une fois l'Exe ouvert, vous repérez la ressource qui nous intéresse. Elle est dans la partie FIRMWARE, sous-clef 133, sous la référence 1033. Vous la sélectionnez et vous devriez donc avoir sous les yeux dans la partie droite, le code de la PROM5A en elle-même. Un petit clic droit et vous sélectionnez "Replace Resource".
S'ouvre alors cette fenêtre-ci, vous sélectionnez votre fichier PROM 5 (que vous aurez récupéré au préalable) grâce au bouton "Open file with new resource", vous entrez manuellement le Resource Type (FIRMWARE) et le Resource Name (133) et vous appuyez sur le bouton "Replace" (laissez Resource Langage vide). Il ne reste alors plus qu'à sauver l'Exe.
Vous avez bien évidemment fait tout ceci sur une copie de l'exécutable, il va sans dire !
Appelez-là donc AppleWin-DOS32.exe par exemple car elle ne vous servira qu'à ça : booter des images Dos 3.2 (ou dérivés). Inutile d'essayer de lancer avec, des disques 16 secteurs...
OK maintenant que nous avons un AppleWin spécial, nous allons pouvoir entrer dans le vif du sujet et sortir l'aspirine !
Si vous bootez un DOS 3.2, la disquette (ou plutôt l'image disque) s'amorce correctement et le premier secteur de la première piste est bien correctement chargé. Il y a donc bien un code compréhensible qui arrive au processeur et non pas le garbage vu plus haut sous Copy II+ 5.x. On s'en doutait juste un petit peu mais bon...
Pour comprendre ce qui se passe, nous allons boot tracer ! Et oui, une PROM 13 secteurs se boot trace comme on le ferait avec une 16 secteurs. La seule petite différence concerne le JMP BOOT1 qui n'est plus en $C6F8 mais en $C6F9. Et on ne saute plus en $801 mais en $301. Action :
]CALL -151 ; passage sous Monitor *9600<C600.C700M ; déplacement en RAM du code en ROM $C600 *96F9 : 4C 65 FF ; remplacement du JMP $301 *9600G ; exécution du BOOT 0 (modifié) * ; et on récupère la main ! *301L ; et on peut lister le contenu du BOOT1 |
0300- 99 0301- B9 00 08 LDA $0800,Y ; Y = #$99 0304- 0A ASL ; décallage de la table de 0305- 0A ASL ; translation 0306- 0A ASL ; pour avoir directement 0307- 99 00 08 STA $0800,Y ; la forme xxxxx000 en sortie de table 030A- C8 INY ; après correspondance nibble>octets 030B- D0 F4 BNE $0301 030D- A6 2B LDX $2B ; #$60 030F- A9 09 LDA #$09 0311- 85 27 STA $27 ; buffer primaire = $900 0313- AD CC 03 LDA $03CC ; $3CC = #$36 0316- 85 41 STA $41 ; (destination) 0318- 84 40 STY $40 031A- 8A TXA 031B- 4A LSR 031C- 4A LSR 031D- 4A LSR 031E- 4A LSR 031F- 09 C0 ORA #$C0 0321- 85 3F STA $3F ; #$C6 0323- A9 5D LDA #$5D 0325- 85 3E STA $3E 0327- 20 43 03 JSR $0343 ; lecture (-> $C65D si SLOT 6) 032A- 20 46 03 JSR $0346 ; dénibblelisation 032D- A5 3D LDA $3D 032F- 4D FF 03 EOR $03FF ; $3FF = #$09 0332- F0 06 BEQ $033A ; a-t'on lu 9 secteurs ? 0334- E6 41 INC $41 ; non ? on continue - buffer + 1 0336- E6 3D INC $3D ; sector + 1 0338- D0 ED BNE $0327 033A- 85 3E STA $3E ; 033C- AD CC 03 LDA $03CC ; préparation JMP BOOT2 033F- 85 3F STA $3F ; vers $3700 0341- E6 3F INC $3F ; #$37 0343- 6C 3E 00 JMP ($003E) 0346- A2 32 LDX #$32 0348- A0 00 LDY #$00 034A- BD 00 08 LDA $0800,X ; AAADE000 034D- 4A LSR ; devient 0AAADE00 034E- 4A LSR ; devient 00AAADE0 034F- 4A LSR ; devient 000AAADE 0350- 85 3C STA $3C ; $3C = 000AAADE 0352- 4A LSR ; devient 0000AAAD 0353- 85 2A STA $2A ; $2A = 0000AAAD 0355- 4A LSR ; devient 00000AAA 0356- 1D 00 09 ORA $0900,X ; 00000AAA ORA AAAAA000 0359- 91 40 STA ($40),Y ; = AAAAAAAA 035B- C8 INY 035C- BD 33 08 LDA $0833,X ; BBBDE000 035F- 4A LSR ; devient 0BBBDE00 0360- 4A LSR ; devient 00BBBDE0 0361- 4A LSR ; devient 000BBBDE 0362- 4A LSR ; devient 0000BBBD (carry = E) 0363- 26 3C ROL $3C ; $3C devient 00AAADEE 0365- 4A LSR ; A devient 00000BBB (carry = D) 0366- 26 2A ROL $2A ; $2A devient 000AAADD 0368- 1D 33 09 ORA $0933,X ; 00000BBBB ORA BBBBB000 036B- 91 40 STA ($40),Y ; = BBBBBBBB 036D- C8 INY 036E- BD 66 08 LDA $0866,X ; CCCDE000 0371- 4A LSR ; devient 0CCCDE00 0372- 4A LSR ; devient 00CCCDE0 0373- 4A LSR ; devient 000CCCDE 0374- 4A LSR ; devient 0000CCCD (carry = E) 0375- 26 3C ROL $3C ; $3C devient 0AAADEEE 0377- 4A LSR ; A devient 00000CCC (carry = D) 0378- 26 2A ROL $2A ; $2A devient 00AAADDD 037A- 1D 66 09 ORA $0966,X ; 00000CCC ORA CCCCC000 037D- 91 40 STA ($40),Y ; = CCCCCCCC 037F- C8 INY 0380- A5 2A LDA $2A ; 00AAADDD 0382- 29 07 AND #$07 ; AND 00000111 = 00000DDD 0384- 1D 99 09 ORA $0999,X ; 00000DDD ORA DDDDD000 0387- 91 40 STA ($40),Y ; = DDDDDDDD 0389- C8 INY 038A- A5 3C LDA $3C ; 0AAADEEE 038C- 29 07 AND #$07 ; AND 00000111 = 00000EEE 038E- 1D CC 09 ORA $09CC,X ; 00000EEE ORA EEEEE000 0391- 91 40 STA ($40),Y ; = EEEEEEEE 0393- C8 INY 0394- CA DEX 0395- 10 B3 BPL $034A ; on boucle ! 0397- AD 99 08 LDA $0899 ; YYXXX000 (YY = 00 en fait) 039A- 4A LSR ; 0YYXXX00 039B- 4A LSR ; 00YYXXX0 039C- 4A LSR ; 000YYXXX = 00000XXX 039D- 0D FF 09 ORA $09FF ; ZZZZZ000 ORA 00000XXX = ZZZZZXXX 03A0- 91 40 STA ($40),Y 03A2- A6 2B LDX $2B ; #$60 03A4- 60 RTS 03FF- 09 |
Première chose, on voit qu'effectivement, c'est un code tout à fait normal (et heureusement) qui est chargé en $301. On remarque ensuite que la routine, pour la lecture des secteurs fait appel directement au code issu de la PROM (en $C65D si la carte DISK II est en SLOT 6). Mais qu'ensuite elle utilise son propre code de dénibblelisation qui commence en $346. J'en ai profité pour commenter un peu le code et détailler notamment les manipulations au niveau des bits lors du décodage 5-3.
Il va maintenant être temps de regarder ce que fait exactement le code contenu dans une PROM 5 13 secteurs et de comparer avec le code ci-dessus (notamment pour la partie dénibblelisation) :
C600- A2 20 LDX #$20 ; préparation Table de Translation (TT) C602- A0 00 LDY #$00 C604- A9 03 LDA #$03 C606- 85 3C STA $3C C608- 18 CLC C609- 88 DEY C60A- 98 TYA C60B- 24 3C BIT $3C C60D- F0 F5 BEQ $C604 C60F- 26 3C ROL $3C C611- 90 F8 BCC $C60B C613- C0 D5 CPY #$D5 C615- F0 ED BEQ $C604 C617- CA DEX C618- 8A TXA C619- 99 00 08 STA $0800,Y C61C- D0 E6 BNE $C604 ; fin préparation table C61E- 20 58 FF JSR $FF58 ; on récupère l'adresse de la routine PROM5 C621- BA TSX ; par le JSR $FF58 (=$60=RTS) C622- BD 00 01 LDA $0100,X ; avec lecture de la pile C625- 48 PHA ; #$C6 (si slot 6) C626- 0A ASL C627- 0A ASL C628- 0A ASL C629- 0A ASL C62A- 85 2B STA $2B ; #$60 (si Slot 6) C62C- AA TAX C62D- A9 D0 LDA #$D0 ; #$D0 C62F- 48 PHA ; on vient d'empiler $C6D0 pour la suite C630- BD 8E C0 LDA $C08E,X ; enclenche C633- BD 8C C0 LDA $C08C,X ; mode lecture C636- BD 8A C0 LDA $C08A,X ; drive 1 C639- BD 89 C0 LDA $C089,X ; motor ON C63C- A0 50 LDY #$50 ; recalibrage de la tête vers Piste 0 C63E- BD 80 C0 LDA $C080,X ; C641- 98 TYA C642- 29 03 AND #$03 C644- 0A ASL C645- 05 2B ORA $2B ; ORA SLOT C647- AA TAX C648- BD 81 C0 LDA $C081,X ; déplacement C64B- A9 56 LDA #$56 ; routine C64D- 20 A8 FC JSR $FCA8 ; de délai C650- 88 DEY C651- 10 EB BPL $C63E C653- A9 03 LDA #$03 ; adresse C655- 85 27 STA $27 ; de C657- A9 00 LDA #$00 ; destination/buffer primaire C659- 85 26 STA $26 ; = $300 C65B- 85 3D STA $3D ; secteur 0 C65D- 18 CLC ; début lecture secteur (c=0) C65E- 08 PHP ; on empile P (pour sauver c) C65F- BD 8C C0 LDA $C08C,X C662- 10 FB BPL $C65F C664- 49 D5 EOR #$D5 ; recherche headers C666- D0 F7 BNE $C65F C668- BD 8C C0 LDA $C08C,X C66B- 10 FB BPL $C668 C66D- C9 AA CMP #$AA ; du champ C66F- D0 F3 BNE $C664 C671- EA NOP C672- BD 8C C0 LDA $C08C,X C675- 10 FB BPL $C672 C677- C9 B5 CMP #$B5 ; adresse = $D5 $AA $B5 C679- F0 09 BEQ $C684 C67B- 28 PLP ; c = 1 si on a déjà lu le champ adresse C67C- 90 DF BCC $C65D ; si c = 0 on recommence C67E- 49 AD EOR #$AD ; header champ data ? C680- F0 1F BEQ $C6A1 ; oui on continue ? C682- D0 D9 BNE $C65D ; non on recommence C684- A0 03 LDY #$03 ; 3 lectures (volume/track/sector) C686- 84 2A STY $2A C688- BD 8C C0 LDA $C08C,X ; nibble 1 C68B- 10 FB BPL $C688 C68D- 2A ROL ; dénible 4:4 phase 1 C68E- 85 3C STA $3C C690- BD 8C C0 LDA $C08C,X ; nibble 2 C693- 10 FB BPL $C690 C695- 25 3C AND $3C ; dénible 4:4 phase 2 C697- 88 DEY C698- D0 EE BNE $C688 ; les 3 double-nibbles ont été lus ? C69A- 28 PLP ; c = 0 suite au dépilement de P C69B- C5 3D CMP $3D ; si oui, sector = 0 ? C69D- D0 BE BNE $C65D ; non ? on recommence C69F- B0 BD BCS $C65E ; c = 1 : on recommence avec le champ adresse C6A1- A0 9A LDY #$9A ; champ data préparation lecture #$9A nibbles C6A3- 84 3C STY $3C C6A5- BC 8C C0 LDY $C08C,X C6A8- 10 FB BPL $C6A5 C6AA- 59 00 08 EOR $0800,Y ; correspondance TT + EOR nibble C6AD- A4 3C LDY $3C C6AF- 88 DEY C6B0- 99 00 08 STA $0800,Y ; vers buffer secondaire : $800-$89A C6B3- D0 EE BNE $C6A3 C6B5- 84 3C STY $3C C6B7- BC 8C C0 LDY $C08C,X ; lecture 256 nibbles C6BA- 10 FB BPL $C6B7 C6BC- 59 00 08 EOR $0800,Y ; correspondance TT + eor nibble C6BF- A4 3C LDY $3C C6C1- 91 26 STA ($26),Y C6C3- C8 INY C6C4- D0 EF BNE $C6B5 C6C6- BC 8C C0 LDY $C08C,X ; lecture nibble de checksum C6C9- 10 FB BPL $C6C6 C6CB- 59 00 08 EOR $0800,Y ; TT + eor C6CE- D0 8D BNE $C65D ; checksum OK ? C6D0- 60 RTS ; correspond à un JMP $C6D1 en fait C6D1- A8 TAY ; début dénibblelization (Y=00) C6D2- A2 00 LDX #$00 C6D4- B9 00 08 LDA $0800,Y ; buffer secondaire C6D7- 4A LSR ; 000xxxbc -> 0000xxxb + carry = c C6D8- 3E CC 03 ROL $03CC,X ; 000xxxxx -> 00xxxxxc | 0xxxxxxcc | xxxxxccc C6DB- 4A LSR ; 0000xxxb -> 00000xxx + carry = b C6DC- 3E 99 03 ROL $0399,X ; 000xxxxx -> 00xxxxxb | 0xxxxxxbb | xxxxxbbb C6DF- 85 3C STA $3C ; 00000xxx C6E1- B1 26 LDA ($26),Y ; buffer primaire (000xxxxx) C6E3- 0A ASL ; 00xxxxx0 C6E4- 0A ASL ; 0xxxxx00 C6E5- 0A ASL ; xxxxx000 C6E6- 05 3C ORA $3C ; (xxxxx000 ORA 00000xxx = xxxxxxxx) C6E8- 91 26 STA ($26),Y C6EA- C8 INY C6EB- E8 INX C6EC- E0 33 CPX #$33 C6EE- D0 E4 BNE $C6D4 C6F0- C6 2A DEC $2A ; boucle 3 fois C6F2- D0 DE BNE $C6D2 C6F4- CC 00 03 CPY $0300 ; #$99 ? C6F7- D0 03 BNE $C6FC C6F9- 4C 01 03 JMP $0301 ; JMP BOOT1 C6FC- 4C 2D FF JMP $FF2D ; affiche ERR+Bip C6FF- FF ??? |
On retrouve en fait un code assez semblable à celui d'une PROM P5A 16 secteurs. On notera particulièrement que :
- les headers de champs adresses sont $D5 $AA $B5 (voici notamment -en partie- pourquoi une PROM P5 13 secteurs est incapable de lire un disque 16 secteurs).
- les headers de champs DATA sont les mêmes qu'en 16 secteurs (à savoir $D5 $AA $AD).
- la routine lit 410 nibbles : 154 en buffer secondaire et 256 en buffer primaire (qui sert aussi de destination). C'est à partir de ces 410 nibbles que sont générés les 256 octets d'une page complète, le tout grâce à un décodage de type 5-3.
- il n'y a aucun test des headers de fin de champs (adresse ou data) comme sur une PROM P5A d'ailleurs.
- la routine de dénibblelisation 5-3 est différente de celle rencontrée plus haut dans le code du BOOT1. Vous l'aurez compris (car c'est en gras...), nous tenons ici l'explication de l'affichage non correct du secteur 0/piste 0 par Copy II+ notamment.
Concrètement que se passe t'il lorsque l'on boote un disque 13 secteurs normal ?
- La PROM P5 charge le secteur 0, piste 0 et utilise sa routine interne de dénibblelisation, une routine que l'on va qualifier de simplifiée.
- on saute au BOOT1 (en $301) pour commencer le chargement du BOOT2. La routine utilise bien la partie lecture nibble de la PROM (en $C65D) mais va utiliser pour la dénibblelisation son propre code (en $346).
Cette routine de dénibblelisation est exactement celle de la RWTS 3.2. La routine dite simplifiée n'est donc utilisée que pour le chargement du Boot Sector et uniquement à ce moment là.
Quand on utilise Copy II+ 5.x en mode DOS 3.2, on force le programme à utiliser une RWTS 3.2 pour lire les secteurs. Il arrive donc à lire et à décoder correctement le contenu de tous les secteurs SAUF celui du secteur 0, piste 0 qui lui utilise un codage différent. Quand je parle de "codage différent", c'est un abus de langage en fait. D'une part parce que dans les deux cas, avec la RWTS 3.2 mais aussi avec la PROM P5, l'encodage (et le décodage) est du même type 5-3 : un octet de 8 bits est en fait séparé en deux parties, 5 bits d'un côté (qui donneront un nibble) et 3 de l'autre, qui compléteront d'autres bits pour former d'autres nibbles (voir le code commenté ci-dessus pour les manipulations de bits). C'est pour cela qu'il faut 410 nibbles pour obtenir 256 octets. Et d'autre part, car ce codage n'est pas une volonté d'encrypter les choses mais répond tout simplement à une limitation physique du séquenceur (la PROM P6 dont nous avons parlé plus haut), obligeant "matériellement" à la nibblelisation pour sauver magnétiquement un octet (et à la dénibblelisation pour le relire).
On a donc deux décodages de type 5-3, l'un par la PROM P5 et l'autre par la RWTS et pourtant ils ne donnent pas un résultat identique. Pourquoi ? En fait si on regarde de plus près les deux routines de dénibblelisation, on s'aperçoit qu'elles ne décodent pas du tout dans le même ordre les octets. Ce qui fait que les deux routines ne sont pas interchangeables. Elles vont bien assembler de la même manière les nibbles mais elles vont sauver l'octet résultant à des endroits différents.
Pour simplifier (beaucoup), la routine de la PROM va avoir tendance à sauver les octets séquentiellement en partant de l'adresse basse du buffer de destination alors que la routine de la RWTS va faire un micmac en les éparpillant un peu partout.
Concrètement, je vous ai fait deux belles tables permettant ainsi de trouver la correspondance entre les emplacements d'octets. L'utilisation est simple : vous avez sous le nez Copy II+ 5.x qui vous affiche le Boot Secteur d'une disquette 13 secteurs. Si vous avez un peu suivi tout ce qui a été dit jusqu'ici, ce qui est affiché ne correspond pas au code tel qu'il sera en mémoire. Les bon octets sont là mais pas aux bonnes places.
Exemple celui en position $00, c'est à dire $F0 correspond si on suit la table 1 ci-après à la position $32 du code chargé en $300 ! On vérifie, on a bien en $332 : F0 !
Table 1 : Correspondance entre Position octet sous Copy II+ et Code Boot Sector 00- 32 65 98 CB FE 31 64 97 80- B2 E5 18 4B 7E B1 E4 17 08- CA FD 30 63 96 C9 FC 2F 88- 4A 7D B0 E3 16 49 7C AF 10- 62 95 C8 FB 2E 61 94 C7 90- E2 15 48 7B AE E1 14 47 18- FA 2D 60 93 C6 F9 2C 5F 98- 7A AD E0 13 46 79 AC DF 20- 92 C5 F8 2B 5E 91 C4 F7 A0- 12 45 78 AB DE 11 44 77 28- 2A 5D 90 C3 F6 29 5C 8F A8- AA DD 10 43 76 A9 DC 0F 30- C2 F5 28 5B 8E C1 F4 27 B0- 42 75 A8 DB 0E 41 74 A7 38- 5A 8D C0 F3 26 59 8C BF B8- DA 0D 40 73 A6 D9 0C 3F 40- F2 25 58 8B BE F1 24 57 C0- 72 A5 D8 0B 3E 71 A4 D7 48- 8A BD F0 23 56 89 BC EF C8- 0A 3D 70 A3 D6 09 3C 6F 50- 22 55 88 BB EE 21 54 87 D0- A2 D5 08 3B 6E A1 D4 07 58- BA ED 20 53 86 B9 EC 1F D8- 3A 6D A0 D3 06 39 6C 9F 60- 52 85 B8 EB 1E 51 84 B7 E0- D2 05 38 6B 9E D1 04 37 68- EA 1D 50 83 B6 E9 1C 4F E8- 6A 9D D0 03 36 69 9C CF 70- 82 B5 E8 1B 4E 81 B4 E7 F0- 02 35 68 9B CE 01 34 67 78- 1A 4D 80 B3 E6 19 4C 7F F8- 9A CD 00 33 66 99 CC FF |
Honnêtement, à mon humble avis, la table 1, on s'en fout un peu car il est bien plus facile de boot tracer pour checker ce qui est chargé en mémoire que de déduire le code à partir des octets affichés en vrac sous Copy II+. Je l'ai toutefois intégrée à l'article pour vous faire plaisir...
La table 2 par contre est plus intéressante car elle permet de retrouver, quand on a le code en $301 sous le nez, à quel emplacement sous Copy II+ 5.x est tel ou tel octet dans le garbage affiché. Et ça, c'est nettement plus funky !
Exemple, vous avez repéré qu'en $343 vous avez un JMP ($003E) qui va charger les différents secteurs par appel à la routine en PROM $C65D. Mais ce même JMP une fois que tout aura été chargé, va aussi servir à sauter vers le boot 2 ! Pourquoi ne pas directement modifier ce JMP sous Copy II+ afin qu'il nous rende la main avant de sauter au boot 2, le tout sans devoir boot tracer ? Pour ce faire, il va falloir modifier les octets entre $33A et $341. Seulement voilà, sous Copy II+, ils ne sont pas du tout en $x3A (ni $x41 d'ailleurs). La table 2 vous permet alors de savoir à quelle position est chaque octet afin de pouvoir le modifier sous Copy II+ ! Allez, je vous laisse faire le truc par vous-même, je ramasse les copies à la fin... (en fait, c'est un mauvais exemple mais j'espère que vous comprenez l'idée).
Table 2 : Correspondance entre Code Boot Sector et Position octet sous Copy II+ 00- FA F5 F0 EB E6 E1 DC D7 80- 7A 75 70 6B 66 61 5C 57 08- D2 CD C8 C3 BE B9 B4 AF 88- 52 4D 48 43 3E 39 34 2F 10- AA A5 A0 9B 96 91 8C 87 90- 2A 25 20 1B 16 11 0C 07 18- 82 7D 78 73 6E 69 64 5F 98- 02 FD F8 F3 EE E9 E4 DF 20- 5A 55 50 4B 46 41 3C 37 A0- DA D5 D0 CB C6 C1 BC B7 28- 32 2D 28 23 1E 19 14 0F A8- B2 AD A8 A3 9E 99 94 8F 30- 0A 05 00 FB F6 F1 EC E7 B0- 8A 85 80 7B 76 71 6C 67 38- E2 DD D8 D3 CE C9 C4 BF B8- 62 5D 58 53 4E 49 44 3F 40- BA B5 B0 AB A6 A1 9C 97 C0- 3A 35 30 2B 26 21 1C 17 48- 92 8D 88 83 7E 79 74 6F C8- 12 0D 08 03 FE F9 F4 EF 50- 6A 65 60 5B 56 51 4C 47 D0- EA E5 E0 DB D6 D1 CC C7 58- 42 3D 38 33 2E 29 24 1F D8- C2 BD B8 B3 AE A9 A4 9F 60- 1A 15 10 0B 06 01 FC F7 E0- 9A 95 90 8B 86 81 7C 77 68- F2 ED E8 E3 DE D9 D4 CF E8- 72 6D 68 63 5E 59 54 4F 70- CA C5 C0 BB B6 B1 AC A7 F0- 4A 45 40 3B 36 31 2C 27 78- A2 9D 98 93 8E 89 84 7F F8- 22 1D 18 13 0E 09 04 FF |
En attendant, si vous êtes un peu curieux, vous vous êtes sans doute posé LA question. Non, pas "mais pourquoi ce blog ? !", ça il n'y a aucune réponse. Non je parlais d'un autre "pourquoi" : Pourquoi avoir fait deux routines ? Pourquoi ne pas avoir tout simplement utilisé l'une ou l'autre... La réponse saute en partie aux yeux. La routine intégrée à la PROM est beaucoup plus compacte. Vu le peu de place disponible (je vous rappelle qu'il n'y a que 256 octets de dispo), la routine de dénibblelisation type RWTS 3.2 n'aurait jamais pu y rentrer... D'accord mais alors pourquoi ne pas avoir gardé celle de la PROM pour la RWTS donc ? Pour info, pour le DOS 3.3 on a la même routine de dénibblelisation (du 6-2 cette fois) et pour la PROM P5A et pour la RWTS 3.3. C'est vrai, mais la routine de la P5 13 secteurs, bien que plus compacte, est plus lente, que la routine de la RWTS 3.2. J'ai fait quelques petits calculs et on obtient - sauf erreur(s) et approximation(s) - une routine qui tourne autour de 7977 cycles pour la PROM contre 7261 cycles pour celle de la RWTS. De plus la routine de la PROM a la fâcheuse tendance à laisser en plan le 256ème octet lors de la dénibblelisation. Cela fait un peu désordre... Bref vous l'aurez compris, Apple n'avait pas d'autres choix que de faire deux routines différentes. Heureusement, quelques mois plus tard, le DOS 3.3 allait mettre tout le monde d'accord...
Pour aller plus loin :
- l'histoire des DOS 3.x, ça se passe bien entendu sur Apple II History et c'est en anglais !
- pour tout comprendre du DISK II, le site incontournable et, qui plus est, en français : HackZApple.
- La bible du DOS 3.3 (mais avec quelques petits détails sur le DOS 3.2, notamment l'agencement des octets lors de la dénibblelisation page 3-16) : Beneath Apple Dos de Don Worth et Pieter Lechner (in english dans le texte). Facilement trouvable en PDF sur le Net. Si vous ne l'avez pas encore, c'est que vous êtes sûrement arrivés ici par erreur...
- vous voulez tester votre AppleWin spécial DOS 3.2 mais vous n'avez rien ? Je vous propose quelques images .nib qui devraient booter parfaitement. Si ce n'est pas le cas, effacez votre Exe et refaites la manipulation décrite en début d'article car elles sont parfaitement fonctionnelles !
- vous avez dans votre collection des disquettes en 13 secteurs ? Vous voulez les préserver et sauver leur contenu pour la postérité : appliquez cet excellent tutoriel de Saltine pour utiliser SST et faire le transfert. Et pensez à me les envoyer par la même occasion !
- et pour finir, quelques images disque capables de booter à la fois sous PROM 5 et PROM 5A. Le principe est simple : sous PROM 5, la disquette boote "normalement". Sous PROM 5A, le boot sector 16 secteurs installe en mémoire une copie de la routine de lecture de la PROM 5 (ainsi que la routine de dénibblelisation) et va charger le disque comme si c'était un 13 secteurs !