Leçon 15 sur 22

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.1Définition de la synthèseComprendre la chaîne de transformation
15.2VHDL synthétisableSéparer RTL et simulation
15.3Inférence de composantsPrévoir le matériel généré
15.4Latches involontairesDétecter et prévenir les verrous
15.5OptimisationAnalyser surface, vitesse et consommation
TP 11Synthèse et analyse matérielleLire 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ériqueRegistres, additions, comparateurs, multiplexeurs
TechnologiqueLUT, bascules, blocs RAM, DSP, buffers
Post-placementInstances associées à des emplacements physiques
Post-routageConnexions 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 processeurProduit un réseau de ressources
L’ordre temporel est centralLa concurrence est centrale
Une boucle peut réutiliser le processeurUne boucle statique peut dupliquer du matériel
Le temps dépend du nombre d’instructionsLe temps dépend des chemins et de l’horloge
Une variable est un emplacement mémoireUne variable peut devenir logique ou registre selon le contexte

 

15.1.10 Synthèse, placement et routage

Étape

Résultat principal

SynthèseNetlist logique et estimation de ressources
MappingAssociation aux LUT, DSP, BRAM et bascules
PlacementPosition des ressources dans le FPGA
RoutageConnexions physiques
Analyse temporelleMarges, fréquence maximale, violations
Génération du bitstreamFichier 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 concurrentesOpérations de tailles déterminées
if / elsif / elseBranches définissant du matériel fini
caseChoix complets et non chevauchants
for loopBornes statiques connues à l’élaboration
for generateNombre d’instances connu
Processus cadencéForme de front reconnue
Variables localesCalcul fini et déterministe
Fonctions puresCorps synthétisable
TableauxDimensions déterminées pour la cible

 

15.2.2 Instructions réservées à la simulation

Construction

Usage

wait for 10 nsAvance du temps dans un testbench
after 5 nsModèle de délai
STD.ENV.stopArrêt de simulation
report / assertDiagnostic ; certaines assertions peuvent être ignorées en synthèse
TextIOLecture et écriture de fichiers de simulation
nowTemps courant du simulateur
'delayedSignal temporel implicite
transportModè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

AdditionFaible à modéré
MultiplicationDSP ou réseau logique
Division par puissance de deuxDécalage
Division variableCircuit important ou itératif
Modulo puissance de deuxSélection de bits
Exponentiation généraleTrè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

MuxConcurrent, if, case, structurelMultiplexeur/LUT
AdditionOpérateur + ou chaîne d’additionneursAdditionneur
RegistreVecteur ou instances de basculesBascules
CompteurBehavioral ou structurelRegistre + logique
ROMcase ou tableau constantLUT/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

10y devient 0
11y devient 1
00 ou 1y 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

PartageRéduiteMultiplexage et fanout possibles
DuplicationAugmentéeChemins 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

LatenceNombre de cycles entre l’entrée et la sortie correspondante
DébitNombre de résultats acceptés ou produits par unité de temps
PipelineAugmente 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éeLimitée par le cheminFaible
PipelinePlus élevéeÉlevéePlusieurs cycles
Itérative partagéeFaibleHorloge possible élevéeNombreux cycles
Table pré-calculéeMémoireRapideSouvent 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’horlogeEffort sur les chemins critiques
Limite de ressourcesPartage ou simplification
PlacementDélais d’interconnexion
Hiérarchie conservéeOptimisations entre blocs limitées
Attributs DSP/RAMChoix 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 logiquesSurface combinatoire
BasculesStockage et pipeline
DSPMultiplications et calculs spécialisés
BRAMMémoire intégrée
FmaxFréquence maximale estimée
SlackMarge temporelle
Puissance estiméeConsommation 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èseVérifier le sous-ensemble RTL
Utiliser after dans le RTLDélai ignoré ou rejetéCompteur synchrone
Boucle non bornéeMatériel indéterminéFSM ou boucle statique
Affectation combinatoire incomplèteLatchValeur par défaut
Bus surdimensionnéSurface et délais inutilesDimensionner
Ignorer les warningsMatériel inattenduAnalyser chaque avertissement
Comparer sans contraintes identiquesConclusion invalideMê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 logiqueLes bancs de test réussissent
Schémas RTL prochesLes styles décrivent la même fonction
Ressources identiques ou prochesOptimisation équivalente
Différences mineuresDé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é

1x12x12
0xA5x00

 

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

Directe0 cycleAucune pour la fonctionDeux additions en cascade
Pipeline2 cycles jusqu’à y_valideRegistres intermédiairesUne 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 fonctionnelle0 cycle2 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 multiplexeurs2
Analyse des schémas RTL3
Création et identification du latch3
Correction du latch3
Comparaison directe/pipeline4
Analyse des ressources et du timing3
Qualité du rapport2
Total20

 

Synthèse du chapitre

Notion

Résumé

SynthèseTransformation du VHDL RTL en matériel.
ÉlaborationRésolution de la hiérarchie et des génériques.
NetlistListe de composants et connexions.
InférenceReconnaissance d’un motif matériel.
VHDL non synthétisableConstruction utilisée seulement en simulation.
LatchStockage sensible au niveau causé par une affectation incomplète.
Valeur par défautMéthode principale de prévention des latches.
Partage de ressourcesRéutilisation d’un opérateur matériel.
PipelineAjout de registres pour réduire le chemin critique.
SurfaceQuantité de ressources utilisées.
FmaxFré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.