Un micro-ordinateur FLEX/6809 DIY - Partie 5
Dans cette cinquième partie, nous allons enfin démarrer le système d'exploitation !Le processus est très bien décrit dans le "Flex Adaptation Guide", les étapes sont les suivantes :
- Ecrire un driver pour la console
- Ecrire un driver pour le disque
- Avec un petit programme "QLoad" et le driver disque, charger depuis le disque vers la mémoire le contenu du fichier FLEX.COR (exécutable Flex sans les pilotes)
- Démarrer Flex
- Depuis Flex, Créer le fichier FLEX.SYS
- Créer le secteur de boot et l'inscrire sur la disquette
- Ecrire un chargeur Flex pour le moniteur
Comme on le voit il y a du travail, mais pas de panique nous allons voir chaque étape en détail !
Le Driver pour la console
Le squelette du pilote est le suivant :
; * ;************************************************** ; ACTUAL ROUTINES START HERE ;***************************** ORG $D370 ; [ici le code] ;************************************************** ; * ; I/O ROUTINE VECTOR TABLE * ; * ORG $D3E5 ; TABLE STARTS AT $D3E5 ; ; * INCHNE FDB INNECH ; INPUT CHAR - NO ECHO ; IHNDLR FDB IHND ; IRQ INTERRUPT HANDLER ; SWIVEC FDB $DFC2 ; SWI3 VECTOR LOCATION ; IRQVEC FDB $DFC8 ; IRQ VECTOR LOCATION ; TMOFF FDB TOFF ; TIMER OFF ROUTINE ; TMON FDB TON ; TIMER ON ROUTINE ; TMINT FDB TINT ; TIMER INITIALIZE ROUTINE ; MONITR FDB $F814 ; MONITOR RETURN ADDRESS ; TINIT FDB INIT ; TERMINAL INITIALIZATION ; STAT FDB STATUS ; CHECK TERMINAL STATUS ; OUTCH FDB OUTPUT ; TERMINAL CHAR OUTPUT ; INCH FDB INPUT ; TERMINAL CHAR INPUT ; END
On voit que le code démarre à l'adresse $D370, et qu'à l'adresse $D3E5 on trouve une table indiquant les adresses de chaque routine. Reste donc à implémenter les différents points d'entrée, pour l'instant seuls INCHNE, TINIT, STAT, OUTCH et INCH sont utiles.
Le code complet est disponible dans le gihtub (io.asm), pour le charger en mémoire il faut utiliser la commande 'L' sur le fichier io.s19 (comme on a fait dans les parties précédentes).
Pour tester le code, on peut écrire des petits programmes de test, par exemple pour écrire la lettre X à l'écran :
ORG $0080 OUTPUT EQU $D37F LDA #'X LBSR OUTPUT RTS ENDLe driver pour les disques Cette fois-ci le squelette du code est comme ceci :
;********************************************** ; DISK DRIVER ROUTINE JUMP TABLE ;********************************************** ORG $DE00 DREAD JMP READ DWRITE JMP WRITE DVERFY JMP VERIFY RESTOR JMP RST DRIVE JMP DRV DCHECK JMP CHKRDY DQUICK JMP CHKRDY DINIT JMP INIT DWARM JMP WARM DSEEK JMP SEEK ; [ici le code] END
Curieusement cela ne fonctionne pas comme le driver console, ici on a une table de sauts à l'adresse $DE00 suivi du code effectif. Je trouve cela plus simple et je ne sais pas pourquoi les deux pilotes ne fonctionnent pas de la même manière (peut être qu'on veut éviter un saut supplémentaire dans le pilote console pour gagner en performance ?).
Pour tester le pilote, il faut comme d'habitude le charger en mémoire avec la commande "L", puis charger ce petit programme (testdisk.asm) :
0001 ; Test Disk - Read the boot sector 0002 ; Laurent FRANCOISE 2021 0003 0004 ; Disk driver must be loaded first 0005 0006 ; Disk driver entry points 0007 de15 INIT EQU $DE15 0008 de0c DRIVE EQU $DE0C 0009 de09 RESTORE EQU $DE09 0010 de00 READ EQU $DE00 0011 0012 c200 SCTBUF EQU $C200 ; DATA SECTOR BUFFER 0013 0014 0200 BUFFER EQU $0200 ; SECTOR DATA 0015 0016 0100 ORG $0100 0017 0018 0100 bd de 15 [ 8 ] JSR INIT ; INIT DISK DRIVER 0019 0020 0103 8e c2 00 [ 3 ] LDX #SCTBUF 0021 0106 6f 03 [ 7 ] CLR 3,X ; 0022 0108 bd de 0c [ 8 ] JSR DRIVE ; SELECT DRIVE 0 0023 0024 010b 8e c2 00 [ 3 ] LDX #SCTBUF 0025 010e bd de 09 [ 8 ] JSR RESTORE ; GO TO TRACK 0 0026 0027 0111 8e 02 00 [ 3 ] LDX #BUFFER ; SECTOR DEST. 0028 0114 86 00 [ 2 ] LDA #0 ; TRACK 0029 0116 c6 01 [ 2 ] LDB #1 ; SECTOR 0030 0118 bd de 00 [ 8 ] JSR READ ; READ SECTOR 0031 0032 011b 39 [ 5 ] RTS
Ce programme va lire le secteur de boot (piste 0, secteur 1). Une fois chargé avec la commande "L", il faut le lancer avec la commande "C 0100" :
>C 0100 PC-F5F1 A-80 B-80 X-02FD Y-E002 U-E7C2 S-E751 CC-D4 DP-00 >D 0200 0300 0 1 2 3 4 5 6 7 8 9 A B C D E F 0200 0A 00 00 00 07 04 00 C1 00 00 00 10 CE C0 7F FC ..............?. 0210 C1 05 FD C3 00 10 8E C4 00 8D 35 81 02 27 10 81 ..........5..'.. 0220 16 26 F6 8D 2B B7 C1 08 8D 26 B7 C1 09 20 EA 8D .&..+....&... .. 0230 1F B7 C1 0A 8D 1A B7 C1 0B 8D 15 1F 89 4D 27 D9 .............M'. 0240 BE C1 0A 34 14 8D 09 35 14 A7 80 5A 26 F5 20 C9 ...4...5...Z&. . 0250 10 8C C4 00 26 0F 8E C3 00 EC 84 27 0B 8D 0D 26 ....&......'...& 0260 9E 10 8E C3 04 A6 A0 39 6E 9F C1 08 8D 2F 86 8C .......9n..../.. 0270 B7 E8 18 8D 5F 8E C3 00 B6 E8 18 85 02 26 08 85 ...._........&.. 0 1 2 3 4 5 6 7 8 9 A B C D E F 0280 01 26 F5 1F 89 20 0A B6 E8 1B A7 80 5A 26 E9 8D .&... ......Z&.. 0290 03 C5 1C 39 F6 E8 18 C5 01 26 F9 39 34 02 B6 E8 ...9.....&.94... 02A0 10 84 FB C1 0A 23 02 8A 04 B7 E8 10 35 02 F7 E8 .....#......5... 02B0 1A B1 E8 19 27 10 B7 E8 1B 8D 0B 86 18 B7 E8 18 ....'........... 02C0 04 8D D0 C5 10 BD C1 CB BD C1 CE 39 88 3B 8D 35 ...........9.;.5 02D0 20 D5 8E C2 D1 BD CD 1E 20 8B 8E C2 E2 BD C2 C6 ....... ....... 02E0 26 17 8E C3 05 BD C2 C6 26 0F 8E 01 00 86 0C A7 &.......&....... 02F0 84 BD D4 06 26 06 7E C1 7E 7E CD 03 7E 7F 7F 7F ....&.~.~~..~??? >
Il faut regarder le registre B, si il contient la valeur $80 c'est que le secteur a été lu sans erreur. Dans l'exemple au dessus j'ai utilisé une disquette avec un secteur de boot, avec celle que l'on a fait dans le dernier article il n'y aura que des zéros dans le dump !
Pour lire un autre endroit de la disquette, il suffit de changer directement la piste et le secteur dans le code (avec la commande M), le fichier LST nous apprend qu'il faut modifier les octets $0115 (piste) et $0117 (secteur).
L'air de rien, arrivé à ce point on a un lecteur de disquette qui fonctionne !
QLoad
On commence vraiment ici les choses sérieuses. Maintenant qu'on a les 2 pilotes de périphériques à disposition, on va pouvoir s'en servir pour lancer Flex pour la première fois, avec la disquette que l'on a créé dans le précédent article.
Si vous vous souvenez on a besoin du fichier FLEX.COR, que l'on a positionné sur la piste 1 / secteur 1 de la disquette. C'est le code exécutable de Flex sans les pilotes, et il occupe une vingtaine de secteurs.
Le programme QLoad (pour "Quick Load") va charger en mémoire le contenu de la piste 1 / secteur 1 et suivre la liste chaînée (les 2 premiers octets de chaque secteur) pour charger successivement toutes les parties du programme, jusqu'à trouver un secteur dont l'élément suivant est 0/0.
Il faut que je précise la signification de "charger en mémoire" car contrairement au programme "testdisk", on ne va pas simplement copier les octets les uns à la suite des autres. Il s'agit ici d'un exécutable Flex, qui fonctionne comme ceci :
- l'octet $02 indique le début d'un bloc :
- les 2 octets suivants indiquent l'adresse de destination
- l'octet suivant indique la taille du bloc
- les données sont à la suite
- l'octet $16 contient l'adresse d'exécution
- les 2 octets suivants indiquent l'adresse
Le programme se lance avec la commande "G C100", en ayant préalablement chargé le pilote console et le pilote disque (cela fait en tout donc 3 programmes à charger, en comptant QLoad). La sortie va ressembler à quelque chose comme ça :
>G C100 0101 80 0102 80 0103 80 0104 80 0105 80 0106 80 0107 80 0108 80 0109 80 010A 80 010B 80 010C 80 010D 80 010E 80 010F 80 0110 80 0111 80 0112 80 0113 80 0114 80 0201 80 0202 80 000ü ASSIST09 >
L'affichage correspond au couple piste/secteur suivi du code de retour de la routine READ ($80 si tout s'est bien passé). Une fois FLEX.COR chargé on revient sur le prompt du moniteur.
Le premier démarrage de Flex !
Pour lancer flex, il suffit de faire un saut à l'adresse de démarrage, qui est $CD00 :
>G CD00 FLEX 9.1 DATE (MM,DD,YY)? 08,24,21 +++
Il faut tout d'abord saisir la date au format indiqué, et appuyer sur ENTREE. Le prompt de Flex apparaît (les 3 signes "plus"). On peut essayer de taper une commande, par exemple "DATE" :
+++DATE AUGUST 24, 1921 +++
... et on constate qu'on est bien en 1921 ! (Il existe un patch pour gérer l'an 2000). La commande "CAT" permet de voir le contenu du disque :
+++CAT CATALOG OF DRIVE NUMBER 0 DISK: FLEX #1 NAME TYPE SIZE PRT FLEX .COR 22 APPEND .CMD 3 ASMB .CMD 48 ASN .CMD 1 BUILD .CMD 1 .... SECTORS LEFT = 50 +++
Ça ressemble à quelque chose qui fonctionne !
Création de FLEX.SYS
On pourrait refaire tout ce processus (charger les pilotes, charger Qload, lancer Qload, faire un saut sur le point d'entrée de Flex) à chaque fois, mais reconnaissons que c'est un peu fastidieux (je l'ai fait quelque temps et je confirme !).
Maintenant qu'on a un système Flex qui tourne, on va pouvoir s'en servir pour créer les briques qui nous manquent pour avoir un démarrage "automatique" du système.
La première étape consiste à créer le fichier FLEX.SYS, qui est la concaténation des 2 pilotes console+disque et de FLEX.COR. Les commandes sont décrites page 25 du "Flex Adaptation Guide".
Tout d'abord il faut regarder io.lst et disk.lst pour voir l'adresse de début et de fin de ces 2 programmes. En regardant on trouve :
- io.lst commence en $D370 et se termine en $D3FC
- disk.lst commence en $DE00 et se termine en $DF3E
En suivant le guide il faut donc taper les commandes :
+++SAVE DISK,DE00,DF3E +++SAVE CONSOLE,D370,D3FC,CD00 +++APPEND FLEX.COR,DISK.BIN,CONSOLE.BIN,FLEX.SYS APPEND COMPLETE +++
Si on veut on peut utiliser la commande "CAT FLEX" pour s'assurer que le fichier FLEX.SYS est bien créé :
+++CAT FLEX CATALOG OF DRIVE NUMBER 0 DISK: FLEX #1 NAME TYPE SIZE PRT FLEX .COR 22 FLEX .SYS 25 SECTORS LEFT = 26
Le secteur de boot
C'est là où il va falloir bien suivre ! Ce que l'on veut faire c'est charger en mémoire le fichier FLEX.SYS, qui contient tout ce dont on a besoin (l'exécutable Flex + les pilotes). On pourrait utiliser Qload, mais ça ne serait pas très malin car il faudrait quand même charger les pilotes au préalable, justement pour lancer Qload. Alors comment faire ?
C'est pour cela que le démarrage d'un système d'exploitation se fait classiquement en plusieurs étapes. Dans notre cas on va en avoir 3 :
- Le moniteur ASSIST09 est lancé au RESET de l'ordinateur, et met en place la communication série vers le terminal
- Un chargeur présent dans le moniteur va récupérer et exécuter le contenu du secteur 1/piste 0 du lecteur de disquette (le "bootsector")
- Le bootsector charge le contenu de FLEX.SYS et lance le système d'exploitation.
L'intérêt de fonctionner comme cela est d'isoler les différentes couches et de les rendre "génériques" (dans le moniteur on peut très bien faire autre chose que récupérer le bootsector, et le bootsector peut très bien faire autre chose que charger Flex).
C'est quelque chose de très standard et encore actuel (par exemple pour Linux cela fait l'enchaînement BIOS-<Grub-<Kernel-<Init).
Voici le code complet du secteur de boot , qui fait 206 octets (et donc tient bien dans un seul secteur !)
0001 0002 ; EQUATES 0003 0004 c07f STACK EQU $C07F 0005 c300 SCTBUF EQU $C300 ; DATA SECTOR BUFFER 0006 e810 PIA EQU $E810 0007 0008 c100 ORG $C100 0009 0010 c100 20 0a [ 3 ] LOAD BRA LOAD0 0011 0012 c102 00 00 00 FCB 0,0,0 0013 c105 07 TRK FCB $07 ; FILE START TRACK 0014 c106 04 SCT FCB $04 ; FILE START SECTOR 0015 c107 00 DNS FCB 0 ; DENSITY FLAG 0016 c108 c1 00 TADR FDB $c100 ; TRANSFER ADDRESS 0017 c10a 00 00 LADR FDB 0 ; LOAD ADDRESS 0018 0019 c10c 10 ce c0 7f [ 4 ] LOAD0 LDS #STACK ; SETUP STACK 0020 c110 fc c1 05 [ 6 ] LDD TRK ; SETUP STARTING TRK & SCT 0021 c113 fd c3 00 [ 6 ] STD SCTBUF 0022 c116 10 8e c4 00 [ 4 ] LDY #SCTBUF+256 0023 0024 ; PERFORM ACTUAL FILE LOAD 0025 0026 c11a 8d 35 [ 7 ] LOAD1 BSR GETCH ; GET A CHARACTER 0027 c11c 81 02 [ 2 ] CMPA #$02 ; DATA RECORD HEADER? 0028 c11e 27 10 [ 3 ] BEQ LOAD2 ; SKIP IF SO 0029 c120 81 16 [ 2 ] CMPA #$16 ; XFR ADDRESS HEADER? 0030 c122 26 f6 [ 3 ] BNE LOAD1 ; LOOP IF NEITHER 0031 c124 8d 2b [ 7 ] BSR GETCH ; GET TRANSFER ADDRESS 0032 c126 b7 c1 08 [ 5 ] STA TADR 0033 c129 8d 26 [ 7 ] BSR GETCH 0034 c12b b7 c1 09 [ 5 ] STA TADR+1 0035 c12e 20 ea [ 3 ] BRA LOAD1 ; CONTINUE LOAD 0036 c130 8d 1f [ 7 ] LOAD2 BSR GETCH ; GET LOAD ADDRESS 0037 c132 b7 c1 0a [ 5 ] STA LADR 0038 c135 8d 1a [ 7 ] BSR GETCH 0039 c137 b7 c1 0b [ 5 ] STA LADR+1 0040 c13a 8d 15 [ 7 ] BSR GETCH ; GET BYTE COUNT 0041 c13c 1f 89 [ 6 ] TFR A,B ; PUT IN B 0042 c13e 4d [ 2 ] TSTA ; TFR A,B + TSTA = TAB 0043 c13f 27 d9 [ 3 ] BEQ LOAD1 ; LOOP IF COUNT=0 0044 c141 be c1 0a [ 6 ] LDX LADR ; GET LOAD ADDRESS 0045 c144 34 14 [ 8 ] LOAD3 PSHS B,X 0046 c146 8d 09 [ 7 ] BSR GETCH ; GET A DATA CHARACTER 0047 c148 35 14 [ 8 ] PULS B,X 0048 c14a a7 80 [ 6 ] STA 0,X+ ; PUT CHARACTER 0049 c14c 5a [ 2 ] DECB ; END OF DATA IN RECORD? 0050 c14d 26 f5 [ 3 ] BNE LOAD3 ; LOOP IF NOT 0051 c14f 20 c9 [ 3 ] BRA LOAD1 ; GET ANOTHER RECORD 0052 0053 ; GET CHARACTER ROUTINE - READS A SECTOR IF NECESSARY 0054 0055 c151 10 8c c4 00 [ 5 ] GETCH CMPY #SCTBUF+256 ; OUT OF DATA? 0056 c155 26 0f [ 3 ] BNE GETCH4 ; GO READ CHARACTER IF NOT 0057 c157 8e c3 00 [ 3 ] GETCH2 LDX #SCTBUF ; POINT TO BUFFER 0058 c15a ec 84 [ 5 ] LDD 0,X ; GET FORWARD LINK 0059 c15c 27 0b [ 3 ] BEQ GO ; IF ZERO, FILE IS LOADED 0060 c15e 8d 0d [ 7 ] BSR READ ; READ NEXT SECTOR 0061 c160 26 9e [ 3 ] BNE LOAD ; START OVER IF ERROR 0062 c162 10 8e c3 04 [ 4 ] LDY #SCTBUF+4 ; POINT PAST LINK 0063 c166 a6 a0 [ 6 ] GETCH4 LDA 0,Y+ ; ELSE, GET A CHARACTER 0064 c168 39 [ 5 ] RTS 0065 0066 ; FILE IS LOADED, JUMP TO IT 0067 0068 c169 6e 9f c1 08 [ 8 ] GO JMP [TADR] ; JUMP TO TRANSFER ADDRESS 0069 0070 ; READ SINGLE SECTOR 0071 ; 0072 ; THIS ROUTINE MUST READ THE SECTOR WHOSE TRACK 0073 ; AND SECTOR ADDRESS ARE IN A ANB B ON ENTRY. 0074 ; THE DATA FROM THE SECTOR IS TO BE PLACED AT 0075 ; THE ADDRESS CONTAINED IN X ON ENTRY. 0076 ; IF ERRORS, A NOT-EQUAL CONDITION SHOULD BE 0077 ; RETURNED. THIS ROUTINE WILL HAVE TO DO SEEKS. 0078 ; A,B,X, AND U MAY BE DESTROYED BY THIS ROUTINE, 0079 ; BUT Y MUST BE PRESERVED. 0080 ; WESTERN DIGITAL EQUATES 0081 0082 e818 COMREG EQU $E818 ; COMMAND REGISTER 0083 e819 TRKREG EQU $E819 ; TRACK REGISTER 0084 e81a SECREG EQU $E81A ; SECTOR REGISTER 0085 e81b DATREG EQU $E81B ; DATA REGISTER 0086 0002 DRQ EQU 2 ; DRQ BIT MASK 0087 0001 BUSY EQU 1 ; BUSY MASK 0088 001c RDMSK EQU $1C ; READ ERROR MASK 0089 008c RDCMND EQU $8C ; READ COMMAND 0090 0018 SKCMND EQU $18 ; SEEK COMMAND 0091 0092 e810 PRA EQU $E810 0093 0094 ; READ ONE SECTOR 0095 0096 c16d 8d 2f [ 7 ] READ BSR XSEEK ; SEEK TO TRACK 0097 c16f 86 8c [ 2 ] LDA #RDCMND ; SETUP READ SECTOR COMMAND 0098 c171 b7 e8 18 [ 5 ] STA COMREG ; ISSUE READ COMMAND 0099 c174 8d 52 [ 7 ] BSR DEL28 ; DELAY 0100 c176 5f [ 2 ] CLRB ; GET SECTOR LENGTH (=256) 0101 c177 8e c3 00 [ 3 ] LDX #SCTBUF ; POINT TO SECTOR BUFFER 0102 c17a b6 e8 18 [ 5 ] READ3 LDA COMREG ; GET WD STATUS 0103 c17d 85 02 [ 2 ] BITA #DRQ ; CHECK FOR DATA 0104 c17f 26 08 [ 3 ] BNE READ5 ; BRANCH IF DATA PRESENT 0105 c181 85 01 [ 2 ] BITA #BUSY ; CHECK IF BUSY 0106 c183 26 f5 [ 3 ] BNE READ3 ; LOOP IF SO 0107 c185 1f 89 [ 6 ] TFR A,B ; SAVE ERROR CONDITION 0108 c187 20 0a [ 3 ] BRA READ6 0109 c189 b6 e8 1b [ 5 ] READ5 LDA DATREG ; GET DATA BYTE 0110 c18c a7 80 [ 6 ] STA 0,X+ ; PUT IN MEMORY 0111 c18e 5a [ 2 ] DECB ; DEC THE COUNTER 0112 c18f 26 e9 [ 3 ] BNE READ3 ; LOOP TIL DONE 0113 c191 8d 03 [ 7 ] BSR XWAIT ; WAIT TIL WD IS FINISHED 0114 c193 c5 1c [ 2 ] READ6 BITB #RDMSK ; MASK ERRORS 0115 c195 39 [ 5 ] RTS ; RETURN 0116 0117 ; WAIT FOR 1771 TO FINISH COMMAND 0118 0119 c196 f6 e8 18 [ 5 ] XWAIT LDB COMREG ; GET WD STATUS 0120 c199 c5 01 [ 2 ] BITB #BUSY ; CHECK IF BUSY 0121 c19b 26 f9 [ 3 ] BNE XWAIT ; LOOP TIL NOT BUSY 0122 c19d 39 [ 5 ] RTS ; RETURN 0123 0124 ; SEEK THE SPECIFIED TRACK 0125 0126 c19e 34 02 [ 6 ] XSEEK PSHS A 0127 c1a0 b6 e8 10 [ 5 ] LDA PRA 0128 c1a3 84 fb [ 2 ] ANDA #%11111011 ; pre-select side 0 0129 c1a5 c1 0a [ 2 ] CMPB #$0A ; side 0 or 1 ? 0130 c1a7 23 02 [ 3 ] BLS XSEEK1 ; side 0 0131 c1a9 8a 04 [ 2 ] ORA #%100 ; side 1 0132 c1ab b7 e8 10 [ 5 ] XSEEK1 STA PRA ; set side 0133 c1ae 35 02 [ 6 ] PULS A 0134 c1b0 f7 e8 1a [ 5 ] STB SECREG ; SET SECTOR 0135 c1b3 b1 e8 19 [ 5 ] CMPA TRKREG ; DIF THAN LAST? 0136 c1b6 27 10 [ 3 ] BEQ DEL28 ; EXIT IF NOT 0137 c1b8 b7 e8 1b [ 5 ] STA DATREG ; SET NEW WD TRACK 0138 c1bb 8d 0b [ 7 ] BSR DEL28 ; GO DELAY 0139 c1bd 86 18 [ 2 ] LDA #SKCMND ; SETUP SEEK COMMAND 0140 c1bf b7 e8 18 [ 5 ] STA COMREG ; ISSUE SEEK COMMAND 0141 c1c2 8d 04 [ 7 ] BSR DEL28 ; GO DELAY 0142 c1c4 8d d0 [ 7 ] BSR XWAIT ; WAIT TIL DONE 0143 c1c6 c5 10 [ 2 ] BITB #$10 ; CHECK FOR SEEK ERROR 0144 ; DELAY 0145 0146 c1c8 bd c1 cb [ 8 ] DEL28 JSR DEL14 0147 c1cb bd c1 ce [ 8 ] DEL14 JSR DEL 0148 c1ce 39 [ 5 ] DEL RTS 0149 0150 END
On y retrouve en grande partie le code de QLoad et les routines du pilote de disque dont on a besoin ici (READ et SEEK). A la fin l'instruction "JMP [TADR]" lance Flex.
Les octets 5 et 6 contiennent la piste et le secteur où commence le fichier FLEX.SYS. Pour connaître les valeurs à indiquer, on peut utiliser la commande
+++LINK FLEX.SYS
qui va positionner ces 2 octets dans le secteur de boot. On peut soit relire le secteur de boot depuis le moniteur avec TestDisk pour trouver les valeurs.
Autre solution avec la commande DUMP, les 2 premiers chiffres sont la piste et le secteur (07 et 04 ici). Il faut appuyer sur ESC pour stopper le défilement :
+++DUMP FLEX.SYS 07 04 07 05 00 01 02 CC 00 35 08 18 3A 00 00 04 00 00 _____L_5__:_____ 00 FF 1B 00 00 00 00 00 00 00 00 00 00 00 00 00 _?______________ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ________________ 00 00 00 00 00 00 00 01 00 00 00 00 00 02 CC 49 ______________LI 01 00 02 CC 4E 5A 2B 2B 2B 04 3F 3F 3F 04 57 48 ___LNZ+++_???_WH 41 54 3F 04 43 41 4E 27 54 20 54 52 41 4E 53 46 AT?_CAN'T TRANSF 45 52 04 4E 4F 54 20 46 4F 55 4E 44 04 44 49 53 ER_NOT FOUND_DIS 4B 20 45 52 52 4F 52 20 23 04 44 52 49 56 45 53 K ERROR #_DRIVES 20 4E 4F 54 20 52 45 41 44 59 04 47 45 54 00 D2 NOT READY_GET_R 0E 4D 4F 4E 00 D3 4A 00 27 10 03 E8 00 64 00 0A _MON_SJ_'__h_d__ 02 CC C0 01 39 02 CC D8 01 39 02 CC E4 01 39 02 _L@_9_LX_9_Ld_9_ CC F8 C4 01 00 00 00 00 00 00 00 7E CD 57 7E CD LxD________~MW~M 6B 7E CD B2 7E CD 09 7E CD 0C 7E CD 0F 7E CD 12 k~M2~M_~M_~M_~M_ 7E CE FA 7E CF 40 7E CE 2C 7E CE 82 7E CF ED 7E ~Nz~O@~N,~N_~Om~ CE B4 7E D0 0E 7E CD EB 7E D0 36 7E D1 A1 7E D0 N4~P_~Mk~P6~Q!~P EA 7E D3 48 7E CF 85 7E CF D4 7E D2 7E 7E D1 2E j~SH~O_~OT~R~~Q.
Pour écrire le secteur sur le disque j'ai fait un petit programme qui est l'équivalent de TestDisk, mais en écriture :
0001 0002 de15 INIT EQU $DE15 0003 de0c DRIVE EQU $DE0C 0004 de09 RESTORE EQU $DE09 0005 de00 READ EQU $DE00 0006 de03 WRITE EQU $DE03 0007 0008 c200 SCTBUF EQU $C200 ; DATA SECTOR BUFFER 0009 0010 c100 BUFFER EQU $C100 0011 0012 0020 ORG $020 0013 0014 0020 TRACK RMB 1 0015 0021 SECTOR RMB 1 0016 0017 0500 ORG $0500 0018 0019 0500 bd de 15 [ 8 ] JSR INIT 0020 0021 0503 8e c2 00 [ 3 ] LDX #SCTBUF 0022 0506 6f 03 [ 7 ] CLR 3,X ; SET DRIVE 0 0023 0508 bd de 0c [ 8 ] JSR DRIVE 0024 0025 050b 8e c2 00 [ 3 ] LDX #SCTBUF 0026 050e bd de 09 [ 8 ] JSR RESTORE 0027 0028 0511 8e c1 00 [ 3 ] LDX #BUFFER 0029 0030 0514 86 00 [ 2 ] LDA #0 0031 0516 97 20 [ 4 ] STA TRACK 0032 0518 86 01 [ 2 ] LDA #1 0033 051a 97 21 [ 4 ] STA SECTOR 0034 0035 051c dc 20 [ 5 ] LDD TRACK 0036 051e bd de 03 [ 8 ] JSR WRITE 0037 0038 0039 0521 39 [ 5 ] RTS
Pour écrire le secteur de boot depuis le moniteur, il faut :
- Charger le pilote disque en mémoire (Commande L)
- Charger le secteur de boot en mémoire (Commande L)
- Charger WriteBootSector en mémoire (Commande L)
- Lancer WriteBootSector (Commande C 0500)
On peut ensuite utiliser TestDisk pour relire le secteur de boot et vérifier que son contenu est bien le bon.
Le chargeur pour le moniteur
Dernier élément, le chargeur du moniteur, dont le rôle est de récupérer le secteur de boot et de l'exécuter.
J'ai ajouté à Assist09 la routine nécessaire, qui ressemble beaucoup à TestDisk + une partie du pilote disque :
1759 1760 ******************************************************* 1761 * FLEX LOADER 1762 ******************************************************* 1763 1764 1765 c100 XLOADER EQU $C100 1766 1767 f804 bd f8 15 [ 8 ] FLEX JSR XINIT 1768 1769 f807 bd f8 56 [ 8 ] JSR XRESTORE 1770 1771 f80a 8e c1 00 [ 3 ] LDX #XLOADER 1772 f80d 86 01 [ 2 ] LDA #1 1773 f80f bd f8 29 [ 8 ] JSR XREAD 1774 1775 f812 7e c1 00 [ 4 ] JMP XLOADER 1776 1777 1778 0002 DRQ EQU 2 ; DRQ BIT MASK 1779 0001 BUSY EQU 1 ; BUSY MASK 1780 001c RDMSK EQU $1C ; READ ERROR MASK 1781 1782 e818 COMREG EQU $E818 ; COMMMAND REGISTER 1783 e819 TRKREG EQU $E819 ; TRACK REGISTER 1784 e81a SECREG EQU $E81A ; SECTOR REGISTER 1785 e81b DATREG EQU $E81B ; DATA REGISTER 1786 008c RDCMND EQU $8C ; READ COMMAND 1787 0008 RSCMND EQU $08 ; RESTORE COMMAND 1788 1789 1790 ; INIT AND WARM 1791 ; 1792 ; DRIVER INITIALIZATION 1793 1794 1795 f815 4f [ 2 ] XINIT CLRA ; select PIA control register 1796 f816 b7 e8 11 [ 5 ] STA CRA 1797 f819 86 0f [ 2 ] LDA #$0F ; PORTA b0..b3 = output 1798 f81b b7 e8 10 [ 5 ] STA DDRA 1799 f81e 86 3c [ 2 ] LDA #%00111100 ; select PIA output register 1800 f820 b7 e8 11 [ 5 ] STA CRA 1801 f823 86 09 [ 2 ] LDA #%00001001 ; b3=1 (FM) 1802 ; b2=0 (side 0) 1803 ; b1-0 = 01 ( drive 1 select) 1804 f825 b7 e8 10 [ 5 ] STA PRA 1805 1806 f828 39 [ 5 ] RTS 1807 1808 ; READ 1809 ; 1810 ; READ ONE SECTOR 1811 ; 1812 ; ENTRY - (X) = Address in memory where sector is to be placed. 1813 ; (A) = Track Number 1814 ; EXIT - (X) May be destroyed 1815 ; (A) May be destroyed 1816 ; (B) = Error condition 1817 ; (Z) = 1 if no error 1818 ; = 0 if an erro 1819 1820 f829 86 8c [ 2 ] XREAD LDA #RDCMND ; SETUP READ SECTOR COMMAND 1821 f82b b7 e8 18 [ 5 ] STA COMREG ; ISSUE READ COMMAND 1822 f82e 17 00 32 [ 9 ] LBSR XDEL28 ; DELAY 1823 f831 5f [ 2 ] CLRB ; GET SECTOR LENGTH (=256) 1824 f832 b6 e8 18 [ 5 ] XREAD3 LDA COMREG ; GET WD STATUS 1825 f835 85 02 [ 2 ] BITA #DRQ ; CHECK FOR DATA 1826 f837 26 08 [ 3 ] BNE XREAD5 ; BRANCH IF DATA PRESENT 1827 f839 85 01 [ 2 ] BITA #BUSY ; CHECK IF BUSY 1828 f83b 26 f5 [ 3 ] BNE XREAD3 ; LOOP IF SO 1829 f83d 1f 89 [ 6 ] TFR A,B ; ERROR IF NOT 1830 f83f 20 0a [ 3 ] BRA XREAD6 1831 f841 b6 e8 1b [ 5 ] XREAD5 LDA DATREG ; GET DATA BYTE 1832 f844 a7 80 [ 6 ] STA 0,X+ ; PUT IN MEMORY 1833 f846 5a [ 2 ] DECB ; DEC THE COUNTER 1834 f847 26 e9 [ 3 ] BNE XREAD3 ; LOOP TIL DONE 1835 f849 8d 03 [ 7 ] BSR XWAIT ; WAIT TIL WD IS FINISHED 1836 f84b c5 1c [ 2 ] XREAD6 BITB #RDMSK ; MASK ERRORS 1837 f84d 39 [ 5 ] RTS ; RETURN 1838 1839 ; WAIT 1840 ; 1841 ; WAIT FOR 1771 TO FINISH COMMAND 1842 1843 f84e f6 e8 18 [ 5 ] XWAIT LDB COMREG ; GET WD STATUS 1844 f851 c5 01 [ 2 ] BITB #BUSY ; CHECK IF BUSY 1845 f853 26 f9 [ 3 ] BNE XWAIT ; LOOP TIL NOT BUSY 1846 f855 39 [ 5 ] RTS ; RETURN 1847 1848 ; RESTORE 1849 1850 f856 86 08 [ 2 ] XRESTORE LDA #RSCMND ; SETUP RESTORE COMMAND 1851 f858 b7 e8 18 [ 5 ] STA COMREG ; ISSUE RESTORE COMMAND 1852 f85b 8d 06 [ 7 ] BSR XDEL28 ; DELAY 1853 f85d 17 ff ee [ 9 ] LBSR XWAIT ; WAIT TIL WD IS FINISHED 1854 f860 c5 d8 [ 2 ] BITB #$D8 ; CHECK FOR ERROR 1855 f862 39 [ 5 ] RTS ; RETURN 1856 1857 ; DELAY 1858 1859 f863 17 00 00 [ 9 ] XDEL28 LBSR XDEL14 1860 f866 17 00 00 [ 9 ] XDEL14 LBSR XDEL 1861 f869 39 [ 5 ] XDEL RTS
Pour en faire une commande du moniteur c'est assez simple, il y a dans le code de ASSIST09 un tableau "CMDTBL" contenant la lettre correspondant à la commande et l'adresse permettant de l'exécuter :
0541 f1c3 04 FCB 4 0542 f1c4 46 FCC /F/ ; 'FLEX' COMMAND 0543 f1c5 06 3f FDB FLEX-*
J'ai choisi très originalement la commande "F". Une fois le code de Assist09 assemblé et programmé dans l'EPROM, au prochain boot on peut enfin démarrer le système d'exploitation en appuyant juste sur une lettre, comme ceci :
ASSIST09 >F FLEX 9.1 DATE (MM,DD,YY)?
Et voilà le travail :-)
Conclusion provisoire
Avec cet article (et les 4 précédents) j'ai décrit tout ce que j'ai réalisé jusqu'à aujourd'hui sur cet ordinateur. Mais il reste encore de nombreuses tâches à réaliser !
En voici quelques unes :
- Adapter NEWDISK pour pouvoir formatter des disquettes depuis Flex
- Gérer la double densité
- Porter PUTBOOT pour rendre une disquette bootable depuis Flex
- Trouver un moyen de copier des fichiers sur la disquette via le port série depuis Assist09
- Ajouter le pilote pour l'imprimante
- Utiliser l'horloge RTC pour éviter d'avoir à saisir la date à chaque démarrage
- Porter Flex V2 (le portage dans ces articles a été fait avec la V1)
- Assembler la version PCB
- Ca serait bien d'avoir la gestion clavier/écran intégré à l'ordinateur, peut être que le connecteur d'extension sur la version PCB pourrait être utile !
- Explorer l'archive de disques Flex pour augmenter la logithèque de cet ordinateur
Et il y en a probablement d'autres !
Ressources
- Le projet github est disponible ici : https://github.com/laurent-fr/LFlex21
- Le code source présenté dans cet article est dans le dossier /software/flex
- Une copie du Flex Adaptation Guide est dans le dossier /doc (fichier 6809fadg.pdf )