Vous êtes sur la page 1sur 22

‫الجمهورية الجزائرية الديمقراطية الشعبية‬

République Algérienne Démocratique et Populaire


‫وزارة التعليم العالي والبحث العلمي‬
Ministère de l'Enseignement Supérieur et de la Recherche
Scientifique

Université des Sciences et de la Technologie Houari


Boumediene USTHB

Faculté de Génie Electrique

Département Electronique
Master Electronique des Systèmes Embarqués ESE

Programmation en Assembleur
pour le DSP TMS320C6713
Présenté par : K. BOUDJIT

B.P. 32 El-Alia, Bab-Ezzouar, Alger 16111 Tél : 213 (0) 21 24 79 12 Poste 805
Fax : 213 (0) 21 24 71 87http://www.usthb.dz/
I. INTRODUCTION .............................................................................................................. 1
II. APERCU DE L’ARCHITECTURE C6000........................................................................ 1
II.1. Fonctionnement de base du DSP .................................................................................... 1
II.2. Instructions ...................................................................................................................... 1
II.3. Fichiers de registre .......................................................................................................... 2
II.4. Unités fonctionnelles ...................................................................................................... 3
Exercice N°1 : ......................................................................................................................... 3
III. OPERATIONS D’ASSEMBLEUR TYPIQUES ............................................................ 3
III.1. Chargement des constantes dans les registres ............................................................... 3
Exercice N°2 : ......................................................................................................................... 3
III.2. Enregistrement des mouvements (moves), mise à zéro ................................................. 3
III.3. Chargement de la mémoire dans les registres................................................................ 4
Exercice N°3 : ......................................................................................................................... 4
III.4. Stockage des données en mémoire ................................................................................ 5
Exercice N°4 : ......................................................................................................................... 5
III.5. Créneaux de retard (Delay slots) ................................................................................... 6
Exemple 1 ............................................................................................................................... 6
III.6. Addition, soustraction et multiplication ........................................................................ 8
Exercice N°5 : ......................................................................................................................... 8
III.7. Branchements et opérations conditionnelles ................................................................. 8
Exercice N°6 : ......................................................................................................................... 9
III.8. Opérations logiques et manipulation de bits.................................................................. 9
III.9. Autres instructions de l’assembleur ............................................................................... 9
III.10. Résumé du jeu d'instructions C67x ............................................................................. 9
IV. DIRECTIVES UTILES POUR LES LANGAGES ASSEMBLEURS ......................... 11
IV.1. Affectation des unités fonctionnelles .......................................................................... 12
Exercice N°7 : ....................................................................................................................... 13
Exercice N°8 : ....................................................................................................................... 14
IV.2. Rédaction du programme interne du produit ............................................................... 14
IV.3. Pipeline, créneaux de retard (Delay slots) et instructions parallèles ........................... 15
IV.4. Instructions et contraintes parallèles ........................................................................... 16
IV.4.1. Contraintes en matière de ressources .................................................................... 16
IV.4.2. Contraintes des unités fonctionnelles ................................................................... 16
IV.4.3. Contraintes croisées .............................................................................................. 16
IV.4.4. Contraintes liées aux chargements et aux stockages ............................................ 17
IV.4.5. Contraintes sur la lecture du registre .................................................................... 17
IV.4.6. Contraintes relatives aux inscriptions au registre ................................................. 17
V. PIPELINE DE LOGICIELS AD HOC ............................................................................. 18
Programmation en Assembleur pour le DSP TMS320C6713
DSP

I. INTRODUCTION
Ce chapitre contient des détails sur la façon de programmer la famille de processeurs TI C6000
en assembleur. La famille de processeurs C6000 comporte de nombreuses variantes. Il ne serait
donc pas possible de décrire ici comment programmer tous les processeurs. Cependant,
l'architecture de base et les instructions sont similaires d'un processeur à l'autre. Elles varient
selon le nombre de registres, la taille des registres, les périphériques de l'appareil, etc. Ce
chapitre part du principe que l'appareil dispose de 32 registres 32 bits polyvalents et de huit
unités fonctionnelles, comme le processeur C6713.

II. APERCU DE L’ARCHITECTURE C6000


Le C6000 se compose d'une mémoire interne, de périphériques (port série, interface de mémoire
externe, etc.) et, surtout, de l'unité centrale qui possède les registres et les unités fonctionnelles
pour l'exécution des instructions. Bien qu'il ne soit pas nécessaire de se préoccuper de
l'architecture interne de l'unité centrale pour compiler et exécuter des programmes, il est
nécessaire de comprendre comment l'unité centrale récupère et exécute les instructions
d'assembleur pour écrire un programme en assembleur optimisé.
II.1. Fonctionnement de base du DSP
Dans de nombreux algorithmes DSP, les opérations Somme des produits ou Multiplier-
Accumuler (MAC) sont très courantes. Une unité centrale DSP est conçue pour traiter les
calculs mathématiques intensifs nécessaires aux algorithmes DSP courants. Pour l'ancienne
implémentation de l'opération MAC, le processeur C6000 dispose de deux multiplicateurs et
chacun d'eux peut effectuer une multiplication de 16 bits à chaque cycle d'horloge. Par exemple,
si nous voulons calculer le produit scalaire de deux vecteurs de longueur 40 a[n] et x[n], nous
devons effectuer des calculs :

𝑦= 𝑎[𝑛]𝑥[𝑛]

(Par exemple, l'algorithme du filtre FIR est exactement le même que celui de cette opération de
point produit). Lorsque a[n] et x[n] sont stockés en mémoire, à partir de n=1, nous devons
calculer a[n]x[n] et l'ajouter à y (y est initialement 0) et répéter cela jusqu'à n=40. Dans le
langage assembleur pour le C6000, cette opération MAC peut être écrite sous la forme :
MPY .M a,x,prod
ADD .L y,prod,y
Ignorez .M et .L pour l'instant. Ici, a, x, prod et y sont des nombres stockés en mémoire et
l'instruction MPY multiplie deux nombres a et x ensemble et stocke le résultat dans prod.
L'instruction ADD ajoute deux nombres y et prod ensemble et stocke le résultat dans la mémoire
de y.
II.2. Instructions
Vous trouverez ci-dessous la structure d'une ligne de code assembleur.
Tableau 1 :
Label : Parallel Bars (||) [Condition] Instruction Unit Operands ;Comments

1 Master Electronique des Systèmes Embarqués ESE – USTHB/FGE


Programmation en Assembleur pour le DSP TMS320C6713
DSP
Les étiquettes (labels) identifient une ligne de code ou une variable et représentent une adresse
mémoire qui contient soit une instruction, soit des données. Le premier caractère d'une étiquette
(label) doit se trouver dans la première colonne et doit être une lettre ou un trait de soulignement
(_) suivi d'une lettre. Les étiquettes (labels) peuvent comporter jusqu'à 32 caractères
alphanumériques.
Une instruction qui s'exécute en parallèle avec l'instruction précédente est signalée par des
barres parallèles (||). Cette dernière est laissé vide pour une instruction qui ne s'exécute pas en
parallèle avec l'instruction précédente.
Chaque instruction de la série C6xxx peut s'exécuter sous condition. Cinq registres sont
disponibles pour les conditions (sur les processeurs C67x) : A1, A2, B0, B1 et B2. Si le registre
est vide, l'instruction s'exécute toujours. Les conditions peuvent prendre une forme telle que
[A1], où l'instruction s'exécute si A1 n'est pas nul. Cela peut être pratique pour faire des boucles
si le compteur est placé dans un registre comme A1 et est compté jusqu'à zéro. La condition est
placée sur l'instruction de branchement qui revient au début de la boucle.
II.3. Fichiers de registre
Où sont stockés les numéros dans l'unité centrale ? Dans le C6000, les numéros utilisés dans
les opérations sont stockés dans le registre. Comme les registres sont directement accessibles
par le chemin de données de l'unité centrale, l'accès aux registres est beaucoup plus rapide que
l'accès aux données de la mémoire externe.
L'unité centrale du C6000 possède deux registres (A et B). Chacun de ces registres est constitué
de seize registres de 32 bits (A0-A15 pour le A et B0-B15 pour le B). Les registres à usage
général peuvent être utilisés pour les données, les pointeurs d'adresses de données ou les
registres de conditions.
Le registre à usage général supporte des données allant de 16 bits à 40 bits en virgule fixe. Les
valeurs supérieures à 32 bits, telles que les quantités longues de 40 bits, sont stockées dans des
paires de registres. Dans une paire de registres, les 32 LSB de données sont placées dans un
registre pair et les 8 MSB restants dans le registre supérieur suivant (qui est toujours un registre
impair). Dans la syntaxe du langage d'assembleur, un deux-points entre deux noms de registre
indique les paires de registres, et le registre impair est spécifié en premier. Par exemple, A1:A0
représente la paire de registres composée de A0 et A1.
Pour l'instant, concentrons-nous uniquement sur le A. Les registres du fichier de registre A sont
nommés de A0 à A15. Chaque registre peut stocker un nombre binaire de 32 bits. Ensuite, les
nombres tels que a, x, prod et y ci-dessus sont stockés dans ces registres. Par exemple, le registre
A0 stocke a. Pour l'instant, supposons que nous interprétions tous les nombres de 32 bits stockés
dans les registres comme des entiers non signés. Par conséquent, la plage de valeurs que nous
pouvons représenter est de 0 à 2 − 1. Supposons que les nombres a, x, prod et y se trouvent
dans les registres A0, A1, A3, A4, respectivement. Les instructions en assembleur ci-dessus
peuvent alors être rédigées de manière spécifique :
MPY .M1 A0,A1,A3
ADD .L1 A4,A3,A4

2 Master Electronique des Systèmes Embarqués ESE – USTHB/FGE


Programmation en Assembleur pour le DSP TMS320C6713
DSP
Le processeur TI C6000 a une architecture load/store. Cela signifie que tous les numéros
doivent être stockés dans les registres avant d'être utilisés comme opérandes des opérations pour
des instructions telles que MPY et ADD. Les numéros peuvent être lus d'un emplacement
mémoire à un registre (en utilisant, par exemple, des instructions LDW, LDB) ou un registre
peut être chargé avec une valeur constante. Le contenu d'un registre peut être stocké dans un
emplacement mémoire (en utilisant, par exemple, les instructions STW, STB).
En plus du registre général, l'unité centrale dispose d'un registre séparé pour les registres de
contrôle. Les registres de contrôle sont utilisés pour contrôler diverses fonctions de l'unité
centrale telles que le mode d'adressage, les interruptions, etc.
II.4. Unités fonctionnelles
Où se déroulent les opérations proprement dites, telles que la multiplication et l'addition ?
L'unité centrale C6000 possède plusieurs unités fonctionnelles qui effectuent les opérations
proprement dites. Chaque registre à 4 unités fonctionnelles nommées M, L, S et D. Les 4 unités
fonctionnelles connectées au registre A sont nommées M1, L1, S1 et D1. Celles qui sont
connectées au registre B sont nommées M2, L2, S2 et D2. Par exemple, l'unité fonctionnelle
.M1 effectue une multiplication sur les opérandes qui se trouvent dans le registre A. Lorsque
l'unité centrale exécute le MPY .M1 A0, A1, A3 ci-dessus, l'unité fonctionnelle .M1 prend la
valeur stockée dans A0 et A1, les multiplie ensemble et stocke le résultat dans A3. La valeur
.M1 dans MPY .M1 A0, A1, A3 indique que cette opération est effectuée dans l'unité .M1.
L'unité .M1 a un multiplicateur de 16 bits et toutes les multiplications sont effectuées par l'unité
.M1 (ou .M2).
De même, l'opération ADD peut être exécutée par l'unité .L1. L'unité .L1 peut effectuer toutes
les opérations logiques telles que l'opération ET (instruction ET) au niveau du bit ainsi que
l'addition (instruction ADD) et la soustraction (instruction SUB) de base.
Exercice N°1 :
En Lisant la description des instructions ADD et MPY dans le document. Écrivez un
programme en assembleur qui calcule A0*(A1+A2)+A3.

III. OPERATIONS D’ASSEMBLEUR TYPIQUES


III.1. Chargement des constantes dans les registres
Très souvent, vous devez charger un registre avec une constante. Les instructions C6x que vous
pouvez utiliser pour cette tâche sont MVK, MVKL et MVKH. Chacune de ces instructions peut
charger une constante de 16 bits dans un registre. L'instruction MVKL charge les 16 bit
inférieurs et l'instruction MVKH charge les 16 bit supérieurs dans le registre. Pour charger des
valeurs de 32 bits dans un registre, les deux instructions sont nécessaires.
Exercice N°2 :
(Chargement des constantes) : Rédiger des instructions en assembleur pour faire ce qui suit :
1. Chargez la constante 16 bits 0xff12 sur A1.
2. Chargez la constante 32 bits 0xabcd45ef dans B0.
III.2. Enregistrement des mouvements (moves), mise à zéro
Le contenu d'un registre peut être copié dans un autre registre en utilisant l'instruction MV. Il
existe également l'instruction ZERO qui permet de mettre un registre à zéro.
3 Master Electronique des Systèmes Embarqués ESE – USTHB/FGE
Programmation en Assembleur pour le DSP TMS320C6713
DSP
III.3. Chargement de la mémoire dans les registres
Comme le processeur C6x possède une architecture dite "load/store", vous devez d'abord
charger le contenu de la mémoire dans un registre pour pouvoir le manipuler. Les instructions
assembleur de base que vous utilisez pour le chargement sont LDB, LDH et LDW pour le
chargement de données de 8, 16 et 32 bits à partir de la mémoire. (Il existe quelques variantes
de ces instructions pour la manipulation différente des signes des valeurs chargées).
Cependant, pour spécifier l'adresse de l'emplacement de mémoire à partir duquel vous devez
charger, vous devez charger un autre registre (utilisé comme index d'adresse) et vous pouvez
utiliser différents modes d'adressage pour spécifier les emplacements de mémoire de plusieurs
manières différentes. Le mode d'adressage est la méthode par laquelle une instruction calcule
l'emplacement d'un objet en mémoire. Le tableau ci-dessous énumère toutes les manières
différentes possibles de traiter les pointeurs d'adresse dans le processeur C6x. Notez la
similarité avec la manipulation des pointeurs C.
Tableau 2 : Modes d'adressage C6x.
Syntax Memory address accessed Pointer modification
*R R None
*++R R Preincrement
*-R R Predecrement
*R++ R Postincrement
*R- R Postdecrement
*+R[disp] R+disp None
*-R[disp] R+disp None
*++R[disp] R+disp Preincrement
*-R[disp] R+disp Predecrement
*R++[disp] R+disp Postincrement
*R-[disp] R+disp Postdecrement

Le [disp] spécifie le nombre d'éléments en mot, demi-mot ou octet, selon le type d'instruction
et il peut être soit une constante de 5 bits, soit un registre. L'incrémentation/décrémentation des
registres d'index se fait également en fonction du nombre d'octets dans le mot, le demi-mot ou
l'octet. Les modes d'adressage avec déplacements sont utiles lorsqu'on accède à un bloc
d'emplacements mémoire. Ceux avec incrémentation/décrémentation automatique sont utiles
lorsqu'un bloc est accédé consécutivement pour implémenter un tampon, par exemple, pour
stocker des échantillons de signaux pour implémenter un filtre numérique.
Exercice N°3 :
(Chargement de mémoire) : Supposons que les valeurs suivantes sont stockées dans des
adresses mémoire :
Loc 32-bit value
100h fe54 7834h
104h 3459 f34dh
108h 2ef5 7ee4h

4 Master Electronique des Systèmes Embarqués ESE – USTHB/FGE


Programmation en Assembleur pour le DSP TMS320C6713
DSP
10ch 2345 6789h
110h ffff eeddh
114h 3456 787eh
118h 3f4d 7ab3h
Supposons que A10 = 0000 0108h. Trouvez le contenu de A1 et A10 après avoir exécuté
chacune des instructions suivantes.
1. LDW .D1 *A10, A1
2. LDH .D1 *A10, A1
3. LDB .D1 *A10, A1
4. LDW .D1 *-A10[1], A1
5. LDW .D1 *+A10[1], A1
6. LDW .D1 *+A10[2], A1
7. LDB .D1 *+A10[2], A1
8. LDW .D1 *++A10[1], A1
9. LDW .D1 *-A10[1], A1
10. LDB .D1 *++A10[1], A1
11. LDB .D1 *-A10[1], A1
12. LDW .D1 *A10++[1], A1
13. LDW .D1 *A10-[1], A1
III.4. Stockage des données en mémoire
Le stockage du contenu du registre utilise les mêmes modes d'adressage. Les instructions en
assembleurs utilisées pour le stockage sont STB, STH et STW.
Exercice N°4 :
(Stockage à la mémoire) : Écrire les instructions en assembleur pour stocker la constante 32
bits 53fe 23e4h à l'adresse mémoire 0000 0123h.
Parfois, il devient nécessaire d'accéder à une partie des données stockées en mémoire. Par
exemple, si vous stockez le mot de 32 bits 0x11223344 à l'emplacement mémoire 0x8000, les
quatre octets ayant les adresses emplacement 0x8000, emplacement 0x8001, emplacement
0x8002 et emplacement 0x8003 contiennent la valeur 0x11223344. Ensuite, si je lis les données
de l'octet à l'emplacement de mémoire 0x8000, quelle serait la valeur de l'octet à lire ?
La réponse dépend du mode endian du système de mémoire. Dans le mode "little endian", les
adresses mémoire inférieures contiennent la partie LSB des données. Ainsi, les octets stockés
dans les adresses de quatre octets seront comme indiqué dans le tableau 1.3.

5 Master Electronique des Systèmes Embarqués ESE – USTHB/FGE


Programmation en Assembleur pour le DSP TMS320C6713
DSP
Tableau 3 : Mode de stockage "Little endian".
0x8000 0x44
0x8001 0x33
0x8002 0x22
0x8003 0x11

Dans le mode big endian, les adresses mémoire inférieures contiennent la partie MSB des
données. Ainsi, nous avons
Tableau 4 : Mode de stockage du big endian.
0x8000 0x11
0x8001 0x22
0x8002 0x33
0x8003 0x44
III.5. Créneaux de retard (Delay slots)
Dans l'unité centrale C6x, il faut exactement un cycle d'horloge de l'unité centrale pour exécuter
chaque instruction. Cependant, les instructions telles que LDW doivent accéder à la mémoire
externe lente et les résultats du chargement ne sont pas disponibles immédiatement à la fin de
l'exécution. Ce retard des résultats de l'exécution est appelé créneau (slots) de retard.
Exemple 1
Par exemple, considérons le chargement du contenu de la mémoire à l'adresse pointée par A10
vers A1 et ensuite le déplacement des données chargées vers A2. Vous pourriez être tenté
d'écrire un simple code en assembleur de 2 lignes comme suit :
1 LDW .D1 *A10, A1
2 MV .D1 A1,A2
Qu'est-ce qui ne va pas avec le code ci-dessus ? Le résultat de l'instruction LDW n'est pas
disponible immédiatement après l'exécution de LDW. En conséquence, l'instruction MV ne
copie pas la valeur souhaitée de A1 à A2. Pour éviter cette exécution indésirable, nous devons
faire en sorte que l'unité centrale attende que le résultat de l'instruction LDW soit correctement
chargé dans A1 avant d'exécuter l'instruction MV. Pour les instructions de chargement, nous
avons besoin de 4 cycles d'horloge supplémentaires jusqu'à ce que le résultat du chargement
soit valide. Pour faire attendre l'unité centrale pendant 4 cycles d'horloge, nous devons insérer
4 instructions NOP (no operations) entre LDW et MV. Chaque instruction NOP rend l'unité
centrale inactive pendant un cycle d'horloge. Le code résultant sera comme suit :
1 LDW .D1 *A10, A1
2 NOP
3 NOP
4 NOP
5 NOP
6 MV .D1 A1,A2
6 Master Electronique des Systèmes Embarqués ESE – USTHB/FGE
Programmation en Assembleur pour le DSP TMS320C6713
DSP
ou simplement vous pouvez écrire
1 LDW .D1 *A10, A1
2 NOP 4
3 MV .D1 A1,A2
Alors, pourquoi le concepteur de l'unité centrale n'a-t-il pas fait en sorte que l'instruction LDW
prenne 5 cycles d'horloge au départ, plutôt que de laisser le programmeur insérer 4 NOP ? La
réponse est que vous pouvez insérer d'autres instructions que les NOP dans la mesure où ces
instructions n'utilisent pas le résultat de l'instruction LDW ci-dessus. De cette manière, l'unité
centrale peut exécuter des instructions supplémentaires en attendant que le résultat de
l'instruction LDW soit valide, ce qui réduit considérablement le temps d'exécution total de
l'ensemble du programme.
Tableau 5: Delay slots
Description Instructions Delay slots
Single Cycle All instructions except following 0
Multiply MPY, SMPY etc. 1
Load LDB, LDH, LDW 4
Branch B 5
La latence de l'unité fonctionnelle indique combien de cycles d'horloge chaque instruction
utilise réellement une unité fonctionnelle. Toutes les instructions C6x ont une latence d'unité
fonctionnelle, ce qui signifie que chaque unité fonctionnelle est prête à exécuter l'instruction
suivante après un cycle d'horloge, indépendamment des délais des instructions. Par conséquent,
les instructions suivantes sont valables :
1 LDW .D1 *A10, A4
2 ADD .D1 A1,A2,A3
Bien que la première instruction LDW ne charge pas correctement le registre A4 pendant
l'exécution de l'ADD, l'unité fonctionnelle D1 devient disponible dans le cycle d'horloge juste
après celui dans lequel l’instruction LDW est exécutée.
Pour clarifier l'exécution des instructions avec créneaux de retard, pensons à l'exemple suivant
de l'instruction LDW. Supposons que A10 = 0x0100 et A2=1, et que votre intention est de
charger A9 avec le mot de 32 bits à l'adresse 0x0104. Les instructions 3 MV ne sont pas liées à
l'instruction LDW. Elles font autre chose.
1 LDW .D1 *A10++[A2], A9
2 MV .L1 A10, A8
3 MV .L1 A1, A10
4 MV .L1 A1, A2
5 ...
Nous pouvons poser plusieurs questions intéressantes à ce stade :

7 Master Electronique des Systèmes Embarqués ESE – USTHB/FGE


Programmation en Assembleur pour le DSP TMS320C6713
DSP
1. Quelle est la valeur chargée sur le A8 ? C'est-à-dire, dans quel cycle d'horloge, le pointeur
d'adresse est mis à jour ?
2. Peut-on charger le registre de décalage d'adresse A2 avant que l'instruction LDW n'achève
le chargement effectif ?
3. Est-il légal de charger le registre A10 avant que la première instruction LDW n'ait fini de
charger le contenu de la mémoire en A9 ? Autrement dit, pouvons-nous changer le pointeur
d'adresse avant que les 4 créneaux de retard (delay slots) ne s'écoulent ?
Voici les réponses :
1. Bien qu'il faille 4 cycles d'horloge supplémentaires pour que l'instruction LDW charge le
contenu de la mémoire sur A9, le pointeur d'adresse et les registres d'offset (A10 et A2) sont
lus et mis à jour dans le cycle d'horloge où l'instruction LDW est émise. Par conséquent, à la
ligne 2, A8 est chargé avec le A10 mis à jour, c'est-à-dire A10 = A8 =0x104.
2. Comme le LDW lit les registres A10 et A2 au cours du premier cycle d'horloge, vous êtes
libre de modifier ces registres et de ne pas affecter le fonctionnement du premier LDW.
3. Nous avons déjà répondu à cette question ci-dessus.
La même théorie s'applique aux instructions MPY et B (lorsque l'on utilise un registre comme
adresse de succursale). Le MPY lit les valeurs sources dans le premier cycle d'horloge et charge
le résultat de la multiplication après le deuxième cycle d'horloge. Pour B, le pointeur d'adresse
est lu au cours du premier cycle d'horloge, et le branchement réel se produit après le 5e cycle
d'horloge. Ainsi, après le premier cycle d'horloge, vous êtes libre de modifier les registres de la
source ou du pointeur d'adresse. Pour plus de détails, reportez-vous au tableau 5 dans la
description du jeu d'instructions ou lisez la description de l'instruction individuelle.
III.6. Addition, soustraction et multiplication
Il existe plusieurs instructions pour l'addition, la soustraction et la multiplication sur le
processeur C6x. Les instructions de base sont ADD, SUB et MPY. ADD et SUB ont 0 délai (ce
qui signifie que les résultats de l'opération sont immédiatement disponibles), mais le MPY a 1
délai (le résultat de la multiplication est valable après un cycle d'horloge supplémentaire).
Exercice N°5 :
(Additionner, soustraire et multiplier) : Ecrire un programme en assembleur pour calculer (
0000 ef35h + 0000 33dch - 0000 1234h ) * 0000 0007h
III.7. Branchements et opérations conditionnelles
Souvent, vous devez contrôler l'exécution du programme en passant à un autre bloc de code.
L'instruction B fait le travail dans l'unité centrale C6x. L'adresse de la branche peut être
spécifiée par déplacement ou stockée dans un registre qui sera utilisé par l'instruction B.
L'instruction B a 5 intervalles de retard, ce qui signifie que la branche réelle se produit dans le
5e cycle d'horloge après l'exécution de l'instruction.
Dans de nombreux cas, en fonction du résultat des opérations précédentes, vous exécutez
l'instruction de branchement sous condition. Par exemple, pour mettre en œuvre une boucle,
vous décrémentez le compteur de boucle de 1 chaque fois que vous exécutez un ensemble
d'instructions et, chaque fois que le compteur de boucle n'est pas nul, vous devez passer au

8 Master Electronique des Systèmes Embarqués ESE – USTHB/FGE


Programmation en Assembleur pour le DSP TMS320C6713
DSP
début du bloc de code pour itérer les opérations de la boucle. Dans l'unité centrale C6x, ce
branchement conditionnel est mis en œuvre à l'aide des opérations conditionnelles. Bien que B
puisse être l'instruction mise en œuvre le plus souvent à l'aide d'opérations conditionnelles,
toutes les instructions en C6x peuvent être conditionnelles.
Les instructions conditionnelles sont représentées dans le code par des crochets, [ ], entourant
le nom du registre de condition. Par exemple, l'instruction B suivante n'est exécutée que si B0
est non nul :
1 [B0] B .L1 A0
Pour exécuter une instruction de manière conditionnelle lorsque le registre des conditions est à
zéro, nous utilisons ! devant le registre. Par exemple, l'instruction B est exécutée lorsque B0 est
égal à zéro.
1 [!B0] B .L1 A0
Tous les registres ne peuvent pas être utilisés comme registres d'état. Dans les appareils C62x
et C67x, les registres qui peuvent être testés dans des opérations conditionnelles sont B0, B1,
B2, A1, A2.
Exercice N°6 :
(Boucle simple) : Ecrire un programme en assembleur calculant la somme ∑ 𝑛 en mettant
en œuvre une simple boucle.
III.8. Opérations logiques et manipulation de bits
Les opérations logiques et les manipulations de bits sont accomplies par les instructions AND,
OR, XOR, CLR, SET, SHL et SHR.
III.9. Autres instructions de l’assembleur
D'autres instructions utiles comprennent des instructions IDLE et de comparaisons telles que
CMPEQ etc.
III.10. Résumé du jeu d'instructions C67x
L'ensemble des instructions qui peuvent être exécutées dans chaque unité fonctionnelle est le
suivant (voir le tableau 6 : Unité S, le tableau 7 : Unité L, le tableau 8 : Unité D et le tableau 9
: Unité M). Veuillez-vous référer au guide de référence des unités centrales et des jeux
d'instructions TMS320C62x/C67x pour une description détaillée de chaque instruction.
Tableau 6 .S Unit
Instruction Description
ADD(U) addition d'entiers signés ou non signés sans saturation
ADDK addition d'entiers en utilisant une constante signée de 16 bits
ADD2 deux entiers de 16 bits s'ajoutent aux moitiés supérieure et inférieure du
registre
B Branchement utilisant un registre
CLR Nettoyer un champ de bit
EXT extraire et signer-étendre un champ de bits
MV passer de registre en registre
MVC se déplacer entre le contrôle et le registre

9 Master Electronique des Systèmes Embarqués ESE – USTHB/FGE


Programmation en Assembleur pour le DSP TMS320C6713
DSP
MVK déplacer une constante de 16 bits dans un registre et signer extend
MVKH déplacer une constante de 16 bits dans les bits supérieurs d'un registre
NEG négation (pseudo-opération)
NOT bitwise NOT
OR bitwise OU
SET mettre un champ de bits
SHL décalage arithmétique à gauche
SHR décalage arithmétique à droite
SSHL décalage à gauche avec saturation
SUB(U) soustraction d'un nombre entier signé ou non signé sans saturation
SUB2 deux sous-ensembles entiers de 16 bits sur les moitiés supérieure et
inférieure du registre
XOR exclusive OR
ZERO zéro un registre (pseudo-opération)

Tableau 7 .L Unit
Instruction Description
ABS valeur absolue entière avec saturation
ADD(U) addition d'entiers signés ou non signés sans saturation
AND bitwise AND
CMPEQ comparaison d'entiers pour l'égalité
CMPGT(U) comparaison d'entiers signés ou non signés pour plus de
CMPLT(U) comparaison d'entiers signés ou non signés pour moins de
LMBD détection du bit le plus à gauche
MV passer de registre en registre
NEG négation (pseudo-opération)
NORM normaliser un entier
NOT bitwise NOT
+OR bitwise OR
SADD addition d'entiers avec saturation à la taille du résultat
SAT saturer un nombre entier de 40 bits en un nombre entier de 32 bits
SSUB soustraction d'entiers avec saturation à la taille du résultat
SUBC soustraction et décalage d'un nombre entier conditionnel - utilisé pour la
division
XOR exclusive OR
ZERO zéro un registre (pseudo-opération)

Tableau 8 .D Unit
Instruction Description
ADD(U) addition d'entiers signés ou non signés sans saturation
ADDAB (B/H/W) addition d'entiers en utilisant le mode d'adressage
LDB (B/H/W) charge de la mémoire avec un décalage constant de 15 bits
MV passer de registre en registre
STB (B/H/W) stocker en mémoire avec un décalage de registre ou un décalage
constant non signé de 5 bits

10 Master Electronique des Systèmes Embarqués ESE – USTHB/FGE


Programmation en Assembleur pour le DSP TMS320C6713
DSP
SUB(U) soustraction d'un nombre entier signé ou non signé sans saturation
SUBAB (B/H/W) soustraction d'entiers en utilisant le mode d'adressage
ZERO zéro un registre (pseudo-opération)
Tableau 9 .M Unit
Instruction Description
MPY (U/US/SU) nombre entier signé ou non signé multiplier 16lsb*16lsb
MPYH (U/US/SU) nombre entier signé ou non signé multiplier 16msb*16msb
MPYLH nombre entier signé ou non signé multiplier 16lsb*16msb
MPYHL nombre entier signé ou non signé multiplier 16msb*16lsb
SMPY (HL/LH/H) Multiplication entière avec décalage à gauche et saturation

IV. DIRECTIVES UTILES POUR LES LANGAGES ASSEMBLEURS


Outre le jeu d'instructions du CPU, il existe des commandes spéciales pour l'assembleur qui lui
ordonnent d'effectuer diverses tâches lors de l'assemblage du code. Il existe des directives utiles
en assembleur que vous pouvez utiliser pour faire connaître à l'assembleur divers paramètres,
tels que .set, .macro, .endm, .ref, .align, .word, .byte .include.
La directive .set définit un nom symbolique. Par exemple, vous pouvez avoir :
1 count .set 40
L'assembleur remplace chaque occurrence de comptage par 40.
La directive .ref est utilisée pour déclarer des noms symboliques définis dans un autre fichier.
Elle est similaire à la déclaration externe en C.
La directive .space réserve un espace mémoire avec un nombre précis d'octets. Par exemple,
vous pouvez avoir :
1 buffer .space 128
Pour définir un tampon de taille 128 octets. Le tampon de symbole à l'adresse du premier octet
réservé par .space. La directive .bes est similaire à .space, mais le label à l'adresse du dernier
octet réservé.
Pour mettre une valeur constante dans la mémoire, vous pouvez utiliser .byte, .word, etc. Si
vous avez :
1 const1 .word 0x1234
L’assembleur place la constante de mot 0x1234 à un emplacement de la mémoire et const1 à
l'adresse de l'emplacement de la mémoire. .byte etc. Fonctionne de la même manière.
Parfois, vous devez placer vos données ou codes à des limites d'adresse mémoire spécifiques
telles que mot, demi-mot, etc. Vous pouvez utiliser la directive .align pour ce faire. Par exemple,
si vous avez :
1 .align 4
2 buffer .space 128
3 ...

11 Master Electronique des Systèmes Embarqués ESE – USTHB/FGE


Programmation en Assembleur pour le DSP TMS320C6713
DSP
La première adresse des 128 octets réservés est à la limite du mot en mémoire, c'est-à-dire que
les 2 LSB de l'adresse (en binaire) sont 0. De même, pour l'alignement des demi-mots, vous
devez disposer de la directive .align pour ce faire. Par exemple, si vous avez :
1 .align 2
2 buffer .space 128
3 ...
La directive .include est utilisée pour lire les lignes sources d'un autre fichier. L'instruction
1 .include ''other.asm''
saisira les lignes dans other.asm à cet endroit. Ceci est utile lorsque vous travaillez avec
plusieurs fichiers. Au lieu de faire un projet ayant plusieurs fichiers, vous pouvez simplement
inclure ces différents fichiers dans un seul fichier.
Comment rédiger les commentaires dans votre programme assembleur ? Tout ce qui suit ; est
considéré comme un commentaire et ignoré par l'assembleur. Par exemple,
1 ; this is a comment
2 ADD .L1 A1,A2,A3 ;add a1 and a2
IV.1. Affectation des unités fonctionnelles
Chaque instruction a des unités fonctionnelles particulières qui peuvent l'exécuter. Il est à noter
que certaines instructions peuvent être exécutées par plusieurs unités fonctionnelles différentes.
La figure suivante montre comment les données et les adresses peuvent être transférées entre
les registres, les unités fonctionnelles et la mémoire externe. Si vous observez attentivement, le
chemin de destination (marqué dst) sortant des unités .L1, .S1, .M1 et D1 est connecté au fichier
de registre A.
Note : Cela signifie que toute instruction ayant l'un des registres A comme destination (le
résultat de l'opération est stocké dans l'un des registres A) doit être exécutée dans l'une de ces
4 unités fonctionnelles.
Pour la même raison, si les instructions ont comme destination des registres B, les unités .L2,
.S2, .M2 et D2 doivent être utilisées.

12 Master Electronique des Systèmes Embarqués ESE – USTHB/FGE


Programmation en Assembleur pour le DSP TMS320C6713
DSP

Figure 1: TMS320C67x DSP Block Diagram


Par conséquent, si vous connaissez l'instruction et le registre de destination, vous devriez
pouvoir y affecter l'unité fonctionnelle.
Exercice N°7 :
(Unités fonctionnelles) : Énumérez toutes les unités fonctionnelles que vous pouvez attribuer à
chacune de ces instructions :
1. ADD .?? A0,A1,A2
2. B .?? A1
3. MVKL .?? 000023feh, B0
4. LDW .?? *A10, A3

13 Master Electronique des Systèmes Embarqués ESE – USTHB/FGE


Programmation en Assembleur pour le DSP TMS320C6713
DSP
Si vous regardez à nouveau la figure, chaque unité fonctionnelle doit recevoir une des données
sources du fichier de registre correspondant. Par exemple, regardez l'instruction assembleur
suivante :
1 ADD .L1 A0,B0,A1
L'unité L1 reçoit les données de A0 (c'est naturel) et B0 (ce n'est pas le cas) et stocke le résultat
dans A1 (c'est une obligation). Le chemin de données par lequel le contenu de B0 est transmis
à l'unité L1 est appelé chemin 1Xcross. Lorsque cela se produit, nous ajoutons x à l'unité
fonctionnelle pour désigner le chemin de croisement :
1 ADD .L1x A0,B0,A1
De même, le chemin des données du registre B vers les unités .M2, .S2 et .L2 est appelé chemin
croisé 2X.
Exercice N°8 :
(Traverser le chemin) : Énumérez toutes les unités fonctionnelles qui peuvent être affectées à
chacune des instructions :
1. ADD .??? B0,A1,B2
2. MPY .??? A1,B2,A4
En fait, lorsque vous écrivez un programme en assembleur, vous pouvez omettre complètement
l'affectation de l'unité fonctionnelle. L'assembleur détermine les unités fonctionnelles
disponibles et les attribue correctement. Cependant, les unités fonctionnelles attribuées
manuellement vous aident à déterminer où l'exécution a lieu et comment les données circulent
entre les registres et les unités fonctionnelles. Cela est particulièrement utile lorsque vous
mettez plusieurs instructions en parallèle. Nous en apprendrons davantage sur les instructions
parallèles plus tard.
IV.2. Rédaction du programme interne du produit
Maintenant, vous devriez en savoir assez sur l'assembleur C6x pour mettre en œuvre
l'algorithme de calcul du produit intérieur

𝑦= 𝑎 ∗ 𝑥

Exercice N°9 :
(Produit intérieur) : Écrivez le programme complet en assembleur du produit intérieur à calculer

𝑦= 𝑎 ∗ 𝑥

où 𝑎 et 𝑥 prennent les valeurs suivantes :


a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, a }
x[] = { f, e, d, c, b, a, 9, 8, 7, 6 }

14 Master Electronique des Systèmes Embarqués ESE – USTHB/FGE


Programmation en Assembleur pour le DSP TMS320C6713
DSP
Les valeurs 𝑎 et 𝑥 doivent être stockées en mémoire et le produit interne est calculé en lisant
le contenu de la mémoire.
IV.3. Pipeline, créneaux de retard (Delay slots) et instructions parallèles
Lorsqu'une instruction est exécutée, elle comporte plusieurs étapes, qui sont la recherche, le
décodage et l'exécution. Si ces étapes sont effectuées une à la fois pour chaque instruction, les
ressources de l'unité centrale ne sont pas pleinement utilisées. Pour augmenter le débit, les CPU
sont conçues pour être en pipeline, ce qui signifie que les étapes précédentes sont exécutées en
même temps.
Sur le processeur C6x, la recherche d'instructions se compose de 4 phases : générer l'adresse de
recherche (F1), envoyer l'adresse à la mémoire (F2), attendre les données (F3) et lire le code
opération de la mémoire (F4). Le décodage se compose de 2 phases ; envoi aux unités
fonctionnelles (D1) et décodage (D2). L'étape d'exécution peut comporter jusqu'à 6 phases (E1
à E6) selon les instructions. Par exemple, les instructions de multiplication (MPY) ont un retard
de 1, ce qui donne deux phases d'exécution. De même, les instructions de chargement (LDx) et
de branchement (B) ont respectivement 4 et 5 retards.
Lorsque le résultat d'une instruction est utilisé par l'instruction suivante, un nombre approprié
de NOP (pas d'opération ou de retard) doit être ajouté après les instructions de multiplication
(un NOP), de chargement (quatre NOP, ou NOP 4), et de branchement (cinq NOP, ou NOP 5)
afin de permettre au pipeline de fonctionner correctement. Sinon, avant que le résultat de
l'instruction en cours ne soit disponible (qui doit être utilisé par l'instruction suivante), les
instructions suivantes sont exécutées par le pipeline, ce qui génère des résultats indésirables. Le
code suivant est un exemple de code pipeline avec insertion de NOP :
1 MVK 40,A2
2 loop: LDH *A5++,A0
3 LDH *A6++,A1
4 NOP 4
5 MPY A0,A1,A3
6 NOP
7 ADD A3,A4,A4
8 SUB A2,1,A2
9 [A2] B loop
10 NOP 5
11 STH A4,*A7
Dans la ligne 4, nous avons besoin de 4 NOP car A1 est chargé par l'instruction LDH dans la
ligne 3 avec 4 retards. Après 4 retards, la valeur de A1 est disponible pour être utilisée dans le
MPY A0,A1,A3 de la ligne 5. De même, nous avons besoin de 5 délais après l'instruction de la
boucle [A2] B de la ligne 9 pour empêcher l'exécution de STH A4,*A7 avant qu'un
branchement n'ait lieu.

15 Master Electronique des Systèmes Embarqués ESE – USTHB/FGE


Programmation en Assembleur pour le DSP TMS320C6713
DSP
L'architecture C6x Very Large Instruction Word (VLIW), plusieurs instructions sont capturées
et traitées simultanément. C'est ce qu'on appelle un paquet de recherche (FP). Ce paquet permet
au C6x d'extraire simultanément huit instructions de la mémoire sur puce. Parmi les 8
instructions extraites en même temps, plusieurs d'entre elles peuvent être exécutées en même
temps si elles n'utilisent pas les mêmes ressources CPU en même temps. Comme l'unité centrale
dispose de 8 unités fonctionnelles distinctes, 8 instructions au maximum peuvent être exécutées
en parallèle, bien que le type d'instructions parallèles soit limité car elles ne doivent pas se gêner
mutuellement dans l'utilisation des ressources de l'unité centrale. Dans la liste de l’assembleur,
les instructions parallèles sont indiquées par des symboles à double tube (||). Lors de l'écriture
de code en assembleur, en concevant le code de manière à maximiser l'exécution parallèle des
instructions (grâce à une affectation correcte des unités fonctionnelles, etc.
IV.4. Instructions et contraintes parallèles
Nous avons vu que l'unité centrale C67x possède 8 unités fonctionnelles. Chaque instruction en
assembleur est exécutée dans l'une de ces 8 unités fonctionnelles, et il faut exactement un cycle
d'horloge pour l'exécution. Ensuite, pendant qu'une instruction est exécutée dans l'une des unités
fonctionnelles, que font les 7 autres unités fonctionnelles ? Les autres unités fonctionnelles
peuvent-elles exécuter d'autres instructions en même temps ?
La réponse est OUI. Ainsi, l'unité centrale peut exécuter au maximum 8 instructions par cycle
d'horloge. Les instructions exécutées dans le même cycle d'horloge sont appelées instructions
parallèles. Alors, quelles instructions peuvent être exécutées en parallèle ? La réponse est courte
: dans la mesure où les instructions parallèles n'utilisent pas la même ressource de l'unité
centrale, elles peuvent être mises en parallèle. Par exemple, les deux instructions suivantes
n'utilisent pas la même ressource du CPU et peuvent être exécutées en parallèle.
1 ADD .L1 A0,A1,A2
2 || ADD .L2 B0,B1,B2
IV.4.1. Contraintes en matière de ressources
Alors, quelles sont les contraintes des instructions parallèles ? Examinons plus en détail les
contraintes en matière de ressources.
IV.4.2. Contraintes des unités fonctionnelles
C'est simple. Chaque unité fonctionnelle ne peut exécuter qu'une seule instruction par cycle
d'horloge. En d'autres termes, les instructions utilisant la même unité fonctionnelle ne peuvent
pas être mises en parallèle.
IV.4.3. Contraintes croisées
Si vous regardez le diagramme du chemin des données de l'unité centrale C67x, il n'existe qu'un
seul chemin croisé entre le fichier du registre B et les unités fonctionnelles L1, M1 et S1. Cela
signifie que le chemin croisé ne peut être utilisé qu'une fois par cycle d'horloge. Ainsi, les
instructions parallèles suivantes ne sont pas valables car le chemin transversal 1x est utilisé
pour les deux instructions.
1 ADD .L1x A0,B1,A2
2 || MPY .M1x A5,B0,A3

16 Master Electronique des Systèmes Embarqués ESE – USTHB/FGE


Programmation en Assembleur pour le DSP TMS320C6713
DSP
La même règle s'applique pour le chemin de croix 2x du registre A aux unités fonctionnelles
L2, M2 et S2.
IV.4.4. Contraintes liées aux chargements et aux stockages
Les unités D sont utilisées pour les instructions de chargement et de stockage. Si vous examinez
le diagramme de cheminement des données C67x, les adresses de chargement/stockage peuvent
être obtenues du côté A ou B en utilisant les multiplexeurs qui se connectent entre eux pour
générer les adresses DA1 et DA2. Ainsi, les instructions telles que
1 LDW .D2 *B0, A1
est valable. L'unité fonctionnelle doit se trouver du même côté que le registre source d'adresses
(indice d'adresse en B0 et donc D2 ci-dessus), car les unités D1 et D2 doivent recevoir les
adresses des côtés A et B, respectivement.
Une autre contrainte est qu'en chargeant un registre dans un fichier de registre à partir de la
mémoire, vous ne pouvez pas stocker simultanément un registre dans le même fichier de
registre en mémoire. Par exemple, les instructions parallèles suivantes ne sont pas valables :
1 LDW .D1 *A0, A1
2 || STW .D2 A2, *B0
IV.4.5. Contraintes sur la lecture du registre
Vous ne pouvez pas avoir plus de quatre lectures du même registre à chaque cycle d'horloge.
Ainsi, ce qui suit n'est pas valable :
1 ADD .L1 A1, A1, A2
2 || MPY .M1 A1, A1, A3
3 || SUB .D1 A1, A4, A5
IV.4.6. Contraintes relatives aux inscriptions au registre
Un registre ne peut pas être écrit plus d'une fois dans un même cycle d'horloge. Toutefois, il
convient de noter que l'écriture effective dans les registres peut ne pas avoir lieu dans le même
cycle d'horloge que celui au cours duquel l'instruction est exécutée. Par exemple, l'instruction
MPY écrit dans le registre de destination au cours du cycle d'horloge suivant. Ainsi, ce qui suit
est valable :
1 ADD .L1 A1, A1, A2
2 || MPY .M1 A1, A1, A2
Les deux instructions suivantes (non parallèles) ne sont pas valables (pourquoi ?) :
1 MPY .M1 A1, A1, A2
2 ADD .L1 A3, A4, A2
Certains de ces conflits d'écriture sont très difficiles à détecter et ne sont pas détectés par
l'assembleur. Il convient d'être particulièrement prudent lorsque les instructions comportent des
créneaux de retard non nuls.

17 Master Electronique des Systèmes Embarqués ESE – USTHB/FGE


Programmation en Assembleur pour le DSP TMS320C6713
DSP

V. PIPELINE DE LOGICIELS AD HOC


À ce stade, vous vous êtes peut-être demandé pourquoi le processeur C6x permet des
instructions parallèles et génère autant de maux de tête avec les contraintes de ressources, en
particulier avec les instructions à créneaux de retard (delay slots). Et pourquoi ne pas
simplement faire en sorte que l'instruction MPY prenne 2 cycles d'horloge pour s'exécuter, de
sorte que nous puissions toujours utiliser le résultat multiplié après l'avoir émise ?
La raison en est qu'en exécutant les instructions en parallèle, nous pouvons réduire le temps
d'exécution total du programme. Un programme en assembleur bien écrit exécute autant
d'instructions que possible dans chaque cycle d'horloge pour mettre en œuvre l'algorithme
souhaité.
La raison pour laquelle les créneaux de retard (delay slots) sont autorisés est que, bien qu'il
faille 2 cycles d'horloge pour qu'une instruction MPY génère le résultat, nous pouvons exécuter
une autre instruction en attendant le résultat. De cette façon, on peut réduire le nombre de cycles
d'horloge gaspillés en attendant le résultat d'instructions lentes, ce qui augmente la vitesse
d'exécution globale.
Mais comment mettre les instructions en parallèle ? Bien qu'il existe une manière systématique
de le faire (nous l'apprendrons un peu plus tard), à ce stade, vous pouvez essayer de restructurer
votre code assembleur pour exécuter autant d'instructions que possible en parallèle. Et, vous
devriez essayer d'exécuter d'autres instructions dans les créneaux de retard de ces instructions
comme MPY, LDW, etc., au lieu d'insérer des NOP pour attendre que les instructions
produisent les résultats.

18 Master Electronique des Systèmes Embarqués ESE – USTHB/FGE

Vous aimerez peut-être aussi