Retro-ingénierie d'une carte Z80 : partie 4 - premiers codes en assembleur
Bonjour à tous,
Il y a de nombreux mois, j'ai récupéré une ancienne centrale téléphonique analogique à base de Z80.
Comme c'est le week-end, j'en profite pour me repencher sur ce projet personnel.
Après un assez long travail de rétro-ingénierie, création d'une EEPROM (pour remplacer l'UVProm), ajout d'une interface homme-machine... Le projet vient de connaître une avancée majeure puisque j'y ai exécuté mes premiers codes assembleurs.
Premier code assembleur Z80 exécuté sur la carte |
Si la petite histoire de cette carte vous intéresse, vous pouvez consulter les articles suivants:
- Retro-Ingénierie d'une carte Z80 : partie 3 - EEPROM et Interface Homme-Machine
- Retro-ingénierie d'une carte Z80 : partie 2
- Retro-ingénierie d'une carte Z80
- Récupération: du Z80 dans une vieille centrale téléphonique analogique (DTMF)
Programmeur d'EEPROM
Mon plus gros et celui qui m'aura arrêté le plus longtemps est le programmeur d'EEPROM. Un qui soit capable de fonctionner sous Linux.
Après de longue recherche, j'ai fini par opter pour un XGecu Pro (un programmeur multi-fonctionnel) que l'on peu aussi installer sous Linux à l'aide de Wine.
Si cela vous intéresse, j'ai documenté l'installation et l'utilisation des EEPROM créée pour le projet.
Source: Wiki de MCHobby |
- XGecu sous Linux
Installer Xgpro de votre programmeur universel XEGU T56, T48, TL866II plus sous Linux (Ubuntu/Mint) - XGecu pratique
Programmer une EEPROM GLS27SF512 pour remplacer une ROM 27C512
HASKEL-Z80 / Z80-ASM
J'ai complété le dépôt du projet avec le sous répertoire Z80-ASM. Ce dernier contient un readme.md détaillant les différentes étapes de programmation.
Après quelques recherche, j'ai utilisé z80asm (z80asm manpage @ Ubuntu) pour assembler mes exemples.
C'est l'assembleur utilisé par John Winans dans son projet Z80 retro (voir sa chaîne YouTube). S'il a été capable d'écrire le Bios CPM avec z80asm alors ont doit pouvoir tout assembler.
Ce qu'il y a de bien avec z80asm c'est qu'il produit aussi un fichier .lst avec le détail de l'assemblage des instructions (et résultat binaire).
Autre intérêt de z80asm est qu'il est possible de le combiner avec un MakeFile pour produire le binaire à téléverser sur l'EEPROM.
PROGS=\ 01_minimal.bin \ 02_in_out.bin all: $(PROGS) clean: rm -f ldr rm -f *.lst *.bin *.hex DATE := $(shell date --rfc-3339=seconds) GIT_VERSION := $(shell git describe --long --dirty; git show -s --format='%ci') %.bin: %.asm cat $< | sed -e "s/@@DATE@@/$(DATE)/g" -e "s/@@GIT_VERSION@@/$(GIT_VERSION)/g" | z80asm - -o $@ --list=$(basename $@).lst world: clean all 01_minimal.bin: 01_minimal.asm 02_in_out.bin: 02_in_out.asm
Documentation des cartes
N'hésitez pas à naviguer dans les différents répertoires du dépôt pour trouver les schémas et informations utiles des différentes cartes.
https://github.com/mchobby/kicad-public-projects/tree/main/HASKEL-Z80
Conditions de tests
Préambule
Le système d'origine n'a aucune interface d'interaction avec l'humain (pas de LED, pas de bouton, pas d'afficheur) pour la simple raison que c'est une centrale téléphonique analogique.
L'interface de la carte CPU est assurée par une carte analogique par l'intermédiaire de nombreux GPIO exposés par des PIO (des composants Z80 spécialisés pour créer des entrées/sorties).
Cela réclame donc une programmation assembleur plus importante... par forcement évident pour un néophyte.
Interface homme-machine simplifiée
Appris de mes curiosité avec le RC2014 (une autre machine Z80), il est possible d'utiliser quelques composants avec une ou deux instructions assembleur!
Les instructions assembleurs IN (lire des entrées) ou OUT (modifier des sorties) permettent donc d'interagir avec l'environnement très facilement.
C'est ainsi qu'est née la carte CPU-BOARD-AddOn disponible sur le dépôt GitHub.
Premier test : allumer les LEDs
le programme assembleur 01-minimal.asm se résume en deux lignes.
Il envoi la valeur $0F (15 en décimal, 00001111 en binaire) pour activer les 4 sorties de poids faible (à droite) vers le périphérique de sortie destiné aux LEDs (sur le port $1D)
org 0x0000 ; Cold reset Z80 entry point. loop: ld a, $0f ; Lit LED 0, 1, 2, 3 out ($1d),a ; LED port jp loop
Comme il est interdit d'écrire une valeur directement sur un port, la valeur est chargée dans l'accumulateur (A) puis la valeur de l'accumulateur est envoyé vers le périphérique connecté sur le port $1D (qui sont les LEDs).
Et voici le résultat
Premier code assembleur Z80 exécuté sur la carte |
Pourquoi une boucle?
L'instruction jp loop permet d'exécuter encore et encore l'activation des LEDs.
Cela n'est pas nécessaire d'un point de vue fonctionnel. Le programme pourrait utiliser un halt à la place du jump (instruction jp).
J'ai cependant eu un problème de faux contact, ce que j'ai fini par découvrir après avoir presque tout démonté... et plus de 5 heures de débogage.
Contre toutes évidences, le code ne produisait pas le résultat attendu!
En cas de problème, il faut essayer de comprendre ce qui ne fonctionne pas normalement alors que l'ensemble ne dispose pas encore d'interface utilisateur!
C'est pour cela il est beaucoup plus facile de travailler sur une section de code au fonctionnement répétitif!
Cela permet sonder tranquillement les différents signaux du Z80 et de la carte à l'aide d'un oscilloscope... ils sont supposés être répétitif ;-) .
Dans le cas d'une exécution unique avec une instruction HALT, nous n'aurions que 20-30 ms de diagnostique sous la main. Et il faudrait redémarrer le programme en pressant le bouton Reset
Deuxième test : Lire l'état des boutons
le programme assembleur 02-in-out.asm se résume également en deux lignes.
Il effectue une lecture sur le port $1C pour acquérir l'état des 8 bits... donc des boutons qui y sont branchés.
Ensuite il envoi la valeur obtenue vers port $1D (où sont connectés les LEDs).
Ce programme est donc supposé allumer les LEDs pour lesquelles le bouton correspondant est pressé.
org 0x0000 ; Cold reset Z80 entry point. loop: in a,($1c) ; Read buttons out ($1d),a ; Apply to LEDs jp loop
xxx
Ce qui produit le résultat suivant lorsque le programme est en cours d'exécution
Deuxième code assembleur Z80 exécuté sur la carte |
Ensuite
A partir de maintenant les explorations et tests vont pourvoir se poursuivre avec:
- la RAM de 2 Kio
- les 3x PIO présents sur la CPU-BOARD
- la 2ieme & 3ieme ROM.
- Ajouter un SIO (UART)
sur le connecteur RC2014 présent sur le CPU-BOARD-AddOn - Utiliser le générateur de tonalité présent sur la CPU-BOARD (voir schéma)
Écrire un commentaire