Les appels système : une porte de deux octets
Un programme qui veut afficher, lire un fichier ou connaître l’heure frappe à une porte de deux octets. Le noyau, de l’autre côté, fait le travail. Simple, et sans rien réserver dans la mémoire du programme.
Dans cette page
Le principe
Le programme prépare un bloc de paramètres dans sa propre mémoire, à l’endroit de son choix (sauf en page zéro). Puis il écrit l’adresse de ce bloc dans la porte :
- l’octet bas en
$FFF8; - l’octet haut en
$FFF9, ce qui déclenche l’appel.
Il attend ensuite que le noyau remette $FFF9 à zéro. Les résultats et le code d’erreur sont alors
dans son bloc.
$FFF9.Le bloc a toujours la même forme :
| Octet | Contenu |
|---|---|
| +0 | numéro du service (SYSTEME, ECRAN, FICHIERS…) |
| +1 | numéro de la fonction dans ce service |
| +2 | code d’erreur, écrit par le noyau (0 = succès) |
| +3 et suivants | les paramètres, puis les résultats |
En assembleur (64tass), avec la bibliothèque libe65 fournie :
lda #<bloc
ldx #>bloc
jsr e65_porte ; ou la macro #E65_APPEL bloc
lda bloc+E65_ERREUR ; 0 = succès
bloc: .byte E65_SVC_ECRAN, E65_ECRAN_TEXTE, 0
.word $0400 ; adresse de la page de texte
.byte $1F ; blanc sur bleu
Pourquoi c’est différent
Une façon courante de dialoguer avec un système est une zone fixe : une « boîte aux lettres » à
une adresse convenue, où l’on dépose les paramètres. Morpheus, par exemple, utilise 8 octets en
$FF00. Eliott65 fait autrement :
- aucune zone réservée : le bloc est où le programme veut, il peut en avoir plusieurs ;
- aucun code résident : pas de routine du système à appeler en mémoire 6502 ;
- l’appel est synchrone : quand la 6502 sort de sa boucle, le travail est fait.
Comment le noyau voit la porte
Avec le bus PIO + DMA, aucun cœur ARM ne voit passer les écritures de la 6502. Le noyau, sur le
cœur 0, surveille donc l’octet $FFF9 dans la mémoire de la 6502. Dès qu’il n’est plus nul, il
lit le bloc, traite l’appel, écrit les résultats, puis remet $FFF9 à zéro.
C’est pour cela que l’octet haut doit être non nul : le bloc ne peut pas être en page zéro.
Combien ça coûte
Le programme LATENCE.E65 a mesuré le coût d’un appel depuis la 6502 elle-même, avec l’horloge
du système : 1 000 tours d’une boucle vide, puis 1 000 tours avec un appel SYSTEME PING.
| Durée | |
|---|---|
| un tour de boucle vide | 2,77 µs |
| un appel système complet | 4,99 µs, soit ≈ 36 cycles |
Sur ces 36 cycles, une trentaine sont les instructions de la 6502 elle-même (préparer, écrire la porte, boucler, revenir). Le noyau ajoute environ 1 µs.
Le pire cas n’est pas mesuré : un appel qui tombe pendant que le pilote USB scrute le hub (une fois par seconde, quelques millisecondes) attend d’autant.
Les règles à connaître
- Pas d’appel dans un gestionnaire d’interruption. Entre l’écriture de
$FFF8et celle de$FFF9, une interruption qui ferait son propre appel écraserait l’octet bas. Si c’est indispensable, le programme principal encadre ses appels parPHP / SEI … PLP. - La 6502 n’est pas gelée pendant l’appel : son horloge continue, ses interruptions sont servies, même pendant un long accès à la clé.
FICHIERS EXECUTERne revient pas en cas de succès : le nouveau programme a pris la place.
Les services
| N° | Service | Pour quoi faire |
|---|---|---|
| 0 | SYSTEME | temps, informations, hibernation, processus (lancer, céder, dormir, terminer, tuer) |
| 1 | ECRAN | mire, texte simple, texte en couleur, graphisme |
| 2 | CLAVIER | file de touches dans la mémoire du programme, lecture, disposition |
| 3 | STOCKAGE | lire et écrire des blocs de 512 octets sur la clé |
| 4 | FICHIERS | lister, lire, écrire, supprimer, exécuter |
| 5 | GRAPHIQUE | mémoire vidéo, palette, plans, lutins, trame |
| 6 | SON | notes et mélodies sur le haut-parleur de la carte |
La liste complète, avec chaque bloc de paramètres et chaque code d’erreur, est dans la référence de l’API.
Une seule source pour l’API
L’API est décrite une seule fois, dans un fichier Python du dépôt. Deux choses en sont générées :
la documentation de référence et le fichier d’inclusion e65.inc pour l’assembleur. Un test vérifie
que les deux sont à jour. Le principe est le même que celui de Morpheus, qui génère aussi son code de
répartition et sa documentation depuis une source unique.