Assembleur Z80 sur RC2014 - Small Computer Monitor APIs
Bonjour à tous,
Dans la série de vidéos sur le Spectrum s'appuie sur les interfaces (API) disponible sur le Spectrum.
API Spectrum vs API SCM
Le RC2014 n'est pas un Spectrum et ne dispose pas des API Spectrum... mais il dispose de ses API décrite dans la documentation de SCM (voir le billet "Learning the Small Computer Monitor", Google Group, Document PDF).
Ce billet se penche sur quelques API digne d'intérêt en présentant l'appel dans SCM avec la commande API et puis l'appel depuis du code assembleur.
API $02 - Sortie caractère
L'API 2 envoi un caractère sur le périphérique de sortie (la console active).
Le caractère est envoyé en paramètre à l'API. L'exemple ci-dessous affiche le caractère W (87 décimal, 0x57) sur la console.
* * * *API 2 $57 W57 0057 *
Une fois l'appel effectué, la lettre W est bien visible avant de recevoir le retour des l'appel.
L'appel d'API en ASSEMBLEUR se fait avec un appel à RST $30 en indiquant le numéro de fonction dans le registre C et le paramètre dans le registre A.
ld a, 'W' ; charger caractère ld c,$02 ; API a appeler RST 30 ; Appel d'API
Voici le programme assemblé.
*a 8000 8000: 0E 57 .W LD C,$57 > ld a,'W' 8000: 3E 57 >W LD A,$57 8002: 3E 02 >. LD A,$02 > ld c,$002 8002: 0E 02 .. LD C,$02 8004: F7 . RST 30 > rst 30 8004: F7 . RST 30 8005: C9 . RET > ret 8005: C9 . RET 8006: 00 . NOP > . *g 8000 W*
La première instruction peut aussi être ld a,$57 . L'instruction RET permet de rendre la main à SCM.
API $01 - Entrée caractère
L'API 1 permet de capturer un caractère sur le périphérique d'entrée/sortie. L'appel d'API attend la réception (saisie) d'un caractère puis indique la valeur de celui-ci par retour d'API.
*api 1 6C 0001 *
L'API indique le caractère $6C (108 en décimal), cela correspond au caractère "l" (L minuscule).
En assembleur, la valeur ASCII est retourné dans le registre A.
ld c,$01 ; input char rst 30 ret
Alors comme l'assembleur n'affiche pas le contenu des registres pendant son exécution, il faudra placer un breakpoint (point d'arrêt) sur la ligne $8003, ce qui permettra d'inspecter la valeur du registre A avant qu'il ne soit modifié.
*a 8000 8000: 00 . NOP > ld c,$01 8000: 0E 01 .. LD C,$01 8002: 00 . NOP > rst 30 8002: F7 . RST 30 8003: 00 . NOP > ret 8003: C9 . RET 8004: 00 . NOP > . *b 8003 Breakpoint set *g 8000 Breakpoint PC:8003 AF:7438 BC:2501 DE:6DA4 HL:0325 IX:EB4A IY:EA39 Flags:---H---- *
Le breakpoint est placé avec la commande "b 8003". Quand le programme est démarré avec "g 8000", il attend la pression d'une touche (entrée sur la console) puis le breakpoint s'active sur l'instruction RET (juste avant son exécution).
Presser la touche Entrée pour exécuter la ligne suivante.
L'activation du breakpoint affiche l'état des registres. Le registre A contient la valeur $72, ce qui correspond à la lettre "r".
API $07 - Retour à la ligne
L'API 7 permet d'envoyer une séquence de retour à la ligne avec les caractères CR/LF ($0A/$0D). Cela évite de faire deux appels d'API consécutifs.
C'est une fonction bien pratique.
API $06 - Sortie d'une ligne
L'API 6 permet de sortir une chaîne de caractère complète sur la sortie de la console. La chaîne doit être terminée par un NULL (codé 0x00).
Cette API reçoit l'adresse de la chaîne de caractère en RAM ou ROM. Cette adresse est communiquée par le registre DE.
Il faut donc avoir une telle chaîne de caractère définie quelque-part, ce que nous allons faire à l'adresse $8500 avec "e 8500". La zone aura au préalable été remplie avec des 0x00 et la commande "m 8500" permet de vérifier le contenu de la mémoire.
*fill 8500 8600 00 *e 8500 8500: 00 . NOP > "RC2014 is really AWESOME! 8519: 00 . NOP > 00 851A: 00 . NOP > . *m 8500 8500: 52 43 32 30 31 34 20 69 73 20 72 65 61 6C 6C 79 RC2014 is really 8510: 20 41 57 45 53 4F 4D 45 21 00 00 00 00 00 00 00 AWESOME!....... 8520: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 8530: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 8540: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 8550: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 8560: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 8570: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Maintenant que l'information est en place dans la mémoire, il est possible de d'appeler l'API.
* **api 6 8500 RC2014 is really AWESOME!00 851A *
Le 00 851A présenté sont les retours de l'API. $851A est par ailleurs l'adresse du dernier caractère de la chaîne (avant le $00).
Appel en assembleur
Pour appeler cette API, il faut initialiser le registre DE avec l'adresse de la chaîne de caractères.
*a 8000 8000: 00 . NOP > ld de,$8500 8000: 11 00 85 ... LD DE,$8500 8003: 00 . NOP > ld c,$6 8003: 0E 06 .. LD C,$06 8005: 00 . NOP > rst 30 8005: F7 . RST 30 8006: 00 . NOP > ret 8006: C9 . RET 8007: 00 . NOP > . *g 8000 RC2014 is really AWESOME!* *
Après l'affichage de la chaîne, SCM présente immédiatement son invite de commande "*" sans retour à la ligne puisqu'il n'y en a pas dans la chaîne de caractères.
API $04 - Entrée une ligne
L'API 4 permet de saisir une ligne sur le périphérique d'entrée jusqu'à la longueur indiquée lors de l'appel (ou jusqu'au retour clavier). La chaîne de caractère est stockée dans l'emplacement mémoire prévu à cet effet.
La chaîne de caractère est terminée par un 0x00 (NULL) mais ne contiendra pas le retour clavier ($0D). L'emplacement du caractère 0x00 doit être prévu dans la mémoire pour y être également stocké.
La chaîne de caractères stockée à l'adresse indiquée (par le registre DE) et la longueur de la chaîne encodée est retournée dans le registre A (longueur excepté 0x00).
Dans l'exemple ci-dessous, nous allons stocker une chaîne de caractères de 25 caractères (donc un emplacement de 26 caractères pour le 0x00) à l'emplacement $8500.
Pour rendre la saisie évidente nous allons pré-initialiser la mémoire $8500 à $8600 avec des 0xFF.
*fill 8500 8600 FF *m 8500 8500: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF ................ 8510: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF ................ 8520: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF ................ 8530: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF ................ 8540: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF ................ 8550: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF ................ 8560: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF ................ 8570: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF ................ *
L'intérêt de cet API concerne surtout les programmes que l'on pourrait écrire en assembleur à partir de $8000.
ld de,$8500 ; storage buffer ld a,$1a ; len 25 + null ld c,$04 ; Input line API rst $30 ; call API ret ; return SCM
Voici l'assemblage du code:
8000: 00 . NOP > ld de,8500 8000: 11 00 85 ... LD DE,$8500 8003: 00 . NOP > ld a, $1a 8003: 3E 25 >% LD A,$25 8005: 00 . NOP > ld c,4 8005: 0E 04 .. LD C,$04 8007: 00 . NOP > rst 30 8007: F7 . RST 30 8008: 00 . NOP > ret 8008: C9 . RET 8009: 00 . NOP > . * *
En exécutant le code, il est possible de saisir jusque 25 caractères que l'on peut ensuite visualiser en mémoire à l'adresse $8500.
*g 8000 Dodo teste son RC2014 en *m 8500 8500: 44 6F 64 6F 20 74 65 73 74 65 20 73 6F 6E 20 52 Dodo teste son R 8510: 43 32 30 31 34 20 65 6E 20 00 FF FF FF FF FF FF C2014 en ....... 8520: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF ................ 8530: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF ................ 8540: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF ................ 8550: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF ................ 8560: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF ................ 8570: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF ................
Il est effectivement possible de saisir jusqu'à 25 caractères (même si le dernier est un espace 0x20). La chaîne de caractères se termine bien par un null (0x00).
API $0A - Delay (ms)
L'API $0A permet de créer une pause en x milliseconde. Ce délai est calculé sur base d'une horloge CPU cadencée 7.37Mhz. Si la fréquence d'horloge est différente alors il faudra appliquer une règle de trois pour adapter le délai d'attente souhaité.
voici quelques instructions assembleurs.
ld de,+2000 ; 2000ms (decimal) ld c, $0A ; delay API rst 30 ret ; return to SCM
Ensuite
Ce ne sont là que quelque-unes des API les plus utiles pour tester des routines assembleurs avec Small Computer Monitor (SCM).
Voyez les autres APIs décritent dans la documentation de SCM (voir le billet "Learning the Small Computer Monitor", Google Group, Document PDF).
Écrire un commentaire