IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Introduction au Motorola ColdFire


précédentsommairesuivant

III. Modèle de programmation

III-A. Syntaxe

Avant d'aller plus loin, il est nécessaire de présenter rapidement la syntaxe Motorola. Ceux qui ont déjà pratiqué l'assembleur savent que chaque constructeur a sa syntaxe propre qui est de plus susceptible de varier suivant le compilateur utilisé. Pour plus de détails, il faudra se référer à la documentation du programme d'assemblage choisi.

  • Les mnémoniques sont suffixées par la taille de l'opérande
  • La source précède la destination.
 
Sélectionnez
MOVE.L D0, D1 ; Place le mot  long (32 bits) contenu dans D0 dans D1  
MOVE.W D0, D1 ; Place le mot (16 bits de poids faible) contenu dans D0 dans D1  
MOVE.B D0, D1 ; Place l'octet (8 bits de poids faible) contenu dans D0 dans D1
  • # est l'opérateur d'immédiateté
  • $ désigne un nombre hexadécimal
  • % désigne un nombre binaire
 
Sélectionnez
MOVE.B #10,D0 ; place 10 (décimale) dans D0 
MOVE.B #$10,D0 ; place 0x10 (hexadécimale) dans D0 
MOVE.B #,D0 ; place 0b10 (binaire) dans D0 
MOVE.B 10,D0 ; place ce qui est à l'adresse 10 dans D0

Les labels commencent en colonne 0 par une lettre. Ils terminent par " : " et contiennent uniquement des caractères alphanumériques ainsi que l'underscore " _ ". Ils sont sensibles à la casse.

 
Sélectionnez
label:  nop             
 bra label

Certains assembleurs (pas très malins) exigent de suffixer la source pour lever l'ambiguïté entre différents opcodes. Cela n'a rien à voir avec la taille de l'opérande.

 
Sélectionnez
MULU.W D0.L,D1

III-B. Modes d'adressage

Avant d'attaquer les instructions attardons-nous sur les modes d'adressages. Ils sont au nombre de onze. Leur choix détermine souvent le succès d'un développement.

Absolu

 
Sélectionnez
MOVE.L $10,D0

Place ce qui est à l'adresse 10 dans D0

Immédiat

 
Sélectionnez
MOVE.L #$10,D0

Place la valeur 10 dans D0

Direct registre d'adresse

 
Sélectionnez
MOVEA.L A0,A1

Place ce qui est dans le registre A0 dans le registre A1

Direct registre de donnée

 
Sélectionnez
MOVE.L D0,D1

Place ce qui est dans D0 dans D1

Indirect registre d'adresse

 
Sélectionnez
MOVE.L (A0),D0

Place ce qui est désigné par l'adresse contenue dans A0 dans D0

Indirect registre d'adresse pré-décrémenté

 
Sélectionnez
MOVE.L -(A0),D0

Décrémente A0 de la taille de l'opérande puis comme indirect registre d'adresse

Indirect registre d'adresse post-incrémenté

 
Sélectionnez
MOVE.L (A0)+,D0

Comme indirect registre d'adresse puis A0 est incrémenté de la taille de l'opérande

Indirect registre d'adresse avec déplacement

 
Sélectionnez
MOVE.L (12,A0),D0

Place dans D0 ce qui est désigné par l'adresse contenue dans A0 +12. Le déplacement est sur 16 bits. L'addition est signée. A0 n'est pas modifié.

Indirect registre d'adresse avec déplacement, index et facteur d'échelle

 
Sélectionnez
MOVE.L (12,A0,D0,S)

L'adresse effective est obtenue en additionnant en signé les 32 bits de A0 au déplacement (ici 12) puis à l'index (D0) multiplié par le facteur d'échelle (S). S peut être égal à 1, 2 ou 4. A0 n'est pas modifié

Relatif

 
Sélectionnez
BRA $2A

On ajoutera 0x2A en signé au Program Counter. Le déplacement est sur 16 bits signé. Généralement on utilise un label.

Relatif compteur programme avec déplacement et relatif compteur programme avec déplacement, index et facteur d'échelle.

 
Sélectionnez
MOVE.W ($14,PC) MOVE.W ($14,PC,D3,S)

Voir indirect registre d'adresse avec déplacement et suivant. Interdit en destination

Pour écrire des modules translatables, il est important de définir une stratégie d'adressage souple. L'utilisation de pointeurs plutôt que d'adresses "dures" est vivement recommandé. On trouvera en annexe toutes les combinaisons possibles entre modes d'adressage et instructions. Le MCF est bien plus contraignant que le 68000 en ce domaine. Il est par exemple impossible d'écrire :

 
Sélectionnez
DIVU.W #1000,D3

Il faut passer la constante par un registre

 
Sélectionnez
MOVE.L #1000,D2 
DIVU.W D2,D3

III-C. Jeu d'instruction

Une instruction est composée d'une mnémonique suffixée et de deux opérandes (une seule dans certains cas). Chaque opérande est elle-même composée d'un couple valeur / mode d'adressage. Lorsque l'instruction modifie une valeur le résultat est toujours placé dans la destination.

Mnémonique Suffixe Source Destination
MOVE .L (A0) D1
    La source est A0 en adressage indirect registre d'adresse La destination est D0 en adressage direct registre de donnée


Certaines instructions ont une incidence sur le CCR et ne supportent pas toutes les tailles d'opérandes. Le détail est fourni en annexe.

L'un des opérateurs est toujours un registre.

On a toujours envie de trouver une façon ludique de présenter les instructions. Malheureusement, je ne vois pas de meilleur moyen pour être relativement concis et exhaustif que d'utiliser des tableaux énumératifs.

Chaque mnémonique présentée correspond à un opcode particulier. Autrement dit, ADD ou ADDQ font tout les deux des additions, mais il s'agit d'instructions totalement différentes d'un point de vue physique. Les câbles utilisés ne sont pas les mêmes. Cela implique qu'il ne faut pas se tromper dans le choix des instructions, si l'on veut des performances optimales. Certains assembleurs sauront choisir entre, par exemple, ADDI, ADDQ ou ADD. Mais ce n'est pas toujours le cas.

Si certaines instructions apparaissent deux fois c'est qu'elles ont un comportement différent suivent les modes d'adressages utilisés.

On peut découper le jeu d'instruction en plusieurs sous catégories : arithmétique, logique, branchement, contrôle, déplacement ... Commençons par les plus populaires :

III-C-1. Les instructions de déplacement

Instruction Explication Exemple
MOVE Déplace la source dans la destination MOVE.L D0,D1
MOVEA La source est transférée dans un registre d'adresse MOVEA.L D0,A1
MOVEM MOVE mémoire vers liste de registres et inversement MOVEM.L DO-7,(A0)
MOVEM.L (A0),D0-7
MOVEQ Placer une constante de 8bits dans un registre de donnée MOVEQ.L #3,D0

III-C-2. Les instructions logiques

Instruction Explication Exemple
AND Source ET Destination AND.L DO,D1
ANDI Constante ET destination ANDI.L #$FF, D1
EOR Source OU EXCLUSIF Destination EOR.L DO,D1
EORI Constante OU EXCLUSIF destination EORI.L #$FF, D1
OR Source OU Destination OR.L DO,D1
ORI Constante OU destination ORI.L #$FF, D1
NOT NON logique NOT.L D0

III-C-3. Les instructions arithmétiques

Instruction Explication Exemple
ADD Source + destination ADD.L D0,D1
ADDA La destination est une adresse ADDA.L D0,A1
ADDI La source est une constante ADDI.L #$FF,D0
ADDQ La source est une constante entre 1 et 8 ADDQ.L #1,D0
ADDX Source + Destination + bit X ADDX.L D0,D1
SUB Destination - Source SUB.L D0,D1
SUBA La destination est une adresse SUBA.L D0,A1
SUBI La source est une constante SUBI.L #$FF,D0
SUBQ La source est une constante entre 1 et 8 SUBQ.L #1,D0
SUBX Source -Destination - bit X SUBX.L D0,D1
MULU.W Multiplie les 2 opérandes de 16 bits résultat sur 32 dans la destination MULU.W D0,D1
MULU.L Multiplie les 2 opérandes de 32 bits. Poids faibles du résultat dans la destination MULU.L D0,D1
MULS.W Comme MULU.W mais en signé MULU.W D0,D1
MULS.L Comme MULU.L mais en signé MULU.L D0,D1
DIVU.W Divise les 32 bits de la destination par les 16 bits de la source.
Le résultat est dans le mot de poids faible de la destination. Le reste dans le poids fort.
DIVU.W D0,D1
DIVU.L Divise les 32 bits de la destination par les 32 bits de la source.
Résultat dans les 32 bits de la destination
DIVU.L D0,D1
DIVS.W Comme DIVU.W mais en signé DIVS.W D0,D1
DIVS.L Comme DIVU.L mais en signé DIVS.L D0,D1

III-C-4. Décalages et permutations

Instruction Explication Exemple
LSL Décalage logique à gauche.
Constante entre 1 et 8
LSL.L #3,D0
LSL.L D1,D0
LSR Décalage logique à droite
Constante entre 1 et 8
LSR.L #3,D0

LSR.L D1,D0
ASL Décalage Arithmétique à gauche.
Constante entre 1 et 8
ASL.L #3,D0

ASL.L D1,D0
ASR Décalage Arithmétique à droite.
Constante entre 1 et 8. Extension de signe
ASR.L #3,D0

ASR.L D1,D0
CLR Force la valeur à zéro CLR.B D0
EXT Etend le signe d'un registre d'un octet à un mot ou d'un mot à un mot long EXT.W D0
EXTB Etend le signe d'un registre d'un octet à un mot long EXT.L D0
NEG L'opérande est soustrait à 0 NEG.L D0
NEGX L'opérande et le bit X sont retranchés à 0 NEGX.L D0
SWAP Permute le mot de poids fort et le mot de poids faible d'un registre SWAP.W D0

III-C-5. Opérations sur les bits

Instruction Explication Exemple
BCHG Le bit est complémenté. La destination est un registre.

Le numéro du bit est modulo 32. La source est une constante
BCHG.L #31,D0
BCHG Le bit est complémenté. La destination est une adresse.
Le numéro du bit est modulo 8. La source est un registre
BCHG.B D0,$1000
BCLR Le bit est forcé à zéro La destination est un registre.
Le numéro du bit est modulo 32. La source est une constante
BCLR.L #31,D0
BCLR Le bit est forcé à zéro La destination est une adresse.
Le numéro du bit est modulo 8. La source est un registre
BCLR.B D0,$1000
BSET Le bit est forcé à un. La destination est un registre.
Le numéro du bit est modulo 32. La source est une constante
BSET.L #31,D0
BSET Le bit est testé est forcé à un.
La destination est une adresse. Le numéro du bit est modulo 8.
La source est un registre
BSET.B D0,$1000
BTST Le bit est testé mais pas modifié.
La destination est un registre. Le numéro du bit est modulo 32.
La source est une constante
BTST.L #31,D0
BTST Le bit est testé mais pas modifié.
La destination est une adresse. Le numéro du bit est modulo 8.
La source est un registre
BTST.B D0,$1000

III-C-6. Tests, comparaisons, branchements

Instruction Explication Exemple
CMP Soustrait la source à la destination. Le résultat n'est pas rangé dans la destination. Le mot d'état seul est affecté CMP.L D0,D1
CMPA Comme CMP pour les registres d'adresse CMPA.L,D0,A0
CMPI Comparaison avec une constante CMPI.L #$FF,D0
TST Compare l'opérande à 0 TST.W,D0
Bcc Voir ci-dessous BEQ BOUCLE
Scc Voir ci-dessous SEQ.B D0
BRA L'exécution continue au label BRA BOU
BSR PC est poussé dans la pile. L'exemption continue au label BSR MONPROC
RTS Pousse le sommet de la pile dans PC RTS
JSR Comme BSR mais l'adresse est codée en dur JSR (A0)
JMP Comme BRA mais l'adresse est codée en dur JMP (A0)

JSR et JMP sont à éviter si l'on veut faire des modules translatables. Préférer BSR et BRA.

Bcc est une série d'instruction qui, si la condition est vérifiée poursuivent l'exécution à un label précis.
cc peut avoir les valeurs suivantes :

Valeur de cc Explication
CC ou HS Retenue à zéro
CS ou LO Retenue à 1
EQ Egal
GE Supérieur ou égal signé
GT Supérieur signé
HI Supérieur
LE Inférieur ou égal signé
LS Inférieur ou égal
LT Inférieur signé
MI Négatif signé
NE Différent
PL Positif signé
VC Pas de débordement signé
VS Débordement signé


Comme Bcc, Scc est une série d'instructions. Si la condition est vraie, l'octet de la destination est forcé à FF sinon, il est mis à zéro.
cc peut avoir les valeurs suivantes :

Valeur de cc Explication
CC Retenue à zéro
CS Retenue à 1
EQ Egal
GE Supérieur ou égal signé
GT Supérieur signé
HI Supérieur
LE Inférieur ou égal signé
LS Inférieur ou égal
LT Inférieur signé
MI Négatif signé
NE Différent
PL Positif signé
VC Pas de débordement signé
VS Débordement signé
F Jamais vrai
T Toujours vrai

III-C-7. Instructions de contrôle et divers

Série des instructions génériques :

Instruction Explication Exemple
LEA Calcule l'adresse effective et la range dans la destination. LEA.L (12,A0),A1
PEA Comme LEA mais pousse le résultat dans la pile PEA.L (12,A0)
LINK Voir gestion des variables  
ULNK Voir gestion des variables  
NOP Ne rien faire NOP
TRAP Voir gestion des exceptions  
MOVE from CCR Copie le CCR dans la destination MOVE.WCCR,D0
MOVE to CCR Copie la source dans le CCR MOVE.W D0,CCR


Série des instructions privilégiées :

Instruction Explication Exemple
MOVE from SR Copie le registre d'état MOVE.W SR,D0
MOVE to SR Copie la source dans le registre d'état MOVE.W D0,SR
MOVEC Transfère le contenu d'un registre dans un registre de contrôle. MOVEC.L D0,VBR
RTE Restaure depuis la pile SR puis PC. RTE
STOP Lance une exception de type RESET STOP #$AF8E

III-D. Exemples

Pour se familiariser avec le jeu d'instruction des MCF, il serait bon de regarder ces quelques exemples/exercices classiques :

III-D-1. Le codage BCD

Ce module, donne en code BCD l'équivalent d'un mot de 16 bits Le nombre de départ est dans les 16 bits de poids faible de D0 Le résultat est dans D1.
Exemple : D0 0000FFFF
donne D1 : 00065535
Cela permet de traduire directement le nombre vers un afficheur sans passer par l'ASCII
Algorithme :
Un mot de 16 bit représente une valeur non signé comprise entre 0 et 65535. On a donc cinq chiffres entre 0 et 9 a trouver pour exprimer la valeur en BCD

 
Sélectionnez
     Entier N //valeur initiale sur 16 bits                              
	Entier r <br/>                                                            
	    <br/>                                                                
	On divise N par 10000 -> premier chiffre du résultat <br/>                
	r <- reste de la division         <br/>                                   
	On divise r par 1000 -> second chiffre du résultat   <br/>                 
	r <- reste de la division      <br/>                                       
	On recommence avec 100 puis 10 -> troisième et quatrième chiffres <br/>   
	Le reste donne le cinquième chiffre     <br/>                             
                       <br/>

La question de la réentrance et de la sauvegarde du contexte sont volontairement ignorées.

 
Sélectionnez
	org $10000
debut:		nop 			;ne rien faire
		andi.L #$FFFF,D0	;on efface les 16 bits de poids fort de D0
		move.L D0,D2		;copions D0 dans D2
		clr.L D1		;effaçons D1
		move.L #10000,D3	;plaçons 10000 dans D3. La division ne supporte pas l'adressage immédiat
		divu.w D3,D2		;divisons de D2 (sur 32 bits) par D3 (sur 16 bit).
					;Le résultat sera dans les 16 bits de poids faible de D2
					;Le reste dans les 16 bits de poids fort de D2
		move.w D2,D1		;on place le resultat dans D1
		lsl.L #4,D1		;on décale D1 de 4 bits vers la gauche
		swap.w D2		;on permute les 16 bits de pods faible et les 16 bits de poids fort de D2
 
fin_1:		nop

Nous avons maintenant, notre première valeur dans la partie supérieure de l'octet de poids faible de D1

D1.B  
15 8 7 6 5 4 3 2 1 0
  . x x x x . . . .

Passons à la seconde valeur

 
Sélectionnez
debut_2:	nop
		andi.L #FFFF,D2
		move.L #1000,D3		;Une division par 10 de D3 serait bien plus couteuse
		divu.w D3,D2
		move.b D2,D3		;ce qui nous interesse est dans l'octet de poids faible de D2
		andi.L #F,D3		;plus précisement dans les 4 premier bits
		or.L D3,D1
		lsl.l #4,D1
		swap.w D2
 
fin_2:		nop

Maintenant que nous avons compris le mécanisme Terminons ou plutôt terminez ....... ;-)

faire des variantes sur 32 bits, en signé ...

III-D-2. Addition de deux mots de 64 bits

Ce module additionne deux mots de 64 bits.
Pour l'instant, nous ne gérons pas les variables. Les opérandes se situerons donc à une adresse mémoire précise. Le résultat sera également placé en mémoire.
Nous réserverons donc un espace de 7x32 bits d'origine mem répartie comme il suit :

label exemple opérande
mem 1000 Opérande 1 poids fort
  ...
  1007 Opérande 1 poids faible
  1008 Opérande 2 poids fort
  ...  
  100F Opérande 2 poids faible
memOp 1010  
  ...  
  1013 Retenue dans le bit de poids faible
  1014 Résultat poids fort
  ...  
  1017  
  1018  
  ...  
  101B Résultat poids faible
  memRes 101C


On réserve 32 bits pour stocker la retenue. Pour une question de performance et à moins d'être vraiment contraint par l'espace, c'est la meilleure solution.

 
Sélectionnez
*Directives d'assemblages et définition de constantes *
 
mem_op equ  $20010	;définition de deux constantes
mem_res equ  $2001C
 
		org $10000	; adresse à laquelle le programme sera chargé
		cpu 5206e	; cela permet de gérer les versions des MCF
		opt optimise=all; On demande au compilateur d'être intelligeant.
 
*dans cet entête, dans ce cas précis seul org est obligatoire. Le reste est donné à titre d'exemple*
debut:	nop
 
	movea.L #mem_op,A0	;mise en place des pointeurs
	movea.L #mem_res,A1
 
	addi.L #0,D0		;mise à zéro du bit x
 
	move.L -(A0),D0		;récupération des poids faibles de l'operande 2
	move.L (-8,A0),D1	;récuperation des poids faibles de l'operande 1
	addx.L D0,D1		;L'utilisation d'addx plustôt que d'add ne se justifiera que plus tard. 
				;En M68K on aurait pu aller chercher la source directement en mémoire 
	move.L D1,-(A1)		;On range les poids faibles du résultat
 
 
 
	move.L -(A0),D0		;Cette sequence est exactement identique à la précedente (d'où l'addx).
	move.L (-8,A0),D1	;Ne pourrait-on pas boucler ? Essayez (attention à la retenue)! est-ce interessant ? 
	addx.L D0,D1		
	move.L D1,-(A1)		
 
 
 
	clr.L D0		;On efface D0
	addx.L D0,D0		;On récupère la retenue
	move.L D0,-(A1)		;On la range
 
fin:	nop

III-D-3. Parcours itératif d'un tableau d'octet

L'objet de ce module, sera de comprendre certains travers liés à l'absence de maîtrise du jeu d'instruction. Le but du jeu sera donc de comprendre en quoi ce code est nul et de l'améliorer.

Le tableau sera désigné par une adresse de départ dans A0 et un offset dans D0. La valeur recherchée sera dans D1.b Le résultat sera un pointeur placé dans A1.

 
Sélectionnez
	org $10000
 
debut :		nop
 
		move.L D0,D2		; sauvegardons l'offset de réference
 
bou:		cmp.B (A0,D2),D1	;La valeur pointé par A0 + offest est-elle la valeur cherchée ?
		beq trouve		;Si oui on va à trouve
		subi.L #1,D2		;Sinon on décrémente l'offset
		bne no_value		;Si l'offset est négatif on a pas trouvé
		bra bou			;Sinon on recommence
 
no_value:	clr.L A1		;Si on n'a rien trouvé, on renvera un pointeur = 0
		bra fin			;et on termine
 
trouve:		movea.L A0,A1		;Si on a trouvé, on calcule l'adresse du pointeur
		adda.L D2,A1
 
fin: 		nop

Il faudrait regarder un peu du coté de l'instruction Scc, de LEA... Puis on doit pouvoir ne pas utiliser de BRA.


précédentsommairesuivant

Copyright © 2005 Joris Dedieu. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.