Notes techniques · Traitement Numérique du Signal

L'architecture qui rend le silicium capable de penser en signal

Du fil unique de Von Neumann jusqu'aux huit unités fonctionnelles parallèles du TMS320C6713, ces notes reconstruisent — sans raccourcis — la pile complète qui transforme un échantillon analogique en calcul utile : architectures matérielles, parallélisme VLIW, pipelines à étages multiples, registres, modes d'adressage, et programmation en assembleur sur DSP TI.

SourceCours DSP — Z. Errachidi Pages couvertes81 → 216 (Ch. III–VI) Niveau3ème année embarqué OptiqueComprendre, pas mémoriser
01010110 01001100 01001001 01010111 · 11000110 01111000 · 10100100 01011010 · 11100110 00010011 · 01110000 01101001 01110000 01100101 01101100 01101001 01101110 01100101
Chapitre III

Architecture des systèmes µp

Avant le DSP, le microprocesseur. Ce chapitre pose le vocabulaire : comment le silicium est-il organisé physiquement (hardware), et comment exécute-t-il un programme (software). Tout ce qui suivra sur le C6713 — VLIW, pipeline, chemins de données — est une variation sophistiquée de ces idées fondamentales.

Hardware — Von Neumann vs Harvard

Un processeur a besoin de deux choses pour exécuter une instruction : le code de l'instruction lui-même (qui est en mémoire programme), et les données sur lesquelles cette instruction opère (qui sont en mémoire données). La question architecturale fondamentale est : ces deux mémoires partagent-elles le même bus, ou ont-elles chacune leur autoroute ? La réponse sépare le monde en deux familles.

VON NEUMANN CPU Mémoire UNIQUE Programme + Données 1 seul bus → goulot d'étranglement HARVARD CPU Programme (instructions) Données (opérandes) Bus 1 Bus 2 2 accès simultanés → idéal pour le streaming de données
Figure 1 — La différence fondamentale tient à un bus.
Von Neumann

Une mémoire unique contient à la fois les instructions et les données. Un seul bus les transporte. Pour exécuter une instruction, le CPU doit : d'abord chercher le code-instruction, puis aller chercher les données. Sérialisé. Simple à concevoir, mais le bus devient le goulot d'étranglement classique — c'est le « Von Neumann bottleneck ».

→ Utilisé dans la plupart des processeurs généralistes (PC).

Harvard

Deux mémoires séparées (programme / données), deux bus indépendants. Le CPU peut lire une instruction et une donnée dans le même cycle d'horloge. La bande passante effective double, et la prédictibilité temporelle s'améliore — capital pour les applications temps-réel.

→ Utilisé dans la plupart des DSP et microcontrôleurs.

⚡ Pourquoi c'est central en DSP

Le DSP traite un flux continu d'échantillons (« streaming data ») : chaque cycle compte. Doubler la bande passante mémoire en utilisant Harvard n'est pas une optimisation cosmétique, c'est ce qui rend le filtrage temps-réel possible. Le C6713 va plus loin avec une « Harvard modifiée » : la mémoire données est elle-même multi-accès (N bus internes), et il y a un cache séparé pour programme (L1P) et données (L1D).

CISC vs RISC — la philosophie du jeu d'instructions

Une autre division architecturale, orthogonale à Von Neumann/Harvard, concerne la nature des instructions que le processeur sait exécuter. Faut-il un grand vocabulaire (mots complexes, expressifs, mais lents à articuler) ou un petit vocabulaire (mots simples qu'on enchaîne à grande vitesse) ?

CISC — ComplexRISC — Reduced
Variété d'instructionsTrès nombreuses, très différentesPeu, simples, uniformes
TailleVariableFixe
RegistresPeu, mais spécialisésBeaucoup, généraux
PipelineDifficile (instr. de tailles différentes)Naturel
Exemplex86 (Intel)ARM, MIPS, TMS320C6x
Pour ton intuition d'ingénieur
Si tu veux du parallélisme et un pipeline efficace, RISC est presque obligatoire : des instructions de taille fixe permettent au processeur de prévoir l'arrivée de la prochaine, et donc de la précharger pendant qu'il exécute la courante. C'est exactement le pari du C6x.

Anatomie du CPU — UAL + UC + Registres

Le CPU se décompose en trois sous-unités reliées par des bus internes. Chacune a un rôle précis dans le cycle Fetch → Decode → Execute que tout processeur, du Z80 au C6713, répète des milliards de fois par seconde.

UnitéSigleRôle
Unité Arithmétique & LogiqueUAL / ALULe cœur du calcul. Additionneurs, soustracteurs, comparateurs, ET/OU/NON. Souvent dédoublée en UAL entière, FPU (calcul réel), et unité multimédia.
Unité de ContrôleUC / CULe chef d'orchestre. Récupère l'instruction (Fetch), la décode, génère les signaux qui pilotent l'UAL et la mémoire.
RegistresMémoire interne minuscule, ultra-rapide. Stocke les opérandes et résultats temporaires pendant l'exécution.

Le cycle Fetch–Decode–Execute en pratique

Considère cette séquence d'instructions, typique d'un programme assembleur :

LOAD  R1, 0x100   ; charger en R1 la valeur stockée à l'adresse 0x100
ADD   R1, R2      ; R1 ← R1 + R2
STORE R1, 0x100   ; écrire R1 à l'adresse 0x100

Pour LOAD R1, 0x100, le CPU :

  1. Fetch — l'UC va chercher l'instruction en mémoire programme, à l'adresse pointée par le compteur programme (PC).
  2. Decode — l'UC analyse les bits : opcode = LOAD, opérande source = adresse 0x100, opérande destination = R1.
  3. Execute — l'UC envoie un signal lecture sur le bus de contrôle, l'adresse 0x100 sur le bus d'adresses ; la mémoire renvoie la donnée sur le bus de données ; l'UC l'écrit dans R1.

Les types de registres

CatégorieExemples (x86)Fonction
Registre d'instruction (IR)Contient l'instruction en cours.
Compteur Programme (PC)Adresse de la prochaine instruction.
Registres générauxAX, BX, CX, DXOpérandes & résultats temporaires.
Registres d'adresses / pointeursSI, DI, SP, BPPointer vers des zones mémoire (sources, destinations, pile, base).

Mémoires & Bus internes

La cache, ou comment cacher la lenteur de la RAM

La RAM principale est lente par rapport au CPU (typiquement 100× plus lente). La parade : intercaler une mémoire petite mais ultra-rapide près du CPU, qui garde une copie des données et instructions récemment utilisées. C'est la cache.

  • L1 : la plus petite, la plus rapide, intégrée au CPU.
  • L2 : plus grande, légèrement plus lente. Sur le C6713, on aura L1P (programme) + L1D (données) + L2 (mixte).

Les trois bus

Un bus, c'est juste un faisceau de pistes électriques partagé. Il y en a trois :

  • Bus d'adresses — unidirectionnel (CPU → mémoire). « Je veux lire/écrire à cette adresse. »
  • Bus de données — bidirectionnel. Transporte la donnée elle-même.
  • Bus de contrôle — transporte les signaux read/write, interruptions, synchronisation.

Lecture d'une donnée en mémoire : (1) adresse sur le bus d'adresses, (2) signal « read » sur le bus de contrôle, (3) la mémoire pose la donnée sur le bus de données.

Classification des mémoires non-volatiles

TypeVolatile ?Caractéristique
RAMOuiLecture/écriture rapide. Perd tout sans alim.
ROMNonLecture seule. Contient le programme de démarrage.
OTP (One-Time Programmable)NonProgrammable une fois. Plus de modification possible.
EPROMNonEffaçable aux UV (~15 min). Réutilisable mais lent.
EEPROMNonEffaçable électriquement, octet par octet.
FLASHNonEEPROM plus rapide, mais effacement seulement par bloc.

Architecture logicielle — du C au binaire

Un programme est une séquence d'instructions ; une instruction est une opération élémentaire. Chaque µp a son propre jeu d'instructions, encodées en binaire (le langage machine), illisibles pour un humain.

Pour rendre cela écrivable, on utilise des couches d'abstraction :

Langage C main.c Compilateur Assembleur code.asm Assembleur (outil) Code objet code.o Linker .out binaire haut niveau ─────────────────────────── bas niveau
Figure 2 — La chaîne de compilation : abstraction → bits.

Une instruction binaire se découpe en deux parties :

  • Code opération (opcode) — ce que le µp doit faire (ADD, MOV, etc.).
  • Code opérande — sur quoi il doit le faire (les registres, les valeurs, les adresses).

Instruction simple vs complexe

Simple

« Incrémenter R1. » Tout se passe à l'intérieur du CPU, un seul additionneur intervient. Typiquement 1 cycle d'horloge.

Complexe

« Incrémenter le contenu de l'adresse mémoire 0x200. » Implique trois étapes : lire la mémoire, additionner, réécrire. Plusieurs cycles.

Modes d'adressage — comment l'opérande est désigné

ModeIdéeExemple
ImmédiatLa valeur est codée dans l'instruction.MOV #0x55, W0 → charge la constante 0x55 dans W0
DirectL'instruction donne l'adresse où trouver la valeur.MOV EAX, [0x12345678]
IndirectL'instruction désigne un registre qui contient l'adresse.MOV EAX, [EBX] → EBX contient l'adresse cible

L'indirect est crucial : c'est ce qui permet aux pointeurs et aux boucles. Sans lui, impossible de parcourir un tableau.

Le pipeline — exécuter plusieurs instructions à la fois

L'idée est volée à l'industrie automobile : une chaîne de montage où chaque poste fait une tâche pendant que les autres font les leurs. Au lieu d'exécuter Fetch → Decode → Execute séquentiellement pour chaque instruction, on dédie un étage à chaque phase et on les fait tourner en parallèle.

Séquentiel vs Pipeline — 3 instructions Cycle 1 2 3 4 5 6 7 8 9 Séquentiel F1 D1 E1 F2 D2 E2 F3 D3 E3 9 cycles Pipeline (||) F1 D1 E1 F2 D2 E2 F3 D3 E3 5 cycles → gain 4
Figure 3 — Le pipeline ne rend pas une instruction plus rapide, il rend les autres plus rapides en chevauchant.la première instruction prend 3 cycles de latence, mais ensuite une nouvelle instruction termine à chaque cycle.
Idée à retenir

Avec N étages, le pipeline ne divise pas le temps par N (la première instruction prend toujours N cycles), mais il porte le débit à 1 instruction par cycle en régime établi. Le C6x pousse l'idée à l'extrême : l'étage Fetch est décomposé en 4 sous-phases (PG, PS, PW, PR), Decode en 2 (DP, DC), et Execute peut compter jusqu'à 10 phases (E1…E10). On y revient en détail au chapitre IV.

Chapitre IV

Architecture des DSP TMS320C6x

Maintenant qu'on a les bases, on regarde ce que Texas Instruments a fait pour pousser un processeur au-delà de 1800 MFLOPS sur un signal audio en temps réel. La réponse tient en quatre mots : parallélisme architectural à tous les étages.

Pourquoi le parallélisme — SISD, SIMD, MIMD, VLIW

Un processeur classique exécute une instruction sur une donnée à la fois (SISD). Pour aller plus vite sans monter en fréquence — ce qui coûte cher en chaleur et en énergie — il faut faire plusieurs choses à la fois. Plusieurs stratégies existent :

ModèleSignifiePrincipe
SISDSingle Instr, Single DataLe µp classique. Une opération, une donnée, à la fois.
SIMDSingle Instr, Multiple DataUne même opération appliquée en parallèle à plusieurs données. Idéal pour additionner deux vecteurs.
MIMDMultiple Instr, Multiple DataPlusieurs cœurs exécutant chacun son propre programme sur ses propres données. C'est ton CPU multicœur.
VLIWVery Long Instruction WordUn seul processeur, mais une instruction qui pointe vers plusieurs unités fonctionnelles en parallèle.

VLIW — la clé du C6x

L'architecture VLIW est la spécificité du TMS320C6x. Au lieu de demander au CPU de découvrir dynamiquement quelles instructions peuvent s'exécuter en parallèle (ce que font les CPUs « superscalaires » comme x86), VLIW délègue ce travail au compilateur. Le compilateur regroupe lui-même les instructions parallélisables en un mot long, et le matériel les distribue mécaniquement.

Avantages VLIW
  • Parallélisme fin
  • Unités indépendantes
  • Hardware simple (pas de découverte dynamique)
  • Bonne prédictibilité temporelle
Inconvénients
  • Bande passante mémoire élevée (instructions plus longues)
  • Code binaire plus volumineux
  • Très dépendant de la qualité du compilateur

Exemple d'un mot d'instruction VLIW : ADD R1,R2,R3 | MUL R4,R5,R6 | LOAD R7,[R8] — trois opérations indépendantes, exécutées en un seul cycle par trois unités fonctionnelles différentes.

Familles TI & l'architecture VelociTI

Texas Instruments commercialise plusieurs familles de DSP, classées par arithmétique (virgule fixe / flottante) et largeur de registres :

FamilleArithmétiqueUsage typique
C1x, C2x, C2xx, C54xVirgule fixe 16 bitsFax, contrôle embarqué, téléphones cellulaires
C3x, C4xVirgule flottante 32 bitsVisiophones, traitement parallèle
C6xSelon sous-familleStations de base, hautes performances
C62x, C64xVirgule fixeVidéo, télécom
C67x (dont C6713)Virgule flottanteAudio pro, imagerie médicale
C674xFixe + flottanteFusion C67x et C64x

Tous les C6x partagent la même architecture de base baptisée VelociTI, dérivée du VLIW classique mais modifiée pour autoriser plusieurs paquets d'exécution dans un seul paquet de lecture — souplesse qu'on détaille en §4.6.

Architecture VelociTI - 2 data paths et 8 unités fonctionnelles
Figure 4 — L'architecture VelociTI du C6000 : deux chemins de données symétriques, chacun avec 4 unités fonctionnelles.

Deux chemins de données symétriques

Le CPU se divise en deux moitiés (DP1 et DP2), chacune contenant :

  • 16 registres 32 bits (A0–A15 pour DP1, B0–B15 pour DP2).
  • 4 unités fonctionnelles spécialisées :
    • .L — ALU (arithmétique & logique)
    • .S — Décalages, branchements, manipulation de bits, ALU
    • .M — Multiplication
    • .D — Load/Store : mouvement de données mémoire ↔ registres

Soit 8 unités fonctionnelles au total (L1, S1, M1, D1, L2, S2, M2, D2). Le CPU peut donc lancer jusqu'à 8 instructions en parallèle par cycle.

⚡ La cadence du C6x

Mot d'instruction = 8 × 32 bits = 256 bits par cycle. L'opération signature du DSP, le MAC (Multiply-Accumulate), nécessite trois étapes : .D charge la donnée, .M multiplie, .L additionne — et le C6x peut faire tout cela en un seul cycle grâce aux unités indépendantes. C'est ce qui rend le filtrage RIF temps réel possible.

TMS320C6713 — anatomie complète

Le C6713 est le membre virgule flottante de la famille C67x. C'est lui qu'on programme typiquement dans les TPs.

Architecture interne du DSP C6713
Figure 5 — Block diagram interne du C6713 : CPU au centre, cache L1/L2 à droite, périphériques série/parallèle/temporels à gauche.

Spécifications clés

CaractéristiqueValeur
Fréquence d'horloge300 MHz
Performance entière2400 MIPS (8 instr × 300 MHz)
Performance flottante1800 MFLOPS
Unités fonctionnelles2 ALU fixe (D1, D2), 4 ALU fixe/flot (L1, L2, S1, S2), 2 MUL fixe/flot (M1, M2)
Mémoire interne cache256 KB
Mémoire externe adressable1 GB
Conformité virgule flottanteIEEE 754

Hiérarchie mémoire & cartographie

Cache à deux niveaux

  • L1P — 4 KB, cache programme de niveau 1.
  • L1D — 4 KB, cache données de niveau 1, set-associative à 2 voies.
  • L2 — 256 KB, partagé programme + données, organisé en :
    • 64 KB de cache (divisé en 4 blocs de 16 KB)
    • 192 KB de SRAM

La répartition L2 cache/SRAM est configurable via le registre L2CFG. C'est rare et puissant : tu peux dédier plus de SRAM si tu veux contrôler manuellement le placement, ou plus de cache si tu fais confiance au hardware.

Cartographie mémoire du C6713
Figure 6 — La memory map du C6713 (datasheet TI). Quatre régions principales.

Espace adressable — 4 GB

Le bus d'adresses fait 32 bits, donc 2³² = 4 GB théoriques. Cartographiés ainsi :

PlageRégionTaille
0x0000 0000 → 0x0003 FFFFMémoire interne L2256 KB
0x0004 0000 → 0x7FFF FFFFEspace mixte : registres périphériques (Timer, McBSP, HPI, GPIO…) + zones réservées~2 GB
0x8000 0000 → 0xBFFF FFFFMémoire externe (EMIF), 4 blocs de 256 MB : CE0, CE1, CE2, CE31 GB
0xC000 0000 → 0xFFFF FFFFRéservé1 GB

Les unités fonctionnelles L, S, M, D

Chaque chemin de données contient quatre spécialistes. Voici leur fiche de poste précise :

UnitéEn virgule fixeEn virgule flottante
.L (L1, L2)
Arithmétique & logique
Arithmétique, comparaison, opérations logiques 32/40 bitsConversions INT→SP, INT→DP, DP→SP
.S (S1, S2)
Décalages, branches
Décalages 32/40 bits, branchements, génération de constantes, arithmétique 32 bitsRéciproque, valeur absolue, racine carrée ; conversion SP→DP ; comparaisons, add/sub en SP/DP
.M (M1, M2)
Multiplication
16×16 bits, 32×32 bitsMultiplication SP & DP
.D (D1, D2)
Load/Store & adressage
Génération d'adresse 32 bits (linéaire ou circulaire), load/store avec offset 5 bits (15 bits sur .D2), arithmétique 32 bitsIdem (transferts de réels)
⚠ Contrainte critique

Tous les transferts mémoire (load et store) doivent passer par .D1 ou .D2. C'est la seule porte d'entrée/sortie vers la mémoire. La FPU n'existe pas dans tous les modèles — par exemple le C6211 n'en a pas.

Fetch Packet (FP) & Execute Packet (EP)

VelociTI raffine le VLIW. Avant lui, un mot VLIW était aussi un paquet d'exécution. C'était rigide : si tu ne pouvais pas paralléliser 8 instructions, tu gaspillais des slots avec des NOP.

VelociTI dissocie deux notions :

  • Fetch Packet (FP) — l'unité de lecture mémoire. Toujours 8 instructions de 32 bits = 256 bits.
  • Execute Packet (EP) — un sous-ensemble d'instructions du FP qui s'exécutent réellement en parallèle.

Un FP contient au minimum 1 EP (8 instr en parallèle → cas idéal) et au maximum 8 EP (8 instructions séquentielles, comme si pas de parallélisme).

Le bit P — le marqueur de fin de paquet

Comment le hardware sait-il qu'un EP se termine ? Le LSB de chaque instruction (le bit P, noté ||) le dit :

  • bit P = 1 → l'instruction suivante fait partie du même EP (parallèle).
  • bit P = 0 → l'instruction suivante démarre un nouvel EP (séquentiel).

La dernière instruction d'un FP a toujours bit P = 0 (un EP ne peut pas déborder sur le FP suivant).

⚠ Règle dure

Dans un même EP, chaque instruction doit utiliser une unité fonctionnelle différente. Sinon collision matérielle. C'est au compilateur (ou à toi, en assembleur) de garantir ça.

Exemple FP avec 2 EP
Figure 7 — Un FP de 8 instructions contenant 2 EP : EP1 (ADD, ADD, …) puis EP2 (STW, STW, ADDK, NOP). Les flèches indiquent vers quelle unité chaque instruction est dispatchée.

Le pipeline C6x — Fetch (4), Decode (2), Execute (1 à 10)

On revient au pipeline, mais cette fois à l'échelle du C6x. Au lieu des 3 étages génériques F/D/E, chaque étage est décomposé en sous-phases, pour maximiser le débit.

Étage Fetch — 4 phases

SiglePhaseAction
PGProgram address GenerationLe CPU calcule l'adresse du prochain FP.
PSProgram address SendL'adresse est envoyée vers la mémoire.
PWProgram address WaitAttente que la mémoire ait fini la lecture.
PRProgram Packet ReceiveLe FP arrive au CPU.

Étage Decode — 2 phases

SiglePhaseAction
DPDispatch PhaseChaque instruction de chaque EP est envoyée vers son unité fonctionnelle.
DCDecode PhaseLes opérandes sont décodés (registres sources/destinations).

Étage Execute — 1 à 10 phases

L'exécution se déroule en une phase E1 pour la plupart des instructions en virgule fixe (latence = 1 cycle). Mais certaines opérations sont plus lentes et bloquent leur unité pendant plusieurs phases :

InstructionPhasesDélai (cycles à insérer)
Multiplication (MPY)E1–E21
Load (LDH, LDW)E1–E54
Branch (B)E1–E65

Le nombre total de phases peut donc atteindre 6 en virgule fixe (E1…E6) et 10 en virgule flottante (E1…E10).

Pipeline C6x à virgule fixe
Figure 8 — Au cycle 7, six FP sont simultanément dans le pipeline : E1, DC, DP, PR, PW, PS, PG. C'est ça, « l'effet pipeline ».
⚡ Implication pratique

Quand tu écris en assembleur, tu dois insérer des NOP après les instructions à latence. Par exemple, après un MPY : 1 NOP. Après un LDH : 4 NOP. Après un B : 5 NOP. Sinon, l'instruction suivante essaiera d'utiliser un résultat pas encore disponible — comportement indéfini. Le compilateur C s'en occupe automatiquement, mais en assembleur c'est ta responsabilité.

Registres & chemins croisés (1X, 2X, T1, T2)

32 registres généraux

Deux files de 16 registres 32 bits chacune : A0–A15 pour le chemin A, B0–B15 pour le chemin B. Chaque registre peut servir indifféremment :

  • De donnéeADD .L1 A1, A2, A3 → A3 = A1 + A2
  • De pointeur d'adresseLDW .D1 *A4++, A5 → charge ce que pointe A4 dans A5, puis incrémente A4
  • De condition[B0] B label → branche à label si B0 ≠ 0

Largeurs supportées

Un registre peut traiter des données de plusieurs tailles :

  • 16 bits (SHORT) — paquet d'octets
  • 32 bits (INT ou SP — simple précision flottante)
  • 40 bits (LONG) — usage interne, paires de registres
  • 64 bits (Double LONG ou DP — double précision flottante)

Pour 40 ou 64 bits, on utilise une paire de registres : LSB dans un registre d'index pair, MSB dans l'index impair suivant. Combinaisons valides : A1:A0, A3:A2, A5:A4… et B1:B0, B3:B2, B5:B4… etc.

Usages spéciaux

  • A0, A1 et B0, B1, B2 — peuvent être utilisés comme registres de condition pour les instructions conditionnelles. Exemple : [B1] B .S1 Loop (saute à Loop si B1 ≠ 0).
  • A4–A7 et B4–B7 — utilisés pour l'adressage circulaire.

Chemins croisés 1X et 2X

Chemins croisés 1X et 2X
Figure 9 — Les chemins croisés autorisent une unité d'un côté à lire un registre de l'autre côté.

Par défaut, les unités du chemin A ne peuvent lire que les registres A, et symétriquement pour B. Mais TI a ajouté deux ponts (cross paths) pour souplesse :

  • 1X — autorise L1, S1, M1 à lire les registres B.
  • 2X — autorise L2, S2, M2 à lire les registres A.

Limite : une seule lecture croisée par chemin par cycle (donc 2 instructions en parallèle utilisant les cross paths, maximum).

Exemple : MPY .M1X A5, B5, A5 — le suffixe X signale qu'on traverse le chemin croisé pour lire B5.

Chemins croisés mémoire T1 et T2

Sur le côté mémoire, il existe deux bus d'adresses : DA1 (T1) et DA2 (T2). Cela permet de charger d'un côté tout en stockant de l'autre, dans le même cycle. Exemple :

LDW .D1T1 *A0, B5      ; charge *A0 dans B5 via T1
|| STW .D2T1 A5, *B5   ; stocke A5 à l'adresse pointée par B5 via T1

Registres de contrôle — CSR, PCE1, AMR

À côté des 32 registres généraux, le C6x possède une banque de registres de contrôle qui pilotent le comportement global du processeur. Accès uniquement via l'unité .S2, avec l'instruction spécialisée MVC (Move Control).

PCE1 — Program Counter phase E1

Contient l'adresse du FP actuellement en phase E1 du pipeline. Utile pour le debug et la gestion des exceptions.

MVC .S2 PCE1, A0   ; copie l'adresse courante dans A0

CSR — Control Status Register

Registre 32 bits qui regroupe plusieurs flags critiques :

  • PWRD — Power Down mode
  • SAT — Saturation après opération arithmétique
  • EN — Endianness (Big- ou Little-Endian)
  • PCC / DCC — Program / Data Cache Control
  • GIE / PGIE — Global Interrupt Enable (et son état précédent)
Big-Endian

Le MSB est stocké à l'adresse basse. La valeur 0xAABBCCDD se lit en mémoire comme AA BB CC DD.

Little-Endian

Le LSB est stocké à l'adresse basse. La valeur 0xAABBCCDD se lit en mémoire comme DD CC BB AA.

AMR — Addressing Mode Register

Spécifie pour chacun des registres A4–A7 et B4–B7 s'ils opèrent en mode linéaire ou circulaire, et contient la taille du tampon circulaire (BK) avec la formule : taille = 2^(N+1) octets, N étant codé sur 5 bits → tailles de 2 à 4096 octets. On peut sélectionner deux tailles différentes : BK0 et BK1.

Périphériques & système d'interruptions

Communications & interconnexions

SigleNom completFonction
EMIFExternal Memory InterfacePont vers la mémoire externe (4 zones CE0–CE3).
DMA / EDMA(Enhanced) Direct Memory AccessDéplace des données sans intervention du CPU — opération en arrière-plan.
McBSPMultichannel Buffered Serial PortPort série synchrone full-duplex, double-buffered. Interface directe avec codecs et CAN/CNA.
McASPMultichannel Audio Serial PortVersion audio (I²S et variantes).
HPIHost Port InterfacePort parallèle : un processeur « hôte » peut accéder directement à la mémoire du DSP.
I²CInter-Integrated CircuitBus série standard.
GPIOGeneral Purpose I/OInterface parallèle universelle.

Services système

  • Timers 32 bits — mesure de durée, comptage d'événements, génération d'impulsions et d'interruptions, synchronisation du DMA. Source d'horloge interne (Fosc/4) ou externe via le pin TINP, sortie via TOUT.
  • PLL Controller — synchronise les horloges des périphériques.
  • Power Down — mise hors tension quand le CPU est inactif.
  • Boot Configuration — choix du mode de démarrage (mémoire externe, HPI, etc.).

Le système d'interruptions

Sources et table des interruptions
Figure 10 — 16 sources potentielles, multiplexées vers 12 vecteurs CPU. La table d'ISR commence à l'adresse ISTB ; chaque entrée fait 32 octets (8 instructions, soit un FP entier).

Une interruption force le CPU à abandonner sa tâche pour exécuter une routine appelée ISR (Interrupt Service Routine). Le C6713 propose 16 sources d'interruption : 2 timers, 4 IRQ externes, 4 du McBSP, 4 du DMA. Un sélecteur les multiplexe vers 12 entrées CPU (INT4 à INT15) — plus RESET et NMI.

Chaque interruption a une adresse de vecteur espacée de 0x20 (32 octets, soit un FP) à partir de l'ISTB (Interrupt Service Table Base). Par exemple, INT15 est à ISTB+0x1E0. On y place typiquement un B ISR15 + 5 NOP (à cause du délai de branch), puis la vraie routine se trouve à ISR15.

Chapitre V

Programmation des DSP TMS320C6x

On passe à la pratique. Le C6713 se programme en C, en assembleur, ou en linear assembly (un intermédiaire). Pour exploiter pleinement le parallélisme et le pipeline, comprendre l'assembleur reste indispensable — c'est lui qui te donne la clé sur les unités, les EP et les NOP.

Flot de compilation

Trois portes d'entrée vers le binaire :

  • .c — code C, compilé puis assemblé. Productif, portable, mais le compilateur peut laisser des slots inutilisés.
  • .asm — assembleur natif. Contrôle total, mais tu gères toi-même les latences et les unités.
  • .salinear assembly. Style assembleur mais sans devoir choisir les unités et les latences ; un optimiseur s'en occupe. Souvent le meilleur compromis.

Toutes ces sources convergent vers un fichier exécutable .out.

Modes d'adressage du C6713

Deux familles sur l'architecture C6713 :

Adressage indirect / linéaire

Disponible sur tous les registres. Quatre variantes selon comment le pointeur est mis à jour :

SyntaxeSémantique
*RLe registre R contient l'adresse. Pas de modification.
*R++(d)Post-incrément : on utilise R comme adresse, puis R ← R + d. (d=1 par défaut)
*++R(d)Pré-incrément avec modification : R ← R + d, puis on utilise comme adresse.
*+R(d)Pré-incrément sans modification : on utilise (R + d) comme adresse, mais R reste inchangé.

Adressage circulaire — le killer feature DSP

Disponible seulement sur A4–A7 (via .D1) et B4–B7 (via .D2). Le hardware traite le pointeur modulo une taille de buffer : dès qu'il atteint la fin, il revient automatiquement au début. Zéro test logiciel.

⚡ Cas d'usage : filtre RIF

Un filtre RIF d'ordre 8 nécessite les 8 échantillons les plus récents : x[n], x[n-1], …, x[n-7]. À chaque nouvel échantillon, on doit « décaler » le buffer : copier toutes les valeurs d'une case ? Trop coûteux. La solution : un buffer circulaire où le nouveau pointeur écrit « par-dessus » le plus ancien échantillon, qui devient ainsi le plus récent. Le hardware C6x fait cela en un cycle, sans branch, sans test. C'est cette opération qui rend possible le filtrage temps réel à plusieurs MHz.

Le format des instructions assembleur

Une ligne d'assembleur C6x suit cette structure (jusqu'à 7 champs) :

Label: || [condition] Instruction .Unit Operands ; commentaire
ChampOptionnel ?Rôle
LabelOuiÉtiquette d'adresse symbolique (cible de branchement).
||OuiIndique que l'instruction s'exécute en parallèle avec la précédente (même EP).
[cond]OuiExécution conditionnelle. Registres autorisés : A1, A2, B0, B1, B2. [A2] = si A2≠0 ; [!A2] = si A2=0.
InstructionNonSoit une mnémonique (ADD, MPY…), soit une directive (.word, .data…).
.UnitOuiChoix de l'unité fonctionnelle (.L1, .S2, etc.). Si omis, l'assembleur choisit.
OperandsSelon instr.Registres, constantes, pointeurs.
; commentOuiCommentaire jusqu'en fin de ligne.

Note : l'assembleur C6x n'est pas case-sensitive. ADDaddAdd.

Exemples d'instructions usuelles

Arithmétique
ADD .L1 A1, A2, A3      ; A3 = A1 + A2
SUB .L2 B1, B2, B3      ; B3 = B1 − B2
MPY .M1 A4, A5, A6      ; A6 = A4 × A5 (16×16 bits)
Load / Store
   LDH .D2 *B2++, B7        ; B7 ← mem[B2] (16 bits), B2 ← B2+2
|| LDH .D1 *A2++, A7        ; en parallèle : A7 ← mem[A2], A2++
   STW .D1 A3, *A7           ; mem[A7] ← A3 (32 bits)
   LDW *++A4(20), A1        ; pré-incr de 20 mots (80 bytes), charge A1

LDH charge un half-word (16 bits). LDW charge un mot complet (32 bits) — il occupe simultanément les deux chemins D1 et D2.

Branchement & Move
MV  .L1  A1, A2             ; A2 ← A1 (copie)
MVK .S1  42, A1             ; A1 ← 42 (16 bits bas)
MVKH .S1 0, A1              ; charge les 16 bits hauts (ici 0)
[B1] B .S1 Loop                ; saute à Loop si B1 ≠ 0

Notes : une constante 32 bits ne peut pas être chargée d'un coup ; on utilise MVK (16 bits bas) suivi de MVKH (16 bits hauts).

Exemple complet — programme de produit scalaire

On veut calculer somme = Σ c[i] × x[i] pour i = 0…9, avec deux vecteurs entiers signés. Voici le squelette :

; --- Section données ---
        .data
result: .word 0                    ; mot 32 bits initialisé à 0

; --- Section code ---
        .text
        .global main
main:
        MVK  .S1 42, A1            ; A1 = 42 (LSB)
        MVKH .S1 0,  A1            ; A1 = 0x0000_002A
        MVK  .S2 58, A2
        MVKH .S2 0,  A2            ; A2 = 58

        ADD  .L1 A1, A2, A3        ; A3 = 100

        MVKL .S1 result, A4        ; adresse de 'result' (16 bits bas)
        MVKH .S1 result, A4        ; 16 bits hauts
        STW  .D1 A3, *A4           ; *result = A3

        B    .S2 $                  ; boucle infinie ($ = adresse courante)
        NOP  5                      ; 5 NOP requis après branch
⚠ Les NOP obligatoires

Quand tu écris en assembleur, tu dois compenser les latences explicitement. Récapitulatif des règles pour le C6713 :

  • 1 NOP après une MPY
  • 4 NOP après une LDH ou LDW
  • 5 NOP après une instruction B

À tout instant, jusqu'à 16 instructions successives peuvent occuper les trois étages du pipeline simultanément.

Directives d'assembleur

Les directives ne sont pas des instructions du CPU — elles s'adressent à l'assembleur pour structurer le fichier source.

Sections

DirectiveRôle
.sect "name"Crée une section nommée (données ou code).
.dataSection de données initialisées.
.textSection de code exécutable.
.space NRéserve N octets vides. Ex : buffer .space 128

Symboles

DirectiveRôleAnalogie C
.setDéfinit une valeur constante. count .set 40 remplace count par 40 partout.#define
.defExporte un symbole pour qu'il soit visible des autres fichiers.déclaration globale
.refImporte un symbole défini ailleurs.extern

Initialisation de constantes

DirectiveType
.shortEntier 16 bits
.int / .word / .longEntier 32 bits
.floatRéel 32 bits simple précision IEEE 754
.doubleRéel 64 bits double précision IEEE 754

Le compromis Linear Assembly

Le linear assembly (extension .sa) est un langage intermédiaire :

  • Syntaxe proche de l'assembleur classique.
  • Mais : tu utilises des noms symboliques de variables, pas les registres physiques.
  • Tu ne précises ni les unités fonctionnelles, ni les NOP de latence.
  • Un optimizer fait le placement et la planification.

Tu obtiens un code plus efficace qu'en C, plus rapide à écrire qu'en assembleur. Le meilleur des deux mondes quand tu n'as pas le temps d'optimiser à la main.

Chapitre VI

DSK C6713 — la carte de développement

La théorie incarnée. Le DSK est le kit officiel TI pour mettre les mains dans le silicium. Comprendre ses composants, c'est savoir où plugger un signal et comment le lire après traitement.

La plateforme DSK C6713

Le DSK (DSP Starter Kit) est une carte de développement autonome, bon marché, conçue par TI pour qu'on puisse évaluer et développer rapidement des applications C67xx. C'est la référence matérielle pour le C6713.

Composants principaux

  • DSP TMS320C6713 cadencé à 225 MHz (au lieu de 300 MHz max — pour la robustesse industrielle de la carte).
  • Codec stéréo AIC23 — entrée/sortie audio.
  • 16 MB de DRAM synchrone (mémoire de travail).
  • 512 KB de mémoire FLASH non volatile (256 KB utilisables par défaut).
  • 4 LEDs et 4 commutateurs DIP accessibles par l'utilisateur — typique pour signaler l'état ou changer le mode d'exécution.
  • Configuration logicielle via registres CPLD.
  • Options de boot configurables.
  • Connecteurs d'extension pour cartes filles.
  • Émulateur JTAG embarqué avec interface USB hôte (debug intégré, plus besoin de boîtier externe).

Codec AIC23, McBSP, HPI, EDMA

AIC23 — la passerelle audio

Le codec AIC23 est ce qui permet de faire du DSP utile : il convertit l'audio analogique en numérique (CAN) et inversement (CNA). Il dialogue avec le DSP via le port série McBSP. C'est ce composant qui te donne accès à des entrées Line-in / Mic, et des sorties Line-out / Headphone.

McBSP — le canal série synchrone

Le Multichannel Buffered Serial Port :

  • Full-duplex (lecture et écriture simultanées).
  • Registres de données double-buffered — pendant qu'un échantillon est traité, le suivant est déjà reçu.
  • Horloges et signaux d'encadrage indépendants pour TX et RX.
  • Interface directe avec les codecs et autres composants A/N et N/A connectés en série.

HPI — la porte d'entrée d'un hôte

Le Host Port Interface est un port parallèle qui permet à un processeur hôte (typiquement un microcontrôleur de la carte mère, ou un PC) d'accéder directement à la mémoire du DSP. Pratique pour charger un programme sans passer par JTAG, ou échanger des données à haut débit.

EDMA — la mémoire qui se déplace toute seule

L'Enhanced Direct Memory Access transfère des blocs de données entre régions de la memory map sans intervention du CPU. Tu programmes la source, la destination, la taille — le DMA fait le travail en parallèle. Pendant ce temps, le CPU peut continuer à calculer.

⚡ Le combo gagnant en temps réel

Pour un filtre audio temps réel sur DSK C6713 : l'AIC23 numérise un échantillon → McBSP le pousse en mémoire → EDMA accumule un buffer de N échantillons → quand le buffer est plein, il déclenche une interruption → le CPU lance la routine de filtrage → le résultat repart par le chemin inverse. Le CPU ne touche jamais aux opérations d'I/O. Toute sa puissance reste dédiée au calcul. C'est l'élégance d'une architecture DSP bien conçue.

Annexe

Cheatsheet — à retenir pour l'examen / le TP

Si tu n'as que 5 minutes avant l'épreuve, lis ceci.

Les 10 points qui résument tout

  1. Harvard ≠ Von Neumann : bus séparés programme/données → 2 accès simultanés. Tous les DSP sont en Harvard (modifié).
  2. RISC + VLIW : instructions courtes & uniformes, et un mot d'instruction qui pilote plusieurs unités en parallèle. C'est la combinaison gagnante du C6x.
  3. C6713 = 8 unités fonctionnelles : L1, S1, M1, D1 sur le chemin A ; L2, S2, M2, D2 sur le chemin B. Chacune sa spécialité : L=ALU, S=shift/branch, M=mul, D=load/store.
  4. 32 registres : A0–A15 et B0–B15, 32 bits chacun. Cross paths 1X/2X permettent à une unité de lire un registre de l'autre côté (limité à 1 traversée par chemin par cycle).
  5. Mémoire : L1P 4KB + L1D 4KB + L2 256KB (mixte). Espace adressable 4 GB.
  6. FP & EP : un Fetch Packet = 8 instr × 32 bits = 256 bits ; il contient 1 à 8 Execute Packets. Le bit P (LSB) marque la fin d'un EP.
  7. Pipeline en 3 étages, mais décomposé : Fetch (PG, PS, PW, PR) → Decode (DP, DC) → Execute (E1…E6 fixe, E1…E10 flottant).
  8. NOP obligatoires en assembleur : 1 après MPY, 4 après LDH/LDW, 5 après B.
  9. Adressage circulaire sur A4–A7 et B4–B7 : parfait pour buffers de filtres RIF. Géré en hardware, taille définie par AMR.
  10. Périphériques clés : EMIF (mémoire externe), DMA/EDMA (transferts autonomes), McBSP (série, audio), HPI (accès parallèle hôte), Timers, 16 sources d'interruption multiplexées vers INT4–INT15.
💡 Pour aller plus loin

Si tu veux vraiment internaliser tout ça, un projet de filtrage audio temps réel sur DSK C6713 — par exemple un égaliseur 3 bandes ou un effet d'écho — te forcera à toucher chaque couche : AIC23 → McBSP → buffer circulaire → unité M pour MAC → unité D pour load/store → IRQ. Tu écris d'abord en C, puis tu optimises le hot loop en linear assembly, puis tu compares les performances. C'est exactement ce qu'on demande à un ingénieur embarqué sénior : comprendre la pile entière et savoir où optimiser. À ajouter au portfolio GitHub avec mesures avant/après et oscillogrammes — c'est le genre de projet qui parle aux recruteurs en embedded.