Assembleur Z80 sur RC2014 - Contrôle des ports périphériques avec module Digital I/O
Bonjour à tous,
Dans la série de vidéos sur le Spectrum s'appuie sur les interfaces (API) disponible sur le Spectrum.
Le précédent article traitait des "API Spectrum vc API SCM", aujourd'hui, nous allons manipuler la carte Digital I/O en assembleur déjà abordée dans les billets:
- RC2014: Assemblage et test de la carte Digital I/O (en Basic)
- Z80 - Echanges I/O et application au RC2014 avec carte Digital I/O
Détaille le fonctionnement de la Digital I/O pour Comprendre comment la carte fonctionne pour créer ses propres cartes d'interface.
Rappel Digital I/O
Le module Digital I/O que nous allons utilisé exploite l'adresse/port 0x00. Une écriture sur le port permet d'allumer les LEDs correspondantes, une lecture sur le port permet de lire l'état des boutons.
RC2014: Assemblage et test de la carte Digital I/O |
Pouvoir allumer facilement des LEDs permet de suivre le fonctionnement d'un programme assembleur... ou tester facilement un périphérique matériel.
Contrôle de la carte Digital I/O en assembleur
Pour contrôler la carte, il suffit de lire ou écrire des octets sur le port du périphérique.
Voici un petit programme assembleur qui allume toutes les LEDs du port (les 8 bits). La mémoire est d'abord remplie avec des NOP avant de commencer l'assemblage.
*fill 8000 8050 00 *a 8000 8000: 00 . NOP > ld a,$FF 8000: 3E FF >. LD A,$FF 8002: 00 . NOP > out (0),a 8002: D3 00 .. OUT ($00),A 8004: 00 . NOP > ret 8004: C9 . RET 8005: 00 . NOP > . *
Comme il n'est pas possible d'écrire directement une valeur sur le port de sortie, il faut passer par le registre A.
Puis on transfert le contenu du registre A vers le port de sortie 0x00 avec "out (0),a".
Il est possible d'utiliser la représentation binaire pour fixer l'état des LEDs. En voici un exemple.
ld a,%10000001 ; light first & last LEDs out (0),a ; send to peripheral ret ; return to SCM
En exécutant le programme avec "g 8000", les LEDs s'allumes.
Lecture de la carte Digital I/O en assembleur
L'instruction "in A,($00)" permet de lire l'état du périphérique/port 0 et de le transférer dans le registre A.
Le petit script suivant lit l'état des boutons et l'applique immédiatement sur les LEDs.
* *d 8000 8000: DB 00 .. IN A,($00) 8002: D3 00 .. OUT ($00),A 8004: C3 00 80 ... JP $8000 8007: 00 . NOP 8008: 00 . NOP 8009: 00 . NOP
Semi LARSON Scanner
Le petit script ci-dessous utilise la module Digital I/O pour créer une scanner Larson et l'API $0A pour insérer un délai de 100ms entre deux changements d'états.
Le script termine son exécution si l'un des boutons est pressé sur la carte digital I/O.
Voici une vidéo du fonctionnement de code assemblé.
Code assemblé sur Small Computer Monitor
*fill 8000 8100 00 *d 8000 8000: 3E 01 >. LD A,$01 ; initial value 8002: D3 00 .. OUT ($00),A ; @Loop. Light LEDs 8004: CB 07 .. RLC A ; Rotate Left 8 Bits 8006: F5 . PUSH AF ; store A 8007: 11 F4 01 ... LD DE,$0064 ; 100ms 800A: 0E 0A .. LD C,$0A ; delay API 800C: F7 . RST 30 ; call API 800D: DB 00 .. IN A,($00) ; Request input button 800F: B7 . OR A ; upd. Zero flag 8010: C2 17 80 ... JP NZ,$8017 ; jump @End if not pressed 8013: F1 . POP AF ; restore A 8014: C3 02 80 ... JP $8002 ; Jump @loop 8017: F1 . POP AF ; @End. Clear stack 8018: C9 . RET ; Return to SCM
Quelques explication:
- $8000: Le registre A contiendra la valeur qu'on fera passer d'un bit à l'autre. Le bit 0 est placé à 1.
- $8002-8004: envoi la donnée sur le port de sortie (allume la 1ière LED) puis effectue un décalage circulaire à gauche avec l'instruction RLC.
- $8006: Comme nous allons exécuter un appel d'API (delay) et lire les entrées de la carte digital I/O alors il est fort probable que les registres soient altérés! Il faut donc pousser l'état du registre A sur la Pile pour en sauvegarder l'état.
- $800D: lecture de l'état des boutons sur le port 0 dans le registre A. Cette opération n'altere pas les Flags... donc nous ne pouvons savoir si la valeur réceptionnée est égale à zéro ou supérieure à zéro.
- $800F: effectuer une opération mathématique sur le registre A permettrait de mettre les Flags à jour. La seule opération qui ne modifie pas le contenu de A est A = A or A. On exécute donc "OR A" sur l'accumulateur.
- $8010: Si la valeur du registre A à un flag Z=1 cela signifie qu'aucun bouton n'est pressé. Si aucun bouton pressé alors on peu continuer l'exécution.... Si un bout est pressé Zero Flag = 0 et on peut terminer le programme. L'instruction JP NZ saute vers la fin d'exécution si Non Zero flag.
- $8013-8014: Si ces lignes sont exécutés, c'est qu'aucun bouton n'est pressé. Il faut alors récupérer la valeur A sauvegardée sur la pile/stack. Celle-ci contient déjà la prochaine itération/valeur à afficher sur la carte digital I/O. On peut donc reprendre l'exécution a $8002.
- $8017-8018: Si ces lignes sont exécutés c'est que quelqu'un a pressé sur l'un des boutons. Il faut veiller à retirer la valeur poussé sur la Pile car Small Computer Monitor utilise aussi la pile pour son propre fonctionnement. Si on oublie cette valeur sur la Pile alors le moniteur va perdre les pédales.
Ensuite, l'instruction RET rend la main à l'appelant (soit SCM)
Voilà,
J'espère que vous avez trouvé cela intéressant.
Bon amusement.
Écrire un commentaire