Jeu d`instruction

Transcription

Jeu d`instruction
DSP
Plan









Classification circuits
Présentation générale du domaine DSP
Le choix du DSP
L’architecture interne du 21061
Jeu d’instruction
Registres d’état du DSP
Accès mémoire et pipeline
Les interruptions
Assembleur Sharc
I. Classification
circuits
1) Circuits numériques
a. Qu’est ce qu’un circuit ?


Définition :
Un agencement de transistors qui groupés par
composants réalisent une fonctionnalité
particulière.
3 niveaux de description :
C’est un dessin plannaire (layout, ou vue physique)
 C’est un réseau de transistors (vue structurelle ou netlist). La description est presque toujours hiérarchique.
Vues comme des boîtes noires : encapsulation.
 C’est un comportement (vue fonctionnelle)

Niveau composant:
comportement numérique
Couche
physique
Niveau portes:
comportement logique
Niveau transistor:
comportement électrique
Portes
INV_
OR_
AND_
NAND_
NOR_
XOR_
MSI
LSI
MAJ_
PLA_
MUX_
ALU_
ALU_
DEC_
COMP_
HalfAdder_
HalfAdder_
ADDER_
Fonction MAJ_3 en PLA
s = abc + abc + abc + abc
abc
abc
abc
b. Flot de conception d’un circuit
Description textuelle ou graphique
Compilation, vérification
Simulation fonctionnelle
Placement routage,
simulation temporelle
Programmation circuit
Vérification
Ex: VHDL,
Verilog,
SystemC-RTL
2. Les types de circuit
Les différents types de circuits
Cibles
Processeurs
Généralistes
Circuits
Spécifiques
Classiques
µ-contrôleurs DSP
…
…
…
Programmables
ASIP
FPGA
…
Dédiés
ARD
ASIC
…
Les différents types de circuits
Cibles
Processeurs
Généralistes
Circuits
Spécifiques
Classiques
µ-contrôleurs DSP
Pentium
PowerPC
Alpha
Mips
…
68705
68HC11
80C51
…
ADSP21xx
TMS320xx
DSP56xx
…
Program
mables
ASIP
FPGA
Xilinx
Altera
Atmel
…
Dédiés
ARD
ASIC
Full Custom
Standard Cell
Gate Array
…
Les sigles





FPGA : Field Programmable Gate Array
DSP
: Digital Signal Processor
ASIP
: Application Specific Integrated Processor
ASIC : Application Specific Integrated Circuit
ARD
: Architecture Reconfigurable
Dynamiquement
Les différences
Adresse
Circuit
Données
ASIC
FPGA
(circuit
programmable)
PROC
I - Présentation
générale
Flexibilité Vs performances
Flexibilité
Proc.
généraliste
Coût de conception
µ. Contrôleur
DSP
ASIP
Performances-1
Idem avec l’efficacité énergétique
Générations de DSP
La R&D autour des DSP en France
II – Le choix des DSP
Comparaison DSP / Proc généraliste
Sharc
Pentium
critère
60-66 MHz
2-3 GHz
Fréquence
1 cycle/inst
2-3 cycles/inst
Add
1cycle/inst
1-10 cycles/inst
Mul
1 cycle/inst
20* plus vite =
20*60 = 1,2GHz
~20 cycles/inst
(MMX)
MAC :
Lecture
échantillon
Lecture coef filtre
Mul
ACC
Calcul prochaine @
Comparaison DSP / Proc généraliste
Sharc
Mem on Chip
Pentium
critère
Bus système
Bus + Mem
100-166MHz
(Pentium = 100MHz)
Cache :
On-chip
PCI = 66 MHz
ISA = 8 MHz
Unités de calcul // …
FIR
3 cycles/inst
Questions…

Pourquoi le DSP n’a-t-il pas alors remplacé les
CISC ?
Embarquabilité
 Compatibilité
 Performance limité sur applis générales
 Espace adressable réduit sur DSP


Futur du DSP :
TMS 320C54 ou BlackFin
 = DSP + RISC

Harvard / Von Neuman

Les accès mémoire sont découplés



Harvard :




Accès instructions
Accès données
2 accès // par instruction
2 fois + rapide
Au prix d’une architecture beaucoup plus complexe : tout est
doublé
Von Neumann



Accès mémoire séquentiels
Plus flexible
Archi plus simple
III – Architecture
Sharc
Les concurrents

Texas Instruments





Motorola


TMS320C54x, TMS320C6x…
De 20 à 400 MIPS en mono core
Plus de 2000 MIPS en multi core
Plus souvent en virgule fixe 16 bits
DSP 56x00
Analog Device




1er DSP, 1980, ADSP-2100
3 unités de calculs // : instructions multi-fonctions
1990, famille Sharc (Super Harvard Architecture)
2106x, 66MFLOPS
Caractéristiques de l’architecture Sharc









Architecture de type Harvard (bus Data 40 bits + Bus Program
48 bits)
Mémoire On-Chip de 0,5Mmots de
Cache 32 instructions
16 registres de données (40 bits)
Structure pipeline à 3 étages (F + D + E)
Parallélisme d’instructions (sous certaines conditions)
Unité de calcul avec multiplieur, additionneur en virgule fixe ou
flottante et registre à décalage
2 unités de génération d’adresses (DAG) avec buffers circulaires
(convolutions) et adressage « bit-reversed » (FFT)
Gestion câblée des boucles
Vue système
Architecture interne du 21061
CACHE
MEMORY
32 x 48
DAG 1
8 x 4 x 32
DAG 2
8 x 4 x 24
JTAG TEST &
EMULATION
PROGRAM
SEQUENCER
PMA BUS
24
DMA BUS
32
PMD BUS
48
DMD BUS
40
FLAGS
TIMER
PMA
DMA
PMD
BUS CONNECT
FLOATING & FIXED-POINT
MULTIPLIER,
FIXED-POINT
ACCUMULATOR
DMD
REGISTER
FILE
16 x 40
32-BIT
BARREL
SHIFTER
FLOATING-POINT
& FIXED-POINT
ALU
Mémoire
Organisation mémoire

Memoire interne





Mémoire partagée



(0x0000 0000 -> 0x0007 FFFF)
Registres du proc
IO registers
2 blocs 0 et 1 de 0,5 Mbits = 16K*32 bits
(0x0008 0000 => 0x003F FFFF)
Bus externe = 6 Sharc
Mémoire externe

(0x0040 0000 => 0xFFFF FFFF)
Memory Map
Mémoire interne
256 registres internes
0x 0000 0000
Réservé
0x 0000 0100
Bloc 0 (8K x 48 ou 16K x 32)
Adressage normal
0x 0002 0000
Bloc 1 (8K x 48 ou 16K x 32)
Adressage normal
0x 0002 4000
Alias Bloc 1
Adressage normal
0x 0002 8000
Bloc 0 (32K x 16)
Adressage court
0x 0004 0000
Bloc 1 (32K x 16)
Adressage court
0x 0004 8000
Alias Bloc 1
Adressage court
0x 0005 0000
Mémoire partagée
(Multiprocesseurs)
0x 0008 0000
Mémoire externe
0x 0040 0000
Accès par taille de mots variables

Harvard modifiée : chaque bloc peut contenir
code et données
Organisation mémoire


Mémoire en 2 blocs
Bloc =



8 colonnes de 4K mots de 16 bits
Un accès mot de 16, 32, 40 ou 48 bits
1 instruction = 48 bits

Accès 40/48 bits

Accès 32 bits

Accès 16 bits
Accès 32 bits


Une donnée de 32 bits est stockée sur 2
colonnes => 16 K mots de 32 bits par bloc
8 colonnes utilisables
0x 2 1000
0x 2 0000
0x 2 0FFF
H
L
H
L
0x 2 5000
0x 2 4000
0x 2 4FFF
0x 2 1FFF
H
L
0x 2 5FFF
0x 2 3000
0x 2 2000
0x 2 2FFF
H
L
0x 2 7000
0x 2 6000
H
L
0x 2 6FFF
0x 2 3FFF
H
L
0x 2 8000
Accès 40 et 48 bits




Les données de 40 bits sont stockées dans des mots de
48 bits cadrées sur les MSB
48 bits = 3 colonnes (mot H, M et L)
=> uniquement les 6 pemière colonnes remplies
=> 8K mots de 48 bits
0x 2 0FFF
H
M
L
0x 2 1FFF
L
H
M
H
M
L
0x 2 5FFF
unused
unused
0x 2 5000
0x 2 4000
0x 2 4FFF
unused
0x 2 1000
0x 2 0000
L
H
M
unused
Exemple en bloc B1
0
1
2
3
4
5
6
7
140A 0004 0000 7FA1 1301 0002 A52D 05DF
142A 0000 0020 014B 063E 0002 BC45 69C3
suite

Accès 48 bits :
0x 2 4000
 0x 2 5001


Accès 32 bits :
0x 2 4000
 0x 2 5001


140A 0004 000
063E 0002 014B
140A 0004
0020 014B
Accès 16 bits : // Accès L et H identique à 32
0x 4 8000
 0x 4 8001

0004
140A




‘Mapping’ de l’exécutable dans
l’espace mémoire - segments
MEMORY
{
isr_table { TYPE(PM RAM) START(0x00020000) END(0x000200cF) WIDTH(48) }
seg_init { TYPE(PM RAM) START(0x000200d0) END(0x000200df) WIDTH(48) }
b0_code { TYPE(PM RAM) START(0x000200e0) END(0x00020fff) WIDTH(48) }
b0_data { TYPE(PM RAM) START(0x00022800) END(0x00022cff) WIDTH(32) }
b0_idat { TYPE(DM RAM) START(0x00022d00) END(0x00022fff) WIDTH(32) }




b1_code { TYPE(PM RAM) START(0x00024000) END(0x00024Bff) WIDTH(48) }
b1_data { TYPE(DM RAM) START(0x00024C00) END(0x00024Eff) WIDTH(32) }


seg_heap { TYPE(DM RAM) START(0x00026000) END(0x000266ff) WIDTH(32) }
seg_stak { TYPE(DM RAM) START(0x00026700) END(0x00026Aff) WIDTH(32)}



}
Résultat de l’édition de lien
0xCF28
0x0000
File2.o
Image exécutable
‘loader’ section
‘loader’ section
Code/data (file1.o)
Code/data
.text section
.text section
code
.text (file1.o)
.text (file2.o)
.bss section
data
code
0x0000
File1.o
.text section
code
.data section
Init data
Bibliothèque.lib
.data section
.data (file1.o)
.data (file2.o)
.bss section
.bss (file1.o)
.bss (file2.o)
.data section
Init data
.bss section
data







































}}
Sections de code
ROCESSOR p0{
LINK_AGAINST( $COMMAND_LINE_LINK_AGAINST) // Other object files to link against.
OUTPUT( $COMMAND_LINE_OUTPUT_FILE )
// Resulting executable file name.
SECTIONS{
interupt_vector_table
{
INPUT_SECTIONS( $OBJECTS(seg_rth) $LIBRARIES(seg_rth))
} >isr_table
seg_init
{
INPUT_SECTIONS( $OBJECTS(seg_init) $LIBRARIES(seg_init))
} >seg_init
block0_program_code
{
INPUT_SECTIONS( dotprod_main.doj(seg_pmco) $LIBRARIES(seg_pmco))
} >b0_code
block1_program_code
{
INPUT_SECTIONS( dotprod.doj(seg_pmco) dotprod_func.doj(pm_code1) dotprod_func.doj(pm_code2)
dotprod_func.doj(pm_code3))
} >b1_code
block0_data
{
INPUT_SECTIONS( $OBJECTS(seg_pmda) $LIBRARIES(seg_pmda))
} >b0_data
block1_data
{
INPUT_SECTIONS( $OBJECTS(seg_dmda) $LIBRARIES(seg_dmda))
} >b1_data
stackseg
{
ldf_stack_space = .;
ldf_stack_length = MEMORY_SIZEOF(seg_stak);
} > seg_stak
heap
{
ldf_heap_space = .;
ldf_heap_end = ldf_heap_space + MEMORY_SIZEOF(seg_heap) - 1;
ldf_heap_length = ldf_heap_end - ldf_heap_space;
} > seg_heap
Bus d’adresse

3 bus :

PM (programmes)




Fetch
16Mmots
32 bits d’@
32/40 bits de données
Read/Wr
4Gmots
IO



24 bits d’@
48 bits de données (inst)
DM (data)


Accès // en 1 cycle sauf si
même bloc
17 bits d’@
48 bits de données
PX

Pont entre le bus PM et DM
6 contrôleurs DMA
128 Kmots
Jeu d’instruction
Modes d’adressage

L’accès à la mémoire est utilisé avec :


DM(adr) ou PM(adr) désigne l’accès mémoire par les
bus DM/PM à l’adresse adr
Adressage direct
DM (0x24000) = R0;
 PM (0x24001) = R1;

// accès par bus DM
//accès par bus PM
Adressage indirect : les DAGs




Le Sharc dirpose de 2 jeux de registres DAG1 et DAG
2 (Data Adress Generator) permettant l’adressage
indirect
Dessin
Chaque jeu de registre est doublé (shadows registres)
DAG1 est relié au bus DM, 32 bits


Les registres 0 à 7 sont donc de 32 bits
DAG2 est relié au bus PM, 24 bits

Les registres 8 à 15 sont donc de 24 bits
Les DAGs en adressage indirect
DAG1
(32 bits)
I0
I1
I2
I3
I4
I5
I6
I7
M0
M1
M2
M3
M4
M5
M6
M7
L0
L1
L2
L3
L4
L5
L6
L7
B0
B1
B2
B3
B4
B5
B6
B7
registres d’index
registres modifieurs
registres longueur et base
(buffers circulaires)
registres principaux
registres shadow
Les DAGs
DAG1
(32 bits)
I0
I1
I2
I3
I4
I5
I6
I7
DAG2
(24 bits)
I8
I9
I10
I11
I12
I13
I14
I15
M0
M1
M2
M3
M4
M5
M6
M7
M8
M9
M10
M11
M12
M13
M14
M15
L0
L1
L2
L3
L4
L5
L6
L7
L8
L9
L10
L11
L12
L13
L14
L15
B0
B1
B2
B3
B4
B5
B6
B7
B8
B9
B10
B11
B12
B13
B14
B15
registres principaux
registres shadow
registres principaux
registres shadow
DAGs


Ix registres d’index
Chaque registre Ix peut être associé à un offset
sous forme
D’un immédiat
 Ou d’un registre My (modificateur)


2 modes :
Pré incrémenté sans modification de l’index
 Post incrémenté avec modification

Exemple
Post
 R0 = 0xA0A0A0A0;
 M6 = 2;
 I0 = 0x0002 4000;
 DM(I0, M6) = R0; // I0 est modifié après accès mémoire
et devient 0x0002 4002
Pré
 R0 = 0xA0A0A0A0;
 I0 = 0x0002 4000;
 DM(0xFFFF FFFF, I0) = R0; // accès mémoire à l’@
0x23FFF (+ (-1))et I0 reste à la valeur 0x0002 4000
Adressage circulaire





Utilisation des registres Bx et Lx associés à un reg. Ix
Bx = Base de buffer
Lx = Longueur à initialiser à une valeur non nulle
Lorsque Bx est initialisé, le Ix correspondant est
automatiquement initialisé à la même valeur
Ix est utilisé en indirect normal avec 2 restrictions :



L’offset (My ou Imd) doit être inférieur à Lx
Le mode pré incrémenté ne peut être utilisé
Une interruptions indicative est généré au dépassement
lorsque Ix est ramené circulairement
Exemple





Adressage de buffers circulaires :
B0 = 0x00024000,
//init. de B0 et I0
L0 = 8;
//init. longueur du buffer
M1 = 1;
//init. modifieur
R0 = DM(I0,M1);
//si IO>B0+L0 alors
// I0=B0
L’utilisation des buffers circulaires
B0
L0
longueur et
base du tableau
I0
pointeur sur
le tableau
Les mécanismes de déplacement du
pointeur, de test de la fin du tableau
et de ré-initialisation sont câblés
dans les DAG...
Modes d’adressage
Codes Conditions
Jeu d’instruction du DSP

Instructions de calcul
En virgule fixe
 En virgule flottante
 Du multiplieur (utilisation de MRF et MRB)
 Du registre à décalage
 Instructions parallèles




Instructions de rupture de séquence
Instructions de déplacement avec @ immédiat
Instructions diverses
Architecture interne
Les unités de calcul
PM 48 bits
DM 40/32 bits
Register File
Multiplier
16 x 40 bits
Banc de registres
16 registres désignés par :
 De R0 à R15 en virgule fixe
 De F0 à F15 en virgule flottante
 Format désigné par le nom employé
Les registres principaux sont doublés par des Shadows
registers organisés en 2 blocs
 R0 à R7
 R8 à R15
Chacun peut être actionné pour permettre des
changements de contexte rapide. Activés (au bout de 2
cycles) par un bit du registre MODE1.
Format de représentation des
nombres
Registres sur 40 bits :
 Les opérations entières sont sur 32 bits MSB
 Ignorant les 8 bits LSB en lecture
 Les forçant à 0 en écriture



La lecture registre est réalisé en début de cycle
L’écriture registre en fin de cycle
Une instruction peut donc utiliser le même registre en
entrée et en sortie
Format (suite)

Virgule Fixe
Format Q1.31 (Virgule à droite du MSB)
 Dynamique [-1, +1[
 Ou Q32.0 en entiers


Virgule flottante
IEEE/754
 N = (-1)S.1,M.2E+127
 M = 23 bits
 E = 8 bits

Multiplieur
Fonctionne
 en V. Fixe, Rx
 ou en Flottante, registres Fx ou MR
Le type des opérandes est précisé dans l’instruction :
modificateur XYZ
 X et Y désignent Signed ou Unsigned
 Z désigne le codage : Integer, Fraction, FR fraction
avec arrondi
Exemple : R2 = R0*R1 (SUF)
Le résultat est sur 64 bits
Registre MR du multiplieur

Si le résultat 32 bits est écrit dans Rx, les 32 bits
conservés sont :



Les 32 bits LSB si les opérandes sont I
Les 32 bits MSB si les opérandes sont F (Q1.31)
2 Accumulateurs MR sur 80 bits




MRF (foreground) et MRB (background)
Permutable par un bit de MODE1
Toujours accessibles contrairement aux shadows R.
3 parties : MR0 (32b), MR1(32b) et MR2(16b)
Décaleur (figure en 8bits)
Multi function instructions
Séquenceur
d’instructions
Le pipeline
instruction i
instruction i+1
lecture
décodage exécution
lecture
décodage exécution
lecture
instruction i+2
en permanence !
décodage exécution
temps
Pipeline

Le sharc dispose d’un pipeline à 3 étages
3 instructions sont en cours de traitement
 1 instruction se termine à chaque cycle


Le fonctionnement idéal est perturbé lorsque :

Une instruction N utilise le bus PM pour accéder à la
mémoire. Il y a alors conflit avec la phase de fetch de
l’instruction N+2.

Le compilateur ajoute un cycle d’attente (NOP)
L’instruction N provoque une rupture de séquence
(JUMP, CALL). => Branchements retardés
 L’instruction N+1 adresse la mémoire avec un registre de
DAG modifié par l’instruction N => 1 cycle d’attente

exemple d’utilisation du cache
0x20000:
...
0x20001:
R0 = PM(0x23013);
// lecture sur bus PM
0x20002:
R2 = R0 + R1;
// opération arithmétique
0x20003:
DM(0x24000) = R0;
// écriture sur le bus DM
0x20004:
...
0x20005:
...
exemple d’utilisation du cache
(1ère occurrence)
Execute
Execute
Decode
Decode
Execute
Fetch
Fetch
Execute
Decode
Lecture data sur leDecode
bus
Fetch
PM
Fetch
Decode
Recherche sur le bus PM
0x20000:
...
0x20001:
R0 = PM(0x23013);
0x20002:
R2 = R0 + R1;
0x20003:
DM(0x24000) = R0;
0x20004:
...
0x20005:
...
Les deux opérations nécessitent deux
accès simultanés sur le même bus !
exemple d’utilisation du cache
(1ère occurrence)
....
....
Fetch + Mise en cache
0x20000:
...
0x20001:
R0 = PM(0x23013);
0x20002:
R2 = R0 + R1;
0x20003:
DM(0x24000) = R0;
0x20004:
...
0x20005:
...
Cache instructions :
00 0
01 0
03 1 DM(0x24000) = R0
exemple d’utilisation du cache
(1ère occurrence)
Execute
Decode
....
0x20000:
...
0x20001:
R0 = PM(0x23013);
0x20002:
R2 = R0 + R1;
0x20003:
DM(0x24000) = R0;
0x20004:
...
0x20005:
...
Cache instructions :
00 0
01 0
03 1 DM(0x24000) = R0
exemple d’utilisation du cache
(1ère occurrence)
Execute
Decode
Fetch
0x20000:
...
0x20001:
R0 = PM(0x23013);
0x20002:
R2 = R0 + R1;
0x20003:
DM(0x24000) = R0;
0x20004:
...
0x20005:
...
Cache instructions :
00 0
01 0
03 1 DM(0x24000) = R0
exemple d’utilisation du cache
(1ère occurrence)
Execute
Decode
Fetch
0x20000:
...
0x20001:
R0 = PM(0x23013);
0x20002:
R2 = R0 + R1;
0x20003:
DM(0x24000) = R0;
0x20004:
...
0x20005:
...
Cache instructions :
00 0
01 0
03 1 DM(0x24000) = R0
exemple d’utilisation du cache
(2ème occurrence)
Execute
Execute
Decode
Decode
Execute
Fetch
Fetch
Execute
Decode
Decode
Fetch
Fetch
0x20000:
...
0x20001:
R0 = PM(0x23013);
0x20002:
R2 = R0 + R1;
0x20003:
DM(0x24000) = R0;
0x20004:
...
0x20005:
...
Cache instructions :
00 0
01 0
03 1 DM(0x24000) = R0
exemple d’utilisation du cache
(2ème occurrence)
Execute
Decode
Fetch
0x20000:
...
0x20001:
R0 = PM(0x23013);
0x20002:
R2 = R0 + R1;
0x20003:
DM(0x24000) = R0;
0x20004:
...
0x20005:
...
Cache instructions :
00 0
01 0
03 1 DM(0x24000) = R0
exemple d’utilisation du cache
(2ème occurrence)
Execute
Decode
Fetch
0x20000:
...
0x20001:
R0 = PM(0x23013);
0x20002:
R2 = R0 + R1;
0x20003:
DM(0x24000) = R0;
0x20004:
...
0x20005:
...
Cache instructions :
00 0
01 0
03 1 DM(0x24000) = R0
exemple d’utilisation du cache
(2ème occurrence)
Execute
Decode
Fetch
0x20000:
...
0x20001:
R0 = PM(0x23013);
0x20002:
R2 = R0 + R1;
0x20003:
DM(0x24000) = R0;
0x20004:
...
0x20005:
...
Cache instructions :
00 0
01 0
03 1 DM(0x24000) = R0
Conclusion sur l’utilisation du cache
Le pipeline entraîne l’ajout d’un cycle
supplémentaire à chaque fois qu’un conflit
d’accès au bus est détecté.
La présence du cache d’instruction ne permet
de résoudre le conflit
qu’à la deuxième occurrence seulement.
⇒ Un code optimisé (en vitesse) ne contient de
conflits de bus qu’à l’intérieur des boucles...
problème 2 : Le cas des dépendances de
données


Lors de la phase de décodage de l’instruction, le processeur prépare
l’accès aux données et calcule l’adresse des accès en mémoire.
Il y a conflit de dépendance de données lorsqu’une instruction effectue
un accès en mémoire avec un registre d’index (Ix) modifié lors de
l’instruction précédente.
Execute
0x20002:
Decode
0x20003:
0x20004:
I0 = 0x23013;
// Init index I0
R2 = DM(I0,M0)
// accès avec IO
...
La modification de l’index I0 et le calcul
de l’adresse avec I0 nécessiteront deux cycles
au lieu d’un !
problème 3 : Le cas des ruptures de
séquence
Execute
R0 = R1 + R2;
Execute
Decode
R2 = lshift R2 by 12;
Decode
Execute
Fetch
CALL
Fetch
!!
!!
routine;
routine:
R5 = 1;
R5 = 0;
R9 = min(R5, R2);
I8 = tableau;
...
...
problème 3 : Le cas des ruptures de
séquence
R0 = R1 + R2;
R2 = lshift R2 by 12;
CALL
NOP
!!
routine;
routine:
Fetch
R5 = 1;
R5 = 0;
R9 = min(R5, R2);
I8 = tableau;
...
...
problème 3 : Le cas des ruptures de
séquence
R0 = R1 + R2;
R2 = lshift R2 by 12;
CALL
routine;
R5 = 0;
NOP
I8 = tableau;
...
routine:
Decode
Fetch
R5 = 1;
R9 = min(R5, R2);
...
problème 3 : Le cas des ruptures de
séquence
R0 = R1 + R2;
R2 = lshift R2 by 12;
CALL
routine;
R5 = 0;
I8 = tableau;
...
routine:
Execute
R5 = 1;
Decode
R9 = min(R5, R2);
Fetch
...
⇒ Deux cycles sont perdus (idem lors du retour de la routine) !!
solution : Utilisation des branchements
retardés
Execute
Decode
Execute
CALL
Execute
Fetch
Decode
R0 = R1 + R2;
Execute
Decode
Fetch
Fetch
Decode
R2 = lshift R2 by 12; Execute
Fetch
Decode
R5 = 0;
routine (DB);
I8 = tableau;
routine:
Fetch
R5 = 1;
R9 = min(R5, R2);
...
...
⇒ Pas de perte de cycles au moment du branchement
(idem lors du retour du sous-programme) !
INCONVENIENT : si la rupture de séquence se trouve à
l ’intérieur d’une boucle de moins de trois instructions,
le branchement retardé est impossible !
Suite
Benchmarks
Registres du
processeur
ALU operations
UAL

Registre d’état ASTAT = résultat de l’opération
courante
Registre ASTAT
STKY register
STKY register
Programmation du
DSP
Exemple Y(n) = a.X(n) + b.(n-1)
// Acquisition
 R0 = dm (Entree_Droite);
 R0 = ashift r0 by -1;
 R1 = dm (Entree_Droite);
 R1 = ashift r1 by -1;
 R15 = r0 + r1;
// Traitement
 R2 = 0x7FFF FFFF;
// 1 en Q1.31
 R3 = dm (Coeff_RC);
// r3 = Coef a
 R2 = r2-r3;
// r2 = coef b = 1-a
 R0 = r15*r3 (SSF);
// r0 = x(n)*a
 R1 = dm (Accu_Sortie);
// - R1 = r1 * r2 (SSF);
//r1 = y(n-1) * b
 R4 = r1 + r0
// r4 = a.x(n) + b.y(n-1)
 Dm (Accu_sortie) = r4;
// Sortie
Dm(Sortie_Droite) = r4;
Dm (Sortie_Gauche) = r4;
Modes de programmation

3 choix de programmation
Langage C
 Langage Assembleur
 Mixte

Debut et fin d’un programme






Le mode de programmation C est le mode par défaut si
aucun fichier .LDF n’a été associé.
Dans ce cas le fichier 21061.LDF est utilisé par défaut.
Le fichier 060_hdr.doj qui initialise les tables
d’interruptions et appelle la fonction main() est ajouté.
Le point d’entrée du programme est à l’adresse 0x20005
(2e mot du vecteur RESET)
La fin du programme est un boucle infinie contenant
IDLE associée au label __lib_prog_term.
Le paramètre n de return (n) est écrit dans R0 ou il peut
être lu après l’exécution.
Extension du C ANSI
Mots clés :
 Inline <function>
: indique que le code de
function doit être intégré dans le code l’appelant
 asm(‘’texte’’)
: insère le code ASM dans le
prog C
 dm/pm
: forcer l’allocation es variables
globales ou statique en DM ou en PM
 Segment(‘nom’)
: spécifier explicitement le nom
du segment des instr/données qui suivent
 Bool
: type booléen
Registres et paramètres de fonctions
Paramètres
 Les 3 premiers paramètres passés à une fonction asm sont passés
dans les registres R4,R8 et R12 dans cet ordre. Ensuite les autres
sont passés dans la pile.
Gestion de la pile
 I6 est le frame pointer
 I7 est le stack pointer
Valeur de retour
 La valeur retournée par une fonction est passée dans R0.
Nommage
 Une variable nommée X et C doit être nommée _X en
assembleur
2.4.4) Les instructions parallèles

Certaines instructions peuvent provoquer des opérations en parallèle :
Double additions-soustractions :
R0 = R8+R12, R1 = R8-R12;
 Multiplication/Accumulation et addition/soustraction en virgule fixe
R0 = R1*R4 (SSFR), R2 = R8-R12;
 Multiplication et opération arithmétique en virgule flottante
F2 = F0*F4, F5 = (F8+F12)/2;
 Multiplication et double addition-soustraction en virgule fixe ou flottante
R5=R0*R4(SSFR),R6=R9+R13,R7=R9-R13;
F0=F1*F5, F1=F8+F12, F2=F8-F12;


Ces instructions peuvent s’effectuer également en parallèle avec des
transferts sur les bus DM et PM simultanés...
F0=F1*F5, F1=F8+F12, F5=F8-F12,
F8=DM(I0,M0),F12=PM(I8,M8);
Exemple
Code C :
Int additionne(int a, int b, int c, int d, int e){
Int J;
J = additionne (1,2,3,4,5);
J++;
}
 Code asm compilé
R2 = 5;
// dernier paramètre
DM (I7, -1) = R2; // mise au sommet de pile
R1 = 4;
// avant dernier
DM(I7, -1) = R1;
R12 = 3;
R8 = 2;
R4 = 1;
CJUMP _additionne(DB); // DB = retardé CJUMP fait aussi R2 = I6 et I6 = I7
DM (I7, -1) = R2; // empile R2 = ancien frame pointer
DM(I7, -1) = PC; // empile l’@ courante

MODIFY (I7, 2);
R3 = R0;
R3 = R3 +1;
// Au retour de l’appel dépile les 2 dernier paramètres
// J++
Code du fichier asm
.SECTION/PM seg_pmco;
.GLOBAL _Additionne;
_Additionne :
MODIFY(I7, -1);
DM (-2, I6) = R1;
R0 = R0 +R8;
R0 = R0 + R12, R1 = DM(1, I6); // avant dernier paramètre
R0 = R0 + R1, R1 = DM(1,I6); // dernier paramètre
R0 = R0 + R1, R1 = DM(-2;I6);// Restitue R1
I12 = DM(-1, I6);
// Adresse de retour -1
JUMP (M14, I12) (DB);
I7 = I6;
I6 = DM(0, I6);
// saut de retour, M14 = 1 !!
// restitue la pile
// restitue ‘ancien frame pointer
Illustration
I7
Sauvegarde de R1
Adresse de retour -1
(@ de DM(I7, -1) = PC
Ancienne valeur de I6
(dans le prog principal)
4
(avant dernier param)
5
(dernier param)
I7 au début de
la fonction
I6 (I7 à la fin
de la fonction)
2.4.3) Les boucles câblées


Dans les applications de traitement du signal, la plupart des
traitements font intervenir des calculs sur des structures de
données de taille connue à l’avance (convolutions, matrices,
FFT, etc).
Pour optimiser ces calculs, le processeur DSP possède un
mécanisme de boucles câblées (hardware loops) qui accélère les
R4 boucle.
= 8;
tests de fin de
test de fin
MRF = 0;
LCNTR = 8, DO _loop UNTIL LCE;
R0 = DM(I0,M0);
longueur de la boucle
R5 = lshift R0 by R4;
_loop: MRF= MRF + R5*R5;
...
corps de la boucle
R4 = 8;
MRF = 0;
LCNTR = 8, DO _loop UNTIL LCE;
R0 = DM(I0,M0);
A l’exécution : le compteur
est initialisé, les adresses de fin
et de début sont empilées dans
des piles hardware
R5 = lshift R0 by R4;
_loop: MRF= MRF + R5*R5;
...

Au cycle Fetch : le compteur est décrémenté,
la condition de fin est testée et la prochaine
adresse est calculée (adresse de début ou
prochaine adresse)
Pour la réalisation de boucles imbriquées, le processeur dispose
de piles matérielles (hardware) de profondeur 6 (6 boucles
imbriquées maximum) :
Pile des compteurs de programme,
Pile des compteurs de boucle,
Pile des adresses de fin de boucle.
problème 1 : Le pipeline et les boucles
câblées
R4 = 32;
La condition est un résultat nul
DO _loop UNTIL EQ;
R0 = DM(I0,M0);
_loop: R5 = R0 - R4;
...

Au cycle Fetch : l’indicateur est celui résultant
de l’exécution de R4=32 (pour le premier
passage)...
Pour des boucles de longueur faible, le processeur « duplique »
les instructions dans son pipeline et ajoute, lorsque c’est
nécessaire, des « NOP » en fin de boucle pour la terminaison :
longueur
1
1
2
2
répétition
1 ou 2
>= 3
1
>= 2
dummy cycles
2
0
2
0
problème 2 : Le pipeline, les
branchements et les boucles câblées
R4 = 32;
LCNTR = 8, DO _loop UNTIL LCE;
...
CALL
routine;
R0 = DM(I0,M0);
_loop: R5 = R0 - R4;
...


Cette instruction sera lue (cycle Fetch) deux fois à
cause de l’instruction de branchement : 1ère fois
sans être exécutée (CALL), 2ème fois au retour de
la routine.
⇒ Le compteur de boucle est décrémenté deux fois !
PAS de ruptures de séquence non retardées dans les trois
dernières instructions d’une boucle câblée !
Plus généralement : pas de branchements dans les boucles (code
peu efficace) !
Conclusion sur l’utilisation des boucles
Les boucles câblées sont un moyen efficace d’optimiser les
performances d’un code (traitement du signal = nombreuses
boucles) mais le pipeline impose une attention particulière pour
le codage des boucle !
⇒ Un code optimisé (en vitesse) ne contient de
conflits de bus qu’à l’intérieur des boucles...
⇒ Les boucles doivent être de longeurs significatives
(déroulage des boucles courtes)
⇒ Les boucles ne doivent pas contenir de branchements !