Quelques routines en assembleur pour demomaker sur Amiga

Celui qui débute dans la programmation du hardware de l’Amiga en assembleur MC68000 se gratte souvent la tête pour exécuter des fonctions basiques : charger et afficher une image, lire les touches du clavier, etc.
Le fameux "KingTut.iff" de Deluxe Paint
« King Tut », le fichier IFF ILBM par excellence, dessiné par Avril Harrison en 1986 pour Deluxe Paint. © Electronic Arts.
Pour lui simplifier la tâche, cette page met à disposition le source de routines couvrant de telles tâches, qu’on a voulu abordables en se limitant au strict minimum.
Pour l’heure, on trouvera les sources des routines suivantes… :
Pour assembler ce code avec ASM-One, il est nécessaire de disposer de ce fichier qui contient la liste des offsets des registres du hardware.
L’article sera enrichi au fil des réalisations. Ces mises à jour seront signalées.
Mise à jour du 13/10/2018 : Correction d’un bogue dans le code attendant qu’il s’écoule deux lignes rasters pour acquitter l’interruption du CIA.
Mise à jour du 02/10/2018 : Tous les sources ont été modifiés pour intégrer une section « StingRay’s stuff » qui permet d’assurer le bon fonctionnement sur tous les modèles d’Amiga, notamment dotés d’une carte graphique.
Mise à jour du 19/08/2018 : Correction d’un bogue dans l’interprétation de la valeur retournée par Read () dans IFF.s.

Charger une image au format IFF ILBM et l’afficher

Chargement et affichage d’un fichier IFF ILBM en 5 bitplanes de n’importe quelles dimensions pourvu qu’elles ne dépassent pas DISPLAY_DX x DISPLAY_DY et que sa profondeur (son nombre de biplanes) soit égal à DISPLAY_DEPTH.
Attention! certains logiciels sauvegardent des images en plus de bitplanes qu’on ne le croit (ex : l’excellent Pro Motion NG, qui sauvegarde systématiquement en 8 bitplanes).
L’un des intérêts de ce programme est qu’il fonctionne en ligne de commandes : IFF <picture.iff>. Il contient donc tout le code requis pour vérifier qu’un argument a été fourni pour lecture via ReadArgs () et pour charger un fichier via Read (). Les parties du programme couvrant ces deux fonctionnalités ont été assez blindées et factorisées pour être facilement réutilisées.
Cliquez ici pour télécharger le fichier.

Détecter la pression de touches par polling ou interruption

Lecture d’une touche pressée au clavier en attaquant directement les registre du CIA A. Deux modes sont possibles :
  • le polling : la boucle principale doit régulièrement appeler une routine qui vérifie si une touche a été pressée ou relâchée (cliquez ici pour télécharger le fichier) ;
  • l’interruption : la boucle principale est interrompue par l’exécution d’une routine qui survient si une touche a été pressée ou relâchée (cliquez ici pour télécharger le fichier).
L’Amiga est doté de deux coprocesseurs 8520, dits CIA (Complex Interface Adaptor) : le CIA A et le CIA B.
Le CIA A est un circuit qui dispose de plusieurs fonctionnalités susceptibles de générer une requête d’interruption de niveau 2 (vecteur pointant sur $68). Le CIA B n’est pas susceptible de générer une telle requête d’interruption.
Entre autres (avec ses timers A et B, son alarme, ou des échanges de données – sans doute via les ports série et parallèle), le CIA A peut générer une interruption parce qu’il vient de recevoir le dernier des 8 bits transmis par le clavier lors de la pression ou du relâchement d’une touche.
En effet, le CIA A est relié au clavier via ses broches CNT (signal KCLK) et SP (signal KDAT) : le clavier envoie les bits au CIA A au rythme des fronts montants de son propre signal d’horloge.
Lorsque le CIA A a reçu le dernier des 8 bits, il bascule les 8 bits dans son registre SDR ($BFEC01) et positionne le bit SP dans son registre d’interruption ICR ($BFED01).
Dans la foulée, il génère une requête d’interruption de niveau 2, ce qui entraîne le positionnement du bit PORTS du registre INTREQ.
Dans ces conditions, le gestionnaire d’interruption logé à l’adresse $68 doit commencer par vérifier que c’est bien le CIA A qui est l’origine de la requête d’interruption. Pour cela il doit tester le bit SP du registre ICR. Noter que cet accès en lecture au registre ICR a la vertu de provoquer l’acquittement de toutes les requêtes d’interruption du CIA A, si bien que ce dernier cesse de maintenir sa requête d’interruption niveau 2. Sans cet acquittement, le CIA A maintiendrait le signal par lequel il sollicite une interruption du CPU dans son état, cela entraînerait immédiatement un nouveau positionnement du bit PORTS dans INTREQ au sortir du gestionnaire d’interruption, donc un nouvel appel à ce dernier.
Si le bit SP est à 1, le gestionnaire d’interruption peut lire le registre SDR. Ses bits 7 à 1 correspondent aux inverses des bits 6 à 0 du code de la touche (la liste des codes est ici), et son bit 0 indique si la touche a été pressée (bit à 1) ou relâchée (bit à 0).
Le gestionnaire d’interruption doit alors acquitter la lecture du registre SDR en positionnant le bit SPMODE du registre CRA ($BFEE01) durant 85 microsecondes, avant d’effacer de nouveau ce bit.
Enfin, comme toujours, le gestionnaire d’interruption doit acquitter la requête d’interruption en effaçant le bit PORTS dans INTREQ.
Pour que tout cela fonctionne, le CIA A doit être préalablement configuré. Avant toute chose, il faut donc effacer le bit SPMODE dans le registre CRA du CIA A afin de basculer le CIA A en mode « IN » : c’est dans ce mode que le CIA A se met à lire le signal KDAT sur sa broche SP au rythme des fronts montants du signal KCLK sur sa broche CNT.
Pour plus d’explications, voir l’Amiga Hardware Reference Manual et un exemple donné dans le forum de l’English Amiga Board.
Quelques routines en assembleur pour demomaker sur Amiga