Chapitre 15 — Principes de la synthèse logique
Objectif — Finalité du chapitre Comprendre comment un outil de synthèse transforme une description VHDL en ressources matérielles, identifier les constructions synthétisables, prévenir les latches involontaires et analyser les compromis d’optimisation. |
Objectifs pédagogiques
À la fin de ce chapitre, l’étudiant devra être capable de :
- définir l’élaboration, la synthèse logique et la génération d’une netlist ;
- distinguer simulation, synthèse, placement et routage ;
- identifier les principales constructions VHDL synthétisables ;
- reconnaître les constructions réservées à la simulation ;
- prévoir le composant matériel inféré par une description RTL ;
- identifier l’origine d’un latch involontaire ;
- corriger les affectations et branches incomplètes ;
- lire un schéma RTL et un rapport de ressources ;
- expliquer le partage de ressources et le pipelining ;
- analyser le compromis entre surface, fréquence et consommation ;
- comparer deux architectures VHDL fonctionnellement équivalentes.
Prérequis
- styles de description VHDL ;
- processus combinatoires et cadencés ;
- génériques, generate et hiérarchie ;
- bascules, registres, compteurs et mémoires ;
- bancs de test et simulation RTL.
Organisation du chapitre
Section | Contenu | Compétence principale |
|---|---|---|
| 15.1 | Définition de la synthèse | Comprendre la chaîne de transformation |
| 15.2 | VHDL synthétisable | Séparer RTL et simulation |
| 15.3 | Inférence de composants | Prévoir le matériel généré |
| 15.4 | Latches involontaires | Détecter et prévenir les verrous |
| 15.5 | Optimisation | Analyser surface, vitesse et consommation |
| TP 11 | Synthèse et analyse matérielle | Lire les rapports et schémas RTL |
Concept clé — La synthèse interprète une architecture Le synthétiseur ne traduit pas chaque ligne en une instruction exécutée. Il construit un réseau de ressources matérielles dont le comportement correspond à la description. |
15.1 Définition de la synthèse
La synthèse logique est le processus qui transforme une description matérielle en une représentation structurée composée de portes, multiplexeurs, registres, mémoires et autres ressources compatibles avec la cible.
15.1.1 Transformation du code VHDL en matériel
Description VHDL | Interprétation matérielle possible |
|---|---|
| y <= a and b; | Porte AND ou fonction d’une LUT |
| if sel='0' then y<=a; else y<=b; | Multiplexeur 2 vers 1 |
| if rising_edge(clk) then q<=d; | Bascule D |
| compteur <= compteur + 1; | Registre + incrémenteur |
| memoire(adresse) <= donnee; | Mémoire ou réseau de registres |
15.1.2 Étapes générales
1. Lecture et analyse syntaxique des fichiers.
2. Élaboration des entités, architectures, génériques et instances.
3. Construction d’une représentation RTL interne.
4. Inférence des opérateurs et ressources.
5. Simplification et optimisation logique.
6. Adaptation aux ressources de la technologie cible.
7. Génération d’une netlist et de rapports.
15.1.3 Élaboration du circuit
L’élaboration résout la hiérarchie du projet. Elle sélectionne les architectures, applique les génériques, développe les instructions generate et relie les ports des instances.
| Instance générique élaborée | VHDL |
| U_REG : entity work.registre_n(rtl) generic map ( N => 16 ) port map ( clk => clk, d => donnees, q => sortie ); |
Après élaboration, le composant possède une largeur concrète de 16 bits. Le générique n’est plus une valeur abstraite.
15.1.4 Développement d’un generate
| Chaîne régulière | VHDL |
| GEN_BITS : for i in 0 to N-1 generate begin U_BIT : entity work.cellule(rtl) port map ( entree => a(i), sortie => y(i) ); end generate; |
Le synthétiseur développe N instances distinctes de cellule.
15.1.5 Génération d’une netlist
Une netlist décrit les composants et leurs connexions. Selon l’étape, elle peut être générique ou déjà adaptée aux primitives de la cible.
Netlist | Contenu |
|---|---|
| RTL/générique | Registres, additions, comparateurs, multiplexeurs |
| Technologique | LUT, bascules, blocs RAM, DSP, buffers |
| Post-placement | Instances associées à des emplacements physiques |
| Post-routage | Connexions physiques et délais estimés |
15.1.6 Optimisation logique
- suppression de la logique inutilisée ;
- propagation des constantes ;
- simplification booléenne ;
- partage ou duplication de ressources ;
- réduction des largeurs ;
- utilisation de blocs DSP ou RAM ;
- réorganisation de la logique pour le timing.
15.1.7 Exemple de propagation de constante
| Entrée fixée | VHDL |
| U_BLOC : entity work.fonction(rtl) port map ( enable => '1', a => a, y => y ); |
La logique correspondant au cas enable='0' peut être supprimée, car elle n’est jamais utilisée dans cette instance.
15.1.8 Suppression de logique non observée
| Signal interne sans influence | VHDL |
| signal calcul_inutile : std_logic_vector(7 downto 0); calcul_inutile <= a xor b; y <= a and b; |
Si calcul_inutile ne commande aucune sortie ou ressource conservée, l’outil peut supprimer tout le réseau associé.
15.1.9 Différence entre synthèse et compilation logicielle
Compilation logicielle | Synthèse matérielle |
|---|---|
| Produit des instructions pour un processeur | Produit un réseau de ressources |
| L’ordre temporel est central | La concurrence est centrale |
| Une boucle peut réutiliser le processeur | Une boucle statique peut dupliquer du matériel |
| Le temps dépend du nombre d’instructions | Le temps dépend des chemins et de l’horloge |
| Une variable est un emplacement mémoire | Une variable peut devenir logique ou registre selon le contexte |
15.1.10 Synthèse, placement et routage
Étape | Résultat principal |
|---|---|
| Synthèse | Netlist logique et estimation de ressources |
| Mapping | Association aux LUT, DSP, BRAM et bascules |
| Placement | Position des ressources dans le FPGA |
| Routage | Connexions physiques |
| Analyse temporelle | Marges, fréquence maximale, violations |
| Génération du bitstream | Fichier de configuration de la cible |
Chaîne de conception — Rapport de synthèse Une synthèse réussie ne garantit pas le respect de la fréquence demandée. Le placement-routage et l’analyse temporelle sont nécessaires. |
15.2 VHDL synthétisable et non synthétisable
Le langage VHDL est plus riche que l’ensemble des constructions transformables en matériel. Un testbench peut donc utiliser des éléments interdits ou limités dans le RTL synthétisable.
15.2.1 Instructions généralement synthétisables
Construction | Condition principale |
|---|---|
| Affectations concurrentes | Opérations de tailles déterminées |
| if / elsif / else | Branches définissant du matériel fini |
| case | Choix complets et non chevauchants |
| for loop | Bornes statiques connues à l’élaboration |
| for generate | Nombre d’instances connu |
| Processus cadencé | Forme de front reconnue |
| Variables locales | Calcul fini et déterministe |
| Fonctions pures | Corps synthétisable |
| Tableaux | Dimensions déterminées pour la cible |
15.2.2 Instructions réservées à la simulation
Construction | Usage |
|---|---|
| wait for 10 ns | Avance du temps dans un testbench |
| after 5 ns | Modèle de délai |
| STD.ENV.stop | Arrêt de simulation |
| report / assert | Diagnostic ; certaines assertions peuvent être ignorées en synthèse |
| TextIO | Lecture et écriture de fichiers de simulation |
| now | Temps courant du simulateur |
| 'delayed | Signal temporel implicite |
| transport | Modèle de propagation |
15.2.3 Utilisation limitée de wait
Certains outils acceptent une forme très limitée de wait until pour décrire un processus cadencé, mais cette écriture est moins portable que rising_edge.
| Forme parfois synthétisée | VHDL |
| process begin wait until rising_edge(clk); q <= d; end process; |
| Forme recommandée | VHDL |
| process(clk) begin if rising_edge(clk) then q <= d; end if; end process; |
15.2.4 Wait non synthétisable
| Temporisation de testbench | VHDL |
| wait for 100 ns; enable <= '1'; |
Le matériel n’a pas de notion directe de 100 ns sans horloge ou ressource temporelle. Une temporisation doit être construite avec un compteur.
15.2.5 Gestion des retards
| Délai de simulation | VHDL |
| y <= a after 10 ns; |
| Temporisation matérielle | VHDL |
| if rising_edge(clk) then if compteur = LIMITE then y <= a; compteur <= 0; else compteur <= compteur + 1; end if; end if; |
15.2.6 Boucle synthétisable
| Parité sur largeur fixe | VHDL |
| process(all) variable p : std_logic; begin p := '0'; for i in entree'range loop p := p xor entree(i); end loop; parite <= p; end process; |
La boucle est développée en un réseau XOR. Elle ne s’exécute pas successivement sur un processeur.
15.2.7 Boucle potentiellement non synthétisable
| Nombre d’itérations non borné statiquement | VHDL |
| while condition loop -- Traitement end loop; |
Un while dépendant de données peut exiger un nombre indéterminé d’itérations. Il doit être transformé en machine à états si l’opération s’étend sur plusieurs cycles.
15.2.8 Fichiers et entrées-sorties
Les fichiers TextIO servent surtout aux bancs de test. Une lecture dynamique depuis le système de fichiers n’existe pas comme ressource générique dans un FPGA autonome.
| Lecture de fichier de simulation | VHDL |
| file fichier_stimuli : text open read_mode is "stimuli.txt"; |
Certains outils utilisent cependant un fichier lors de l’élaboration pour initialiser une ROM ou une RAM. Cette possibilité est spécifique au flux d’outils.
15.2.9 Initialisation d’une ROM par constante
| ROM synthétisable | VHDL |
| type rom_t is array (0 to 15) of std_logic_vector(7 downto 0); constant ROM : rom_t := ( x"12", x"34", x"56", x"78", others => x"00" ); data <= ROM(to_integer(unsigned(adresse))); |
15.2.10 Assertions en synthèse
Les assertions sont utiles pour vérifier des paramètres à l’élaboration. Elles peuvent être supprimées du matériel final.
| Validation d’un générique | VHDL |
| assert LARGEUR >= 2 report "LARGEUR doit etre superieure ou egale a 2" severity failure; |
15.2.11 Types et plages
- Utiliser des largeurs explicites et cohérentes.
- Éviter les entiers non bornés lorsqu’une plage précise est connue.
- Choisir unsigned ou signed pour l’arithmétique.
- Vérifier les conversions et redimensionnements.
- Limiter les génériques à des valeurs compatibles avec la cible.
15.2.12 Division et opérations coûteuses
Une opération peut être synthétisable mais très coûteuse. Synthétisable ne signifie pas nécessairement efficace.
Opération | Coût probable |
|---|---|
| Addition | Faible à modéré |
| Multiplication | DSP ou réseau logique |
| Division par puissance de deux | Décalage |
| Division variable | Circuit important ou itératif |
| Modulo puissance de deux | Sélection de bits |
| Exponentiation générale | Très dépendante du cas |
Prudence — Portabilité La prise en charge exacte dépend du standard VHDL, du synthétiseur et de la famille FPGA. Les guides de synthèse de l’outil cible restent la référence pratique. |
15.3 Inférence de composants
L’inférence est la reconnaissance d’un motif VHDL par le synthétiseur, qui le transforme en une ressource matérielle adaptée.
15.3.1 Portes logiques
| Réseau logique | VHDL |
| y <= (a and b) or (not c); |
Sur FPGA, la fonction peut être regroupée dans une ou plusieurs LUT plutôt que dans des portes physiques séparées.
15.3.2 Multiplexeur
| Multiplexeur avec if | VHDL |
| process(all) begin if sel = '0' then y <= a; else y <= b; end if; end process; |
| Multiplexeur avec affectation conditionnelle | VHDL |
| y <= a when sel = '0' else b; |
Les deux formes peuvent produire un réseau équivalent.
15.3.3 Multiplexeur prioritaire
| Chaîne de priorité | VHDL |
| if req0 = '1' then y <= a; elsif req1 = '1' then y <= b; elsif req2 = '1' then y <= c; else y <= d; end if; |
Chaque condition dépend de l’échec des précédentes. Une chaîne profonde peut allonger le chemin critique.
15.3.4 Bascule D
| Inférence d’une bascule | VHDL |
| process(clk) begin if rising_edge(clk) then q <= d; end if; end process; |
15.3.5 Bascule avec enable et reset
| Registre contrôlé | VHDL |
| process(clk, reset) begin if reset = '1' then q <= (others => '0'); elsif rising_edge(clk) then if enable = '1' then q <= d; end if; end if; end process; |
Le synthétiseur peut utiliser les entrées reset et clock enable intégrées aux bascules du FPGA.
15.3.6 Registre
| Registre N bits | VHDL |
| process(clk) begin if rising_edge(clk) then q <= d; end if; end process; |
La largeur de q détermine le nombre de bits de stockage, sauf optimisation de bits constants ou inutilisés.
15.3.7 Compteur
| Compteur ascendant | VHDL |
| process(clk, reset) begin if reset = '1' then compteur <= (others => '0'); elsif rising_edge(clk) then compteur <= compteur + 1; end if; end process; |
Le matériel comprend des bascules et un incrémenteur utilisant souvent les chaînes de retenue dédiées.
15.3.8 Additionneur
| Addition avec retenue | VHDL |
| resultat <= resize(a, resultat'length) + resize(b, resultat'length); |
Les FPGA disposent généralement de chemins de retenue rapides pour les additions.
15.3.9 Multiplicateur
| Produit | VHDL |
| produit <= a * b; |
Selon les largeurs et options, l’outil peut utiliser un bloc DSP, des LUT ou une architecture optimisée.
15.3.10 Mémoire asynchrone en lecture
| RAM simple — Déclarations | VHDL |
| type ram_t is array (0 to 255) of std_logic_vector(7 downto 0); signal ram : ram_t; |
| RAM simple — Écriture et lecture | VHDL |
| process(clk) begin if rising_edge(clk) then if we = '1' then ram(to_integer(unsigned(adresse))) <= data_in; end if; end if; end process; data_out <= ram(to_integer(unsigned(adresse))); |
La lecture asynchrone peut empêcher l’utilisation de certains blocs RAM synchrones selon la famille FPGA.
15.3.11 Mémoire synchrone
| Lecture et écriture synchrones | VHDL |
| process(clk) begin if rising_edge(clk) then if we = '1' then ram(to_integer(unsigned(adresse))) <= data_in; end if; data_out <= ram( to_integer(unsigned(adresse)) ); end if; end process; |
Cette forme correspond souvent mieux aux blocs RAM intégrés.
15.3.12 Registre à décalage
| Décalage | VHDL |
| process(clk) begin if rising_edge(clk) then q <= q(q'high-1 downto 0) & entree_serie; end if; end process; |
Un long registre à décalage peut être implémenté avec des bascules, des LUT configurées en SRL ou une mémoire, selon l’outil.
15.3.13 Comparateur
| Comparaison non signée | VHDL |
| inferieur <= '1' when unsigned(a) < unsigned(b) else '0'; |
15.3.14 Décodage et tables
| Décodeur | VHDL |
| with code select y <= "0001" when "00", "0010" when "01", "0100" when "10", "1000" when others; |
Le résultat peut être une LUT ou un réseau de décodage optimisé.
15.3.15 Influence du style
Fonction | Styles possibles | Matériel attendu |
|---|---|---|
| Mux | Concurrent, if, case, structurel | Multiplexeur/LUT |
| Addition | Opérateur + ou chaîne d’additionneurs | Additionneur |
| Registre | Vecteur ou instances de bascules | Bascules |
| Compteur | Behavioral ou structurel | Registre + logique |
| ROM | case ou tableau constant | LUT/ROM |
Choix du style — Ne pas surcontraindre la structure Une description trop structurelle peut limiter certaines optimisations. Une description RTL claire laisse souvent l’outil exploiter les ressources spécialisées. |
15.4 Inférence involontaire de verrous
Un latch, ou verrou sensible au niveau, est inféré lorsqu’un processus combinatoire doit conserver une ancienne valeur parce qu’une sortie n’est pas affectée dans tous les cas.
15.4.1 Origine d’un latch
| Affectation incomplète | VHDL |
| process(all) begin if enable = '1' then y <= a; end if; end process; |
Lorsque enable vaut 0, aucune nouvelle valeur n’est définie pour y. Pour respecter cette conservation, le synthétiseur doit créer un latch.
15.4.2 Comportement du latch
enable | Entrée a | Sortie y |
|---|---|---|
| 1 | 0 | y devient 0 |
| 1 | 1 | y devient 1 |
| 0 | 0 ou 1 | y conserve sa valeur précédente |
15.4.3 Branche else manquante
| Latch involontaire | VHDL |
| if selection = '1' then sortie <= entree_1; end if; |
| Multiplexeur combinatoire corrigé | VHDL |
| if selection = '1' then sortie <= entree_1; else sortie <= entree_0; end if; |
15.4.4 Case incomplet
| Choix partiel | VHDL |
| case sel is when "00" => y <= a; when "01" => y <= b; when others => null; end case; |
La branche others ne définit pas y. Elle demande implicitement de conserver la valeur précédente.
15.4.5 Valeur par défaut
| Prévention par défaut | VHDL |
| process(all) begin y <= d; if req0 = '1' then y <= a; elsif req1 = '1' then y <= b; elsif req2 = '1' then y <= c; end if; end process; |
La première affectation garantit une valeur pour tous les chemins.
15.4.6 Plusieurs sorties
| Une sortie oubliée | VHDL |
| process(all) begin valide <= '0'; if enable = '1' then y <= a; valide <= '1'; else y <= b; end if; end process; |
Dans cette version, y et valide sont affectés dans tous les chemins. Sans la valeur par défaut de valide, un latch serait inféré pour cette sortie.
15.4.7 Affectations partielles d’un vecteur
| Bits non définis | VHDL |
| process(all) begin y(3 downto 2) <= a; if enable = '1' then y(1 downto 0) <= b; end if; end process; |
Les deux bits de poids faible nécessitent une conservation lorsque enable vaut 0.
15.4.8 Correction d’un vecteur
| Valeur complète par défaut | VHDL |
| process(all) begin y <= (others => '0'); y(3 downto 2) <= a; if enable = '1' then y(1 downto 0) <= b; end if; end process; |
15.4.9 Variable incomplète
| Variable utilisée sans initialisation de tous les chemins | VHDL |
| process(all) variable temp : std_logic; begin if enable = '1' then temp := a; end if; y <= temp; end process; |
temp doit conserver une ancienne valeur lorsque enable vaut 0, ce qui conduit également à du stockage.
15.4.10 Correction avec variable
| Initialisation locale | VHDL |
| process(all) variable temp : std_logic; begin temp := '0'; if enable = '1' then temp := a; end if; y <= temp; end process; |
15.4.11 Latch volontaire
Un latch peut être intentionnel dans certaines architectures, mais il doit être clairement spécifié et supporté par le flux de conception.
| Latch actif au niveau haut | VHDL |
| process(enable, d) begin if enable = '1' then q <= d; end if; end process; |
Attention — FPGA et latches Les FPGA sont principalement optimisés pour les bascules déclenchées sur front. Les latches peuvent compliquer le timing et la vérification. Ils sont généralement évités dans un cours RTL synchrone. |
15.4.12 Latch et processus cadencé
L’absence d’affectation dans une branche d’un processus cadencé ne crée pas un latch. Elle signifie que le registre conserve sa valeur.
| Maintien normal d’un registre | VHDL |
| process(clk) begin if rising_edge(clk) then if enable = '1' then q <= d; end if; end if; end process; |
Le matériel attendu est une bascule avec enable, pas un latch.
15.4.13 Détection dans les rapports
- avertissement « latch inferred » ;
- schéma RTL montrant un verrou ;
- nombre de latches dans le rapport de ressources ;
- chemins temporels sensibles à un niveau ;
- simulation différente de l’intention combinatoire.
15.4.14 Méthodes de prévention
1. Utiliser process(all) pour la sensibilité.
2. Affecter chaque sortie dans tous les chemins.
3. Donner une valeur par défaut au début du processus.
4. Couvrir toutes les branches case.
5. Initialiser les variables avant leur utilisation.
6. Examiner les avertissements de synthèse.
7. Vérifier le schéma RTL.
15.4.15 Checklist combinatoire
Question | Réponse attendue |
|---|---|
| Chaque sortie reçoit-elle une valeur par défaut ? | Oui |
| Chaque if possède-t-il un else utile ou une valeur par défaut ? | Oui |
| Chaque case couvre-t-il tous les choix ? | Oui |
| Chaque variable est-elle initialisée ? | Oui |
| Une conservation de valeur est-elle réellement voulue ? | Non, sauf latch intentionnel |
15.5 Optimisation
L’optimisation vise à obtenir une architecture respectant les contraintes de surface, de fréquence et de consommation. Une amélioration d’un critère peut dégrader les autres.
15.5.1 Partage de ressources
Deux opérations mutuellement exclusives peuvent parfois partager le même opérateur.
| Opérateur sélectionné | VHDL |
| process(all) begin if mode = '0' then resultat <= a + b; else resultat <= c + d; end if; end process; |
L’outil peut créer un additionneur partagé avec des multiplexeurs d’entrée, ou deux additionneurs, selon les contraintes et optimisations.
15.5.2 Duplication de ressources
Pour augmenter la fréquence ou réduire la congestion, l’outil peut dupliquer une logique utilisée par plusieurs destinations.
Stratégie | Surface | Vitesse |
|---|---|---|
| Partage | Réduite | Multiplexage et fanout possibles |
| Duplication | Augmentée | Chemins locaux plus courts |
15.5.3 Réduction de la largeur
| Compteur surdimensionné | VHDL |
| signal compteur : unsigned(31 downto 0); |
| Compteur dimensionné | VHDL |
| signal compteur : unsigned(9 downto 0); -- Suffisant pour 0 à 999 |
Réduire la largeur diminue le nombre de bascules et la taille des opérateurs.
15.5.4 Suppression des bits inutilisés
Le synthétiseur peut supprimer les bits qui n’influencent aucune sortie, mais une largeur correcte améliore la lisibilité et les estimations.
15.5.5 Pipelining
Le pipelining ajoute des registres entre des étapes combinatoires afin de réduire le chemin critique.
| Calcul combinatoire long | VHDL |
| y <= (a * b) + (c * d); |
| Pipeline en deux étapes | VHDL |
| process(clk) begin if rising_edge(clk) then produit_1 <= a * b; produit_2 <= c * d; y <= produit_1 + produit_2; end if; end process; |
La latence augmente, mais la fréquence maximale peut s’améliorer.
15.5.6 Latence et débit
Notion | Définition |
|---|---|
| Latence | Nombre de cycles entre l’entrée et la sortie correspondante |
| Débit | Nombre de résultats acceptés ou produits par unité de temps |
| Pipeline | Augmente souvent la latence mais permet un résultat par cycle après remplissage |
15.5.7 Optimisation de la fréquence
- réduire les chaînes de priorité ;
- insérer des registres de pipeline ;
- utiliser les ressources DSP ;
- limiter le fanout ;
- simplifier les conversions ;
- éviter les opérateurs combinatoires très larges ;
- définir des contraintes réalistes.
15.5.8 Réduction de surface
- réutiliser les opérateurs sur plusieurs cycles ;
- dimensionner précisément les bus ;
- utiliser une mémoire plutôt que de nombreux registres ;
- éviter les duplications inutiles ;
- utiliser des algorithmes itératifs ;
- supprimer les fonctions non nécessaires.
15.5.9 Réduction de consommation
- utiliser clock enable pour éviter les commutations inutiles ;
- réduire la fréquence lorsque possible ;
- limiter les changements de grandes capacités ;
- réduire la largeur et l’activité des bus ;
- utiliser des ressources spécialisées efficaces.
15.5.10 Compromis surface/vitesse
Architecture | Surface | Fréquence | Latence |
|---|---|---|---|
| Combinatoire parallèle | Élevée | Limitée par le chemin | Faible |
| Pipeline | Plus élevée | Élevée | Plusieurs cycles |
| Itérative partagée | Faible | Horloge possible élevée | Nombreux cycles |
| Table pré-calculée | Mémoire | Rapide | Souvent un cycle |
15.5.11 Contraintes d’optimisation
L’outil arbitre selon la cible, les contraintes temporelles, les options de stratégie et les attributs de synthèse.
Contrainte | Influence |
|---|---|
| Période d’horloge | Effort sur les chemins critiques |
| Limite de ressources | Partage ou simplification |
| Placement | Délais d’interconnexion |
| Hiérarchie conservée | Optimisations entre blocs limitées |
| Attributs DSP/RAM | Choix de ressources spécialisées |
15.5.12 Comparaison de deux architectures
| Architecture A — Opérateur direct | VHDL |
| resultat <= resize(a, 9) + resize(b, 9) + resize(c, 9); |
| Architecture B — Deux étages enregistrés | VHDL |
| process(clk) begin if rising_edge(clk) then somme_ab <= resize(a, 9) + resize(b, 9); resultat <= somme_ab + resize(c, 9); end if; end process; |
La seconde architecture possède une latence et des registres supplémentaires, mais peut atteindre une fréquence plus élevée.
15.5.13 Mesures à comparer
Indicateur | Interprétation |
|---|---|
| LUT / cellules logiques | Surface combinatoire |
| Bascules | Stockage et pipeline |
| DSP | Multiplications et calculs spécialisés |
| BRAM | Mémoire intégrée |
| Fmax | Fréquence maximale estimée |
| Slack | Marge temporelle |
| Puissance estimée | Consommation statique et dynamique |
Méthode — Mesurer plutôt que supposer Deux descriptions similaires peuvent être optimisées différemment selon l’outil et la cible. La comparaison doit utiliser les mêmes contraintes et options. |
Méthode d’analyse d’une synthèse
1. Simuler le circuit et valider sa fonction.
2. Lancer la synthèse avec la bonne entité supérieure.
3. Lire tous les avertissements.
4. Vérifier les ressources inférées.
5. Examiner le schéma RTL.
6. Identifier les latches et signaux supprimés.
7. Comparer les ressources spécialisées attendues.
8. Contrôler les largeurs et conversions.
9. Appliquer les contraintes temporelles.
10. Comparer plusieurs architectures avec les mêmes paramètres.
Checklist avant implantation
- Aucun latch involontaire n’est-il signalé ?
- Les mémoires sont-elles inférées comme prévu ?
- Les multiplications utilisent-elles les DSP souhaités ?
- Les compteurs sont-ils correctement dimensionnés ?
- La logique inutilisée a-t-elle été supprimée volontairement ?
- Les horloges et resets utilisent-ils les ressources dédiées ?
- Les contraintes temporelles sont-elles définies ?
- Le schéma RTL correspond-il à l’architecture attendue ?
Erreurs fréquentes
Erreur | Conséquence | Correction |
|---|---|---|
| Supposer qu’un code simulé est synthétisable | Échec de synthèse | Vérifier le sous-ensemble RTL |
| Utiliser after dans le RTL | Délai ignoré ou rejeté | Compteur synchrone |
| Boucle non bornée | Matériel indéterminé | FSM ou boucle statique |
| Affectation combinatoire incomplète | Latch | Valeur par défaut |
| Bus surdimensionné | Surface et délais inutiles | Dimensionner |
| Ignorer les warnings | Matériel inattendu | Analyser chaque avertissement |
| Comparer sans contraintes identiques | Conclusion invalide | Même cible et mêmes options |
Travaux pratiques
TP 11 — Synthèse et analyse du matériel
1. Objectifs du TP
- synthétiser un multiplexeur ;
- observer le schéma RTL ;
- analyser les ressources utilisées ;
- créer volontairement un latch ;
- corriger la description ;
- comparer deux architectures VHDL ;
- interpréter les messages et rapports de synthèse.
2. Organisation du projet
| Arborescence proposée | Arborescence |
| tp11_synthese/ ├── src/ │ ├── mux4_concurrent.vhd │ ├── mux4_process.vhd │ ├── latch_involontaire.vhd │ ├── latch_corrige.vhd │ ├── somme_directe.vhd │ └── somme_pipeline.vhd ├── sim/ │ ├── tb_mux4.vhd │ ├── tb_latch.vhd │ └── tb_sommes.vhd └── constraints/ └── horloge.xdc_ou_sdc |
3. Partie A — Multiplexeur concurrent
| mux4_concurrent.vhd — Entité | VHDL |
| library IEEE; use IEEE.STD_LOGIC_1164.ALL; entity mux4_concurrent is port ( a, b, c, d : in std_logic_vector(7 downto 0); sel : in std_logic_vector(1 downto 0); y : out std_logic_vector(7 downto 0) ); end entity mux4_concurrent; |
| mux4_concurrent.vhd — Architecture | VHDL |
| architecture rtl of mux4_concurrent is begin with sel select y <= a when "00", b when "01", c when "10", d when others; end architecture rtl; |
4. Partie B — Multiplexeur avec processus
| mux4_process.vhd | VHDL |
| library IEEE; use IEEE.STD_LOGIC_1164.ALL; entity mux4_process is port ( a, b, c, d : in std_logic_vector(7 downto 0); sel : in std_logic_vector(1 downto 0); y : out std_logic_vector(7 downto 0) ); end entity mux4_process; architecture rtl of mux4_process is begin process(all) begin case sel is when "00" => y <= a; when "01" => y <= b; when "10" => y <= c; when others => y <= d; end case; end process; end architecture rtl; |
5. Simulation préalable
| Banc de test commun | VHDL |
| for i in 0 to 3 loop sel <= std_logic_vector(to_unsigned(i, 2)); wait for 1 ns; assert y_concurrent = y_process report "Les architectures divergent" severity error; end loop; |
6. Synthèse du multiplexeur
1. Définir mux4_concurrent comme entité supérieure.
2. Lancer l’analyse et la synthèse.
3. Ouvrir le schéma RTL.
4. Relever le nombre de LUT ou cellules logiques.
5. Répéter avec mux4_process.
6. Comparer les deux résultats.
7. Résultat attendu
Observation | Interprétation |
|---|---|
| Même comportement logique | Les bancs de test réussissent |
| Schémas RTL proches | Les styles décrivent la même fonction |
| Ressources identiques ou proches | Optimisation équivalente |
| Différences mineures | Dépendance aux options et à la cible |
8. Partie C — Création volontaire d’un latch
| latch_involontaire.vhd | VHDL |
| library IEEE; use IEEE.STD_LOGIC_1164.ALL; entity latch_involontaire is port ( a : in std_logic_vector(7 downto 0); enable : in std_logic; y : out std_logic_vector(7 downto 0) ); end entity latch_involontaire; architecture rtl of latch_involontaire is begin process(all) begin if enable = '1' then y <= a; end if; end process; end architecture rtl; |
9. Analyse du latch
- Lancer la synthèse.
- Rechercher l’avertissement relatif au latch.
- Ouvrir le schéma RTL.
- Vérifier que y doit conserver sa valeur lorsque enable=0.
- Noter le nombre de latches ou cellules associées.
10. Banc de test du comportement mémoire
| Scénario | VHDL |
| a <= x"12"; enable <= '1'; wait for 1 ns; assert y = x"12" severity error; enable <= '0'; a <= x"A5"; wait for 1 ns; assert y = x"12" report "Le latch doit conserver la valeur" severity error; |
11. Correction combinatoire
| latch_corrige.vhd | VHDL |
| library IEEE; use IEEE.STD_LOGIC_1164.ALL; entity latch_corrige is port ( a : in std_logic_vector(7 downto 0); enable : in std_logic; y : out std_logic_vector(7 downto 0) ); end entity latch_corrige; architecture rtl of latch_corrige is begin process(all) begin y <= (others => '0'); if enable = '1' then y <= a; end if; end process; end architecture rtl; |
12. Vérification de la correction
enable | a | y corrigé |
|---|---|---|
| 1 | x12 | x12 |
| 0 | xA5 | x00 |
Après synthèse, aucun latch ne doit être nécessaire. Le schéma doit montrer un multiplexeur entre zéro et a.
13. Partie D — Comparaison de deux architectures arithmétiques
| somme_directe.vhd | VHDL |
| library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; entity somme_directe is port ( a, b, c : in unsigned(15 downto 0); y : out unsigned(17 downto 0) ); end entity somme_directe; architecture rtl of somme_directe is begin y <= resize(a, 18) + resize(b, 18) + resize(c, 18); end architecture rtl; |
| somme_pipeline.vhd — Entité | VHDL |
| library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; entity somme_pipeline is port ( clk : in std_logic; reset : in std_logic; valide : in std_logic; a, b, c : in unsigned(15 downto 0); y : out unsigned(17 downto 0); y_valide: out std_logic ); end entity somme_pipeline; |
| somme_pipeline.vhd — Architecture | VHDL |
| architecture rtl of somme_pipeline is signal somme_ab : unsigned(16 downto 0); signal c_retard : unsigned(15 downto 0); signal valide_1 : std_logic; begin process(clk, reset) begin if reset = '1' then somme_ab <= (others => '0'); c_retard <= (others => '0'); valide_1 <= '0'; y <= (others => '0'); y_valide <= '0'; elsif rising_edge(clk) then somme_ab <= resize(a, 17) + resize(b, 17); c_retard <= c; valide_1 <= valide; y <= resize(somme_ab, 18) + resize(c_retard, 18); y_valide <= valide_1; end if; end process; end architecture rtl; |
14. Interprétation du pipeline
Architecture | Latence | Bascules | Chemin combinatoire |
|---|---|---|---|
| Directe | 0 cycle | Aucune pour la fonction | Deux additions en cascade |
| Pipeline | 2 cycles jusqu’à y_valide | Registres intermédiaires | Une addition principale par étage |
15. Banc de test des sommes
| Vérification de la version directe | VHDL |
| a <= to_unsigned(100, 16); b <= to_unsigned(200, 16); c <= to_unsigned(300, 16); wait for 1 ns; assert y_directe = to_unsigned(600, 18) severity error; |
| Vérification de la version pipeline | VHDL |
| valide <= '1'; a <= to_unsigned(100, 16); b <= to_unsigned(200, 16); c <= to_unsigned(300, 16); wait until rising_edge(clk); valide <= '0'; wait until rising_edge(clk); wait for 1 ns; assert y_valide = '1' and y_pipeline = to_unsigned(600, 18) report "Pipeline incorrect" severity error; |
16. Contraintes temporelles
| Exemple de contrainte d’horloge | Contraintes |
| create_clock -period 10.000 -name clk [get_ports clk] |
Une période de 10 ns correspond à une fréquence demandée de 100 MHz.
17. Mesures à relever
Mesure | Directe | Pipeline |
|---|---|---|
| LUT / cellules logiques | ||
| Bascules | ||
| DSP éventuels | ||
| Fréquence maximale | ||
| Slack à 100 MHz | ||
| Latence fonctionnelle | 0 cycle | 2 cycles |
18. Analyse des schémas RTL
- Identifier les multiplexeurs du mux4.
- Identifier les latches de la version volontairement incomplète.
- Vérifier leur disparition après correction.
- Repérer la chaîne d’addition dans somme_directe.
- Repérer les registres de pipeline.
- Comparer les chemins entre entrées et sorties.
19. Questions d’analyse
1. Quelle différence existe entre élaboration et synthèse ?
2. Pourquoi deux styles de multiplexeur peuvent-ils produire le même matériel ?
3. Pourquoi la branche manquante infère-t-elle un latch ?
4. Pourquoi l’absence d’affectation dans un processus cadencé est-elle différente ?
5. Quel matériel remplace le latch après la valeur par défaut ?
6. Pourquoi somme_pipeline utilise-t-elle davantage de bascules ?
7. Pourquoi sa fréquence maximale peut-elle être supérieure ?
8. Quelle différence existe entre latence et débit ?
9. Pourquoi faut-il utiliser les mêmes contraintes pour comparer ?
10. Une simulation réussie garantit-elle le respect temporel ?
20. Extensions proposées
- Comparer un additionneur direct et un additionneur structurel.
- Tester une multiplication avec et sans bloc DSP.
- Comparer une ROM écrite par case et par tableau constant.
- Étudier une RAM à lecture synchrone et asynchrone.
- Ajouter un troisième étage de pipeline.
- Comparer plusieurs largeurs de bus.
- Étudier l’effet d’une contrainte de 200 MHz.
- Créer volontairement un latch sur un seul bit d’un vecteur.
21. Barème indicatif
Critère | Points |
|---|---|
| Synthèse des deux multiplexeurs | 2 |
| Analyse des schémas RTL | 3 |
| Création et identification du latch | 3 |
| Correction du latch | 3 |
| Comparaison directe/pipeline | 4 |
| Analyse des ressources et du timing | 3 |
| Qualité du rapport | 2 |
| Total | 20 |
Synthèse du chapitre
Notion | Résumé |
|---|---|
| Synthèse | Transformation du VHDL RTL en matériel. |
| Élaboration | Résolution de la hiérarchie et des génériques. |
| Netlist | Liste de composants et connexions. |
| Inférence | Reconnaissance d’un motif matériel. |
| VHDL non synthétisable | Construction utilisée seulement en simulation. |
| Latch | Stockage sensible au niveau causé par une affectation incomplète. |
| Valeur par défaut | Méthode principale de prévention des latches. |
| Partage de ressources | Réutilisation d’un opérateur matériel. |
| Pipeline | Ajout de registres pour réduire le chemin critique. |
| Surface | Quantité de ressources utilisées. |
| Fmax | Fréquence maximale estimée. |
| Compromis | Équilibre surface, vitesse, latence et consommation. |
Autoévaluation
1. Que produit la synthèse ?
Réponse : Une netlist de ressources matérielles.
2. Que fait l’élaboration ?
Réponse : Elle résout les instances, génériques et generate.
3. after est-il destiné au RTL synthétisable ?
Réponse : Non, il modélise surtout un délai de simulation.
4. Quelle forme infère une bascule ?
Réponse : Un processus avec rising_edge.
5. Quelle erreur crée un latch combinatoire ?
Réponse : Une sortie non affectée dans tous les chemins.
6. Comment prévenir un latch ?
Réponse : Avec des affectations complètes ou des valeurs par défaut.
7. Une opération synthétisable est-elle toujours économique ?
Réponse : Non.
8. Que fait le pipeline ?
Réponse : Il découpe le chemin combinatoire avec des registres.
9. Que peut améliorer le pipeline ?
Réponse : La fréquence maximale et le débit.
10. Quels rapports faut-il consulter ?
Réponse : Ressources, schéma RTL, timing et avertissements.
Exercice de consolidation
Identifier le matériel inféré par le processus suivant, expliquer le problème éventuel et proposer une correction combinatoire.
| Énoncé | VHDL |
| process(all) begin if mode = "00" then y <= a; elsif mode = "01" then y <= b; elsif mode = "10" then y <= c; end if; end process; |
| Correction | VHDL |
| process(all) begin y <= d; if mode = "00" then y <= a; elsif mode = "01" then y <= b; elsif mode = "10" then y <= c; end if; end process; |
La première version infère un latch pour conserver y lorsque mode=11. La correction décrit un multiplexeur à quatre choix.
Suite du cours — Transition vers la suite Après les principes de synthèse, le cours peut aborder l’implantation sur FPGA, les contraintes de broches et d’horloge, le placement-routage et la génération du bitstream. |