Table des matières

Retourner au sommaire

Le FDC

Basé sur les articles publiés dans Quasar CPC numéros 12, 13, 14, 15 et 16, Assembleur : Hardware, par OffseT.

Décrire les quelques instructions secondaires restantes et rajouter des informations sur les timings.

Rajouter l'explication sur les autres gaps présents sur le disque et leur influence sur le calcul du gap#3.

Fan De Chichoune ! Vous voici en tête à tête avec l'article dédié au FDC (en français : contrôleur de disquettes). Nous allons ici étudier comment fonctionne ce grand gourou du pilotage de lecteur de disquettes, sa logique de fonctionnement, sa programmation, ses travers, etc..

En conclusion, vous aurez même droit à une bibliothèque de routines complète qui vous permettra de tester la quasi-totalité des fonctions du FDC sans perdre vos neuronnes.

Les prérequis

Nous allons commencer timidement par une petite présentation. En effet, notre brave FDC est une bestiole assez réticente qu'il faut manipuler avec des pincettes… Il vaut donc mieux bien la connaître avant de la triturer.

Ses possibilités

Tel qu'il est câblé sur le CPC, le FDC (Ferronnerie Du Cantal ?) nous permet de gérer deux drives simple ou double densité. Sauf bidouilles, le lecteur interne est obligatoirement un lecteur simple face alors que le lecteur externe peut être un double face. En ce qui concerne le nombre de pistes, le FDC peut en gérer jusqu'à 256 mais, en pratique, on en aura au maximum 82 à 84 pour les lecteurs 3”1/2 et les 5”1/4 dits 80 pistes ; nos braves lecteurs 3” étant eux limités à 42 pistes. La densité ne change quant à elle que le nombre de secteurs par piste. C'est ainsi que sur CPC, le format standard compte 9 secteurs par piste (on est en double densité) alors qu'il y en a 18 sur les disquettes PC (haute densité). La gestion des drives haute densité étant impossible sur CPC et le mode simple densité ne présentant aucun intérêt, nous raisonnerons uniquement en double densité.

Entrons dans le vif du sujet

Puisque c'est le thème principal de cette première section sur le FDC (Fête De Cannes ?), allons y, parlons de la structure de nos petites disquettes. Comme vous le savez certainement, une disquette est coupée en pistes, elles-mêmes partagées en plages que l'on appelle secteurs. Les pistes sont figées, elles dépendent du lecteur de disquettes. C'est ainsi qu'on a des lecteurs 40 pistes et 80 pistes ; et on ne peut rien faire de plus que de tenter de grapiller deux ou trois pistes de plus avant la butée de fin de course. En revanche, dans une piste, on fait à peu près ce qu'on veut comme découpage dans la limite de 6250 octets. Ces quelques octets devront être partagés entre les données proprement dites et des zones d'informations (nom, taille des secteurs) et de temporisation (GAP).

Les secteurs

Le FDC offre une grande liberté... mais attention à ne pas tomber ! Le FDC (Flamberge De Cancrelat ?) nous propose sept tailles de secteurs différentes :

Taille Capacité
0 128
1 256
2 512
3 1024
4 2048
5 4096
6 8192

Bien entendu, la capacité est indiquée en octets. Oui, il est toujours là ! Le petit blond à lunettes vient de lancer sa première critique de l'article ! Un secteur de taille 6 est plus grand qu'une piste ! En fait, ce type de secteur sert à déformater les pistes… ou à créer des formats spéciaux dits à “arrêt moteur”1).

Maintenant, libre à nous de remplir nos petites pistes avec des secteurs dans la limite des 6250 octets disponibles. Mais attention, comme je vous l'ai déjà dit, il faut également prendre en compte les octets de GAP ainsi que quelques octets d'identification. Voici donc la structure exacte d'un secteur :

Les structures de données en italique sont invariables quels que soient les secteurs. Ensuite, les 4 octets d'ID secteur sont respectivement le numéro de piste, le numéro de tête, le nom du secteur et sa taille. Les n octets de données sont bien évidemment le contenu de notre secteur et les n octets de GAP sont en fait la zone de séparation entre deux secteurs consécutifs.

Le tout est d'optimiser le nombre de secteurs par piste et leur taille de façon à avoir un GAP le plus faible possible. Mais attention, il ne faut pas avoir un GAP trop faible car sinon, compte tenu de la variation de la vitesse de rotation des différents lecteurs, votre disquette aura du mal à passer chez certains. Un GAP minimum de 32 octets vous assure que votre disquette sera lisible même sur un lecteur un peu mollasson. Par contre, même si la pratique n'est pas courante, il est tout à fait possible d'avoir des secteurs de tailles différentes sur une même piste. À titre d'exemple, une disquette au format DATA compte 9 secteurs de taille 2 par piste, ce qui nous donne donc un GAP de &78 octets ! Autant vous dire que le jour où votre lecteur n'arrivera plus à lire ce genre de format, il sera vraiment fatigué ! Si on prend le format 206K de Format II (utilitaire du défunt CPC-Infos), on a 10 secteurs de taille 2 par piste, soit un GAP de 51 octets ce qui est beaucoup plus optimisé.

Et le plombage des discs alors ?

On a en effet la possibilité de faire des formats batards, formats écrasés, formats avec “arrêt moteur”, et autres… Mais si ces formats ont connu leur heure de gloire avec le “plombage”, on ne se penchera pas dessus car on cherchera plutôt à optimiser les paramètres “capacité disque” et “vitesse de chargement”2).

Pourquoi le plombage est-il toujours associé à des illustrations macabres ?

L'ordre des secteurs

Tout dépend de ce que l'on veut… Si les secteurs sont lus en séquentiel (c'est le cas de l'Amsdos), il est intéressant de les entrelacer sur la piste ; je m'explique. En format DATA, les secteurs portent les noms &C1 à &C9 et sont formatés comme suit sur la piste : &C1, &C6, &C2, &C7, &C3, &C8, &C4, &C9, &C5. Pourquoi ? Eh bien simplement car quand l'Amsdos va avoir à lire les secteurs &C1 et &C2, il va lancer un ordre de lecture du secteur &C1, récupérer les données, puis lancer l'ordre de lecture du secteur &C2 ; oui mais voilà, le disque tourne en permanence et pendant l'envoi de l'ordre de lecture du deuxième secteur, le début du secteur suivant le secteur &C1 est déjà passé devant la tête de lecture. Or, si ce secteur était &C2, c'est raté et il va falloir refaire un tour complet : perte de temps ! Avec le format entrelacé, le secteur &C2 est en fait le premier qui sera effectivement rencontré puisque c'est le &C6 qu'on aura raté.

Dans le cas où l'on désire lire nos secteurs par bloc, par exemple &C2 à &C7 (les instructions du FDC permettent effectivement de commander la lecture de x secteurs consécutifs du moment où l'on reste sur la même piste), vous l'aurez compris, exit le mode entrelacé, on met tout à la suite. Je ne vous cache pas que c'est avec ce principe là que l'on obtient les meilleurs résultats (plus de 12K par seconde sur un lecteur 3”), mais ça n'est clairement pas adapté à la gestion d'un système de fichiers qui a besoin de travailler avec de petites zones.

FDC : principe de fonctionnement

Et comme par magie, voici le... Face De Chien ? Dans cette section, nous allons voir comment il faut s'y prendre pour communiquer avec le FDC. À la base, c'est plutôt simple puisque tout se fait via deux registres. Le premier, situé à l'adresse &FB7E, est le registre d'état principal. Le second, situé à l'adresse &FB7F, est le registre de données. Nous disposons également d'un troisième port (&FA7E) qui nous permettra d'allumer et d'éteindre les moteurs de tous les lecteurs de disquettes connectés au CPC.

Voyons à présent en détail ce qui se cache derrière chacun de ces ports après quoi, nous enchaînerons sur le protocole de communication à proprement parler et nous serons armés pour étudier quelques unes des 15 instructions que connait notre brave FDC (Face De Cloporte ?).

Les portes d'accès

Le registre d'état principal

Comme sus-cité, le port &FB7E est le registre d'état principal du FDC (Fan De Chichoune ?). Ah, je vois que le petit blond à lunettes va poser une question ? Paf ! Une bonne giffle pour qu'il la ferme ! Non mais !

Reprenons. Voilà un port qui est très simple ; tout d'abord, il ne fonctionne qu'en lecture et nous renvoie des informations d'ordre général sur l'état du FDC (Fils de Contrôleur ?). On peut aller lire ce brave petit registre principal quand bon nous semble, il n'y a aucune restriction d'accès ! C'est bien beau ça, mais quels renseignements nous donne-t-il exactement ?

Hum… je vous demande un instant, le petit blond à lunettes est en train de ramener sa fraise… Et vlam, un coup de clavier PC dans la tronche ! J'espère que je l'ai pas trop abîmé quand même… (le petit blond à lunettes pas le PC !).

Or donc, voici la description de l'octet lu en &FB7E :

Facilitateur De Communication ? Le registre d'état principal

Je me doute que ce schéma doit pour le moment vous laisser sceptique, mais tout va s'éclaircir en abordant la partie sur le protocole de communication et les phases de fonctionnement du FDC (Fan De CPC ?).

Le port de données

Mais pour l'heure, passons au port &FB7F, le port des données. Celui-ci fonctionne à double sens (vous l'aviez sans doute déjà deviné si vous avez bien étudiez la structure du registre d'état principal). C'est grâce à ce port que le FDC (Fou De Chocolat ?) va être programmé, qu'il va recevoir toutes les informations nécessaires aux diverses instructions et qu'il va retourner sa copie (les registres d'état secondaires dont nous parlerons plus bas). Autant vous dire que c'est le port le plus important ! Nous allons en reparler tout de suite avec le protocole de communication.

Le contrôle des moteurs

Et puis enfin, il y a le petit dernier, le port &FA7E, qui va nous permettre, lorsqu'on lui met gentiment son petit bit 0 à 1, d'allumer le moteur de tous les lecteurs de disquettes. Naturellement, on éteint tout en remettant ce bit à 0. Toutefois, deux restrictions, ce port ne marche qu'en écriture et ne permet pas de choisir quel lecteur on allume : c'est tous ou aucun !

Le protocole

Il est en fait assez simple mais il faut être très rigoureux et ne jamais sauter d'étape… Pour arriver à faire cracher le morceau au FDC (Fond De Compensation ?), il faut passer impérativement par trois phases bien distinctes.

Famille De Chipsets ?

Phase d'instruction

La première phase est la phase d'instruction. Concrêtement il s'agit ici d'envoyer sur le port des données (&FB7F) un code d'instruction suivi de ses éventuels paramètres (de 0 à 9 selon le cas). Attention toutefois, une phase d'instruction ne sera acceptée par le FDC (Faute De Calcul ?) que si le bit 4 du registre d'état principal est à 0. Ah, pour une fois le petit blond à lunettes bougonne une remarque intéressante : “que se passe-t-il pour les bits 7, 6 et 5 ?” Eh bien, si on considère une instruction “normale” (qui a donc des paramètres), sitôt le code d'instruction entré, le bit 7 sera mis à 1 (données à transférer par le port &FB7F) et le bit 6 sera mis à 0 (c'est au Z80 d'envoyer ses paramètres). En outre, le bit 5 restera à 0 jusqu'à ce que tous les paramètres soient envoyés. Si tout s'est bien passé, une fois tous les paramètres communiqués, le bit 7 passera à 0 (histoire de faire comprendre au Z80 qu'on veut rester tranquille pour digérer toutes les infos). Et puis enfin, lorsque l'instructions aura été interprêtée, le bit 5 sera placé à 1. On enchaîne alors sur la phase d'exécution.

Phase d'exécution

Vous avez dit exécution ? Comme suggéré ci-dessus, la phrase suivant la phase d'instruction est la phase d'exécution. Celle-ci sera plus ou moins longue suivant l'instruction. C'est pour les instructions de lecture et d'écriture que cette phase est la plus significative puisqu'il faudra alors envoyer ou recevoir les octets relatifs au secteur en cours. Durant cette phase, les bits 6 et 7 du registre d'état principal sont encore actifs et permettent de savoir si le FDC et le Z80 sont en phase… Le bit 5, quant à lui, sera remis à 0 lorsque la phase d'instruction est achevée afin d'indiquer le début de la toute dernière phase : la phase de résultat.

Phase de résultat

On va enfin pouvoir savoir si le FDC (Fromage Du Cantal ?) a tout compris ou s'il n'en a fait qu'à sa tête. Durant la phase de résultat, le FDC va nous renvoyer tout un tas d'octets et les registres d'état secondaires. On va être servis ! En effet, selon l'instruction, on va recevoir jusqu'à 7 (argh !) octets qui nous donnent des foules d'infos sur ce qui s'est passé durant la phase d'exécution. En pratique, 50% de ces infos sont inutiles, mais pour le fun nous les verrons toutes en détail. Il est pas d'accord le petit blond à lunettes ? Et crac ! Une carte mère PC explosée sur la tête (ça fait du bien vous savez). Nous verrons ces valeurs plus en détail avec la liste des instructions…

Les registres d'état secondaires

Femme De Compagnie ? Voici tout de même une rapide présentation de tous les registres d'état secondaires qui nous seront très utiles par la suite. Il sont au nombre de 4 et répondent aux doux noms de ST0, ST1, ST2 et ST3. ST0 renvoie des informations sur l'interruption d'une instruction, ST1 et ST2 vont ensemble et vous informerons sur tout ce qui s'est passé durant la phase d'exécution. Le registre ST3 est en revanche un peu à part car il n'est renvoyé par le FDC (Faucon De Colombie ?) qu'à la demande du Z80 ; celui-ci donne des informations sur l'état des lecteurs. Nous verrons en détail le contenu de ces registres dans la section qui leur est consacrée un peu plus bas.

Les instructions du FDC

Je vais vous donner ici la liste des instructions FDC sans toutefois entrer dans le détail puisque nous les reprendons toutes unes à unes dans les sections suivantes.

On a tout d'abord les instructions de lecture/écriture. Celles-ci sont au nombre de 5 ! Ah ! Je vois que le petit blond à lunettes se gratte la tête d'un air interrogatif… En effet, 5 est un nombre assez curieux. En fait, on a 2 instructions d'écriture et 3 instructions de lecture. On peut lire ou écrire des secteurs classiques (ça fait 2), de même on peut lire et écrire des secteur effacés (ça fait 2+2=4) et lire des blocs (4+1=5, le compte est bon).

Je crois que quelques éclaircissement sont nécessaires. On entend ici par secteur effacés des secteurs qui ont été marqués de façon particulière et qui sont sautés lors d'une lecture classique. C'est juste une façon de “classer” ses secteurs sur un disc. Nous n'utiliserons pas la notion de secteurs effacés par la suite car elle est en fait sans grand intérêt. Ensuite, l'instruction de lecture de blocs ne diffère de l'instruction de lecture de secteurs que par le fait qu'elle permet de lire d'un seul coup les n premiers secteurs successifs sur une même piste. Elle est intéressante dans le cadre de formats sectoriels car rapide mais est difficilement gérable lorqu'on est dans le cas de fichiers qui peuvent être éparpillés un peu partout sur le disc.

On a ensuite l'incontournable instruction de formatage. Puis l'instruction de lecture d'ID qui permet de savoir quel est le prochain secteur qu'on va rencontrer (on n'est pas sensé connaître par coeur son disc). On a ensuite trois instructions qui permettent de vérifier la validité d'un secteur. L'instruction de recalibrage permet quant à elle de renvoyer la tête de lecture en butée (piste 0) ; l'instruction seek placera cette même tête sur la piste désirée.

Enfin, on pourra utiliser 2 instructions d'état qui permettent d'interroger les registres ST0 et ST3 et une instruction de paramétrage pour régler divers paramètres des lecteurs dont le seul utile sur CPC est le temps de changement de piste.

Les opérations de base

Les bases étant posées, nous allons à partir de maintenant apprendre à mettre en œuvre le FDC en rentrant petit à petit dans les routines de la bibliothèque FDC fournie ici. Ces routines sont déjà largement commentées dans le listing lui-même, aussi nous nous focaliserons plutôt sur leur fonctionnement global dans les explications qui suivent.

Feux De Campagne ?

Mise en marche des moteurs

Comme je vous l'ai déjà dit précédemment, sur CPC, le contrôle de l'allumage des moteurs des lecteurs se fait via le port &FA7E. Si on y met 1, on allume et si on y envoie 0, on coupe tout ! La seule chose à laquelle il faut penser, c'est de mettre une petite temporisation après l'ordre d'allumage pour que les moteurs aient le temps d'arriver à leur vitesse de croisière.

Les instructions de base

Voici à présent la liste des instructions du FDC qui sont utilisées dans notre premier petit programme d'exemple ci-dessous. Nous allons en tout et pour tout en voir quatre dans cette section.

En route !

Plait-il ?

Recalibrage

La première instruction que vous allez rencontrer dans l'exemple est l'instruction de recalibrage. Celle-ci permet, comme son nom l'indique, de recalibrer le lecteur de disquettes. Pratiquement, il s'agit d'un ordre de retour en piste 0 de la tete de lecture ; mais pas tout à fait puisque le FDC n'envoie au maximum que 77 impulsions de retour arrière de la tête… Sur un lecteur 3” 40 pistes, ça ne pose aucun problème, mais sur un lecteur 3”1/2, cela peut ne pas suffir si notre tête était au-delà de la piste 77. Pour y remédier, on a deux solutions : être radical et envoyer toujours les ordres de recalibrage par paire (si la tête est déjà en piste 0, il ne se passe rien de toute façon) ou se servir d'informations que le FDC peut nous renvoyer si on lui demande gentiment… comme le numéro de piste en fin d'instruction (c'est celle pour laquelle j'ai opté). Voici l'instruction FDC :

 Nom d'instruction : recalibrage de tête
Code d'instruction : %00000111
         Paramètre : IDlecteur
            Retour : Rien

Bon, je crois que quelques précisions s'imposent à propos de ce que j'ai appelé IDLecteur. Il s'agit en fait d'un code précisant à la fois le numéro du lecteur et la tête concernée par l'instruction. Ce paramètre est demandé par la plupart des instructions et est stockée dans la variable Lecteur de la bibliothèque FDC. Voici sa structure :

Description de l'IDLecteur

Le petit blond à lunettes, toujours fidèle au poste, pose sa question sournoise : “à quoi sert de donner le numéro de tête alors que sur les lecteurs double face les deux têtes sont liées et se déplacent forcément ensemble sur le disc ?” Eh bien ça sert à rien du tout ! Z'avez vu comme je l'ai remballé le trouble-fête ! En effet, c'est, dans ce cas, sans aucun intérêt, mais bon, c'est comme ça (des lecteurs double face aux têtes indépendantes étaient peut-être prévus…).

Interrogation d'état d'interruption

Cyborg, fonctions vitales ok ! La suite logique de l'instruction de recalibrage est l'instruction d'interrogation d'état d'interruption. En effet, il s'agit de l'instruction à utiliser pour tester ce qu'il advient de l'instruction qu'on vient de faire exécuter au FDC. Celle-ci nous renvoie le registre d'état ST0 (dont nous avons déjà parlé plus haut et dont nous reparlerons aussi plus bas) qui va nous permettre d'attendre la fin de l'instruction programmée précédemment. Pour les sceptiques, jetez un coup d'oeil à la routine WaitIns de la bibliothèque de routines… vous constaterez que cette instruction nous renvoie également le numéro de la piste en cours, paramètre que j'utilise dans la routine de recalibrage pour vérifier si je suis effectivement arrivé en piste 0 à la fin de celle-ci. Voici le protocôle complet de l'instruction d'interrogration de l'état des interruptions :

 Nom d'instruction : interrogation de l'état des interruptions
Code d'instruction : %00001000
         Paramètre : Aucun
            Retour : ST0
                     Numéro de piste en cours

Déplacement de tête

L'instruction qui va nous intéresser à présent est celle nous permettant de positionner la tête de lecture où on le désire. Elle répond au doux nom d'instruction de recherche de piste et fonctionne comme suit :

 Nom d'instruction : recherche de piste
Code d'instruction : %00001111
         Paramètre : IDLecteur
                     Numéro de piste
            Retour : Rien

Comme vous pouvez le constater, cette instruction est élémentaire ; elle est utilisée dans la routine GoTo de la bibliothèque.

Hum ?

État des lecteurs

Et puis pour finir, une instruction extrêmement pratique qui permet d'interroger l'état des lecteurs en nous renvoyant le registre d'état ST3 qui nous dit tout sur ce qui se passe dans leur ventre (disquette manquante ou protégée, lecteur défectueux, type de lecteur, etc.). Alors pour récupérer ce registre, il n'y a pas plus simple :

 Nom d'instruction : interrogation des lecteurs
Code d'instruction : %00000100
         Paramètre : IDLecteur
            Retour : ST3

En voilà une instruction qu'elle est pratique ! Elle est utilisée dans la routine ReadST3, pas de surprise. Nous reviendrons plus en détail sur ce registre un peu plus bas.

Mise en pratique

Voici un petit exemple utilisant les quelques routines de base mettant en jeu les instructions vues ci-dessus.

Nous allons en découdre avec le FDC !

; Exemple d'utilisation des routines
 
Exemple di
        ex af,af'
        push af
 
        call moton      ; Réveil
 
        ld a,1          ; On sélectionne
        call sellect    ; le drive B
        ld a,0          ; et
        call seltete    ; la face A
 
        call piste0     ; Recalibrage
 
        le e,81         ; Et paf, on
        call goto       ; fonce en piste 81 !
 
        call piste0     ; Vlam retour en piste 0
 
        call motoff     ; Dodo
 
Restore pop af
        ex af,af'
        ei
        ret
 

Petites précisions

Les quelques exemples qui précèdent ont pour seul objet de titiller la mécanique du lecteur de disquettes. Que ce soit clair : que la disquette présente dans le lecteur soit formatée, non formatée, découpée au cutter (porte-lame pour les puristes) ou je ne sais quoi d'autre, du moment qu'il y a un semblant de disque qui tourne dans le lecteur, on peut faire un recalibrage, déplacer la tête en piste X ou demander l'état du lecteur. À aucun moment, il n'y a de tentative de lecture lors de ces opérations.

Plus simplement, le lecteur n'a pas besoin de la disquette pour se rendre en piste 0 (il y a une butée de début de course) ni pour pour aller en piste X (il compte les pas de son moteur à partir de la piste 0). Ce qui m'amène à répondre à une question d'ailleurs très pertinente de Madram : sans relalibrage le lecteur ne peut pas se rendre sur une piste précise. Toutefois, en temps normal, le recalibrage est à effectuer une seule fois lors de la première utilisation du FDC après allumage de l'ordinateur. Notez tout de même que l'Amsdos fait un recalibrage à chaque fois qu'il rencontre une erreur de lecture avant de retenter sa chance.

Pour en finir avec les remarques sur le listing, comme l'a justement fait remarquer Madram (décidément il va devenir pire que le petit blond à lunettes), la boucle WaitIns qui consiste à attendre que le FDC soit prêt, peut être sans fin s'il est complètement planté (par exemple lors d'une tentative d'accès à un lecteur mal connecté). Il faudrait donc normalement mettre une sécurité ; à titre d'exemple l'Amsdos abandonne tout accès au FDC au bout de quelques secondes et renvoie un “Bad Command”.

Les registres d'état

Avant de nous attaquer aux instructions élaborées, voyons en détail les registres d'état ST0 à ST3 qui vont très vite nous devenir indispensables. En effet, tant que l'on se contente d'ordres simples, le FDC n'a pas grand chose à nous dire, mais dès qu'on lui parle d'opérations de lecture/écriture/formatage, il devient plus bavard et prend un malin plaisir à montrer du doigt la moindre anomalie.

Le registre d'état ST0 est l'un des plus importants car il nous renseigne directement sur ce qui s'est passé durant l'instruction.

Les registres d'état du FDC, un véritable souc ! Registre ST0 :

Le registre d'état ST0

Le registre d'état ST1 est moins dense que ST0 en informations mais il demeure très intéressant.

Registre ST1 :

Le registre d'état ST1

Les informations fournies par le registre ST2 sont un complément direct du registre ST1. La plupart de ses bits précisent d'éventuelles erreur indiquées par le registre ST1.

Registre ST2 :

Le registre d'état ST2

Ah ! Le petit blond à lunettes est de retour ! Pourquoi n'y a-t-il pas de commentaire face aux bits 2 et 3 du registre ST2 ? Eh bien tout simplement car ces bits sont sans intérêt pour le moment car il sont spécifiques à l'instruction “Scan” du FDC que nous verrons plus loin. Pour l'instant, ignorez-les.

Enfin, il y a le fameux registre ST3 qui ne peut être obtenu que par l'instruction d'interrogation de l'état d'un lecteur que nous avons vu la dernière fois.

Registre ST3 :

Comment atteindre l'état ultime ? Le registre d'état ST3

L'instruction de formatage

Nous passons maintenant aux choses sérieuses avec le formatage de nos chers discs. Un petit rappel : le formatage d'une disquette consiste à y réserver les zones de données et de repérage pour pouvoir ensuite l'utiliser. Le FDC dispose d'une instruction de formatage qui est à la fois puissante et très simple à utiliser. En voici les caractéristiques

Ahhhhhh !

 Nom d'instruction : formatage de piste
Code d'instruction : %01001101
        Paramètres : IDlecteur
                     Taille de secteur
                     Nombre de secteur par piste
                     Octet de séparation ID/données
                     Octet de remplissage du secteur
         Exécution : le Z80 envoie au FDC les ID des secteurs à formater dans l'ordre souhaité.
            Retour : ST0
                     ST1
                     ST2
                     Numéro de piste en cours
                     Tête en cours
                     Nom du secteur en cours
                     Taille du secteur en cours

Les plus observateurs d'entre vous auront constaté qu'il y a une phase de plus dans cette instruction par rapport à celles vues précedemment. En fait, non, mais pour toutes les autres instructions déjà vues le FDC n'attendait rien du Z80 pour s'exécuter. Ici - et il en sera d'ailleurs de même pour toutes les opérations de lecture/écriture - la phase d'exécution nécessite un échange de données entre les deux compères. Pour plus de détails, relisez cette section.

Penchons nous à présent sur les paramètres de cette instruction. L'IDLecteur n'a en principe plus de secrets pour vous. La taille des secteurs non plus puisque nous en avons déjà parlé ici. Le nombre de secteurs par piste est bien sûr fonction de la taille des dits secteurs mais, au risque de me répéter, nous avons encore vu tout celà ici. L'octet de séparation ID/données est celui qui servira à remplir le vide entre les champs d'ID et les champs de données dont nous avons parlé dans… oui ! Vous avez deviné, ici ! Et puis pour finir, il y a l'octet de remplissage qui est la valeur que va mettre le FDC dans nos secteurs encore vides (non, nous n'en avons pas parlé dans ici).

Vient ensuite la phase d'exécution durant laquelle on va envoyer successivement les ID des secteurs à formater. C'est à ce moment que l'on choisit le nom et l'ordre de nos secteurs sur la piste. Et devinez où nous avons déjà parlé de l'optimisation des l'ordre des secteurs sur une pistes ? ici bien sûr ! Sinon, en ce qui concerne les noms à proprement parler, vous êtes complètement libres.

Les routines d'exemple

Après la théorie, un peu de pratique ! Nous allons ici étudier trois des routines de la bibliothèque FDC. Figurent également quelques datas que je vous propose d'utiliser pour tester ces routines. Dans tous les cas, n'oubliez pas d'envoyer l'ordre de démarrage du moteur avant tout…

Premier exemple

; Exemple 1 d'utilisation des routines
 
Exemple1
        di
        ex af,af'
        push af
 
        call moton
 
        ld a,1
        call sellect
        ld a,0
        call seltete        
 
        call piste0
 
        ld hl,secta
        ld ix,typpist
        ld e,0
        call fmtpist
 
        call motoff
 
Restore pop af
        ex af,af'
        ei
        ret
 
SectA   db &11,&12,&13,&14,&15,&16,&17,&18,&19,&1a
TypPist db 2,10,&20,&e5
 

Le premier exemple est le plus élémentaire : il permet de formater une piste homogène sur le lecteur et la face en cours. Comme prévu, il n'est fait aucun accès direct au FDC et tout passe entièrement par les routines élémentaires vues précedemment. La routine ”FmtPist” que nous utilisons a besoin de trois paramètres en entrée : la liste des noms des secteurs (par exemple HL=SectA), les paramètres de formatage (au hasard mettez IX=TypPist), et bien sûr, le numéro de la piste à formater. Vous récupérez en sortie les registres d'état S0, ST1 et S2 qui vous permettront de savoir si tout s'est bien passé. Ah ! Il n'a pas pu s'en empêcher ! Le petit blond à lunettes se demande pourquoi je parle de piste homogène… Eh bien tout simplètement car tous les secteurs d'une même piste sont, avec cette routine, de tailles identiques. Il est en effet tout à fait envisageable de créer une piste avec des secteurs de tailles différentes en transférant des ID de secteurs variables lors de la phase d'exécution. Mais attention, calculez bien vos longueurs de secteurs et vos GAP pour ne pas déborder (cf. cette section).

Deuxième exemple

; Exemple 2 d'utilisation des routines
 
Exemple2
        di
        ex af,af'
        push af
 
        call moton
 
        ld a,1
        call sellect
        ld a,0
        call seltete        
 
        call piste0
 
        ld hl,secta
        ld ix,typpist
        ld e,0
        ld d,2
        call fmtside
 
        call motoff
 
Restore pop af
        ex af,af'
        ei
        ret
 
SectA   db &11,&12,&13,&14,&15,&16,&17,&18,&19,&1a
TypPist db 2,10,&20,&e5

La deuxième routine que nous utilisons ici, ”FmtSide” est en quelque sortie une macro-routine qui utilise la première pour lancer en boucle le formatage de plusieurs pistes. Il n'y a rien de particulier à signaler à son propos sinon qu'elle ne tient absolument pas compte des éventuelles erreurs renvoyées par ”FmtPist”. Libre à vous d'écrire une routine plus performante.

Troisième exemple

; Exemple 3 d'utilisation des routines
 
Exemple3
        di
        ex af,af'
        push af
 
        call moton
 
        ld a,1
        call sellect
        ld a,0
        call seltete        
 
        call piste0
 
        ld hl,secta
        ld iy,sectb
        ld ix,typpist
        ld e,0
        ld d,2
        call fmtfull
 
        call motoff
 
Restore pop af
        ex af,af'
        ei
        ret
 
SectA   db &11,&12,&13,&14,&15,&16,&17,&18,&19,&1a
SectB   db &01,&02,&03,&04,&05,&06,&07,&08,&09,&0a
TypPist db 2,10,&20,&e5

Derrière le label ”FmtFull” se cache une autre routine d'exploitation de ”FmtPist”. Celle-ci est similaire en tout point à ”FmtSide” hormis le fait qu'elle ne tient pas compte de la tête en cours puisqu'elle formate en double face. Il vous faudra donc la tester avec un lecteur double face. De même, au niveau des paramètres à fournir en entrée, on différencie la liste des noms des secteurs des faces A et B. Attention, c'est facultatif ! Vous pouvez tout à fait avoir les mêmes noms sur les deux faces… ce qui permet d'utiliser le mode mulitrack en lecture ou écriture de secteurs.

Le mode multitrack

Comme je vous l'ai déjà dit à plusieurs reprises, le FDC dispose en lecture comme en écriture d'une instruction permettant de traiter plusieurs secteurs sur une même piste d'un seul coup. L'exploitation de ce mode de fonctionnement est très importante car elle augmente considérablement les taux de transfert. Eh bien, le mode multitrack permet d'oublier la notion de face pour ces instructions.

Je m'explique. Imaginons un disc formaté en utilisant les datas proposés ci-dessous. On a donc des faces A avec des secteurs numérotés de 0 à 9 et des faces B avec des secteurs numérotés de 0 à 9 également. Si on demande au FDC de nous lire les secteurs 0 à 9 d'une piste en mode multitrack, ça marche directement sans avoir à se préoccuper de la face ; les deux seront lues consécutivement. C'est pas une belle option ça ? Un seul ordre de lecture (ou d'écriture) au lieu de deux en mode normal !

; Datas compatibles pour des lectures/écritures en mode multitrack
 
SectA   db &00,&01,&02,&03,&04,&05,&06,&07,&08,&09
SectB   db &00,&01,&02,&03,&04,&05,&06,&07,&08,&09
TypPist db 2,10,&20,&e5

Les instructions de lecture/écriture

La lecture

Nous avons à notre disposition trois instructions de lecture. La lecture de secteurs, la lecture de secteurs effacés, et la lecture de piste. Comme je vous l'ai déjà fait remarquer il y a quelques temps, les secteurs dits effacés n'ont qu'un intéret limité et ne représentent absolument pas des données effectivement effacées du disque mais simplement des secteurs “marqués” comme tels. Relisez les sections précédentes si, comme le petit blond à lunettes, vous n'avez pas encore assimilé toutes les notions relatives aux pistes et aux secteurs.

Mais revenons-en à ce qui nous intéresse : le descriptif de ces instructions. Tout d'abord, voici la lecture de secteurs :

Un peu de lecture...

 Nom d'instruction : lecture de secteurs
Code d'instruction : %t1000110
        Paramètres : IDlecteur
                     Numéro de piste
                     Numéro de tête
                     Nom du premier secteur à lire
                     Taille de secteur
                     Nom du dernier secteur à lire
                     Octet de séparation ID/données
                     Longueur effective de secteur
                     (si taille de secteur=0)
         Exécution : le FDC envoie au Z80 le contenu des secteurs demandés
            Retour : ST0
                     ST1
                     ST2
                     Numéro de piste en cours
                     Tête en cours
                     Nom du secteur en cours
                     Taille du secteur en cours

Je rassure tout de suite le petit blond à lunettes : le petit t en bit 7 du code d'instruction n'est pas une faute de frappe ! C'est un paramètre ; s'il est mis à 1 alors on passe en mode multitrack (cf. cette section) !

Et puis enfin, je dois vous mettre en garde sur le fait que le numéro de piste, le numéro de tête et les informations sur la taille des secteurs ne sont là que pour vérification de la validité du header des secteurs. La tête doit avoir préalablement été déplacée sur la piste où l'on désire lire les secteurs et la tête de lecture (lorsque le mode multitrack est désactivé) est choisie via l'IDLecteur.

Bonne lecture ! Vient ensuite l'instruction de lecture des secteurs effacés. Celle-ci a exactement les mêmes paramètres et se comporte de la même manière. Je me contente donc de vous donner son code d'instruction : %t1001100.

Et puis pour en finir avec la lecture de nos discs, nous avons à notre disposition l'instruction de lecture de piste. Celle-ci est similaire à l'instruction de lecture de secteurs utilisée avec le paramètre “Nom du premier secteur à lire” égal au premier secteur de la piste et a comme avantage d'être plus rapide. Concrêtement elle permet de lire le contenu des X premiers secteurs de la piste. Toutefois, si le secteur indique comme “Nom du dernier secteur à lire” n'existe pas, c'est tous les secteurs de la piste qui seront lus. En outre, les quatre premiers paramètres à fournir après l'IDLecteur ne sont là que pour permettre au FDC de positionner certains flags des registres d'état et n'ont donc pas d'influence sur le déroulement de l'instruction. Le petit blond à lunettes s'impatiente, voici donc son descriptif :

 Nom d'instruction : lecture de piste
Code d'instruction : %01000010
        Paramètres : IDlecteur
                     Numéro de piste
                     Numéro de tête
                     Nom de secteur
                     Taille de secteur
                     Nom du dernier secteur à lire
                     Octet de séparation ID/données
                     Longueur effective de secteur
                     (si taille de secteur=0)
         Exécution : le FDC envoie au Z80 le contenu des secteurs demandés
            Retour : ST0
                     ST1
                     ST2
                     Numéro de piste en cours
                     Numéro de tête en cours
                     Nom du secteur en cours
                     Taille du secteur en cours

Attention : pas de mode multitrack ici !

L'écriture

Les instructions d'écriture sont au nombre de deux : l'écriture de secteurs et l'écriture de secteurs effacés. Ces deux instructions sont très similaires à leurs équivalents en lecture. Mais attention, comme je vous l'ai déjà précisé précédemment, on ne peut écrire que dans un secteur existant sur la piste en cours ! Toute instruction d'écriture de secteurs sera mise en échec si le secteur demandé n'a pas été préalablement formaté sur la piste ; les instructions d'écriture ne peuvent en aucun cas créer un secteur. Celles-ci ne sont là que pour “remplir” ceux-ci.

Voici donc le descriptif de nos deux dernières instructions FDC ; l'écriture de secteurs :

L'écriture, c'est tout un art !

 Nom d'instruction : écriture de secteurs
Code d'instruction : %t1000101
        Paramètres : IDlecteur
                     Numéro de piste
                     Numéro de tête
                     Nom du premier secteur à écrire
                     Taille de secteur
                     Nom du dernier secteur à écrire
                     Octet de séparation ID/données
                     Longueur effective de secteur
                     (si taille de secteur=0)
         Exécution : le Z80 envoie au FDC les données à écrire sur le disque
            Retour : ST0
                     ST1
                     ST2
                     Numéro de piste en cours
                     Numéro de tête en cours
                     Nom du secteur en cours
                     Taille du secteur en cours

Tout comme pour les instructions de lecteur, le petit t permet d'activer le mode multitrack s'il est mis à 1. Mais dans ce cas, le disque doit être dans un format adéquat comme vu précédemment.

Et puis pour finir, nous avons l'instruction d'écriture de secteurs effacés. Comme celle-ci fonctionne de la même manière que pour les secteurs “normaux”, je vous donne juste son code d'instruction : %t1001001.

Mais le FDC a encore un bon nombre d'autres instructions… je vais très rapidement vous en décrire certaines qui pourront peut-être vous êtres utiles mais sachez qu'avec tout ce que nous avons déjà vu, vous avez tous les éléments en main pour créer et gérer vos formats de disque.

Les derniers trucs

J'ai rien compris... Une instruction assez pratique si vous avez oublié le nom de vos secteurs sur la piste en cours : la lecture des ID des secteurs. Grâce à cette instruction, vous pouvez demander au FDC de vous communiquer quelle est l'ID du prochain secteur rencontré.

 Nom d'instruction : lecture de l'ID du prochain secteur
Code d'instruction : %01001010
        Paramètres : IDlecteur
         Exécution : Le FDC bosse, rien à lire ou envoyer.
            Retour : ST0
                     ST1
                     ST2
                     Numéro de piste en cours
                     Numéro de tête en cours
                     Nom du secteur en cours
                     Taille du secteur en cours

Pour la première fois depuis le début de cet article, on a enfin une instruction qui nous donne des informations utiles dans les quatre derniers octets !

Et puis pour finir, je vous donner l'instruction permettant de régler le délai d'attente piste à piste. Plus vous avez un lecteur récent, plus ce délai peut être réduit (un lecteur 3” a besoin d'un plus grand délai qu'un 3”1/2).

 Nom d'instruction : réglage du temps piste à piste
Code d'instruction : %00000011
        Paramètres : %dddd0000
                     %00000000

Les bits dddd déterminent notre délai d'attente. Si vous mettez 1111 ce délais est minimum et un 0000 spécifie un délai maximum. Un délai trop rapide provoque des erreurs de lecture et un délai trop grand est un perte de performance notable. Les autres bits qui sont ici figés à 0 ont en fait également une signification, seulement pour des lecteurs au format 8”, aussi je pense que personne n'est concerné. Le bit 0 du deuxième paramètre permet quant à lui de sélectionner le mode non DMA qui est le seul disponible sur CPC.

Voilà, nous avons fait le tour du chip le plus délicat à programmer sur CPC ; j'espère que toutes ces informations vous seront utiles.

Listing : bibliothèque de routines

Télécharger le listing au format Maxam 1.5

;
; Routines de gestion du FDC en Hardware
; OffseT of Futurs' pour Quasar CPC (1997-1999)
; Version 6
;
 
        Org &8000
        Nolist
 
; Exemple d'utilisation des routines
 
Init    di
        ex af,af'
        push af
 
        call moton
 
        ld a,1
        call sellect
        ld a,0
        call seltete        
 
        call piste0
 
;       ld e,82
;       call goto
 
;       ld hl,sectb
;       ld ix,typpist
;       ld e,0
;       call fmtpist
 
        ld hl,secta
        ld iy,sectb
        ld ix,typpist
        ld e,0
        ld d,2
        call fmtfull
 
        ld de,&8000
        ld ix,typpist
        ld iy,&c000
        ld hl,&111a
        call sectr
 
        call motoff
 
Restore pop af
        ex af,af'
        ei
        ret
 
;
; Utilitaires FDC en trackdisk
;
 
;
; Lecture de secteurs en double densité
; avec gestion des erreurs
;
; In    ; E=Piste
;         D=Mode multitrack (0=Off / 128=On)
;         IX pointe sur les paramètres secteurs
;         (Taille,Nombre par piste,octet GAP#3,octet de remplissage)
;         H=Premier secteur à lire
;         L=Dernier secteur à lire
;         IY=Adresse du tampon
; Out   ; FlagErr=Statut des erreurs
;       ; IY=Fin du tampon
 
SectR   call litsecs
        call testerr
        ld (flagerr),a
        ret
 
 
;
; Écriture de secteurs en double densité
;
; In    ; E=Piste
;         D=Mode multitrack (0=Off / 128=On)
;         IX pointe sur les paramètres secteurs
;         (Taille,Nombre par piste,octet GAP#3,octet de remplissage)
;         H=Premier secteur à lire
;         L=Dernier secteur à lire
;         IY=Adresse du tampon
; Out   ; FlagErr=Statut des erreurs
;       ; IY=Fin du tampon
 
SectW   call ecrsecs
        call testerr
        ld (flagerr),a
        ret
 
 
;
; Lecture de secteurs en double densité
;
; In    ; E=Piste
;         D=Mode multitrack (0=Off / 128=On)
;         IX pointe sur les paramètres secteurs
;         (Taille,Nombre par piste,octet GAP#3,octet de remplissage)
;         H=Premier secteur à lire
;         L=Dernier secteur à lire
;         IY=Adresse du tampon
; Out   ; E=ST0
;         D=ST1
;         L=ST2
;         H=Piste courante
; Modif ; AF, AF', BC=&FA7E, IY=fin du tampon
 
LitSecS push de
        call goto
        pop de
        ld a,%01100110  ; Ordre de lecture en DD
        or d            ; Bit multitrack
        call putfdc
        ld a,(lecteur)
        ld d,a
        ld a,(tete)
        sla a
        sla a
        or d
        call putfdc     ; Lecteur/Tête
        ld a,e
        call putfdc
        ld a,(tete)     ; Envoi de l'ID
        call putfdc
        ld a,h
        call putfdc
        ld a,(ix+0)
        call putfdc
        ld a,l
        call putfdc
        ld a,&20
        call putfdc
        xor a
        call putfdc
 
WaitDAT in a,(c)
        jp p,waitdat
        and 32
        jr z,finlit
        inc c
        in a,(c)
        dec c
        ld (iy),a
        inc iy
        jr waitdat
 
FinLit  call getfdc
        ld e,a
        call getfdc
        ld d,a
        call getfdc
        ld l,a
        call getfdc
        ld h,a
        call getfdc
        call getfdc
        call getfdc
        ret
 
 
;
; Écriture de secteurs en double densité
;
; In    ; E=Piste
;         D=Mode multitrack (0=Off / 128=On)
;         IX pointe sur les paramètres secteurs
;         (Taille,Nombre par piste,octet GAP#3,octet de remplissage)
;         H=Premier secteur à lire
;         L=Dernier secteur à lire
;         IY=Adresse du tampon
; Out   ; E=ST0
;         D=ST1
;         L=ST2
;         H=Piste courante
; Modif ; AF, AF', BC=&FA7E, IY=fin du tampon
 
EcrSecS push de
        call goto
        pop de
        ld a,%01000101  ; Ordre d'écrture en DD
        or d            ; Bit multitrack
        call putfdc
        ld a,(lecteur)
        ld d,a
        ld a,(tete)
        sla a
        sla a
        or d
        call putfdc     ; Lecteur/Tête
        ld a,e
        call putfdc
        ld a,(tete)     ; Envoi de l'ID
        call putfdc
        ld a,h
        call putfdc
        ld a,(ix+0)
        call putfdc
        ld a,l
        call putfdc
        ld a,&20
        call putfdc
        xor a
        call putfdc
 
WaitECR in a,(c)
        jp p,waitecr
        and 32
        jr z,finecr
        ld a,(iy)
        inc iy
        inc c
        out (c),a
        dec c
        jr waitecr
 
Finecr  call getfdc
        ld e,a
        call getfdc
        ld d,a
        call getfdc
        ld l,a
        call getfdc
        ld h,a
        call getfdc
        call getfdc
        call getfdc
        ret
 
 
;
; Formatage homogène d'un disc en simple face
;
; In    ; HL pointe sur la liste des noms des secteurs
;         IX pointe sur les paramètres secteurs
;         (Taille,Nombre par piste,octet GAP#3,octet de remplissage)
;         E=Piste de départ
;         D=Piste d'arrivée
; Out   ; FlagErr=Statut des erreurs
;         D=Piste courante
;         E=ST0
; Modif ; AF, AF', BC=&FA7E, HL
 
FmtSide xor a
        ld (flagerr),a
        ld a,d
        cp e
        ret c
        push de
        call piste0
        pop de
LoopSid push de
        push hl
        call fmtpist
        call testerr
        pop hl
        pop de
        cp 1
        jr z,loopsid
        cp 3
        jp putflagerrc
        cp 2
        call z,putflagerri
        ld a,e
        inc e
        cp d
        jr nz,loopsid
        call piste0
        or a
        ret
 
 
;
; Formatage homogène d'un disc en double face
;
; In    ; HL=Pointe sur la liste des noms des secteurs face A
;         IY pointe sur la liste des noms des secteurs face B
;         IX pointe sur les paramètres secteurs
;         (Taille,Nombre par piste,octet GAP#3,octet de remplissage)
;         E=Piste de départ
;         D=Piste d'arrivée
; Out   ; C=Erreur dans les données
;         D=Piste courante
;         E=ST0
; Modif ; AF, AF', BC=&FA7E, HL
 
FmtFull xor a
        ld (flagerr),a
        ld a,(tete)
        push af
        ld a,d
        cp e
        ret c
        push de
        call piste0
        pop de
LoopFul push de
        push hl
        xor a
        call seltete
        push de
        push hl
        call fmtpist
        call testerr
        pop hl
        pop de
        pop hl
        pop de
        cp 1
        jr z,loopful
        cp 3
        jp z,putflagerrc
        cp 2
        call z,putflagerri
LoopFu2 push de
        push hl
        ld a,1
        call seltete
        push iy
        pop hl
        call fmtpist
        call testerr
        pop hl
        pop de
        cp 1
        jr z,loopfu2
        cp 3
        jp z,putflagerrc
        cp 2
        call z,putflagerri
        ld a,e
        inc e
        cp d
        jr nz,loopful
        call piste0
        pop af
        ld (tete),a
        or a
        ret
 
 
;
; Formatage d'une piste homogène
; In    ; HL=Pointe sur la liste des noms des secteurs
;         IX pointe sur les paramètres secteurs
;         (Taille,Nombre par piste,octet GAP#3,octet de remplissage)
;         E=piste
; Out   ; E=ST0
;         D=ST1
;         L=ST2
; Modif ; AF, AF', BC=&FA7E, H
 
FmtPist call goto
        ld e,d
        ld a,%01001101
        call putfdc     ; Ordre de formatage
        ld a,(lecteur)
        ld d,a
        ld a,(tete)
        sla a
        sla a
        or d
        call putfdc     ; Lecteur & Tête
        ld a,(ix+0)
        call putfdc     ; Taille des secteurs
        ld a,(ix+1)
        call putfdc     ; Nombre de secteurs
        ld a,(ix+2)
        call putfdc     ; Octet GAP#3
        ld a,(ix+3)
        call putfdc     ; Octet remplissage
 
        ld d,(ix+1)     ; Envoi des 4 octets
LoopFmt ld a,e          ; d'ID pour chaque secteur
        call putfdc
        ld a,(tete)
        call putfdc
        ld a,(hl)
        call putfdc
        inc hl
        ld a,(ix+0)
        call putfdc
        dec d
        jr nz,loopfmt
 
        call getfdc
        ld e,a
        call getfdc
        ld d,a
        call getfdc
        ld l,a
        ld h,4
LoopFm2 call getfdc
        dec h
        jr nz,loopfm2
 
        ret
 
;
; Routines élémentaires FDC
;
 
;
; Choix du lecteur courant
; In    ; A=numéro de lecteur
; Modif ; AF
 
SelLect and 3
        ld (lecteur),a
        ret
 
;
; Choix de la tête courante
; In    ; A=numéro de tete
; Modif ; AF
 
SelTete and 1
        ld (tete),a
        ret
 
;
; Allumage des moteurs
; Modif ; AF, BC=&FA7E
 
MotOn   ld a,(moteurs)  ; État des moteurs
        or a            ; Retour direct
        ret nz          ; si déjà allumés
        ld bc,&fa7e     ; Sinon mise à
        inc a           ; jour de l'état
        ld (moteurs),a  ; des moteurs et 
        out (c),a       ; allumage
        ld bc,&f520     ; Attente de
Tempo   in a,(c)        ; quelques VBL
        rra             ; pour etre sur
        jr nc,tempo     ; d'atteindre
Wait    in a,(c)
        rra
        jr c,wait
        dec c           ; la vitesse
        jr nz,tempo     ; de croisière
        ret             ; Fini !
 
;
; Arret des moteurs
; Modif ; AF, BC=&FA7E
 
MotOff  xor a           ; Mise à zéro de
        ld bc,&fa7e     ; l'état des moteurs
        ld (moteurs),a  ; et arret des
        out (c),a       ; moteurs
        ret             ; Fini !
 
;
; Recalibrage du lecteur courant
; Out   ; D=piste courante
;         E=ST0
; Modif ; AF, AF', BC=&FB7E
 
Piste0  ld bc,&fb7e
Twice   ld a,%00000111  ; Ordre de recalibrage
        call putfdc     ; Envoi au FDC
        ld a,(lecteur)  ; pour le lecteur
        call putfdc     ; courant
        call waitins
        ld a,d
        or a            ; calibrage
        jr nz,twice     ; Sinon
        ret             ; Fini !
 
;
; Positonnement sur une piste
; In    ; E=piste où aller
; Out   ; D=piste courante
;         E=ST0
; Modif ; AF, AF', BC=&FB7E
 
GoTo    ld bc,&fb7e
        ld a,%00001111
        call putfdc
        ld a,(lecteur)
        ld d,a
        ld a,(tete)
        sla a
        sla a
        or d
        call putfdc
        ld a,e
        call putfdc
        jp waitins
 
;
; Attente de fin d'instruction
; In    ; BC=&FB7E
; Out   ; D=piste courante
;         E=ST0
; Modif ; AF, AF'
 
WaitIns ld a,%00001000
        call putfdc
        call getfdc
        ld e,a
        call getfdc
        ld d,a
        ld a,e
        and %00100000
        jr z,waitins
        ret
 
;
; Lecture du registre ST3
; In    ; BC=&FB7E
; Out   ; A=ST3
; Modif ; F, AF', E
 
ReadST3 ld a,%00000100
        call putfdc
        ld a,(lecteur)
        ld e,a
        ld a,(tete)
        sla a
        sla a
        or e
        call putfdc
        jp getfdc
 
 
; Envoi d'une valeur sur le port de données
; In    ; BC=&FB7E
;         A=valeur a envoyer
; Modif ; F, AF'
 
PutFDC  ex af,af'
LoopPut in a,(c)
        jp p,loopput
        ex af,af'
        inc c
        out (c),a
        dec c
        ret
 
;
; Réception d'une valeur sur le port de données
; In    ; BC=&FB7E
; Out   ; A=valeur lue
; Modif ; F, AF'
 
GetFDC  ex af,af'
LoopGet in a,(c)
        jp p,loopget
        ex af,af'
        inc c
        in a,(c)
        dec c
        ret
 
;
; Gestion des erreurs disque
; In    ; E=ST0
;         D=ST1
;         L=ST2
; Out   ; A=Statut des erreurs
;         0 ; Pas d'erreur
;         1 ; Erreur signalée et Retry demandé
;         2 ; Erreur signalée et Ignore demandé
;         3 ; Erreur signalée et Cancel demandé
 
TestErr ld a,e
        bit 3,a
        jr nz,discmis
        and 254
        bit 7,a
        jr nz,unknow
        ld a,d
        and 127
        jr z,ok
        cp 1
        jr z,unform
        cp 2
        jr z,discpro
        cp 4
        jr z,secmis
        jr unknow
Ok      ld a,l
        or a
        jr nz,discerr
        xor a
        ret
 
DiscMis ld hl,discmistext
        call putscr
        jr retcan
Unknow  ld hl,unknowtext
        call putscr
        jr ignretcan
Unform  ld hl,unformtext
        call putscr
        jr ignretcan
DiscPro ld hl,discprotext
        call putscr
        jr retcan
SecMis  ld hl,secmistext
        call putscr
        jp ignretcan
DiscErr ld hl,discerrtext
        call putscr
        jp ignretcan
 
PutSCR  ld a,(hl)
        or a
        ret z
        call &bb5a
        inc hl
        jr putscr
 
RetCan  ld hl,retcantext
        call putscr
        call &bb00
LoopRetCan
        xor a
        call &bb06
        cp "r"
        jr z,retry
        cp "a"
        jr z,cancel
        jr loopretcan
 
IgnRetCan
        ld hl,ignretcantext
        call putscr
        call &bb00
LoopIgnRetCan
        xor a
        call &bb06
        cp "r"
        jr z,retry
        cp "i"
        jr z,ignore
        cp "a"
        jp z,cancel
        jr loopignretcan
 
Retry   call &bb5a
        ld a,1
        ret
 
Ignore  call &bb5a
        ld a,2
        ret
 
Cancel  call &bb5a
        ld a,3
        ret
 
;
 
PutFlagErrI
        ld a,2
        ld (flagerr),a
        ret
 
PutFlagErrC
        ld a,3
        ld (flagerr),a
        ret
 
 
; Data programme
;
 
Moteurs db 0
Lecteur db 0
Tete    db 0
FlagErr db 0
 
DiscMisText   db 13,10,"Disque manquant",13,10,0
UnknowText    db 13,10,"Problème inconnu !",13,10,0
UnformText    db 13,10,"Disque non formaté",13,10,0
DiscProText   db 13,10,"Disque protégé contre l'écriture",13,10,0
SecMisText    db 13,10,"Secteur non trouvé",13,10,0
DiscErrText   db 13,10,"Erreur de données",13,10,0
RetCanText    db 13,10,"Recommencer ou Abandonner ? ",0
IgnRetCanText db 13,10,"Recommencer, Abandonner ou Ignorer ? ",0
 
 
;
; Data Test
;
 
SectA   db &11,&12,&13,&14,&15,&16,&17,&18,&19,&1a
SectB   db &01,&02,&03,&04,&05,&06,&07,&08,&09,&0a
TypPist db 2,10,&20,&e5
 
;
; Routine de traçage
;
 
Debug   pop af
        ex af,af'
        ei
brk
        di
        ex af,af'
        push af
        ret
1) NDOffseT : sujet à développer dans l'article lors de futures mises à jour
2) Quoique les secteurs de taille 6 avec “arrêt moteur” puissent répondre à ces deux critères !