Un micro-ordinateur FLEX/6809 DIY - Partie 2
Dans cette deuxième partie nous allons mettre en place le moniteur, qui va résider en ROM et sera lancé au chargement de l'ordinateur.
Comme je le disais dans le premier article, je m'inspire librement de la description du Tavernier 6809, et je suis donc parti sur le moniteur ASSIST09 que je connaissais déjà.
Le code source de ce moniteur est disponible dans l'annexe B du "MC6809 - MC6809E Microprocessor Programming Manual" (Motorola, 1981). C'est donc un peu le moniteur "officiel" de ce processeur !
Pour éviter une fastidieuse recopie à la main du code source, j'en ai trouvé une version toute faite ici https://github.com/jefftranter/6809/tree/master/sbc/assist09
Adaptation du code
Assist09 est prévu pour un système 6809 avec un timer 6840 et un terminal série. Du coup il y a peu de modifications à effectuer pour le faire fonctionner sur ma carte.
Ci-dessous le diff complet depuis le code d'origine :
--- assist09-orig.asm 2021-08-11 13:31:40.447344300 +0200 +++ ../assist09-orig.asm 2021-07-17 10:23:16.182291900 +0200 @@ -14,12 +14,12 @@ ********************************************* * GLOBAL MODULE EQUATES ******************************************** -ROMBEG EQU $F800 ; ROM START ASSEMBLY ADDRESS -RAMOFS EQU -$1900 ; ROM OFFSET TO RAM WORK PAGE -ROMSIZ EQU 2048 ; ROM SIZE +ROMBEG EQU $F000 ; ROM START ASSEMBLY ADDRESS +RAMOFS EQU -$900 ; ROM OFFSET TO RAM WORK PAGE +ROMSIZ EQU 4096 ; ROM SIZE ROM2OF EQU ROMBEG-ROMSIZ ; START OF EXTENSION ROM -ACIA EQU $E008 ; DEFAULT ACIA ADDRESS -PTM EQU $E000 ; DEFAULT PTM ADDRESS +ACIA EQU $E808 ; DEFAULT ACIA ADDRESS +PTM EQU $E800 ; DEFAULT PTM ADDRESS DFTCHP EQU 0 ; DEFAULT CHARACTER PAD COUNT DFTNLP EQU 5 ; DEFAULT NEW LINE PAD COUNT PROMPT EQU '> ; PROMPT CHARACTER @@ -164,6 +164,9 @@ * NOTE THAT THE WORK RAM PAGE MUST BE 'RAMOFS' * FROM THE ROM BEGINNING ADDRESS. ******************************************** + ORG $E000 + FCB 0 + ORG ROMBEG ; ROM ASSEMBLY/DEFAULT ADDRESS ***************************************************** @@ -350,11 +353,11 @@ BEQ CMD ; BRANCH IF NOT TO USE A PTM CLR PTMTM1-PTM,X ; SET LATCH TO CLEAR RESET CLR PTMTM1+1-PTM,X ; AND SET GATE HIGH - LDD #$01A6 ; SETUP TIMER 1 MODE + LDD #$93A6 ; SETUP TIMER 1 MODE STA PTMC2-PTM,X ; SETUP FOR CONTROL REGISTER1 STB PTMC13-PTM,X ; SET OUTPUT ENABLED/ * SINGLE SHOT/ DUAL 8 BIT/INTERNAL MODE/OPERATE - CLR PTMC2-PTM,X ; SET CR2 BACK TO RESET FORM + ;CLR PTMC2-PTM,X ; SET CR2 BACK TO RESET FORM * FALL INTO COMMAND PROCESSOR *************************************************** @@ -832,10 +835,18 @@ * COON - OUTPUT CONSOLE INITIALIZATION * A,X VOLATILE CION EQU * -COON LDA #3 ; RESET ACIA CODE +COON + LDXLSAB FIXME - BNE CODTAD ; RELEASE CONTROL IF NOT - STA ,U ; STORE INTO DATA REGISTER + BEQ CODTAD ; RELEASE CONTROL IF NOT + STA 1,U ; STORE INTO DATA REGISTER RTS ; RETURN TO CALLER *E
Les principales modifications effectuées :
- constantes au début du programme pour correspondre au plan d'adressage
- ajout du $ORG E000 pour obtenir un fichier binaire de 8Ko correspondant à la taille de l'EPROM
- dans CION/COON, ajout du code pour initialiser le timer 2 (qui génère la fréquence d'horloge pour l'ACIA)
- quelques corrections dans les routines entrées/sortie console pour correspondre à un ACIA 6850
Pour assembler le moniteur, cela se passe comme le programme "hello" de la partie précédente :
as9 assist09-lflex.asm -l c s cre s19 objcopy --input-target=srec --output-target=binary assist09-lflex.s19 assist09.bin
Utilisation de Assist09
Les commandes
Une fois le fichier assist09.bin mis sur l'EPROM, au prochain démarrage de l'ordinateur un prompt apparait :
ASSIST09 >
Les commandes principales sont les suivantes :
Commande | Description |
---|---|
G [addr] | GO exécuter le programme à l'adresse [addr] (4 chiffres hexa). Si [addr] n'est pas précisé le programme est exécuté à l'adresse PC courante |
C [addr] | CALL même chose mais fait un BRA à l'adresse indiquée, un RTS renvoie au prompt du moniteur |
L | LOAD charge un programme en mémoire depuis la console au format S19 |
P [addr1] [addr2] | PUNCH envoie le contenu entre addr1 et addr2 vers la console, au format S19 |
D [addr1] [addr2] | DUMP affiche le contenu de la mémoire entre addr1 et addr2 |
B [addr] | génère un point d'arrêt à l'adresse [addr] |
M [addr] | permet d'afficher et modifier une donnée en mémoire |
R | permet d'afficher et modifier le contenu des registres |
Il faut tout taper en majuscules. Un descriptif plus complet est disponible sur le lien github de assist09 cité plus haut.
Pour utiliser les fonctions de debuggage (point d'arrêt), il faut que l'interrupteur reliant la sortie du timer 1 du 6840 à la broche \NMI du 6809 soit fermé.
Les points d'entrée
On peut tout à fait utiliser les différents points d'entrée de Assist09 pour ses propres programmes. Les fonctions suivantes sont disponibles :
******************************************* * ASSIST09 MONITOR SWI FUNCTIONS * THE FOLLOWING EQUATES DEFINE FUNCTIONS PROVIDED * BY THE ASSIST09 MONITOR VIA THE SWI INSTRUCTION. ****************************************** INCHNP EQU 0 ; INPUT CHAR IN A REG - NO PARITY OUTCH EQU 1 ; OUTPUT CHAR FROM A REG PDATA1 EQU 2 ; OUTPUT STRING PDATA EQU 3 ; OUTPUT CR/LF THEN STRING OUT2HS EQU 4 ; OUTPUT TWO HEX AND SPACE OUT4HS EQU 5 ; OUTPUT FOUR HEX AND SPACE PCRLF EQU 6 ; OUTPUT CR/LF SPACE EQU 7 ; OUTPUT A SPACE MONITR EQU 8 ; ENTER ASSIST09 MONITOR VCTRSW EQU 9 ; VECTOR EXAMINE/SWITCH BRKPT EQU 10 ; USER PROGRAM BREAKPOINT PAUSE EQU 11 ; TASK PAUSE FUNCTION
Pour s'en servir, il faut utiliser l'interruption logicielle SWI, et mettre dans l'octet suivant le numéro de la fonction désirée. Par exemple pour écrire le caractère A :
TESTA LDA #'A SWI FCB 1
Le gros avantage de cette méthode d'appel est que le programme n'a pas besoin de connaître l'adresse à laquelle se situe la routine.
Hello World
Essayons de refaire le programme "Hello World" dans l'environnement du moniteur :
; Hello World / ASSIST09 PDATA1 EQU 2 EOT EQU $04 ORG $0100 LEAX MSG,PCR SWI FCB PDATA1 RTS ; Hello Message MSG FCC /Hello, World!/ FCB 13 FCB 10 FCB EOT
C'est beaucoup plus simple que la version du premier article !
Pour l'assembler :
as9 hello.asm -l c s cre s19
Le fichier hello.s19 est celui qu'il va falloir envoyer à l'ordinateur :
S11A0100308D00033F023948656C6C6F2C20576F726C64210D0A0426 S9030000FC
Pour faire cela j'utilise le logiciel 'RealTerm' sous Windows, mais n'importe quel émulateur de terminal qui permet d'envoyer un fichier texte fera l'affaire.
Pour le charger donc, appuyer sur "L" puis [entrée], et envoyer le fichier. A la fin du chargement j'ai deux caractères "00" qui s'affichent, je ne suis pas certain que cela soit normal mais il suffit d'appuyer sur [Entrée] pour obtenir un nouveau prompt
Pour lancer le programme, il faut utiliser la fonction "C" comme ceci :
>C 0100 Hello, World! PC-F5D1 A-00 B-00 X-0107 Y-E002 U-E7C2 S-E751 CC-F4 DP-00 >
Comme on le voit le moniteur affiche l'état des registres avant de rendre la main, ce qui est bien pratique.
Debuggage
Le fichier hello.lst généré par l'assembleur permet de voir le code machine correspondant à chaque instruction en assembleur, ainsi que les différentes adresses associées :
0001 ; Hello World / ASSIST09 0002 0003 0002 PDATA1 EQU 2 0004 0008 MONITOR EQU 8 0005 0006 0004 EOT EQU $04 0007 0008 0100 ORG $0100 0009 0010 0100 30 8d 00 03 [ 9 ] LEAX MSG,PCR 0011 0104 3f [19 ] SWI 0012 0105 02 FCB PDATA1 0013 0106 39 [ 5 ] RTS 0014 0015 ; Hello Message 0016 0107 48 65 6c 6c 6f 2c MSG FCC /Hello, World!/ 20 57 6f 72 6c 64 21 0017 0114 0d FCB 13 0018 0115 0a FCB 10 0019 0116 04 FCB EOT 0020
Par exemple essayons de mettre un point d'arrêt juste avant l'appel à l'interruption, on voit que c'est à l'adresse 0104 :
>B 0104 0104 >
Maintenant lançons à nouveau le programme :
>C 0100 PC-0104 A-00 B-00 X-0107 Y-E002 U-E7C2 S-E74F CC-F0 DP-00 >
Comme prévu nous reprenons la main avec le compteur de programme à l'adresse 0104. On voit que le registre X a pour valeur 0107, ce qui est bien l'adresse de la chaîne de caractères à afficher.
On va faire quelques modifications pour afficher "World?" à la place de la chaîne prévue.
Tout d'abord on va changer la valeur du registre X pour pointer sur la première lettre du mot 'World', soit l'adresse 010E. Pour cela on va utiliser la fonction 'R'. La touche ',' permet de passer au champ suivant, au niveau du registre X on saisit la nouvelle valeur puis on valide avec entrée :
>R PC-0104 A-00 B-00 X-0107 Y-E002 U-E7C2 S-E74F CC-F0 DP-00 PC-, A-, B-, X-010E >R PC-0104 A-00 B-00 X-010E Y-E002 U-E7C2 S-E74F CC-F0 DP-00 PC- >
Enfin, remplaçons le point d'exclamation par un point d'interrogation. Le fichier hello.lst nous indique que c'est à l'adresse 0113. On peut aussi le vérifier en faisant un dump de la mémoire à partir de l'adresse 0100 :
>D 0100 011F 0 1 2 3 4 5 6 7 8 9 A B C D E F 0100 30 8D 00 03 3F 02 39 48 65 6C 6C 6F 2C 20 57 6F 0...?.9Hello, Wo 0110 72 6C 64 21 0D 0A 04 7F 7F 7F 7F 7F 7F 7F 7F 7F rld!...
La commande 'M' permet de changer cette valeur en mémoire ( le code ASCII en hexa de '!' est 21, celui de '?' est 3F) :
>M 0113 21-3F >
Nous pouvons maintenant relancer le programme avec la commande 'G' :
>G World? PC-F5D1 A-00 B-00 X-010D Y-E002 U-E7C2 S-E751 CC-F4 DP-00 >
Et nous avons bien l'affichage souhaité !
Comme on le voit on a pas mal de moyen de tester les programmes directement avec l'ordinateur, ce qui va être très utile pour la suite.
Ressources
Le projet Github https://github.com/laurent-fr/LFlex21 contient le code source du moniteur ainsi que le fichier .bin correspondant, dans le répertoire software/assist09