11/08/2021

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
+       LDX      <VECTAB+.PTM
+       LDA     #$93
+       STA      PTMC2-PTM,X
+       LDD     #2
+       STD      PTMTM2-PTM,X
+       CLRA
+       STA      PTMC13-PTM,X
+       LDA      #3              ; RESET ACIA CODE
        LDX      <VECTAB+.ACIA   ; LOAD ACIA ADDRESS
        STA      ,X              ; STORE INTO STATUS REGISTER
-       LDA      #$51            ; SET CONTROL
+       LDA      #$15            ; SET CONTROL
        STA      ,X              ; REGISTER UP
 RTS    RTS                      ; RETURN TO CALLER

@@ -866,10 +877,10 @@
 CODTRT  PULS    PC,U,D,CC       ; RESTORE REGISTERS AND RETURN

 CODTAD  LBSR    XQPAUS          ; TEMPORARY GIVE UP CONTROL
-CODTAO  LDB     1,U             ; LOAD ACIA CONTROL REGISTER
+CODTAO  LDB     ,U              ; LOAD ACIA CONTROL REGISTER
         BITB    #$02            ; ? TX REGISTER CLEAR >LSAB 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 :

  • 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 : PUNCH <addr1> <addr2> 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