Apprendre l'assembleur 6809 en 10 minutes

 

Copyrigh (c)1998 Dan Truong, ENSSAT, 6 rue de Kerampont, B.P. 447, 22305 Lannion Cedex.

 

 

Syntaxe

 

Les commentaires sont précédés d'un ";" ou d'une "*".

 

par exemple:

; un commentaire

* un commentaire

 

Les mnémoniques de l'assembleur et les pseudo-ops sont écrites sur 3 ou 4 caractères. Les noms choisis permettent de se rapeler facilement de l'opération exécutée

 

par exemple:

ADDA #$55 ; effectue l'addition A+$55->A

DB $12 ; réserve un octet en mémoire, initalisé à $12 (declare byte)

 

Les constantes peuvent être écrite en ASCII, en décimal ou en hexadécimal.

 

par exemple:

 

; Les 3 déclarations suivantes sont équivalentes:

db 'A' ; en ASCII

db 65 ; en décimal

db $41 ; en hexadécimal

 

Notez que le 6809 code tout sur des octets, les différentes façons d'écrire les valeurs ont donc juste pour but de faciliter la tache du programmeur (gerér du texte directement en ASCII, des entiers en décimal ou en hexa, etc.).

Par exemple, on pourrait écrire du code illisible, et très dur à rédiger. Les deux bouts de codes suivant sont équivalents:

 

lda #$65

db 72 ; ici on a remplacé la mnémonique par son code-op

db 'A' ; (notez qu'il faut déjà chercher pour le connaitre)

bne suite$

ldx Message$

jsr AFF_TXT

...

 

lda #$65

cmpa #$65 ; c'est quand même plus lisible comme ca!

bne suite$

ldx Message$

jsr AFF_TXT

...

 

Les labels font 32 caractères maximum, ils sont suivis de ":". On différencie les majuscules des minuscules. Les labels globaux sont définis dans tous le programme dans tout le programme. ils doivent donc être uniques. Les labels locaux ne ne sont définis qu'entre deux labels globaux. Ils peuvent donc être redéfinis dans le programme. On les déclare en les faisant suivre d'un "$".

 

par exemple:

 

ROUTINE1: ; Label global, il ne peut être défini qu'une fois

ldx #Message$

jsr AFF_TXT

Menu$: ; Label local

jsr LIRE_CAR

cmpa #0

bne Menu2$

rts ; fin de routine

Menu2$:

cmpa #1

bne $Menu

jsr MENU1

jmp Menu$

Message$:

db 'Menu de la routine 1',0

 

ROUTINE2: ; Label global, tous les anciens labels locaux sont oubliés

ldx #Message$

jsr AFF_TXT

Menu$: ; Label local, on réutilise le nom "Menu$"

jsr LIRE_CAR

;...

bne Menu$ ; quand on saute il n'y a pas d'ambiguité

Message$:

db 'Menu de la routine 2',0

 

 

Les pseudo-opérations et directives de compilation

 

Le compilateur comprends plusieurs pseudo-opérations. Une pseudo-op ne se traduit pas en une instruction machine, mais est comprise par le compilateur qui effectue l'action correspondante.

 

par exemple:

 

Douze EQ $12 ; Définit le nom "Douze"

lda #Douze ; Le compilateur remplacera "Douze" par $12 automatiquement

 

On peut réserver et initialiser une zone mémoire pour y déclarer du texte, des entier ou des flotants:

 

par exemple:

 

DB 'je peux afficher ce texte a l''écran' ; une chaine de texte

DB 0,$12 ; deux octets

DW $ffff ; un mot 16 bits

FLOAT 175.12 ; un flotant 32 bits

DOUBLE 175.2 ; un flotant 64 bits

 

On peut réserver et initaliser beaucoup d'espace en mémoire:

 

BLKB 32,0 ; on reserve 32 octets mis à zéro

BLKW 32,$FF ; on réserve 32 mots (64 octets), initialisés à 255.

 

Il existe d'autres pseudo-opérations et directives de compilation. Si vous en avez besoin, reportez vous à la documentation de l'assembleur 6809.

 

Modes d'adressage

 

Le mode d'adressage est spécifié par des caractères # ou []

 

par exemple:

 

si en mémoire on a la valeur $33 à l'adresse $12 et la valeur $ff à l'adresse $33 alors

 

lda #$12 ; immédiat: A <- $12 charge la constante dans le registre A

lda $12 ; direct: A <- $33 charge dans A le contenu à l'adresse $12

lda [$12] ; indirect: A <- $ff charge dans A le contenu à l'adresse

; pointée par le contenu à l'adresse $12

lda ,X ; indexé: charge dans A le contenu à l'adresse pointée par

; le registre X

lda ,X+ ; post-incrémentation: idem, ensuite X est incrémenté de 1

lda ,X++ ; idem, ensuite X est incrémenté de 2

lda , X- ; on peut aussi décrémenter X de 1 ou 2...

lda #5,X ; charge dans A le contenu de la RAM a l'adresse pointée

; par le registre X augmentée de 5

; L'offset doit tenir soit sur 5, 8 ou 16 bits

lda [$5],X ; on peut faire des combinaisons...

 

 

Les registres

 

Il y a 2 registres A et B 8 bits pour travailler, qui peuvent être combinés et utilisés comme un registre 16 bits appelé D.

Il y a deux registres spéciaux 8 bits CC et DP. CC contient les drapeaux d'exécution (résultats de l'UAL, et drapeaux d'interruption). DP (?).

Il y a aussi 2 registres d'index 16 bits, X et Y, et 2 registres de pile 16 bits U et S. On peut utiliser X et Y a volonté, mais il ne faut pas modifier U ou S directement, car ils servent à gérer les piles.

 

Registres 8 bits:

A accumulateur A

B accumulateur B

CC registre de codes conditions (drapeaux de l'UAL)

DP (?)

 

Registres 16 bits:

D = A (poids forts de D), B (poids faible de D)

X registre d'index (lda ,X)

Y registre d'index (lda ,Y)

U pointeur de pile utilisateur (pulu/pshu)

S pointeur de pile système (puls/pshs)

 

 

Les instructions de base

 

Voici une liste (non exhaustive) des instructions disponibles. Par convention on note R pour un registre a définir. Par exemple, si on parle de ldR où R peut être A, B ou D, alors il y a 3 instructions, lda, ldb et ldd. Lorsqu'on écrit NN, cela représente le paramètre de l'instruction utilisé pour faire l'adressage mémoire. Par exemple si on écrit "ldR NN", on peut en fait utiliser l'instruction "lda #$12".

 

ldR NN

stR NN

charge/stocke une valeur dans le registre R

(où R est A,B,D,X,Y,U,S au choix)

addR adcR andR aslR asrR bitR clrR

cmpR comR decR eorR incR lslR negR

orR rolR rorR sbcR tstR NN

effectuent une opération arithmetique ou logique entre le registre R et la RAM.

par exemple, eorR (exclusive or), lslR (logical shift left), rolR (rotate bits left)

(où R est soit A ou B)

addR subR cmpR NN

effectue une opération arithmetique ou logique entre le registre R et la RAM

(où R est A, B ou D)

abx

additionne le registre B (8 bits) à X (B+X->X)

mul

multiplie A par B, résultat dans D (AxB->D)

sex

extention des bits de signe du registre (?)

leasR

...

daa

decimal adjust A (?)

exg R1, R2

echange le contenu de deux registres de même taille

(où R1 et R2 sont soit 8 bits: A, B CC ou DP, soit 16 bits: X,Y,S,U ou PC)

tfr R1,R2

copie le contenu de R1 dans R2

(où R1 et R2 sont soit 8 bits: A, B CC ou DP, soit 16 bits: X,Y,S,U ou PC)

pshR1 R2

pulR1 R2

empile/dépile le contenu du registre R2 dans la pile R1

(où R1 est soit S soit U et R2 est un autre registre)

bcc bcs beq bne bge

bgt bhi bhs ble NN ...

branchements conditionnels

bra NN

branchement inconditionnel

jmp NN

saut inconditionnel

jsr NN

saut inconditionnel à une routine (qui finit par un "rts")

rts

saut de retour vers l'adresse de l'appel (empilée dans la pile S)

 

Pour une description plus détaillée du jeu d'instruction, voyez la documentation du processeur 6809 ou prenez un livre de programmation du 6809 à la bibliothèque.

 

Utilisation de la pile

 

Lorsqu'il n'y a pas assez de registres pour travailler, on peut sauvegarder temporairement des registres dans la pile (c.a.d. en mémoire) avant de les réutiliser avec pshs/puls.

On peut utiliser soit la pile système (S) soit la pile utilisateur (U).

Attention: il faut impérativement avoir dépiler tous les registres qu'on a empilé avant de faire un rts, sinon le système plante.

 

exemple:

TestAxB:

; on verifie que A*B est superieur a 255 mais on veut garder A et B intact

...

pshs A ; ... donc on les empile

pshs B

mult ; A*B -> D : la multiplication efface A et B !

cmpd #$00FF ; c'est pour ca qu'on a sauvés A et B

ble Erreur$

puls B ; on dépile A et B

puls A

...

rts

Erreur$:

ldx Message$

jsr AFF_TXT

rts

Message$:

db " A x B est trop petit"

 

Les instructions jsr/rts utilisent la pile pour faire des routines réutilisables. Jsr empile le PC puis saute à l'adresse de la routine demandée. Rts effectue automatiquement le saut de retour en dépilant le PC.

 

exemple:

Main:

jsr LIT_CAR ; lecture de B

jsr ASC_TO_BIN

tfr A, B

jsr LIT_CAR ; lecture de A

jsr ASC_TO_BIN

jsr Mult8Bit ; (1) on appele la routine AxB->A

cmpa #$55

ble AffA$ ; si AxB <= $55 on veut afficher A*B*3

tfr B, A ; sinon on affiche B*3 (en recopiant B dans A)

AffA$:

ldb #$3 ; on multiplie par 3

jsr Mult8Bit ; (2) on réutilise la routine AxB->B

jsr AFF_VAL

rts

 

;-----------------------------

; cette routine fait AxB->A sans effacer B.

 

Mult8Bit:

pshs B

mult

cmpb #$0

bne Erreur$

puls B

rts ; on retourne automatiquement en (1) ou en (2)

Erreur$:

ldx Message$

jsr AFF_TXT

rts

Message$:

db "Erreur: A x B -> A (dépassement de capacité)"

 

Remarques sur la chaine de compilation

 

Le compilateur détecte peu d'erreurs à la compilation. Par exemple "mult X, B" ne génère pas d'erreur. Le compilateur ignore le surplus de texte et se contente de générer un "mult" qui fait AxB->D.

 

La méthode de compilation est la suivante pour le projet:

- ecrire un fichier source

edit program.asm

- compiler le programme.

x6809 program

On obtient un fichier objet program.obj

- linker le programme. Il faut générer un fichier .hex (option h)

link

program

1000

(taper entrée jusqu'au choix des options)

h

On obtient un fichier texte program.hex contenant des nombres en hexa

- utiliser le terminal de windows pour envoyer le code sur la carte 6908

mettre la carte 6809 en mode transfert de programme (T)

lancer terminal

menu Transfert/Envoyer un fichier texte

selectionner program.hex

cliquer OK

Il faudra peut être configurer le mode de transfert du terminal:

Menu paramètre/Communications 1200 baud, 8 bits, parité aucune, xon/xoff, 1 bit d'arrêt, port COM2.

- il reste à exécuter le programme

lancer le programme sur la console WYSE (g1000)

 

Si l'affichage du WYSE ne marche pas il faut le configurer:

Touche setup (F3)

On se déplace dans le menu du bas avec les flèches, on sélectionne avec espace, on sort avec setup

choisir communication, et mettre emission et réception à 1200 bauds (même paramètres que ceux utilisés pour terminal)

Si il y a toujours un problème, vous pouvez vérifier que l'écran émule bien du VT100, que le clavier est bien US, etc.

Note: les cables VISU et PC ne sont pas équivalents, ne les confondez pas.

 

Fin.