Central Input/Output utility
Le CIO est un utilitaire gérant les accès en INPUT/OUTPUT sur les différents périphériques.
Les commandes BASIC comme PRINT, INPUT, GRAPHICS, LPRINT, ... ne sont en fait que des commandes simplifiées pour appeler le CIO. Basic se débrouillant alors pour passer tous les paramètres comme il faut.
Il est cependant possible de déclencher les routines du CIO grâce à d'autres commandes BASIC: Comme OPEN, GET, PRINT et XIO. Cependant, il faudra gérer soit même tous les codes attendus par le CIO.
De même, il est possible de déclencher ces routines en assembleur. Là aussi, il faudra passer les bons codes, mais ce n'est pas aussi compliqué que cela.
Les canaux du CIO:
Le CIO utilise 8 canaux pour accéder aux devices. Des canaux que l'on numérotera de 0 à 7.
Le Basic se réserve 3 canaux:
- 0 utilisé en permanence pour l'éditeur.
- 6 Utilisé pour les opérations graphiques (inutilisé si pas d'opération graphique).
- 7 Utilisé pour les accès cassette, disquette et imprimante (inutilisé si pas d'accès à l'un de ces périphériques nommés).
En assembleur, on fait tout ce que l'on veut, tous les canaux sont libres (à moins que vous n'utilisiez encore le basic avec votre code).
Les différentes étapes d'utilisation des routines du CIO:
Pour utiliser les routines du CIO, il faut:
- Fermer le canal (Pas forcément nécessaire, mais un autre programme a pu l'ouvrir et ne pas le fermer ! Dans ce cas, l'ouverture ne pourrait pas ensuite se (re)faire.)
- Ouvrir le canal (et ne pas refaire l'ouverture si déjà ouvert !)
- Lire/Ecrire un/plusieurs octets.
- Fermer le canal à partir du moment où l'on ne s'en sert plus !
Bien entendu, pour ouvrir, lire/écrire et enfin fermer un périphérique, il faut passer des paramètres comme le nom du périphérique, le type d'accès, ...
Ces informations seront passées dans l'IOCB du canal utilisé.
La structure de l'IOCB:
La structure de l'IOCB ne sert que pour du code machine. En effet, en BASIC, ce sont les instructions qui stockeront automatiquement les bonnes valeurs dans la structure correspondant au canal choisi.
L'Input Output Control Block(IOCB) occupe une taille de 16 octets par canaux. Donc pour les 8 IOCB : 8 x 16 = 128 octets en tout.
L'IOCB du canal 0 démarre en $0340. Pour trouver le début de l'IOCB pour un canal précis, il suffit alors de multiplier ce canal par 16...
Marrant, pour le canal
1, on obtient 16 qui fait $10 en hexa. Pour le canal 2, on obtient 32 qui fait
$20 en hexa. et ainsi de suite. Et en fait, plus besoin de faire des calculs:
pour le canal 5 par exemple, il suffit d'écrire $50.
Offset (Adresse à partir du canal 0): | Nom | Explication |
0 ($0340) | ICHID | Handler, à $FF si inutilisé |
1 ($0341) | ICDNO | Numéro du device (pour les disquettes) |
2 ($0342) | ICCOM | commande |
3 ($0343) | ICSTA | status |
4 ($0344) | ICBAL | Adresse buffer (partie basse) |
5 ($0345) | ICBAH | Adresse buffer (partie haute) |
6 ($0346) | ICPTL | Adresse routine PUT BYTE (utilisé par Basic) (partie basse) |
7 ($0347) | ICPTH | Adresse routine PUT BYTE (utilisé par Basic) (partie haute) |
8 ($0348) | ICBLL | Longueur du buffer (partie basse) |
9 ($0349) | ICBLH | Longueur du buffer (partie haute) |
$A ($034A) | ICAX1 | Information auxiliaire |
$B ($034B) | ICAX2 | Information auxiliaire |
$C ($034C) | ICAX3 | Information auxiliaire |
$D ($034D) | ICAX4 | Information auxiliaire |
$E ($034E) | ICAX5 | Information auxiliaire |
$F ($034F) | ICAX6 | Information auxiliaire |
ICHID
Lorsqu'un canal est ouvert, ICHID est un index vers une table de handlers qui pointe sur les routines du device. à $FF si fermé.
ICDNO
Numéro du device dans le cas où il existe plusieurs devices de même nom (D0, D1, D2 en Basic: D pour Disquette et 0 pour le premier lecteur, 1 pour le second, ...)
ICCOM
Commande que le CIO doit exécuter:
Commande | Valeur (en hexa) |
Open | $03 |
Close | $0C |
Get | $07 |
Put | $0B |
Input | $05 |
$09 | |
Status Request | $0D |
... | > $0D, ces commandes dépendent du device |
Open, Close et Status
peuvent être lancées sur des canaux déjà (ou encore)
fermés.
ICSTA
Contient un code erreur si problème. Si le bit 7 est à 0, c'est qu'il n'y a pas d'erreur.
ICBAL et ICBAH
Avant l'ouverture d'un canal, ce pointeur est positionné sur un buffer contenant le nom de device (Cette chaîne doit se terminer par 0 ou $9B).
Avant un INPUT ou OUTPUT, buffer qui contiendra les données à lire ou à écrire.
ICPTL et ICPTH
Réservé au Basic...
ICBLL et ICBLH
Doit contenir la longueur maximum du buffer définie dans ICBAL ou ICBAH. Cette valeur peut être modifiée par le CIO en lecture sur un device si le nombre d'octets reçu est inférieur. La valeur sera alors égale aux nombres d'octets effectivement lus.
ICAX1 à ICAX6
Informations auxiliaires.
Ouvrir un canal du CIO
Avant tout, il faut ouvrir un canal. Mais pour cela, il faut indiquer dans l'IOCB correspondant les informations suivantes:
Paramètre | Valeur |
ICCOM | OPEN ($03) |
ICBAL | Adresse sur le nom du périphérique (partie basse) |
ICBAH | Adresse sur le nom du périphérique (partie haute) |
ICAX1 | En général Lecture/Ecriture mais aussi CLEAR et PLOT/DRAWTO si périphérique S: |
ICAX2 | En général 0, ou mode écran pour le périphérique S: |
ICBAL et ICBAH pointent sur un buffer contenant le device (RAPPEL 0 ou $9B en fin de chaîne !).
Format d'écriture ICAX1:
128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 |
C | S | W | R | A |
Ce sont essentiellement les bits R et W qui sont utilisés. Les bits suivants sont plus spécifiques au device S:.
A : pour Append, A TESTER !!!
R : pour Read, afin de permettre un accès en lecture sur le périphérique.
W : pour Write, afin d'accéder en écriture sur un périphérique.
S : Pour Split : Contrairement à la commande BASIC GRAPHICS, la valeur 16 permet d'avoir des lignes en mode texte en bas de l'écran.
C : Pour Clear : Lors de l'ouverture de l'écran, effacement de l'écran.
On peut bien évidemment combiner les différents bits: R + W permettant par exemple d'accéder en lecture et écriture à un périphérique (Remarque: cela ne change pas la taille du fichier sur une disquette).
En sortie:
Le registre P voit son bit N positionné si une erreur se produit.
Squelette d'appel "open" en assembleur:
Pour ouvrir un canal en BASIC, il faut utiliser la commande OPEN:
OPEN #canal,icax1,icax2,device:file name
Lecture/Ecriture sur un canal:
Lire une chaîne de caractères:
La lecture s'arrêtera sur un retour chariot ($9B) ou EOL ou enfin sur EOF.
Les paramètres à passer sont:
Paramètre | Valeur |
ICCOM | INPUT ($05) |
ICBAL | Adresse d'un buffer qui contiendra l'enregistrement lu (partie basse) |
ICBAH | Adresse d'un buffer qui contiendra l'enregistrement lu (partie haute) |
ICBLL | Taille du buffer (Partie basse) |
ICBLH | Taille du buffer (Partie haute) |
Remarque : Si le nombre de caractères reçus est inférieur à la taille du buffer, alors ICBLL et ICBLH contiennent le nombre de caractères effectivement lus.
Squelette d'appel "input" en assembleur, voir code plus bas.
En BASIC, la commande équivalente est INPUT:
INPUT #canal,Variable de type caractère
INPUT #canal,Variable arithmétique Dans ce cas, on ne pourra saisir que des chiffres et .
La commande s'arrête sur EOL (touche return si clavier K:).
Envoyer une chaîne de caractères:
L'écriture de la chaîne s'arrêtera à la taille/nombre de caractères. Remarque, la commande EOL est ignorée dans la chaîne. Par contre, un caractère EOL est systématiquement envoyé à la fin de la chaîne.
Les paramètres à passer sont:
Paramètre | Valeur |
ICCOM | PRINT ($09) |
ICBAL | Adresse d'un buffer les données à envoyer (partie basse) |
ICBAH | Adresse d'un buffer les données à envoyer (partie haute) |
ICBLL | Taille du buffer/nombre de caractères (Partie basse) |
ICBLH | Taille du buffer/nombre de caractères (Partie haute) |
Squelette d'appel "PRINT" en assembleur, voir code plus bas.
En BASIC, la commande équivalente est PRINT:
avec ;
PRINT #canal;OUT$
ou PRINT #canal;"TEXTE"
ou , dans ce cas, affichage d'espace devant la chaîne de caractères.
ou PRINT #canal,OUT$
ou enfin PRINT #canal,"TEXTE"
La réutilisation de PRINT sans fermeture au préalable du canal ajoute le texte à la suite.
Pour lire n octets:
Cette commande va lire des octets. Elle ne gère donc pas le code EOL. C'est un caractère comme un autre...
Ce sera donc cette commande qu'il faudra utiliser pour lire un fichier autre qu'un fichier texte. (image, binaire, ... dans lesquels il n'y a effectivement pas de code EOL).
Cette commande s'arrête sur EOF, ICBLL et ICBLH. Contient alors la taille réellement lue.
Les paramètres à passer sont:
Paramètre | Valeur |
ICCOM | GET ($07) |
ICBAL | Adresse d'un buffer qui contiendra l'enregistrement lu (partie basse) |
ICBAH | Adresse d'un buffer qui contiendra l'enregistrement lu (partie haute) |
ICBLL | Taille du buffer (Partie basse) |
ICBLH | Taille du buffer (Partie haute) |
Squelette d'appel "GET" en assembleur, voir code plus bas.
En basic, la commande équivalente et GET.
GET #canal,var
Ou var est une variable numérique.
La commande get
lit un octet et un seul. Il faudra donc boucler pour lire tout un fichier par
exemple. Dans ce cas, l'instruction TRAP s'avèrera indispensable si l'on
ne connait pas la taille du fichier.
EXAMPLE:
Pour écrire n octets:
Cette commande va écrire des octets. Elle ne gère donc pas le code EOL. C'est un caractère comme un autre...
Ce sera donc cette commande qu'il faudra utiliser pour écrire un fichier autre qu'un fichier texte. (image, binaire, ... dans lesquels il n'y a effectivement pas de code EOL).
Les paramètres à passer sont:
Paramètre | Valeur |
ICCOM | PUT ($0B) |
ICBAL | Adresse d'un buffer contenant les données à écrire (partie basse) |
ICBAH | Adresse d'un buffer contenant les données à écrire (partie basse) |
ICBLL | Taille du buffer (Partie basse) |
ICBLH | Taille du buffer (Partie haute) |
Squelette d'appel "PUT" en assembleur, voir code plus bas.
En BASIC, la commande équivalente est PUT
PUT #1,OUT
Où OUT est une variable numérique. On ne peut donc écrire
qu'un octet à la fois.
Voici un exemple de squelette pour lire/écrire des données.
Clôturer un canal:
Cette fonction est indispensable, elle va libérer l'accès à un canal du CIO et permet ainsi aux autres programmes son utilisation.
Sur une disquette, le nom du fichier sera enregistré à ce moment là .
Les paramètres à passer sont:
Paramètre | Valeur |
ICCOM | CLOSE ($0C) |
Appel en assembleur:
En basic, la commande équivalente est CLOSE.
CLOSE #canal
Annexe