Chapitre 9 — Génériques, composants réutilisables et hiérarchie
Objectif — Finalité du chapitre Concevoir des blocs VHDL paramétrables et réutilisables, maîtriser le passage des génériques, générer des structures matérielles régulières et organiser un projet en composants hiérarchiques validés séparément. |
Objectifs pédagogiques
À la fin de ce chapitre, l’étudiant devra être capable de :
- expliquer le principe de généricité en VHDL ;
- déclarer des génériques de types integer, positive, boolean et time ;
- définir une valeur par défaut ;
- utiliser generic map lors d’une instanciation ;
- distinguer association par position et association par nom ;
- utiliser for generate pour répéter une structure ;
- utiliser if generate pour inclure conditionnellement du matériel ;
- identifier les conditions statiques requises lors de l’élaboration ;
- construire une hiérarchie à partir de composants réutilisables ;
- organiser une bibliothèque de blocs validés ;
- développer un additionneur, un registre et un multiplexeur paramétrables ;
- comparer plusieurs valeurs du générique N en simulation et en synthèse.
Prérequis
- entités, architectures et instanciation directe ;
- styles structurel, comportemental et par flot de données ;
- types std_logic_vector, unsigned et positive ;
- processus cadencés et logique combinatoire ;
- additionneurs complets et propagation de retenue.
Organisation du chapitre
Section | Contenu | Compétence principale |
|---|---|---|
| 9.1 | Notion de généricité | Paramétrer la taille et le comportement |
| 9.2 | Déclaration des génériques | Écrire une interface configurable |
| 9.3 | Passage des paramètres | Configurer une instance avec generic map |
| 9.4 | Génération de matériel | Créer des structures répétitives ou conditionnelles |
| 9.5 | Réutilisation et hiérarchie | Organiser, maintenir et valider les blocs |
| TP 6 | Composants paramétrables | Développer et comparer plusieurs configurations |
Concept clé — Moment de la configuration La valeur d’un générique est fixée lors de l’élaboration, avant la simulation du circuit et avant la synthèse. Elle configure la structure matérielle ; elle ne se modifie pas dynamiquement pendant le fonctionnement. |
9.1 Notion de généricité
La généricité permet de décrire une famille de composants à partir d’un seul code source. Les différences entre les membres de la famille sont exprimées par des paramètres appelés génériques.
9.1.1 Pourquoi paramétrer un composant ?
- éviter de dupliquer le même code pour 4, 8, 16 ou 32 bits ;
- adapter un composant à plusieurs projets ;
- centraliser les corrections et améliorations ;
- rendre l’intention de dimensionnement explicite ;
- faciliter les tests automatiques sur plusieurs configurations ;
- constituer une bibliothèque de blocs génériques.
9.1.2 Composant fixe et composant générique
| Registre fixé à 8 bits | VHDL |
| entity registre_8bits is port ( clk : in std_logic; d : in std_logic_vector(7 downto 0); q : out std_logic_vector(7 downto 0) ); end entity registre_8bits; |
| Registre générique | VHDL |
| entity registre_nbits is generic ( N : positive := 8 ); port ( clk : in std_logic; d : in std_logic_vector(N-1 downto 0); q : out std_logic_vector(N-1 downto 0) ); end entity registre_nbits; |
La même entité peut être élaborée avec N = 4, 8, 16 ou toute autre valeur positive compatible avec les contraintes du projet.
9.1.3 Paramétrage de la taille d’un vecteur
| Largeur définie par N | VHDL |
| generic ( N : positive := 8 ); port ( entree : in std_logic_vector(N-1 downto 0); sortie : out std_logic_vector(N-1 downto 0) ); |
Repère — Pourquoi N-1 downto 0 ? Un vecteur de N bits possède N indices. Avec la convention descendante courante, les indices vont de N-1 à 0. |
9.1.4 Paramétrage du comportement
Un générique ne sert pas uniquement à définir une largeur. Il peut activer une option, choisir une polarité, fixer un nombre d’étages ou définir une durée de simulation.
| Génériques de différents types | VHDL |
| generic ( N : positive := 8; RESET_ACTIF_HAUT: boolean := true; VALEUR_INITIALE : std_logic := '0'; PERIODE_SIM : time := 10 ns ); |
9.1.5 Valeurs par défaut
Une valeur par défaut rend le générique facultatif lors de l’instanciation. Si generic map est absent ou ne mentionne pas ce paramètre, la valeur par défaut est utilisée.
| Valeur par défaut de 8 bits | VHDL |
| generic ( N : positive := 8 ); |
| Instance utilisant la valeur par défaut | VHDL |
| U_REG : entity work.registre_nbits(rtl) port map ( clk => clk, d => d8, q => q8 ); |
9.1.6 Contraindre les valeurs
Le type du générique limite les valeurs autorisées. positive interdit zéro et les valeurs négatives, ce qui évite des plages de vecteurs invalides.
Déclaration | Valeurs autorisées | Usage |
|---|---|---|
| N : positive := 8 | 1, 2, 3, ... | Largeur, nombre d’étages |
| M : natural := 0 | 0, 1, 2, ... | Nombre pouvant être nul |
| MODE : boolean := false | true ou false | Activer une option |
| MAXIMUM : integer range 1 to 1024 := 255 | 1 à 1024 | Plage contrôlée |
| PERIODE : time := 20 ns | Valeurs temporelles | Bancs de test et modèles |
9.1.7 Génériques et ressources matérielles
Modifier N change généralement le nombre de bascules, de LUT, de bits de mémoire ou d’étages arithmétiques instanciés.
Composant | N = 4 | N = 8 | N = 16 |
|---|---|---|---|
| Registre N bits | 4 bascules | 8 bascules | 16 bascules |
| Additionneur à propagation | 4 étages | 8 étages | 16 étages |
| Bus logique | 4 fils | 8 fils | 16 fils |
| Masque bit à bit | 4 opérations | 8 opérations | 16 opérations |
9.1.8 Générique et signal de commande
Générique | Signal |
|---|---|
| Fixé avant l’exécution | Évolue pendant l’exécution |
| Configure la structure | Transporte une donnée ou une commande |
| Pas de broche physique directe | Peut être relié à une broche |
| Utilisé dans les tailles et generate | Utilisé dans les équations et processus |
| Valeur constante pour une instance | Valeur temporelle |
Attention — Erreur fréquente Un générique ne remplace pas un signal de sélection dynamique. Pour changer une opération pendant le fonctionnement, il faut utiliser un port ou un signal, pas un générique. |
9.1.9 Généricité et réutilisation
Une bonne généricité évite de multiplier les versions _4bits, _8bits et _16bits. Elle ne doit toutefois pas rendre l’interface excessivement complexe.
- paramétrer les dimensions réellement variables ;
- fournir des valeurs par défaut raisonnables ;
- documenter les plages valides ;
- éviter des génériques dépendants ou contradictoires ;
- tester plusieurs configurations représentatives.
9.2 Déclaration d’un générique
La clause generic est placée dans l’entité avant la clause port. Les génériques deviennent visibles dans les déclarations de ports et dans les architectures associées.
9.2.1 Syntaxe demandée
| Déclaration minimale | VHDL |
| generic ( N : positive := 8 ); |
9.2.2 Entité complète
| Composant largeur N | VHDL |
| library IEEE; use IEEE.STD_LOGIC_1164.ALL; entity inverseur_nbits is generic ( N : positive := 8 ); port ( entree : in std_logic_vector(N-1 downto 0); sortie : out std_logic_vector(N-1 downto 0) ); end entity inverseur_nbits; |
| Architecture utilisant N | VHDL |
| architecture rtl of inverseur_nbits is begin sortie <= not entree; end architecture rtl; |
9.2.3 Plusieurs génériques
| Largeur et valeur de reset | VHDL |
| entity registre_nbits is generic ( N : positive := 8; RESET_VALUE : std_logic := '0' ); port ( clk, reset : in std_logic; d : in std_logic_vector(N-1 downto 0); q : out std_logic_vector(N-1 downto 0) ); end entity registre_nbits; |
9.2.4 Générique vectoriel
Un générique peut contenir une valeur vectorielle, mais sa taille doit être déterminable. Une méthode robuste consiste à utiliser un vecteur non contraint en VHDL-2008 ou à lier sa longueur à un autre générique selon les capacités de l’outil.
| Valeur initiale liée à N | VHDL |
| generic ( N : positive := 8; INIT_VALUE : std_logic_vector(N-1 downto 0) := (others => '0') ); |
Règle — Ordre des génériques Lorsqu’un générique utilise un paramètre précédent dans sa contrainte, N doit être déclaré avant INIT_VALUE. |
9.2.5 Générique boolean
| Option de parité | VHDL |
| generic ( N : positive := 8; AJOUTER_PARITE : boolean := false ); |
Ce type de paramètre peut être utilisé dans une instruction if generate pour inclure ou supprimer une partie du matériel.
9.2.6 Générique de type énuméré
Un paquetage peut définir un type énuméré représentant plusieurs politiques de fonctionnement.
| Type de stratégie dans un paquetage | VHDL |
| package options_pkg is type saturation_t is ( TRONCATURE, SATURATION ); end package options_pkg; |
| Utilisation comme générique | VHDL |
| generic ( N : positive := 8; MODE : saturation_t := TRONCATURE ); |
9.2.7 Génériques dans l’architecture
| Compteur paramétrable | VHDL |
| architecture rtl of compteur_modulo is signal compteur : natural range 0 to MODULO-1 := 0; begin process(clk, reset) begin if reset = '1' then compteur <= 0; elsif rising_edge(clk) then if compteur = MODULO-1 then compteur <= 0; else compteur <= compteur + 1; end if; end if; end process; end architecture rtl; |
9.2.8 Assertions sur les génériques
Une assertion concurrente peut vérifier qu’une combinaison de paramètres respecte les hypothèses du composant.
| Vérification statique | VHDL |
| assert N >= 2 report "N doit etre superieur ou egal a 2" severity failure; |
| Vérification d’une profondeur paire | VHDL |
| assert (PROFONDEUR mod 2) = 0 report "La profondeur doit etre paire" severity failure; |
Validation — Échec précoce Les assertions sur les génériques détectent les configurations invalides dès l’élaboration ou le début de la simulation, avant qu’une erreur subtile n’apparaisse dans le circuit. |
9.2.9 Valeur par défaut et documentation
Élément | Recommandation |
|---|---|
| Nom | Court et explicite : N, LARGEUR, PROFONDEUR, MODE |
| Type | Le plus restrictif possible |
| Valeur par défaut | Configuration courante et valide |
| Commentaire | Unité, plage et effet matériel |
| Assertion | Conditions impossibles à exprimer par le type |
9.2.10 Erreurs fréquentes
Erreur | Conséquence | Correction |
|---|---|---|
| N déclaré integer sans plage | Valeurs nulles ou négatives possibles | Utiliser positive |
| Générique déclaré après port | Erreur de syntaxe | Placer generic avant port |
| Valeur par défaut incompatible | Erreur d’analyse | Respecter le type et la plage |
| Vecteur INIT de mauvaise taille | Erreur de contrainte | Lier sa taille à N |
| Générique inutilisé | Interface trompeuse | Le supprimer ou l’implémenter |
| Paramètres trop nombreux | Composant difficile à comprendre | Séparer les fonctions |
9.3 Passage des paramètres
La clause generic map associe les valeurs choisies aux génériques formels d’une instance. Cette association peut être effectuée par position ou par nom.
9.3.1 Forme générale
| Instanciation avec generic map | VHDL |
| U1 : entity work.nom_entite(rtl) generic map ( parametre_1 => valeur_1, parametre_2 => valeur_2 ) port map ( -- Connexions ); |
9.3.2 Association par nom
| Registre de 16 bits | VHDL |
| U_REG16 : entity work.registre_nbits(rtl) generic map ( N => 16, RESET_VALUE => '0' ) port map ( clk => clk, reset => reset, d => entree16, q => sortie16 ); |
- ordre libre ;
- intention explicite ;
- possibilité d’omettre des génériques possédant une valeur par défaut ;
- résistance aux changements d’ordre dans l’entité.
9.3.3 Association par position
| Association positionnelle | VHDL |
| U_REG16 : entity work.registre_nbits(rtl) generic map ( 16, '0' ) port map ( clk, reset, entree16, sortie16 ); |
La première valeur correspond au premier générique, la deuxième au second. La même règle s’applique aux ports si le port map est positionnel.
Attention — Risque de maintenance L’association par position est compacte mais sensible à l’ordre des déclarations. Une permutation de deux génériques de même type peut produire une configuration valide mais incorrecte. |
9.3.4 Association mixte
VHDL autorise certaines associations mêlant position et noms, mais les éléments positionnels doivent précéder les éléments nommés. Pour une lecture claire, il est préférable d’utiliser une seule méthode.
| Exemple mixte à éviter | VHDL |
| generic map ( 16, RESET_VALUE => '0' ); |
9.3.5 Utilisation de la valeur par défaut
| Seul N est redéfini | VHDL |
| U_REG32 : entity work.registre_nbits(rtl) generic map ( N => 32 ) port map ( clk => clk, reset => reset, d => entree32, q => sortie32 ); |
RESET_VALUE conserve sa valeur par défaut.
9.3.6 Plusieurs instances, plusieurs configurations
| Trois largeurs différentes | VHDL |
| U_REG4 : entity work.registre_nbits(rtl) generic map (N => 4) port map (clk => clk, reset => reset, d => d4, q => q4); U_REG8 : entity work.registre_nbits(rtl) generic map (N => 8) port map (clk => clk, reset => reset, d => d8, q => q8); U_REG16 : entity work.registre_nbits(rtl) generic map (N => 16) port map (clk => clk, reset => reset, d => d16, q => q16); |
9.3.7 Passage d’un générique du niveau supérieur
Un composant générique peut transmettre son propre paramètre à ses sous-composants.
| Propagation de N dans la hiérarchie | VHDL |
| entity systeme_nbits is generic ( N : positive := 8 ); port ( clk : in std_logic; a : in std_logic_vector(N-1 downto 0); q : out std_logic_vector(N-1 downto 0) ); end entity systeme_nbits; |
| Sous-instance utilisant N | VHDL |
| U_REG : entity work.registre_nbits(rtl) generic map ( N => N ) port map ( clk => clk, reset => '0', d => a, q => q ); |
9.3.8 Expressions constantes dans generic map
| Expression élaborée | VHDL |
| U_MEM : entity work.memoire(rtl) generic map ( LARGEUR => N, PROFONDEUR => 2 ** ADRESSE_BITS ) port map ( -- Connexions ); |
L’expression doit être calculable lors de l’élaboration. Elle peut utiliser des constantes et des génériques du niveau supérieur.
9.3.9 Association de génériques de type time
| Banc de test configurable | VHDL |
| U_CLOCK : entity work.generateur_horloge(simulation) generic map ( PERIODE => 20 ns ) port map ( clk => clk ); |
9.3.10 Erreurs de generic map
Message ou symptôme | Cause probable | Correction |
|---|---|---|
| No association for generic | Générique obligatoire non fourni | Ajouter une valeur ou une valeur par défaut |
| Type mismatch | Valeur incompatible | Convertir ou corriger le type |
| Bounds error | Valeur hors plage | Respecter la contrainte |
| Port width mismatch | N ne correspond pas aux signaux | Adapter la largeur des signaux |
| Unexpected hardware size | Mauvaise valeur passée par position | Utiliser l’association nommée |
| Entity not found | Ordre de compilation incorrect | Compiler le composant avant le niveau supérieur |
9.4 Génération de matériel
Les instructions generate créent conditionnellement ou répétitivement des instructions concurrentes. Elles sont évaluées lors de l’élaboration et permettent de construire des structures régulières sans dupliquer manuellement le code.
9.4.1 Caractère concurrent
generate est placé dans le corps d’une architecture. Les éléments générés sont des instances, des affectations concurrentes, des processus ou d’autres blocs generate.
9.4.2 Génération répétitive avec for generate
| Forme générale | VHDL |
| etiquette : for i in plage generate begin -- Instructions concurrentes répétées end generate etiquette; |
9.4.3 Banque d’inverseurs
| Un inverseur par bit | VHDL |
| GEN_INV : for i in 0 to N-1 generate begin sortie(i) <= not entree(i); end generate GEN_INV; |
Le synthétiseur crée N inverseurs. L’indice i est une constante locale différente pour chaque itération.
9.4.4 Instanciation répétitive
| Chaîne de registres | VHDL |
| GEN_REG : for i in 0 to N-1 generate begin U_DFF : entity work.bascule_d(rtl) port map ( clk => clk, d => d(i), q => q(i) ); end generate GEN_REG; |
9.4.5 Déclarations locales au generate
| Bloc généré avec signal local | VHDL |
| GEN_ETAGE : for i in 0 to N-1 generate signal local_i : std_logic; begin local_i <= a(i) and b(i); y(i) <= local_i xor commande; end generate GEN_ETAGE; |
9.4.6 Génération conditionnelle avec if generate
| Forme générale | VHDL |
| GEN_OPTION : if CONDITION_STATIQUE generate begin -- Matériel présent si la condition est vraie end generate GEN_OPTION; |
9.4.7 Parité optionnelle
| Ajout conditionnel de la parité | VHDL |
| GEN_PARITE : if AJOUTER_PARITE generate begin process(all) variable p : std_logic; begin p := '0'; for i in donnees'range loop p := p xor donnees(i); end loop; parite <= p; end process; end generate GEN_PARITE; GEN_SANS_PARITE : if not AJOUTER_PARITE generate begin parite <= '0'; end generate GEN_SANS_PARITE; |
9.4.8 If generate avec else en VHDL-2008
| Deux architectures conditionnelles | VHDL |
| GEN_RESET : if RESET_ACTIF_HAUT generate begin reset_interne <= reset; else generate reset_interne <= not reset; end generate GEN_RESET; |
9.4.9 Condition statique
La condition d’un if generate doit être déterminable à l’élaboration. Elle peut dépendre d’un générique ou d’une constante, mais pas d’un signal qui change pendant le fonctionnement.
Expression | Valide pour generate ? | Pourquoi |
|---|---|---|
| N > 8 | Oui | N est un générique |
| AJOUTER_PARITE | Oui | Boolean générique |
| MODE = RAPIDE | Oui | Valeur générique énumérée |
| enable = '1' | Non | enable est un signal dynamique |
| compteur = 10 | Non | compteur évolue dans le temps |
9.4.10 Génération conditionnelle selon la taille
| Traitement réservé aux grandes largeurs | VHDL |
| GEN_LARGE : if N >= 16 generate begin indicateur_large <= '1'; end generate GEN_LARGE; GEN_PETIT : if N < 16 generate begin indicateur_large <= '0'; end generate GEN_PETIT; |
9.4.11 Création de structures régulières
- additionneurs à propagation de retenue ;
- registres et bancs de bascules ;
- chaînes de délais cadencés ;
- réseaux de comparateurs ;
- arbres logiques ;
- interfaces répliquées ;
- matrices de traitement.
9.4.12 Chaîne d’additionneurs complets
| Signaux de retenue | VHDL |
| signal retenues : std_logic_vector(N downto 0); retenues(0) <= cin; cout <= retenues(N); |
| Génération des N étages | VHDL |
| GEN_FA : for i in 0 to N-1 generate begin U_FA : entity work.additionneur_complet(structurelle) port map ( a => a(i), b => b(i), cin => retenues(i), somme => somme(i), cout => retenues(i+1) ); end generate GEN_FA; |
9.4.13 Noms hiérarchiques
Chaque itération crée une instance distincte. Les outils affichent généralement des noms hiérarchiques contenant l’étiquette du generate et l’indice, par exemple GEN_FA(3).U_FA.
9.4.14 Generate et processus
| Un processus par voie | VHDL |
| GEN_VOIE : for i in 0 to N-1 generate begin process(clk) begin if rising_edge(clk) then q(i) <= d(i); end if; end process; end generate GEN_VOIE; |
9.4.15 Case generate en VHDL-2008
| Choix d’une structure | VHDL |
| GEN_MODE : case MODE generate when ECONOMIQUE => -- Architecture peu coûteuse when RAPIDE => -- Architecture plus parallèle end generate GEN_MODE; |
Compatibilité — Support des outils Les formes avancées de generate dépendent de la version VHDL activée. Les exemples VHDL-2008 nécessitent une configuration explicite de l’outil. |
9.4.16 Coût du déroulement
Une génération répétitive crée du matériel réel. Doubler N peut presque doubler certaines ressources et augmenter le chemin critique, selon l’architecture.
Structure | Ressources en fonction de N | Effet temporel |
|---|---|---|
| Registre N bits | N bascules | Chemin généralement constant |
| Additionneur ripple N bits | N additionneurs complets | Propagation approximativement croissante |
| Comparaison bit à bit | N comparateurs élémentaires | Réduction logique supplémentaire |
| Multiplexeur N voies | Croissance avec N et la largeur | Profondeur de sélection variable |
9.4.17 Erreurs fréquentes avec generate
Erreur | Conséquence | Correction |
|---|---|---|
| Étiquette absente ou dupliquée | Hiérarchie confuse ou erreur | Nommer chaque generate |
| Limite dépendant d’un signal | Non élaborable | Utiliser un générique ou une constante |
| Indice hors plage | Erreur d’élaboration | Vérifier i et i+1 |
| Plusieurs branches pilotent la même sortie | Pilotes multiples | Rendre les conditions exclusives |
| N = 0 | Plage vide ou invalide | Déclarer N positive |
| Structure très grande | Ressources excessives | Analyser avant synthèse |
9.5 Réutilisation des composants
La réutilisation consiste à concevoir un bloc une fois, le vérifier indépendamment puis l’intégrer dans plusieurs systèmes. Les génériques et la hiérarchie rendent cette démarche plus efficace.
9.5.1 Conception modulaire
- une responsabilité claire par composant ;
- une interface stable ;
- des dépendances limitées ;
- des génériques cohérents ;
- un banc de test associé ;
- une documentation des hypothèses et latences.
9.5.2 Granularité des composants
Un composant doit être suffisamment autonome pour être réutilisé, mais pas si petit que la hiérarchie devienne inutilement profonde.
Granularité | Exemple | Évaluation |
|---|---|---|
| Trop fine | Une entité pour chaque inverseur interne | Code et hiérarchie lourds |
| Adaptée | Additionneur, registre, UART TX | Fonction autonome testable |
| Trop large | Système complet monolithique | Réutilisation et test difficiles |
9.5.3 Bibliothèque de composants
Les unités validées peuvent être compilées dans une bibliothèque dédiée au lieu de la bibliothèque work.
| Référence à une bibliothèque | VHDL |
| library composants; U_ADD : entity composants.additionneur_nbits(rtl) generic map ( N => 16 ) port map ( a => a16, b => b16, cin => cin, somme => somme16, cout => cout ); |
9.5.4 Paquetage de types et constantes
| Paquetage partagé | VHDL |
| package projet_pkg is constant LARGEUR_PAR_DEFAUT : positive := 8; subtype octet_t is std_logic_vector(7 downto 0); end package projet_pkg; |
9.5.5 Déclaration de composants dans un paquetage
La méthode traditionnelle peut centraliser les déclarations component dans un paquetage. Avec l’instanciation directe, cette duplication est souvent inutile, mais elle reste rencontrée dans des projets anciens.
| Paquetage de composants | VHDL |
| package composants_pkg is component registre_nbits is generic ( N : positive := 8 ); port ( clk, reset : in std_logic; d : in std_logic_vector(N-1 downto 0); q : out std_logic_vector(N-1 downto 0) ); end component; end package composants_pkg; |
9.5.6 Maintenance
La modularité limite l’impact d’une modification. Si l’interface reste stable, une architecture interne peut être optimisée sans changer les niveaux supérieurs.
- corriger une seule source générique ;
- versionner les interfaces ;
- conserver des tests de non-régression ;
- documenter les changements de comportement ;
- éviter de modifier silencieusement les valeurs par défaut.
9.5.7 Validation séparée des blocs
- Écrire les exigences du composant.
- Tester chaque valeur limite des génériques.
- Simuler les combinaisons fonctionnelles.
- Utiliser des assertions automatiques.
- Synthétiser plusieurs configurations.
- Vérifier ressources et timing.
- Intégrer ensuite le bloc dans le niveau supérieur.
- Réaliser un test d’intégration.
9.5.8 Banc de test générique
Un banc de test peut lui-même contenir un générique afin d’être relancé avec plusieurs tailles, ou instancier plusieurs configurations simultanément.
| Banc de test avec N | VHDL |
| entity tb_additionneur is generic ( N : positive := 8 ); end entity tb_additionneur; |
| Exécution GHDL avec générique | Terminal |
| ghdl -r --std=08 tb_additionneur -gN=16 |
9.5.9 Tests de non-régression
Configuration | But du test |
|---|---|
| N = 1 | Taille minimale et indices limites |
| N = 4 | Cas pédagogique facile à observer |
| N = 8 | Configuration par défaut |
| N = 16 | Croissance des ressources |
| Valeurs maximales | Propagation de retenue et débordement |
| Reset et enable | Comportement temporel du registre |
9.5.10 Documentation d’un composant
Rubrique | Contenu attendu |
|---|---|
| Fonction | Description concise du bloc |
| Génériques | Type, défaut, plage et effet |
| Ports | Sens, type, polarité et protocole |
| Latence | Combinatoire ou nombre de cycles |
| Reset | Synchrone/asynchrone et valeur |
| Hypothèses | Fréquence, valeurs autorisées |
| Validation | Bancs de test et configurations |
| Synthèse | Ressources et technologie ciblée |
9.5.11 Hiérarchie de projet
| Organisation possible | Arborescence |
| projet/ ├── rtl/ │ ├── commun/ │ │ ├── additionneur_nbits.vhd │ │ └── registre_nbits.vhd │ ├── controle/ │ └── top/ ├── tb/ ├── contraintes/ └── scripts/ |
9.5.12 Critères de qualité
- génériques utiles et correctement typés ;
- interface cohérente pour toutes les configurations ;
- aucune hypothèse cachée sur N ;
- code compatible avec plusieurs outils ;
- tests reproductibles ;
- messages d’assertion compréhensibles ;
- absence d’avertissements de synthèse non justifiés.
Méthode de conception d’un composant paramétrable
1. Identifier ce qui varie réellement entre les utilisations.
2. Choisir des génériques de types restrictifs.
3. Définir une configuration par défaut valide.
4. Écrire les tailles à partir des génériques et des attributs.
5. Éviter les constantes numériques cachées.
6. Ajouter des assertions de configuration.
7. Utiliser generate pour les répétitions statiques.
8. Tester la valeur minimale, la valeur par défaut et une grande valeur.
9. Comparer les ressources et le timing.
10. Documenter l’interface et les limites.
Checklist avant réutilisation
- Le composant compile-t-il dans une bibliothèque propre ?
- Les génériques ont-ils des noms et types explicites ?
- Les ports dépendent-ils correctement de N ?
- Les valeurs par défaut sont-elles sûres ?
- Les branches generate sont-elles exclusives ?
- Les indices i et i+1 restent-ils dans les plages ?
- Le banc de test couvre-t-il plusieurs configurations ?
- Les résultats de synthèse sont-ils acceptables ?
Travaux pratiques
TP 6 — Composants paramétrables
1. Objectifs du TP
- développer un additionneur sur N bits ;
- développer un registre sur N bits ;
- développer un multiplexeur de données de largeur N ;
- générer une chaîne de N additionneurs complets ;
- utiliser generic map par nom ;
- tester N = 4, 8 et 16 ;
- comparer la version structurelle et une version arithmétique ;
- observer la croissance des ressources et du chemin critique.
2. Organisation des fichiers
| Arborescence proposée | Arborescence |
| tp6_composants_parametrables/ ├── src/ │ ├── additionneur_complet.vhd │ ├── additionneur_nbits_structurel.vhd │ ├── additionneur_nbits_rtl.vhd │ ├── registre_nbits.vhd │ └── mux2_nbits.vhd └── sim/ ├── tb_additionneur_multi_n.vhd ├── tb_registre_multi_n.vhd └── tb_mux_multi_n.vhd |
3. Partie A — Additionneur complet élémentaire
| additionneur_complet.vhd | VHDL |
| library IEEE; use IEEE.STD_LOGIC_1164.ALL; entity additionneur_complet is port ( a, b, cin : in std_logic; somme : out std_logic; cout : out std_logic ); end entity additionneur_complet; architecture rtl of additionneur_complet is begin somme <= a xor b xor cin; cout <= (a and b) or (a and cin) or (b and cin); end architecture rtl; |
4. Partie B — Additionneur structurel sur N bits
| additionneur_nbits_structurel.vhd — Entité | VHDL |
| library IEEE; use IEEE.STD_LOGIC_1164.ALL; entity additionneur_nbits_structurel is generic ( N : positive := 8 ); port ( a, b : in std_logic_vector(N-1 downto 0); cin : in std_logic; somme : out std_logic_vector(N-1 downto 0); cout : out std_logic ); end entity additionneur_nbits_structurel; |
| additionneur_nbits_structurel.vhd — Architecture | VHDL |
| architecture structurelle of additionneur_nbits_structurel is signal retenues : std_logic_vector(N downto 0); begin retenues(0) <= cin; cout <= retenues(N); GEN_FA : for i in 0 to N-1 generate begin U_FA : entity work.additionneur_complet(rtl) port map ( a => a(i), b => b(i), cin => retenues(i), somme => somme(i), cout => retenues(i+1) ); end generate GEN_FA; end architecture structurelle; |
5. Partie C — Additionneur RTL sur N bits
| additionneur_nbits_rtl.vhd — Entité | VHDL |
| library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; entity additionneur_nbits_rtl is generic ( N : positive := 8 ); port ( a, b : in std_logic_vector(N-1 downto 0); cin : in std_logic; somme : out std_logic_vector(N-1 downto 0); cout : out std_logic ); end entity additionneur_nbits_rtl; |
| additionneur_nbits_rtl.vhd — Architecture | VHDL |
| architecture rtl of additionneur_nbits_rtl is signal resultat : unsigned(N downto 0); begin process(all) variable resultat_v : unsigned(N downto 0); begin resultat_v := resize(unsigned(a), N+1) + resize(unsigned(b), N+1); if cin = '1' then resultat_v := resultat_v + 1; end if; resultat <= resultat_v; end process; somme <= std_logic_vector(resultat(N-1 downto 0)); cout <= resultat(N); end architecture rtl; |
6. Partie D — Registre sur N bits
| registre_nbits.vhd — Entité | VHDL |
| library IEEE; use IEEE.STD_LOGIC_1164.ALL; entity registre_nbits is generic ( N : positive := 8; RESET_VALUE : std_logic := '0' ); port ( clk, reset : in std_logic; enable : in std_logic; d : in std_logic_vector(N-1 downto 0); q : out std_logic_vector(N-1 downto 0) ); end entity registre_nbits; |
| registre_nbits.vhd — Architecture | VHDL |
| architecture rtl of registre_nbits is begin process(clk, reset) begin if reset = '1' then q <= (others => RESET_VALUE); elsif rising_edge(clk) then if enable = '1' then q <= d; end if; end if; end process; end architecture rtl; |
7. Partie E — Multiplexeur paramétrable
Le nombre d’entrées reste 2, mais la largeur des mots est définie par N.
| mux2_nbits.vhd | VHDL |
| library IEEE; use IEEE.STD_LOGIC_1164.ALL; entity mux2_nbits is generic ( N : positive := 8 ); port ( a, b : in std_logic_vector(N-1 downto 0); sel : in std_logic; y : out std_logic_vector(N-1 downto 0) ); end entity mux2_nbits; architecture rtl of mux2_nbits is begin y <= a when sel = '0' else b; end architecture rtl; |
8. Partie F — Instanciation de plusieurs valeurs de N
| Trois additionneurs structurels | VHDL |
| U_ADD4 : entity work.additionneur_nbits_structurel(structurelle) generic map (N => 4) port map ( a => a4, b => b4, cin => cin, somme => somme4, cout => cout4 ); U_ADD8 : entity work.additionneur_nbits_structurel(structurelle) generic map (N => 8) port map ( a => a8, b => b8, cin => cin, somme => somme8, cout => cout8 ); U_ADD16 : entity work.additionneur_nbits_structurel(structurelle) generic map (N => 16) port map ( a => a16, b => b16, cin => cin, somme => somme16, cout => cout16 ); |
9. Banc de test comparatif des additionneurs
| tb_additionneur_multi_n.vhd — Déclarations | VHDL |
| library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; use STD.ENV.ALL; entity tb_additionneur_multi_n is end entity tb_additionneur_multi_n; architecture simulation of tb_additionneur_multi_n is signal a4, b4 : std_logic_vector(3 downto 0); signal s4_struct, s4_rtl : std_logic_vector(3 downto 0); signal c4_struct, c4_rtl : std_logic; signal a8, b8 : std_logic_vector(7 downto 0); signal s8_struct, s8_rtl : std_logic_vector(7 downto 0); signal c8_struct, c8_rtl : std_logic; signal a16, b16 : std_logic_vector(15 downto 0); signal s16_struct, s16_rtl : std_logic_vector(15 downto 0); signal c16_struct, c16_rtl : std_logic; signal cin : std_logic := '0'; begin |
| Instances N = 4 — Partie 1 | VHDL |
| U_S4 : entity work.additionneur_nbits_structurel(structurelle) generic map (N => 4) port map ( a => a4, b => b4, cin => cin, somme => s4_struct, cout => c4_struct ); U_R4 : entity work.additionneur_nbits_rtl(rtl) generic map (N => 4) port map ( a => a4, b => b4, cin => cin, somme => s4_rtl, cout => c4_rtl ); |
| Instances N = 8 et N = 16 — Partie 2 | VHDL |
| U_S8 : entity work.additionneur_nbits_structurel(structurelle) generic map (N => 8) port map ( a => a8, b => b8, cin => cin, somme => s8_struct, cout => c8_struct ); U_R8 : entity work.additionneur_nbits_rtl(rtl) generic map (N => 8) port map ( a => a8, b => b8, cin => cin, somme => s8_rtl, cout => c8_rtl ); U_S16 : entity work.additionneur_nbits_structurel(structurelle) generic map (N => 16) port map ( a => a16, b => b16, cin => cin, somme => s16_struct, cout => c16_struct ); U_R16 : entity work.additionneur_nbits_rtl(rtl) generic map (N => 16) port map ( a => a16, b => b16, cin => cin, somme => s16_rtl, cout => c16_rtl ); |
10. Stimuli et assertions
| Tests des trois largeurs | VHDL |
| stimuli : process begin cin <= '0'; a4 <= x"F"; b4 <= x"1"; a8 <= x"C8"; b8 <= x"64"; a16 <= x"FFFF"; b16 <= x"0001"; wait for 1 ns; assert s4_struct = s4_rtl and c4_struct = c4_rtl report "Divergence N=4" severity error; assert s8_struct = s8_rtl and c8_struct = c8_rtl report "Divergence N=8" severity error; assert s16_struct = s16_rtl and c16_struct = c16_rtl report "Divergence N=16" severity error; assert c4_struct = '1' and s4_struct = x"0" report "Erreur 15 + 1" severity error; assert unsigned(c8_struct & s8_struct) = to_unsigned(300, 9) report "Erreur 200 + 100" severity error; assert c16_struct = '1' and s16_struct = x"0000" report "Erreur 65535 + 1" severity error; report "Comparaison multi-N terminee" severity note; stop; wait; end process; end architecture simulation; |
11. Banc de test du registre
| Horloge et instance | VHDL |
| signal clk : std_logic := '0'; signal reset : std_logic := '1'; signal enable : std_logic := '0'; signal d8, q8 : std_logic_vector(7 downto 0); clk <= not clk after 5 ns; U_REG8 : entity work.registre_nbits(rtl) generic map ( N => 8, RESET_VALUE => '0' ) port map ( clk => clk, reset => reset, enable => enable, d => d8, q => q8 ); |
| Scénario du registre | VHDL |
| stimuli : process begin d8 <= x"A5"; wait for 12 ns; reset <= '0'; wait until rising_edge(clk); wait for 1 ns; assert q8 = x"00" report "Le registre ne doit pas charger si enable=0" severity error; enable <= '1'; wait until rising_edge(clk); wait for 1 ns; assert q8 = x"A5" report "Chargement incorrect" severity error; d8 <= x"3C"; enable <= '0'; wait until rising_edge(clk); wait for 1 ns; assert q8 = x"A5" report "Conservation incorrecte" severity error; wait; end process; |
12. Banc de test du multiplexeur
| Test de N = 4 et N = 16 | VHDL |
| a4_mux <= x"3"; b4_mux <= x"C"; sel <= '0'; wait for 1 ns; assert y4_mux = x"3" severity error; sel <= '1'; wait for 1 ns; assert y4_mux = x"C" severity error; a16_mux <= x"1234"; b16_mux <= x"ABCD"; sel <= '0'; wait for 1 ns; assert y16_mux = x"1234" severity error; |
13. Compilation avec GHDL
| Ordre de compilation | Terminal |
| ghdl -a --std=08 src/additionneur_complet.vhd ghdl -a --std=08 src/additionneur_nbits_structurel.vhd ghdl -a --std=08 src/additionneur_nbits_rtl.vhd ghdl -a --std=08 src/registre_nbits.vhd ghdl -a --std=08 src/mux2_nbits.vhd ghdl -a --std=08 sim/tb_additionneur_multi_n.vhd ghdl -e --std=08 tb_additionneur_multi_n ghdl -r --std=08 tb_additionneur_multi_n --vcd=tb_additionneur_multi_n.vcd |
14. Comparaison des configurations
Composant | N = 4 | N = 8 | N = 16 | Tendance attendue |
|---|---|---|---|---|
| Additionneur structurel | 4 étages | 8 étages | 16 étages | Ressources et délai augmentent |
| Additionneur RTL | Largeur 4 | Largeur 8 | Largeur 16 | Outil choisit l’implémentation |
| Registre | 4 bascules | 8 bascules | 16 bascules | Croissance linéaire |
| Multiplexeur 2:1 | 8 LUT possibles selon architecture | idem largeur 8 | idem largeur 16 | Croissance avec la largeur |
15. Mesures de synthèse à relever
Configuration | LUT | Bascules | Chemin critique | Fréquence maximale |
|---|---|---|---|---|
| Additionneur structurel N=4 | ||||
| Additionneur structurel N=8 | ||||
| Additionneur structurel N=16 | ||||
| Additionneur RTL N=4 | ||||
| Additionneur RTL N=8 | ||||
| Additionneur RTL N=16 |
16. Observations demandées
- Vérifier que la même source fonctionne pour N = 4, 8 et 16.
- Comparer les sorties structurelles et RTL.
- Observer les noms hiérarchiques générés.
- Vérifier le comportement du reset et de enable.
- Comparer la taille des vecteurs dans le simulateur.
- Relever les ressources de synthèse.
- Comparer la fréquence maximale des additionneurs.
- Expliquer l’impact du ripple-carry lorsque N augmente.
17. Questions d’analyse
1. Pourquoi le type positive est-il préférable pour N ?
2. À quel moment la valeur de N est-elle fixée ?
3. Quelle différence existe entre generic map et port map ?
4. Pourquoi l’association nommée est-elle plus sûre ?
5. Quel matériel crée la boucle for generate ?
6. Pourquoi le signal retenues possède-t-il N+1 bits ?
7. Comment tester la taille minimale N = 1 ?
8. Pourquoi les versions structurelle et RTL peuvent-elles produire le même schéma après optimisation ?
9. Quel effet N a-t-il sur le registre ?
10. Comment transformer le multiplexeur 2:1 en multiplexeur à K entrées ?
18. Extensions proposées
- Créer un additionneur/soustracteur générique.
- Ajouter un générique de reset synchrone ou asynchrone.
- Créer un registre à décalage sur N bits.
- Créer un multiplexeur à K entrées en VHDL-2008.
- Ajouter une parité optionnelle avec if generate.
- Créer un comparateur N bits.
- Comparer ripple-carry et carry-lookahead génériques.
- Compiler les composants dans une bibliothèque dédiée.
19. Barème indicatif
Critère | Points |
|---|---|
| Additionneur complet élémentaire | 1 |
| Additionneur structurel générique | 4 |
| Additionneur RTL générique | 2 |
| Registre générique | 3 |
| Multiplexeur générique | 2 |
| Bancs de test multi-N | 3 |
| Comparaison synthèse et timing | 3 |
| Qualité, modularité et compte rendu | 2 |
| Total | 20 |
Synthèse du chapitre
Notion | Résumé |
|---|---|
| Générique | Paramètre fixé lors de l’élaboration. |
| Valeur par défaut | Configuration utilisée si aucune valeur n’est passée. |
| generic map | Associe les valeurs aux paramètres d’une instance. |
| Association nommée | Utilise nom => valeur et améliore la maintenance. |
| Association positionnelle | Dépend strictement de l’ordre. |
| for generate | Répète une structure matérielle un nombre statique de fois. |
| if generate | Inclut du matériel selon une condition statique. |
| Hiérarchie | Assemble des composants paramétrables. |
| Bibliothèque | Regroupe des unités compilées et réutilisables. |
| Validation séparée | Teste chaque bloc avant intégration. |
| N | Influence les largeurs, ressources et parfois le timing. |
Autoévaluation
1. Quand un générique est-il évalué ?
Réponse : Lors de l’élaboration.
2. Quel type convient à une largeur strictement positive ?
Réponse : positive.
3. Quel mot-clé passe les valeurs des génériques ?
Réponse : generic map.
4. Quelle association est la plus lisible ?
Réponse : L’association par nom.
5. Que produit for generate ?
Réponse : Plusieurs copies de matériel concurrent.
6. Une condition generate peut-elle dépendre de enable ?
Réponse : Non, si enable est un signal dynamique.
7. Pourquoi retenues a-t-il N+1 bits ?
Réponse : Pour la retenue d’entrée et les N retenues de sortie.
8. Quel avantage offre un composant paramétrable ?
Réponse : Une source unique pour plusieurs tailles.
9. Comment vérifier une configuration invalide ?
Réponse : Avec un type restrictif et des assertions.
10. Que faut-il comparer pour N = 4, 8 et 16 ?
Réponse : Fonction, ressources et timing.
Exercice de consolidation
Créer un bloc générique qui effectue un AND bit à bit entre deux vecteurs de N bits. Ajouter un générique INVERSION permettant de choisir entre AND et NAND lors de l’élaboration.
| Correction proposée — Entité | VHDL |
| library IEEE; use IEEE.STD_LOGIC_1164.ALL; entity bloc_and_generique is generic ( N : positive := 8; INVERSION : boolean := false ); port ( a, b : in std_logic_vector(N-1 downto 0); y : out std_logic_vector(N-1 downto 0) ); end entity bloc_and_generique; |
| Correction proposée — Architecture | VHDL |
| architecture rtl of bloc_and_generique is signal and_i : std_logic_vector(N-1 downto 0); begin and_i <= a and b; GEN_AND : if not INVERSION generate begin y <= and_i; end generate GEN_AND; GEN_NAND : if INVERSION generate begin y <= not and_i; end generate GEN_NAND; end architecture rtl; |
Suite du cours — Transition vers la suite La maîtrise des composants génériques et de la hiérarchie prépare l’étude des circuits séquentiels : horloges, bascules, registres, resets et synchronisation. |