Cours gratuits » Cours informatique » Cours programmation » Cours Assembleur » Tutoriel Méthodologie de programmation en assembleur

Tutoriel Méthodologie de programmation en assembleur

Problème à signaler:

Télécharger



★★★★★★★★★★3.5 étoiles sur 5 basé sur 1 votes.
Votez ce document:

Programmation en assembleur du LC3

Programmation en assembleur du LC-3

            Introduction      l’architecture du LC-3

Allure gØnØrale d’un programme

Les instructions que l’on va utiliser

Les instructions de chargement et rangement

Les instructions de branchement Un exemple de programme

Les routines et la pile

Les routines

Un exemple de routine

Mise en place d’une pile d’exØcution Un exemple d’utilisation de la pile

Conclusion

Introduction

Le LC-3 est un processeur developpØ dans un but pØdagogique par Yale N. Patt et J. Patel dans [Introduction to Computing Systems : From Bits and Gates to C and Beyond, McGraw-Hill, 2004].

Des sources et exØcutables sont disponibles              l’adresse :

Nous allons nous baser sur le LC-3 pour illustrer les points suivants :

Comment programme t’on en assemble

ur?

Comment mettre en place des routines?

Comment mettre en place une pile d’exØcution de programme?

Ce cours est inspirØ de celui d’Olivier Carton (UniversitØ Paris Diderot - Paris 7), disponible l’adresse :

Plan

Programmation en assembleur du LC-3

            Introduction      l’architecture du LC-3

Allure gØnØrale d’un programme

Les instructions que l’on va utiliser

Les instructions de chargement et rangement

Les instructions de branchement Un exemple de programme

Les routines et la pile

Les routines

Un exemple de routine

Mise en place d’une pile d’exØcution Un exemple d’utilisation de la pile

Conclusion

La mØmoire centrale et les registres du LC-3

La mØmoire est organisØe par mots de 16 bits, avec un adressage sur 16 bits :

adresses de (0000)H                 (FFFF)H.

Les registres :

 8 registres gØnØraux 16 bits : R0, ,R7. Toutefois,

I R6 est utilisØ spØci quement pour la gestion de la pile d’exØcution,

I R7 est utilisØ pour stocker l’adresse de retour d’un appel de fonction.

 quelques registres spØci ques 16 bits :

I PC (Program Counter) et IR (Instruction Register)

I PSR (Program Status Register) plusieurs drapeaux binaires,

 Les bits N,Z,P du PSR indiquent si la derni?re valeur rangØe dans un registre gØnØral est strictement nØgative, zØro ou strictement positive.

Plan

Programmation en assembleur du LC-3

            Introduction      l’architecture du LC-3

Allure gØnØrale d’un programme

Les instructions que l’on va utiliser

Les instructions de chargement et rangement

Les instructions de branchement Un exemple de programme

Les routines et la pile

Les routines

Un exemple de routine

Mise en place d’une pile d’exØcution Un exemple d’utilisation de la pile

Conclusion

Forme gØnØrale d’un programme

Un programme source Øcrit en langage d’assemblage est un chier texte qui comporte une suite de lignes. Sur chaque ligne, on trouve :

soit une instruction (ADD, LD, BR, ); soit une macro (GETC, OUT, );

soit une directive d’assemblage (.ORIG, .BLKW, );

Une ligne peut Œtre prØcØdØe par une Øtiquette pour rØfØrencer son adresse.

.ORIG x3000

; directive pour le dØbut de programme

; partie dØdiØe au code

<- il s’agit d’un commentaire

loop:          GETC

; macro marquØe par une Øtiquette

LD R1,cmpzero

; instruction

HALT

; partie dØdiØe aux donnØes

; macro

cmpzero: .FILL xFFD0

; Øtiquette et directive

.END

; directive


Constantes

Il existe deux types de constantes.

 Les cha nes de caract?res qui apparaissent uniquement apr?s la directive .STRINGZ : elles sont dØlimitØes par deux caract?res " et implicitement terminØes par le caract?re nul.

 Les entiers relatifs en hexadØcimal sont prØcØdØs d’un x; sinon, ce sont des dØcimaux (le prØ x # est optionnel). Ils peuvent appara tre comme

I opØrandes immØdiats des instructions (attention               la taille des opØrandes), I paramØtres des directives .ORIG, .FILL et .BLKW.

Exemple :

                   .ORIG x3000                      ; Constante enti?re en base 16

                   AND R2,R1,2                      ; Constante enti?re en base 10

                   ADD R6,R5,#-1                    ; Constante enti?re nØgative en base 10

                    .STRINGZ "Cha ne"            ; Constante cha ne de caract?res

Directives d’assemblage

 .ORIG adresse

            SpØci e l’adresse          laquelle doit commencer le bloc d’instructions qui suit.

 .END

Termine un bloc d’instructions.

 .FILL valeur

RØserve un mot de 16 bits et le remplit avec la valeur constante donnØe en param?tre.

 .STRINGZ chaine

RØserve un nombre de mots Øgal        la longueur de la cha ne de caract?res plus un caract?re nul (code ASCII 0) et y place la cha ne.

 .BLKW nombre

Cette directive rØserve le nombre de mots de 16 bits passØ en param?tre.

Les interruptions prØdØ nies :   appels syst?me

L’instruction TRAP appelle un gestionnaire d’interruptions mis en place par le petit syst?me d’exploitation du LC-3 : il s’agit donc d’un appel syst?me. Chaque appel syst?me est identi Ø par une constante sur 8 bits.

Dans l’assembleur du LC-3, on peut utiliser les macros suivantes :

instruction

macro

description

TRAP x00

HALT

termine un programme (rend la main         l’OS)

TRAP x20

GETC

lit au clavier un caract?re ASCII et le place dans l’octet de poids faible de R0

TRAP x21

OUT

Øcrit l’Øcran le caract?re ASCII placØ dans l’octet de poids faible de R0

TRAP x22

PUTS

Øcrit      l’Øcran la cha ne de caract?res pointØe par R0

TRAP x23

IN

lit au clavier un caract?re ASCII, l’Øcrit l’Øcran, et le place dans l’octet de poids faible de R0

Plan

Programmation en assembleur du LC-3

            Introduction      l’architecture du LC-3

Allure gØnØrale d’un programme

Les instructions que l’on va utiliser

Les instructions de chargement et rangement

Les instructions de branchement Un exemple de programme

Les routines et la pile

Les routines

Un exemple de routine

Mise en place d’une pile d’exØcution Un exemple d’utilisation de la pile

Conclusion

Les instructions du LC-3

Les instructions du LC-3 se rØpartissent en trois classes.

1      Instructions arithmØtiques et logiques : ADD, AND, NOT.

2      Instructions de chargement et rangement :

I   LD, ST : load et store

I LDR, STR : comme LD et ST mais avec un adressage relatif

I LEA : load e ective address

3      Instructions de branchement :

I   BR : branch

I JSR : jump subroutine

I TRAP : interruption logicielle

I RET : de retour de routine

Il y aussi NOP, pour no operation, qui ne fait rien Pour simpli er les choses, d’autres instructions du jeu d’instruction du LC3 sont ici omises.

RØcapitulatif des instructions du LC-3

syntaxe

action

NZP

     

codage

       

opcode

 

arguments

     

F

E

D

C

B

A

9

8

7

6

5

4

3

2

1

0

NOT DR,SR

DR <- not SR

*

 

1 0 0 1

 

DR

SR

1 1 1 1 1 1

ADD DR,SR1,SR2

DR <- SR1 + SR2

*

 

0 0 0 1

 

DR

SR1

0

0 0

SR2

ADD DR,SR1,Imm5

DR <- SR1 + SEXT(Imm5)

*

 

0 0 0 1

 

DR

SR1

1

Imm5

AND DR,SR1,SR2

DR <- SR1 and SR2

*

 

0 1 0 1

 

DR

SR1

0

0 0

SR2

AND DR,SR1,Imm5

DR <- SR1 and SEXT(Imm5)

*

 

0 1 0 1

 

DR

SR1

1

Imm5

LEA DR,label

DR <- PC + SEXT(PCo set9)

*

 

1 1 1 0

 

DR

PCo set9

LD DR,label

DR <- mem[PC + SEXT(PCo set9)]

*

 

0 0 1 0

 

DR

PCo set9

ST SR,label

mem[PC + SEXT(PCo set9)] <- SR

   

0 0 1 1

 

SR

PCo set9

LDR DR,BaseR,O set6

DR <- mem[BaseR + SEXT(O set6)]

*

 

0 1 1 0

 

DR

BaseR

O set6

STR SR,BaseR,O set6

mem[BaseR + SEXT(O set6)] <- SR

   

0 1 1 1

 

SR

BaseR

O set6

BR[n][z][p] label

Si (cond) PC <- PC + SEXT(PCo set9)

   

0 0 0 0

 

n

z

p

PCo set9

NOP

No Operation

   

0 0 0 0

 

0

0

0

0 0 0 0 0 0 0 0 0

RET (JMP R7)

PC <- R7

   

1 1 0 0

 

0 0 0

1 1 1

0 0 0 0 0 0

JSR label

R7 <- PC; PC <- PC + SEXT(PCo set11)

   

0 1 0 0

 

1

PCo set11

                                     

Notez par exemple que l’addition (ADD) se dØcline de deux fa ons :

ADD DR, SR1, SR2

ADD DR, SR1, Imm5

La colonne NZP indique les instructions qui mettent                  jour les drapeaux NZP.

Plan

Programmation en assembleur du LC-3

            Introduction      l’architecture du LC-3

Allure gØnØrale d’un programme

Les instructions que l’on va utiliser

Les instructions de chargement et rangement

Les instructions de branchement Un exemple de programme

Les routines et la pile

Les routines

Un exemple de routine

Mise en place d’une pile d’exØcution Un exemple d’utilisation de la pile

Conclusion

LD et ST

On ne va dØcrire que LD, mais le principe est symØtrique pour ST.

 syntaxe : LD DR,label

,? le label servira     dØsigner une adresse mØmoire AdM.  action : DR ? Mem[PC + Sext(PCO set9)]

I valeur de PC apr?s son incrØmentation lors du chargement ; si adI est l’adresse de l’instruction, PC = adI+1.

                   I PCO set9 est un dØcalage en complØment         2 sur 9 bits.

                  I La case mØmoire chargØe est donc celle        l’adresse :

                               adM = adI + 1 + Sext(PCO set9),              adI ? 255 ? adM ? adI + 256.

C’est l’assembleur qui va se charger du calcul de PCO set9 : le programmeur en langage d’assemblage utilise des labels. Notez que la distance entre une instruction LD et la case mØmoire dont elle peut charger le contenu est limitØe.

LDR et STR

On ne va dØcrire que LDR, mais le principe est symØtrique pour STR.

syntaxe : LDR DR,baseR,O set6

action : DR ? Mem[baseR + Sext(PCO set6)]

Avec LDR et STR, on peut accØder toutes les adresses de la mØmoire, ce qui permet de lever les limitations de LD/ST. On utilise ces instructions pour manipuler des donnØes sur la pile, comme les variables locales des fonctions; accØder aux ØlØments d’un tableau ou d’une cha ne de caract?res.

baseR est utilisØ comme un pointeur. Par contre, comment initialiser baseR?

LEA

LEA permet de charger une adresse dans un registre gØnØral.

syntaxe : LEA DR,label

action : DR ? PC + Sext(PCO set9)

L’adresse est calculØe comme pour LD, mais seule l’adresse est chargØe dans DR.

Cette instruction est utile pour :

charger l’adresse d’un tableau dans un registre, charger l’adresse de la base de la pile d’exØcution.

On se sert donc de LEA pour initialiser un pointeur.

Plan

Programmation en assembleur du LC-3

            Introduction      l’architecture du LC-3

Allure gØnØrale d’un programme

Les instructions que l’on va utiliser

Les instructions de chargement et rangement

Les instructions de branchement Un exemple de programme

Les routines et la pile

Les routines

Un exemple de routine

Mise en place d’une pile d’exØcution Un exemple d’utilisation de la pile

Conclusion

BR

On rØalise avec BR des branchements inconditionnels ou conditionnels.

Trois drapeaux N, Z et P (majuscules) du PSR sont mis             jour d?s qu’une nouvelle valeur est chargØe dans l’un des registres gØnØraux :

            N passe      1 si cette valeur est strictement nØgative,

            Z passe      1 si cette valeur est zØro,

            P passe       1 si cette valeur est strictement positive.

L’instruction BR contient trois bits n, z et p (minuscules) : syntaxe : BR[n][z][p] label

action : si cond alors PC ? PC+Sext(PCO set9) avec cond = (n z p)+(n = N)+(z = Z)+(p = P)

L’assembleur se charge de calculer PCO set9 d’apr?s le label fourni : il faut nØanmoins garder     l’esprit le fait que la distance du saut est limitØe

Plan

Programmation en assembleur du LC-3

            Introduction      l’architecture du LC-3

Allure gØnØrale d’un programme

Les instructions que l’on va utiliser

Les instructions de chargement et rangement

Les instructions de branchement Un exemple de programme

Les routines et la pile

Les routines

Un exemple de routine

Mise en place d’une pile d’exØcution Un exemple d’utilisation de la pile

Conclusion

Un exemple

On veut Øcrire un programme qui range     l’adresse dØsignØe par res la longueur d’une cha ne de caract?res se trouvant              l’adresse string. Point de dØpart :

.ORIG x3000

                                     ; Ici viendra notre code

HALT       ; Pour mettre fin       l’exØcution string: .STRINGZ "Hello World" res:           .BLKW #1

.END

On va traduire le pseudo-code suivant :

R0 <- string;        // R0 pointe vers le dØbut de la cha ne R1 <- 0;           // Le compteur R1 est initialisØ  0

while((R2 <- Mem[R0]) != ’\0’) {

            R0 <- R0+1;          // IncrØmentation du pointeur

            R1 <- R1+1;          // IncrØmentation du compteur

}

         res <- R1;               // Rangement du rØsultat

Cela donne au        nal le programme suivant :

.ORIG x3000

                    LEA R0,string                ; Initialisation du pointeur R0

                   AND R1,R1,0                  ; Le compteur R1 est initialisØ             0

loop:            LDR R2,R0,0                   ; Chargement dans R2 du caractere pointØ par R0

                  BRz end                       ; Test de sortie de boucle

                   ADD R0,R0,1               ; IncrØmentation du pointeur

                   ADD R1,R1,1              ; IncrØmentation du compteur

BR loop end:           ST R1,res

HALT ; Cha ne constante string: .STRINGZ "Hello World" res:       .BLKW #1

.END

Plan

Programmation en assembleur du LC-3

            Introduction      l’architecture du LC-3

Allure gØnØrale d’un programme

Les instructions que l’on va utiliser

Les instructions de chargement et rangement

Les instructions de branchement Un exemple de programme

Les routines et la pile

Les routines

Un exemple de routine

Mise en place d’une pile d’exØcution Un exemple d’utilisation de la pile

Conclusion

Les routines

En assembleur, une routine est juste une portion de code :

 l’adresse de la premi?re instruction de cette portion de code est connue, et marquØe par un label;

 on peut e ectuer un saut vers cette portion de code (instruction JSR), qui constitue un appel   la routine;

               la      n de l’exØcution de la routine, une instruction de retour (RET) fait

            repasser PC           l’adresse suivant celle de l’instruction d’appel de la routine.

Une routine correspond un peu une fonction dans un langage de haut niveau : en fait, le programmeur doit gØrer beaucoup de choses lui-mŒme

JSR et RET

Lorsqu’une routine est appelØe, il faut mØmoriser l’adresse laquelle doit revenir s’exØcuter le programme             la             n de la routine.

JSR stocke l’adresse de retour dans R7, puis e ectue un branchement l’adresse passØe comme opØrande. RET permet de retourner            la routine appelante, par un saut     l’adresse contenue dans R7.

Dans le programme, on fera par exemple appel          la routine sub :

                JSR sub                    ; R7 <- PC ; PC <- PC + SEXT(PCoffset11)

Dans la routine, le retour au programme principal se fera avec RET :

; routine sub sub:

               RET                    ; PC <- R7

Un exemple de routine

On reprend le programme pour calculer la longueur d’une cha ne de caract?res :

 

.ORIG x3000

 
 

LEA R0,string

; Initialisation du pointeur R0

 

AND R1,R1,0

; Le compteur R1 est initialisØ                     0

loop:

LDR R2,R0,0

; Chargement dans R2 du caractere pointØ par R0

 

BRz end

; Test de sortie de boucle

 

ADD R0,R0,1

; IncrØmentation du pointeur

 

ADD R1,R1,1

; IncrØmentation du compteur

BR loop end:           ST R1,res

HALT ; Cha ne constante string: .STRINGZ "Hello World" res:       .BLKW #1

.END

On va Øcrire une routine strlen pour calculer la longueur d’une cha ne de caract?res dont l’adresse est placØe dans R0, et qui rend son rØsultat dans R0.

Solution

; Programme principal

                    LEA R0,chaine1               ; Chargement dans R0 de l’adresse de la cha ne

                    JSR strlen                  ; Appel de la routine

ST R0,lg1

HALT ; DonnØes chaine1: .STRINGZ "Hello World" lg1: .BLKW #1

; Routine pour calculer la longueur d’une cha ne terminØe par ’\0’.

; param?tre d’entrØe                  : R0 adresse de la cha ne

; param?tre de sortie : R0 longueur de la cha ne

strlen: AND R1,R1,0

; Mise            0 du compteur : c = 0

loop:

LDR R2,R0,0

; Chargement dans R2 du caract?re pointØ par R0

 

BRz fini

; Test de fin de cha ne

 

ADD R0,R0,1

; IncrØmentation du pointeur

 

ADD R1,R1,1

BR loop

; IncrØmentation du compteur

fini:

ADD R0,R1,0

; R0 <- R1

 

RET

; Retour           l’appelant

Plan

Programmation en assembleur du LC-3

            Introduction      l’architecture du LC-3

Allure gØnØrale d’un programme

Les instructions que l’on va utiliser

Les instructions de chargement et rangement

Les instructions de branchement Un exemple de programme

Les routines et la pile

Les routines

Un exemple de routine

Mise en place d’une pile d’exØcution Un exemple d’utilisation de la pile

Conclusion

Quand une routine en appelle une autre, elle doit sauvegarder son adresse de retour avant l’appel, et la restaurer apr?s.

; programme principal JSR sub1

; routine sub1 sub1: JSR sub2

              RET                                           ; Probl?me : ici R7 ne contient l’adresse de retour vers sub1 !

; (puisque sub2 a ØtØ appelØe juste avant )

; routine sub2 sub1: RET

Une mØthode est de mettre en place une pile d’exØcution, qui permet de gØrer mŒme les appels rØcursifs. Il faut aussi sauvegarder les registres dont on souhaite retrouver le contenu apr?s l’exØcution d’une routine.

On donne ici une mani?re de gØrer une pile d’exØcution sur le LC-3 :

           R6 est rØservØ     la gestion de la pile.

            R6 est initialisØ     un adresse de      fond de pile     dØsignØe par stackend.

R6 donne toujours l’adresse de la derni?re valeur mise sur la pile.

La pile cro t dans le sens des adresses dØcroissantes.

 
 
 

xFFFF

Mise en place de la pile d’exØcution :

.ORIG x3000 ; Programme principal main:              LD R6,spinit              ; on initialise le pointeur de pile

HALT

; Gestion de la pile spinit:        .FILL stackend

.BLKW #15 stackend: .BLKW #1             ; adresse du fond de la pile

.END

Empilement d’un registre Ri :

ADD R6,R6,-1 ; dØplacement du sommet de pile STR Ri,R6,0 ; rangement de la valeur DØpilement du sommet de pile dans un registre Ri :

                        LDR Ri,R6,0             ; rØcupØration de la valeur

                       ADD R6,R6,1             ; restauration du sommet de pile

Un exemple utilisant la pile

On reprend notre exemple, d’abord sous la forme d’un pseudocode :

main(void) {

sub1(); }

sub1(void) {

sub2();

return;

}

sub2(void) {

return;

}

On ajoute la gestion de la pile d’exØcution :

main(void) {

sub1(); } sub1(void) {

push(R7);

sub2();

// sauvegarde de l’adresse de retour R7

R7 <- pop();

// restauration de l’adresse de retour

return;

} sub2(void) {

return;

}

Rem : si sub2 faisait appel               d’autres routines, il serait nØcessaire qu’elle sauvegarde aussi son adresse de retour!

En langage d’assemblage du LC3, cela donne pour le programme principal :

; Programme principal main:    LD R6,spinit              ; on initialise le pointeur de pile

                       JSR sub1              ; appel          la routine sub1

HALT

; MØmoire rØservØe              la pile spinit:             .FILL stackend

.BLKW #15 stackend: .BLKW #1             ; adresse du fond de la pile

Et pour les deux routines sub1 et sub2 :

; routine sub1

 

sub1: ADD R6,R6,#-1

;

STR R7,R6,#0 JSR sub2

; sauvegarde de l’adresse de retour R7.

LDR R7,R6,#0

; restaure le registre R7.

ADD R6,R6,#1

;

RET

; routine sub2 sub2:

; retour           l’appelant

RET

; retour           l’appelant

Conclusion

Nous avons vu :

un exemple de langage d’assemblage;

comment peuvent Œtre mis en place les appels de routines et la pile;

,? utile pour sauvegarder variables, param?tres et adresse de retour

Les Øtapes suivantes seraient de voir comment transformer :

du code en langage d’assemblage vers le langage machine

,? assemblage;

du code en langage de haut niveau vers un langage d’assemblage ,? compilation.

source du programme langage C

compilateur

programme traduit en langage d’assemblage

assembleur

langage machine code objet

   
 

117