Leçon 8 sur 22

Chapitre 8 — Styles de description VHDL

Objectif — Finalité du chapitre

Comprendre les trois grands styles de description VHDL — flot de données, comportemental et structurel — puis choisir et combiner ces styles selon le niveau d’abstraction, la réutilisabilité et la complexité du circuit.

Objectifs pédagogiques

À la fin de ce chapitre, l’étudiant devra être capable de :

  • définir le style par flot de données ;
  • traduire des équations logiques en affectations concurrentes ;
  • utiliser des processus pour une description comportementale ;
  • décomposer un circuit en sous-composants réutilisables ;
  • déclarer et instancier un composant ;
  • réaliser les connexions avec port map ;
  • utiliser l’instanciation directe d’entité ;
  • distinguer association par position et association par nom ;
  • comparer les styles selon la lisibilité, la réutilisabilité et l’abstraction ;
  • combiner plusieurs styles dans une architecture hiérarchique ;
  • concevoir un additionneur 4 bits à partir de demi-additionneurs et d’additionneurs complets ;
  • comparer une version structurelle à une version comportementale.

Prérequis

  • entités, architectures, ports et signaux internes ;
  • affectations concurrentes ;
  • processus, instructions if et case ;
  • types std_logic, std_logic_vector et unsigned ;
  • instanciation directe rencontrée dans les travaux pratiques précédents ;
  • tables de vérité du demi-additionneur et de l’additionneur complet.

Organisation du chapitre

Section

Contenu

Compétence principale

8.1Description par flot de donnéesExprimer directement les relations entre signaux
8.2Description comportementaleDécrire un algorithme ou une décision dans un processus
8.3Description structurelleAssembler des sous-composants
8.4Instanciation directeRéférencer une entité compilée sans composant intermédiaire
8.5Comparaison des stylesChoisir le niveau d’abstraction adapté
TP 5Additionneur hiérarchiqueConcevoir et vérifier un système à plusieurs niveaux

 

Concept clé — Styles complémentaires

Les styles de description ne sont pas exclusifs. Un projet réel combine fréquemment une architecture structurelle au niveau supérieur, des processus comportementaux dans les contrôleurs et des équations de flot de données pour les fonctions simples.

 

8.1 Description par flot de données

Le style par flot de données décrit les relations entre les entrées, les signaux internes et les sorties. Il met l’accent sur la circulation et la transformation des données plutôt que sur la décomposition physique en composants.

8.1.1 Principe

Les sorties sont écrites sous forme d’équations ou d’affectations concurrentes. Chaque équation est active en permanence et est réévaluée lorsque l’un de ses opérandes change.

Porte logique simple  |  VHDL
architecture flot_donnees of porte_et is
begin
    s <= a and b;
end architecture flot_donnees;

 

8.1.2 Équations logiques

Une fonction booléenne peut être transcrite presque directement en VHDL. Les parenthèses rendent les niveaux logiques et la priorité explicites.

Fonction combinatoire  |  VHDL
architecture flot_donnees of fonction_logique is
begin
    y <= (a and b)
         or
         (c and not d);
end architecture flot_donnees;

 

Élément de l’équation

Matériel probable

a and bPorte AND
not dInverseur
c and not dPorte AND
Somme logique des deux termesPorte OR

 

8.1.3 Affectations concurrentes

Décomposition avec signaux intermédiaires  |  VHDL
architecture flot_donnees of circuit is
    signal terme_1 : std_logic;
    signal terme_2 : std_logic;
begin
    terme_1 <= a and b;
    terme_2 <= c xor d;
    y <= terme_1 or terme_2;
end architecture flot_donnees;

 

Les trois affectations fonctionnent en parallèle. L’ordre de leur écriture n’impose pas un ordre d’exécution.

8.1.4 Circuits combinatoires simples

  • portes logiques ;
  • comparateurs élémentaires ;
  • multiplexeurs ;
  • décodeurs ;
  • encodeurs simples ;
  • additionneurs combinatoires ;
  • opérations de masquage et de concaténation.
Multiplexeur 2 vers 1  |   VHDL
architecture flot_donnees of mux2 is
begin
    y <= a when sel = '0'
         else b;
end architecture flot_donnees;

 

Décodeur 2 vers 4  |   VHDL
architecture flot_donnees of decodeur2_4 is
begin
    with entree select
        sortie <= "0001" when "00",
                  "0010" when "01",
                  "0100" when "10",
                  "1000" when others;
end architecture flot_donnees;

 

8.1.5 Opérations vectorielles

Masquage d’un bus  |   VHDL
architecture flot_donnees of masque_bus is
begin
    sortie <= donnees and masque;
end architecture flot_donnees;

 

Concaténation de champs  |  VHDL
trame <= entete & donnee & controle;

 

8.1.6 Opérations arithmétiques

Le style par flot de données convient aussi aux opérations arithmétiques lorsque les types et les largeurs sont explicites.

Addition non signée avec retenue  |  VHDL
architecture flot_donnees of additionneur is
begin
    somme <= resize(a, somme'length)
             + resize(b, somme'length);
end architecture flot_donnees;

 

8.1.7 Avantages du flot de données

  • code compact pour les fonctions simples ;
  • correspondance directe entre équations et matériel ;
  • concurrence visible ;
  • facilité de lecture pour un petit réseau combinatoire ;
  • synthèse généralement prévisible ;
  • peu de structure syntaxique.

8.1.8 Limites du flot de données

  • expressions longues difficiles à maintenir ;
  • description moins naturelle pour une logique algorithmique complexe ;
  • gestion de nombreuses conditions parfois peu lisible ;
  • réutilisation limitée si le circuit n’est pas décomposé ;
  • hiérarchie matérielle moins explicite.

Choix — Quand l’utiliser ?

Le flot de données est particulièrement adapté aux petits circuits combinatoires, aux équations booléennes, aux connexions directes et aux opérations vectorielles simples.

 

8.1.9 Exemple : comparateur simple

Comparateur non signé  |  VHDL
architecture flot_donnees of comparateur is
begin
    egal <= '1' when a = b else '0';

    inferieur <= '1'
        when unsigned(a) < unsigned(b)
        else '0';

    superieur <= '1'
        when unsigned(a) > unsigned(b)
        else '0';
end architecture flot_donnees;

 

8.1.10 Exemple : demi-additionneur

Le demi-additionneur possède deux entrées et deux sorties. La somme est obtenue par XOR et la retenue par AND.

Demi-additionneur par flot de données  |  VHDL
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity demi_additionneur is
    port (
        a, b    : in   std_logic;
        somme   : out std_logic;
        retenue : out std_logic
    );
end entity demi_additionneur;

architecture flot_donnees of demi_additionneur is
begin
    somme   <= a xor b;
    retenue <= a and b;
end architecture flot_donnees;

 

a

b

somme

retenue

0000
0110
1010
1101

 

8.2 Description comportementale

Le style comportemental décrit ce que le circuit doit faire à l’aide d’instructions séquentielles regroupées dans des processus. Le code se rapproche d’un algorithme, tout en décrivant du matériel synthétisable.

8.2.1 Utilisation des processus

Processus combinatoire  |  VHDL
architecture comportementale of mux2 is
begin
    process(all)
    begin
        if sel = '0' then
            y <= a;
        else
            y <= b;
        end if;
    end process;
end architecture comportementale;

 

Le processus est concurrent vis-à-vis du reste de l’architecture, mais ses instructions internes sont exécutées séquentiellement.

8.2.2 Description algorithmique

Une description algorithmique exprime des étapes de calcul, des décisions, des valeurs par défaut et des boucles. Elle est utile lorsque la fonction est plus simple à comprendre sous forme d’algorithme que sous forme d’équation.

Comptage des bits à 1  |   VHDL
architecture comportementale of compteur_uns is
begin
    process(all)
        variable total : natural range 0 to donnees'length;
    begin
        total := 0;

        for i in donnees'range loop
            if donnees(i) = '1' then
                total := total + 1;
            end if;
        end loop;

        nombre <= to_unsigned(total, nombre'length);
    end process;
end architecture comportementale;

 

8.2.3 Conditions avec if

Comparateur comportemental  |  VHDL
process(all)
begin
    egal      <= '0';
    inferieur <= '0';
    superieur <= '0';

    if unsigned(a) = unsigned(b) then
        egal <= '1';
    elsif unsigned(a) < unsigned(b) then
        inferieur <= '1';
    else
        superieur <= '1';
    end if;
end process;

 

8.2.4 Sélections avec case

Unité logique comportementale  |  VHDL
process(all)
begin
    case operation is
        when "00" =>
            y <= a and b;

        when "01" =>
            y <= a or b;

        when "10" =>
            y <= a xor b;

        when others =>
            y <= not a;
    end case;
end process;

 

8.2.5 Valeurs par défaut

Un processus combinatoire doit définir toutes ses sorties pour tous les chemins. Une valeur par défaut réduit le risque de latch.

Valeurs par défaut  |  VHDL
process(all)
begin
    y      <= (others => '0');
    valide <= '0';

    if enable = '1' then
        y      <= resultat;
        valide <= '1';
    end if;
end process;

 

8.2.6 Variables locales

Calcul intermédiaire  |  VHDL
process(all)
    variable somme_v : unsigned(8 downto 0);
begin
    somme_v := resize(a, 9) + resize(b, 9);

    somme   <= somme_v(7 downto 0);
    retenue <= somme_v(8);
end process;

 

8.2.7 Description combinatoire et séquentielle

Type de processus

Rôle

Exemple

CombinatoireSorties fonction immédiate des entréesMultiplexeur, comparateur
CadencéMémorise les données au front d’horlogeRegistre, compteur
Avec reset asynchroneInitialisation immédiateRegistre réinitialisable
Banc de testProduit des stimuli temporelsProcessus avec wait

 

Registre comportemental  |  VHDL
architecture comportementale of registre is
begin
    process(clk, reset)
    begin
        if reset = '1' then
            q <= (others => '0');
        elsif rising_edge(clk) then
            q <= d;
        end if;
    end process;
end architecture comportementale;

 

8.2.8 Avantages du style comportemental

  • adapté aux décisions complexes ;
  • description naturelle des machines à états ;
  • utilisation de variables et de boucles ;
  • regroupement cohérent des sorties d’une fonction ;
  • lecture proche d’un algorithme ;
  • facilité d’évolution des conditions.

8.2.9 Limites du style comportemental

  • le matériel inféré peut être moins évident pour un débutant ;
  • une affectation incomplète peut créer un latch ;
  • une longue chaîne if/elsif peut augmenter le chemin critique ;
  • certaines constructions algorithmiques ne sont pas synthétisables ;
  • les boucles doivent être bornées et maîtrisées.

Attention — Comportemental ne signifie pas logiciel

Même si le code utilise des instructions algorithmiques, il est traduit en portes, registres, multiplexeurs et réseaux combinatoires. La consommation de ressources dépend de la structure décrite.

 

8.2.10 Exemple : demi-additionneur comportemental

Version avec case  |   VHDL
architecture comportementale of demi_additionneur is
begin
    process(all)
    begin
        case a & b is
            when "00" =>
                somme   <= '0';
                retenue <= '0';

            when "01" | "10" =>
                somme   <= '1';
                retenue <= '0';

            when others =>
                somme   <= '0';
                retenue <= '1';
        end case;
    end process;
end architecture comportementale;

 

8.3 Description structurelle

Le style structurel décrit un circuit comme un assemblage de sous-composants. Il rend explicites la hiérarchie, les instances et les connexions, à la manière d’un schéma électronique textuel.

8.3.1 Décomposition en sous-composants

Un système complexe est divisé en blocs plus simples, chacun possédant sa propre entité et une architecture validée.

Système

Sous-composants possibles

Additionneur 4 bitsQuatre additionneurs complets
Processeur simpleUAL, registres, contrôleur, mémoire
Interface UARTGénérateur de baud rate, émetteur, récepteur
ChronomètreDiviseur de fréquence, compteurs, décodeur sept segments
Filtre numériqueMultiplicateurs, additionneurs, registres

 

8.3.2 Signaux internes

Les sous-composants sont reliés par des signaux internes. Ces signaux correspondent aux fils du niveau hiérarchique.

Déclaration de connexions internes  |  VHDL
architecture structurelle of circuit is
    signal sortie_et : std_logic;
    signal sortie_ou : std_logic;
begin
    -- Instances et connexions
end architecture structurelle;

 

8.3.3 Déclaration de composants

Dans la forme traditionnelle, l’architecture déclare une interface de composant avant de l’instancier. La déclaration doit être compatible avec l’entité qui sera liée.

Déclaration d’un composant  |  VHDL
component and_gate is
    port (
        a : in  std_logic;
        b : in  std_logic;
        s : out std_logic
    );
end component;

 

8.3.4 Instanciation d’un composant

Instance d’une porte AND  |  VHDL
U1 : and_gate
    port map (
        a => x,
        b => y,
        s => z
    );

 

U1 est l’étiquette unique de l’instance. and_gate est le nom du composant déclaré. La clause port map associe les ports formels du composant aux signaux réels du niveau supérieur.

8.3.5 Connexion par port map

Terme

Définition

Exemple

Port formelPort déclaré dans le composant ou l’entitéa, b, s
Signal réelSignal ou port du niveau supérieurx, y, z
AssociationLien entre le formel et le réela => x
Étiquette d’instanceNom unique de l’exemplaireU1

 

8.3.6 Association par nom

Association nommée  |  VHDL
U1 : and_gate
    port map (
        a => x,
        b => y,
        s => z
    );

 

  • ordre libre ;
  • lecture explicite ;
  • maintenance plus sûre ;
  • adaptée aux composants possédant de nombreux ports.

8.3.7 Association par position

Association positionnelle  |  VHDL
U1 : and_gate
    port map (
        x,
        y,
        z
    );

 

Les signaux sont associés selon l’ordre de déclaration des ports. Une modification de l’interface peut rendre cette écriture dangereuse.

Bonne pratique — Recommandation

Privilégier l’association par nom dans les supports pédagogiques et les projets maintenables.

 

8.3.8 Exemple complet traditionnel

Entité de niveau supérieur  |  VHDL
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity circuit_structurel is
    port (
        a, b, c : in  std_logic;
        y       : out std_logic
    );
end entity circuit_structurel;

 

Architecture structurelle — Partie 1  |  VHDL
architecture structurelle of circuit_structurel is
    component and_gate is
        port (
            a, b : in  std_logic;
            s    : out std_logic
        );
    end component;

    component or_gate is
        port (
            a, b : in  std_logic;
            s    : out std_logic
        );
    end component;

    signal s_et : std_logic;
begin

 

Architecture structurelle — Partie 2  |  VHDL
    U_AND : and_gate
        port map (
            a => a,
            b => b,
            s => s_et
        );

    U_OR : or_gate
        port map (
            a => s_et,
            b => c,
            s => y
        );
end architecture structurelle;

 

8.3.9 Liaison des composants

Lors de l’élaboration, l’outil doit déterminer quelle entité et quelle architecture correspondent à chaque déclaration de composant. Cette liaison peut être implicite, définie par une configuration ou évitée grâce à l’instanciation directe d’entité.

8.3.10 Génériques dans une instance

Composant paramétrable  |  VHDL
component registre 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 component;

 

Association du générique  |  VHDL
U_REG : registre
    generic map (
        N => 16
    )
    port map (
        clk => clk,
        d   => donnee_16bits,
        q   => sortie_16bits
    );

 

8.3.11 Avantages du style structurel

  • hiérarchie matérielle explicite ;
  • réutilisation des composants validés ;
  • développement en équipe facilité ;
  • tests unitaires possibles pour chaque bloc ;
  • correspondance naturelle avec une architecture système ;
  • remplacement d’une implémentation sans modifier les interfaces.

8.3.12 Limites du style structurel

  • code plus long ;
  • nombreux signaux internes ;
  • risque d’erreurs de connexion ;
  • déclarations de composants redondantes avec la forme traditionnelle ;
  • peu adapté à une fonction logique très simple ;
  • hiérarchie excessive si les blocs sont trop petits.

Choix — Quand l’utiliser ?

Le style structurel devient particulièrement utile lorsque le système possède plusieurs blocs réutilisables, des interfaces stables et une hiérarchie fonctionnelle claire.

 

8.4 Instanciation directe d’entité

L’instanciation directe référence explicitement une entité déjà compilée, sa bibliothèque et éventuellement son architecture. Elle évite la déclaration préalable d’un composant.

8.4.1 Syntaxe demandée

Instanciation directe  |  VHDL
U1 : entity work.and_gate
    port map (
        a => x,
        b => y,
        s => z
    );

 

Le mot entity indique une instanciation directe. work représente la bibliothèque de travail. and_gate est l’entité à instancier.

8.4.2 Sélection explicite de l’architecture

Entité et architecture  |  VHDL
U1 : entity work.and_gate(rtl)
    port map (
        a => x,
        b => y,
        s => z
    );

 

La mention (rtl) sélectionne l’architecture nommée rtl. Sans cette mention, l’outil applique ses règles de liaison.

8.4.3 Avantages

  • aucune déclaration de composant à dupliquer ;
  • référence explicite à la bibliothèque ;
  • possibilité de sélectionner une architecture ;
  • réduction des incompatibilités entre composant et entité ;
  • code plus court et plus facile à maintenir.

8.4.4 Comparaison avec l’instanciation traditionnelle

Critère

Composant déclaré

Entité directe

Déclaration localeNécessaireNon
Bibliothèque visibleLiaison séparéeÉcrite dans l’instance
Choix d’architectureConfiguration ou liaisonPossible avec entité(architecture)
Risque d’interface désynchroniséePlus élevéRéduit
Compatibilité avec anciens styles/outilsTrès largeLarge dans les outils modernes

 

8.4.5 Instanciation directe avec générique

Registre générique  |  VHDL
U_REG16 : entity work.registre(rtl)
    generic map (
        N => 16
    )
    port map (
        clk => clk,
        d   => entree_16bits,
        q   => sortie_16bits
    );

 

8.4.6 Instances multiples

Deux instances de la même entité  |  VHDL
U_AND1 : entity work.and_gate(rtl)
    port map (
        a => a,
        b => b,
        s => s1
    );

U_AND2 : entity work.and_gate(rtl)
    port map (
        a => c,
        b => d,
        s => s2
    );

 

Chaque instance possède ses propres connexions et correspond à une ressource matérielle distincte, sauf optimisation possible par l’outil.

8.4.7 Ports laissés ouverts

Sortie non utilisée  |  VHDL
U_BLOC : entity work.bloc(rtl)
    port map (
        entree       => entree,
        sortie_utile => sortie,
        diagnostic   => open
    );

 

Le mot open peut être utilisé lorsqu’un port de sortie n’est pas connecté. Son usage sur les ports d’entrée dépend de l’existence d’une valeur par défaut et des règles du langage.

8.4.8 Connexion à une constante

Entrée fixée  |   VHDL
U_BLOC : entity work.bloc(rtl)
    port map (
        enable => '1',
        entree => donnee,
        sortie => resultat
    );

 

8.4.9 Ordre de compilation

L’entité instanciée doit être analysée avant le niveau qui l’utilise. L’ordre de compilation est donc important.

Ordre indicatif  |  Terminal
ghdl -a --std=08 and_gate.vhd
ghdl -a --std=08 top_level.vhd

 

8.4.10 Erreurs fréquentes

Erreur

Cause

Correction

Entité introuvableFichier non compilé ou mauvaise bibliothèqueCompiler dans le bon ordre
Architecture introuvableNom incorrectVérifier l’architecture sélectionnée
Port inconnuNom différent dans l’entitéComparer le port map à l’interface
Largeur incompatibleVecteurs de tailles différentesAdapter ou convertir
Type incompatiblesigned, unsigned ou std_logic_vector mélangésAjouter une conversion explicite
Étiquette dupliquéeDeux instances portent le même nomUtiliser une étiquette unique

 

8.5 Comparaison des styles

Le choix d’un style dépend de la taille du circuit, de son niveau hiérarchique, de la nature de la fonction et de la facilité avec laquelle le concepteur souhaite relier le code au matériel.

8.5.1 Comparaison générale

Critère

Flot de données

Comportemental

Structurel

Vision principaleRelations entre signauxFonction ou algorithmeAssemblage de blocs
Instructions typiquesAffectations concurrentesProcessus, if, case, bouclesInstances, port map
AbstractionMoyenneÉlevéeFaible à moyenne
Hiérarchie expliciteFaibleFaible à moyenneForte
UsageCombinatoire simpleLogique complexe et cadencéeSystèmes hiérarchiques
Longueur du codeCourteMoyenneSouvent longue

 

8.5.2 Lisibilité

La lisibilité dépend du type de problème. Une équation simple est plus lisible en flot de données, tandis qu’un contrôleur complexe est souvent plus clair dans un processus.

Fonction

Style généralement le plus lisible

Porte logiqueFlot de données
Multiplexeur simpleFlot de données ou comportemental
Encodeur prioritaireComportemental
Machine à étatsComportemental
Additionneur à propagation de retenue étudié comme réseauStructurel
Système composé de plusieurs sous-fonctionsStructurel au niveau supérieur

 

8.5.3 Réutilisabilité

La réutilisabilité repose surtout sur des entités bien définies, des génériques et une hiérarchie stable. Le style structurel facilite l’assemblage de blocs réutilisables, mais chaque bloc peut être décrit par n’importe quel style.

  • interfaces clairement définies ;
  • génériques pour les dimensions ;
  • absence de dépendance inutile au niveau supérieur ;
  • bancs de test unitaires ;
  • bibliothèques de composants validés.

8.5.4 Niveau d’abstraction

Niveau

Description

Exemple

Comportemental élevéCe que le circuit doit faireif, case, algorithme
RTLTransferts, registres et logique combinatoireprocessus cadencé et logique de prochaine valeur
Flot de donnéesRelations entre valeurséquations et affectations
StructurelBlocs et connexionsinstances de composants

 

8.5.5 Facilité de synthèse

Les trois styles sont synthétisables lorsqu’ils utilisent des constructions prises en charge. La facilité de synthèse dépend davantage de la clarté du matériel décrit que du nom du style.

Situation

Impact possible

Équation combinatoire simpleSynthèse directe et optimisable
Processus combinatoire completSynthèse correcte sans latch
Boucle statiqueDéroulement matériel
Processus avec affectations incomplètesLatch involontaire
Hiérarchie structurelle profondeConservation ou aplatissement selon l’outil
Division algorithmique complexeRessources importantes, quel que soit le style

 

8.5.6 Adaptation à la complexité

Complexité du bloc

Style conseillé

Très faible : porte, équationFlot de données
Faible : multiplexeur, décodeurFlot de données ou comportemental
Moyenne : UAL, encodeur prioritaireComportemental
Élevée : contrôleur, protocoleComportemental structuré
Système de plusieurs modulesStructurel au niveau supérieur
Projet completCombinaison des trois styles

 

8.5.7 Un même circuit, trois descriptions

Considérons la fonction y = (a AND b) OR c.

Version flot de données  |  VHDL
architecture flot_donnees of exemple is
begin
    y <= (a and b) or c;
end architecture flot_donnees;

 

Version comportementale  |  VHDL
architecture comportementale of exemple is
begin
    process(all)
    begin
        if a = '1' and b = '1' then
            y <= '1';
        else
            y <= c;
        end if;
    end process;
end architecture comportementale;

 

Version structurelle  |  VHDL
architecture structurelle of exemple is
    signal s_et : std_logic;
begin
    U_ET : entity work.and_gate(rtl)
        port map (a => a, b => b, s => s_et);

    U_OU : entity work.or_gate(rtl)
        port map (a => s_et, b => c, s => y);
end architecture structurelle;

 

Le synthétiseur peut produire une logique équivalente pour les trois architectures. La différence principale se situe dans la manière dont le concepteur exprime et organise la fonction.

8.5.8 Style mixte

Architecture mixte — Partie 1  |  VHDL
architecture mixte of systeme is
    signal resultat_alu : std_logic_vector(7 downto 0);
    signal valide_i     : std_logic;
begin
    U_ALU : entity work.ual(comportementale)
        port map (
            a         => a,
            b         => b,
            operation => operation,
            resultat  => resultat_alu
        );
Architecture mixte — Partie 2  |  VHDL
    valide_i <= enable and not erreur;

    process(clk)
    begin
        if rising_edge(clk) then
            if valide_i = '1' then
                sortie <= resultat_alu;
            end if;
        end if;
    end process;
end architecture mixte;

 

Pratique — Approche réaliste

Le style mixte est généralement le plus adapté aux projets réels : hiérarchie structurelle, calculs combinatoires par flot de données et logique de contrôle comportementale.

 

8.5.9 Choix guidé

Question

Si la réponse est oui

Style à envisager

La fonction s’écrit-elle en quelques équations ?Expression directeFlot de données
Plusieurs conditions ou boucles sont-elles nécessaires ?Algorithme interneComportemental
Le bloc assemble-t-il des modules existants ?Hiérarchie et connexionsStructurel
Faut-il visualiser clairement la propagation entre étages ?Réseau expliciteStructurel
Le circuit doit-il évoluer fréquemment ?Regroupement fonctionnelComportemental
Le système possède-t-il plusieurs niveaux ?CombinaisonStyle mixte

 

8.5.10 Erreurs de conception à éviter

Erreur

Conséquence

Prévention

Décomposer une porte en trop de sous-composantsCode inutilement longConserver le flot de données
Écrire une UAL complexe en une seule expressionLisibilité faibleUtiliser un processus case
Dupliquer les déclarations de composantsMaintenance difficileInstanciation directe
Utiliser un processus incompletLatchValeurs par défaut
Mélanger les niveaux d’abstraction sans organisationArchitecture confuseDéfinir des frontières de blocs
Instancier avant compilationEntité introuvableGérer les dépendances

 

Méthode de choix et de combinaison des styles

  1. Définir la fonction et les interfaces du bloc.
  2. Identifier les sous-fonctions réutilisables.
  3. Choisir le niveau d’abstraction de chaque sous-fonction.
  4. Utiliser le flot de données pour les équations simples.
  5. Utiliser un processus pour les décisions et algorithmes.
  6. Créer une hiérarchie structurelle pour assembler les blocs.
  7. Privilégier l’instanciation directe d’entité.
  8. Écrire un banc de test pour chaque niveau.
  9. Comparer le schéma RTL au matériel attendu.
  10. Mesurer les ressources et les performances avant de conclure qu’un style est meilleur.

Checklist d’une architecture structurelle

  • Chaque entité instanciée est-elle compilée ?
  • Chaque instance possède-t-elle une étiquette unique ?
  • Les noms de ports sont-ils corrects ?
  • Les types et largeurs sont-ils compatibles ?
  • Les signaux internes sont-ils déclarés ?
  • Aucun signal ne possède-t-il plusieurs pilotes involontaires ?
  • Les génériques sont-ils correctement associés ?
  • Le banc de test couvre-t-il la propagation entre les niveaux ?

Travaux pratiques

TP 5 — Additionneur hiérarchique

1. Objectifs du TP

  • décrire un demi-additionneur par flot de données ;
  • construire un additionneur complet à partir de deux demi-additionneurs ;
  • construire un additionneur 4 bits par propagation de retenue ;
  • instancier plusieurs composants ;
  • utiliser des signaux internes pour les retenues ;
  • écrire une version comportementale équivalente ;
  • simuler les deux versions ;
  • comparer les résultats, le code et le schéma RTL.

2. Rappel fonctionnel

Bloc

Entrées

Sorties

Fonction

Demi-additionneura, bsomme, retenueAddition de deux bits
Additionneur completa, b, cinsomme, coutAddition de trois bits
Additionneur 4 bitsa(3:0), b(3:0), cinsomme(3:0), coutAddition de deux mots

 

3. Organisation des fichiers

Arborescence proposée  |  Arborescence
tp5_additionneur_hierarchique/
├── src/
│   ├── demi_additionneur.vhd
│   ├── additionneur_complet.vhd
│   ├── additionneur4_structurel.vhd
│   └── additionneur4_comportemental.vhd
└── sim/
    ├── tb_demi_additionneur.vhd
    ├── tb_additionneur_complet.vhd
    └── tb_additionneur4.vhd

 

4. Partie A — Demi-additionneur

demi_additionneur.vhd  |   VHDL
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity demi_additionneur is
    port (
        a, b    : in   std_logic;
        somme   : out std_logic;
        retenue : out std_logic
    );
end entity demi_additionneur;

architecture flot_donnees of demi_additionneur is
begin
    somme   <= a xor b;
    retenue <= a and b;
end architecture flot_donnees;

 

5. Banc de test du demi-additionneur

tb_demi_additionneur.vhd — Partie 1  |  VHDL
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use STD.ENV.ALL;

entity tb_demi_additionneur is
end entity tb_demi_additionneur;

architecture simulation of tb_demi_additionneur is
    signal a, b    : std_logic := '0';
    signal somme   : std_logic;
    signal retenue : std_logic;
begin
    DUT : entity work.demi_additionneur(flot_donnees)
        port map (
            a => a,
            b => b,
            somme => somme,
            retenue => retenue
        );
tb_demi_additionneur.vhd — Partie 2  |  VHDL
    stimuli : process
    begin
        a <= '0'; b <= '0'; wait for 10 ns;
        assert somme = '0' and retenue = '0'
            severity error;

        a <= '0'; b <= '1'; wait for 10 ns;
        assert somme = '1' and retenue = '0'
            severity error;

        a <= '1'; b <= '0'; wait for 10 ns;
        assert somme = '1' and retenue = '0'
            severity error;

        a <= '1'; b <= '1'; wait for 10 ns;
        assert somme = '0' and retenue = '1'
            severity error;

        report "Demi-additionneur valide" severity note;
        stop;
        wait;
    end process;
end architecture simulation;

 

6. Partie B — Additionneur complet

Un additionneur complet peut être construit avec deux demi-additionneurs et une porte OR. Le premier additionne a et b. Le second additionne la somme intermédiaire et cin.

additionneur_complet.vhd — Entité  |  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;

 

additionneur_complet.vhd — Architecture, partie 1  |  VHDL
architecture structurelle of additionneur_complet is
    signal somme_1   : std_logic;
    signal retenue_1 : std_logic;
    signal retenue_2 : std_logic;
begin
    U_HA1 : entity work.demi_additionneur(flot_donnees)
        port map (
            a       => a,
            b       => b,
            somme   => somme_1,
            retenue => retenue_1
        );
additionneur_complet.vhd — Architecture, partie 2  |  VHDL
    U_HA2 : entity work.demi_additionneur(flot_donnees)
        port map (
            a       => somme_1,
            b       => cin,
            somme   => somme,
            retenue => retenue_2
        );

    cout <= retenue_1 or retenue_2;
end architecture structurelle;

 

7. Équations de l’additionneur complet

Équations équivalentes  |  Équations
somme = a XOR b XOR cin

cout = (a AND b)
       OR (a AND cin)
       OR (b AND cin)

 

a

b

cin

somme

cout

00000
00110
01010
01101
10010
10101
11001
11111

 

8. Banc de test de l’additionneur complet

tb_additionneur_complet.vhd — Partie 1  |  VHDL
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use STD.ENV.ALL;

entity tb_additionneur_complet is
end entity tb_additionneur_complet;

architecture simulation of tb_additionneur_complet is
    signal entree : std_logic_vector(2 downto 0)
                    := (others => '0');
    signal somme : std_logic;
    signal cout  : std_logic;
begin
    DUT : entity work.additionneur_complet(structurelle)
        port map (
            a     => entree(2),
            b     => entree(1),
            cin   => entree(0),
            somme => somme,
            cout  => cout
        );

 

tb_additionneur_complet.vhd — Partie 2A  |  VHDL
    stimuli : process
        variable valeur : natural;
        variable attendu : unsigned(1 downto 0);
    begin
        for i in 0 to 7 loop
            entree <= std_logic_vector(to_unsigned(i, 3));
            wait for 1 ns;

            valeur := to_integer(unsigned(entree(2 downto 2)))
                    + to_integer(unsigned(entree(1 downto 1)))
                    + to_integer(unsigned(entree(0 downto 0)));
tb_additionneur_complet.vhd — Partie 2B  |  VHDL
            attendu := to_unsigned(valeur, 2);

            assert cout = attendu(1)
               and somme = attendu(0)
                report "Erreur additionneur complet"
                severity error;

            wait for 9 ns;
        end loop;

        report "Additionneur complet valide"
            severity note;
        stop;
        wait;
    end process;
end architecture simulation;

 

9. Partie C — Additionneur 4 bits structurel

L’additionneur 4 bits est construit avec quatre additionneurs complets. La retenue de chaque étage alimente l’entrée cin de l’étage suivant.

additionneur4_structurel.vhd — Entité  |  VHDL
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity additionneur4_structurel is
    port (
        a, b  : in   std_logic_vector(3 downto 0);
        cin   : in   std_logic;
        somme : out std_logic_vector(3 downto 0);
        cout  : out std_logic
    );
end entity additionneur4_structurel;

 

additionneur4_structurel.vhd — Architecture, partie 1  |  VHDL
architecture structurelle of additionneur4_structurel is
    signal retenues : std_logic_vector(4 downto 0);
begin
    retenues(0) <= cin;

    U_FA0 : entity work.additionneur_complet(structurelle)
        port map (
            a => a(0), b => b(0),
            cin => retenues(0),
            somme => somme(0),
            cout => retenues(1)
        );

    U_FA1 : entity work.additionneur_complet(structurelle)
        port map (
            a => a(1), b => b(1),
            cin => retenues(1),
            somme => somme(1),
            cout => retenues(2)
        );
additionneur4_structurel.vhd — Architecture, partie 2  |  VHDL
    U_FA2 : entity work.additionneur_complet(structurelle)
        port map (
            a => a(2), b => b(2),
            cin => retenues(2),
            somme => somme(2),
            cout => retenues(3)
        );

    U_FA3 : entity work.additionneur_complet(structurelle)
        port map (
            a => a(3), b => b(3),
            cin => retenues(3),
            somme => somme(3),
            cout => retenues(4)
        );

    cout <= retenues(4);
end architecture structurelle;

 

10. Propagation de la retenue

Étage

Bits additionnés

Retenue d’entrée

Retenue de sortie

0a(0), b(0)cinretenues(1)
1a(1), b(1)retenues(1)retenues(2)
2a(2), b(2)retenues(2)retenues(3)
3a(3), b(3)retenues(3)cout

 

Architecture — Ripple-carry adder

Cette architecture est appelée additionneur à propagation de retenue. Le chemin critique traverse potentiellement les quatre étages, car chaque retenue dépend de l’étage précédent.

 

11. Partie D — Version comportementale

additionneur4_comportemental.vhd — Entité  |  VHDL
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity additionneur4_comportemental is
    port (
        a, b  : in   std_logic_vector(3 downto 0);
        cin   : in   std_logic;
        somme : out std_logic_vector(3 downto 0);
        cout  : out std_logic
    );
end entity additionneur4_comportemental;
additionneur4_comportemental.vhd — Architecture  |  VHDL
architecture comportementale of additionneur4_comportemental is
begin
    process(all)
        variable resultat_v : unsigned(4 downto 0);
    begin
        resultat_v :=
            resize(unsigned(a), 5)
            + resize(unsigned(b), 5);

        if cin = '1' then
            resultat_v := resultat_v + 1;
        end if;

        somme <= std_logic_vector(resultat_v(3 downto 0));
        cout  <= resultat_v(4);
    end process;
end architecture comportementale;

 

12. Variante compacte par flot de données

Expression concurrente  |  VHDL
resultat <= ('0' & unsigned(a))
           + ('0' & unsigned(b))
           + to_unsigned(
                 1 when cin = '1' else 0,
                 5
             );

 

Cette variante est concise mais peut être moins accessible pour un débutant. La version comportementale explicite le traitement de cin.

13. Banc de test commun aux deux versions

tb_additionneur4.vhd — Déclarations  |  VHDL
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use STD.ENV.ALL;

entity tb_additionneur4 is
end entity tb_additionneur4;

architecture simulation of tb_additionneur4 is
    signal a, b : std_logic_vector(3 downto 0)
                  := (others => '0');
    signal cin  : std_logic := '0';

    signal somme_struct : std_logic_vector(3 downto 0);
    signal cout_struct  : std_logic;

    signal somme_comp : std_logic_vector(3 downto 0);
    signal cout_comp  : std_logic;
begin

 

Instance de la version structurelle  |  VHDL
    DUT_STRUCTUREL :
        entity work.additionneur4_structurel(structurelle)
        port map (
            a => a,
            b => b,
            cin => cin,
            somme => somme_struct,
            cout => cout_struct
        );
Instance de la version comportementale  |  VHDL
    DUT_COMPORTEMENTAL :
        entity work.additionneur4_comportemental(comportementale)
        port map (
            a => a,
            b => b,
            cin => cin,
            somme => somme_comp,
            cout => cout_comp
        );

 

Tests exhaustifs — Partie 1A  |  VHDL
    stimuli : process
        variable valeur_attendue : natural range 0 to 31;
        variable mot_attendu : unsigned(4 downto 0);
    begin
        for va in 0 to 15 loop
            for vb in 0 to 15 loop
                for vc in 0 to 1 loop
                    a <= std_logic_vector(to_unsigned(va, 4));
                    b <= std_logic_vector(to_unsigned(vb, 4));

                    if vc = 0 then
                        cin <= '0';
                    else
                        cin <= '1';
                    end if;
Tests exhaustifs — Partie 1B  |  VHDL
                    wait for 1 ns;

                    valeur_attendue := va + vb + vc;
                    mot_attendu := to_unsigned(
                         valeur_attendue,
                         mot_attendu'length
                    );

 

Tests exhaustifs — Partie 2  |  VHDL
                    assert cout_struct = mot_attendu(4)
                       and unsigned(somme_struct) =
                            mot_attendu(3 downto 0)
                        report "Erreur version structurelle"
                        severity error;

                    assert cout_comp = mot_attendu(4)
                       and unsigned(somme_comp) =
                            mot_attendu(3 downto 0)
                        report "Erreur version comportementale"
                        severity error;

                    assert somme_struct = somme_comp
                       and cout_struct = cout_comp
                        report "Les deux versions different"
                        severity error;

                    wait for 1 ns;
                end loop;
            end loop;
        end loop;

        report "512 combinaisons validees"
            severity note;
        stop;
        wait;
    end process;
end architecture simulation;

 

14. Compilation avec GHDL

Compilation dans l’ordre des dépendances  |  Terminal
ghdl -a --std=08 src/demi_additionneur.vhd
ghdl -a --std=08 src/additionneur_complet.vhd
ghdl -a --std=08 src/additionneur4_structurel.vhd
ghdl -a --std=08 src/additionneur4_comportemental.vhd
ghdl -a --std=08 sim/tb_additionneur4.vhd

ghdl -e --std=08 tb_additionneur4
ghdl -r --std=08 tb_additionneur4    --vcd=tb_additionneur4.vcd

 

Observation du chronogramme  |  Terminal
gtkwave tb_additionneur4.vcd

 

15. Cas de test particuliers

a

b

cin

Résultat sur 5 bits

Interprétation

000000000000000 + 0
001101010010003 + 5 = 8
1111000101000015 + 1 = 16
1111111101111015 + 15 = 30
1111111111111115 + 15 + 1 = 31

 

16. Comparaison structurelle/comportementale

Critère

Version structurelle

Version comportementale

Longueur du codePlus longuePlus courte
Propagation des retenuesVisibleImplicite dans l’opérateur +
RéutilisationAdditionneur complet réutiliséBloc autonome
Compréhension pédagogiqueMontre la hiérarchieMontre la fonction
Évolution vers N bitsGenerate ou plusieurs instancesGénérique et opérateur +
Optimisation par synthèsePossiblePossible
Matériel finalSouvent équivalent après optimisationSouvent équivalent après optimisation

 

17. Observations demandées

  • Vérifier les quatre cas du demi-additionneur.
  • Vérifier les huit cas de l’additionneur complet.
  • Observer la propagation des retenues internes.
  • Tester les valeurs maximales de l’additionneur 4 bits.
  • Comparer les sorties des deux architectures.
  • Examiner les schémas RTL générés.
  • Comparer le nombre de niveaux hiérarchiques.
  • Comparer les ressources et la fréquence maximale après synthèse.

18. Questions d’analyse

1. Pourquoi le demi-additionneur est-il bien adapté au flot de données ?

2. Pourquoi l’additionneur complet peut-il être décrit structurellement avec deux demi-additionneurs ?

3. Quel est le rôle du signal somme_1 ?

4. Pourquoi retenue_1 et retenue_2 sont-elles combinées par OR ?

5. Comment la retenue se propage-t-elle dans l’additionneur 4 bits ?

6. Quelle différence existe entre la hiérarchie du code et le matériel optimisé ?

7. Pourquoi la version comportementale est-elle plus courte ?

8. Les deux versions produisent-elles nécessairement des performances différentes ?

9. Comment généraliser l’additionneur structurel à N bits ?

10. Quel style choisir pour un cours sur la propagation de retenue ?

19. Extensions proposées

  • Créer un additionneur 8 bits.
  • Utiliser une instruction for generate pour N bits.
  • Ajouter un indicateur de débordement signé.
  • Créer un additionneur/soustracteur commandé.
  • Comparer ripple-carry et carry-lookahead.
  • Ajouter un générique définissant la largeur.
  • Implanter l’additionneur sur une carte FPGA.
  • Afficher le résultat sur des LED ou des afficheurs sept segments.

20. Barème indicatif

Critère

Points

Demi-additionneur2
Additionneur complet structurel3
Additionneur 4 bits structurel4
Version comportementale3
Bancs de test et assertions3
Comparaison des architectures2
Analyse du schéma RTL2
Qualité du code et du compte rendu1
Total20

 

Synthèse du chapitre

Notion

Résumé

Flot de donnéesDécrit les relations et équations par affectations concurrentes.
ComportementalDécrit un algorithme avec processus, conditions et boucles.
StructurelDécrit une hiérarchie d’instances et de connexions.
ComponentDéclaration traditionnelle d’une interface à instancier.
port mapAssocie les ports formels aux signaux réels.
Association nomméeConnexion explicite avec =>.
Instanciation directeRéférence entity bibliothèque.nom_entité.
Style mixteCombine hiérarchie, équations et processus.
RéutilisabilitéDépend des interfaces, génériques et tests.
SynthèsePeut optimiser des descriptions différentes vers une logique équivalente.

 

Autoévaluation

1. Quel style utilise principalement des affectations concurrentes ?

Réponse : Le flot de données.

2. Quel style utilise principalement des processus ?

Réponse : Le style comportemental.

3. Quel style explicite les sous-composants ?

Réponse : Le style structurel.

4. Quel mot-clé associe les ports d’une instance ?

Réponse : port map.

5. Quel symbole est utilisé pour une association par nom ?

Réponse : =>.

6. Que représente work ?

Réponse : La bibliothèque de travail.

7. Quel avantage offre l’instanciation directe ?

Réponse : Elle évite la déclaration du composant.

8. Un même circuit peut-il avoir plusieurs architectures ?

Réponse : Oui.

9. Des styles différents peuvent-ils produire le même matériel ?

Réponse : Oui, après synthèse et optimisation.

10. Quel style est généralement utilisé au niveau supérieur d’un grand système ?

Réponse : Le style structurel ou mixte.

Exercice de consolidation

Décrire un circuit qui calcule y = (a XOR b) AND enable selon deux architectures : une architecture par flot de données et une architecture structurelle utilisant une porte XOR et une porte AND.

Architecture par flot de données  |  VHDL
architecture flot_donnees of exercice is
begin
    y <= (a xor b) and enable;
end architecture flot_donnees;

 

Architecture structurelle — Partie 1  |  VHDL
architecture structurelle of exercice is
    signal s_xor : std_logic;
begin
    U_XOR : entity work.xor_gate(rtl)
        port map (
            a => a,
            b => b,
            s => s_xor
        );
Architecture structurelle — Partie 2  |  VHDL
    U_AND : entity work.and_gate(rtl)
        port map (
            a => s_xor,
            b => enable,
            s => y
        );
end architecture structurelle;

 

Suite du cours — Transition vers la suite

Après les styles de description, le cours peut approfondir les génériques, la génération de matériel et la conception de composants paramétrables et réutilisables.