Notions d’assembleur Apprendre l'assembleur 6809 en 10 minutes 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 rappeler 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, initialisé à $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 (gérer 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 connaître) 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’ambiguïté -1- Notions d’assembleur 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 flottant 32 bits DOUBLE 175.2 ; un flottant 64 bits On peut réserver et initialiser beaucoup d'espace en mémoire: BLKB 32,0 ; on réserve 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 -2- Notions d’assembleur cmpR comR decR eorR incR lslR negR orR rolR rorR sbcR tstR NN effectuent une opération arithmétique 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 arithmétique 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 vérifie que A*B est supérieur 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$: -3- Notions d’assembleur 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 sélectionner 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 -4- Notions d’assembleur 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. -5-