Leçon 6 sur 22

Chapitre 6 — Affectations concurrentes

Objectif — Finalité du chapitre

Comprendre le modèle concurrent de VHDL et utiliser les affectations simples, conditionnelles et sélectionnées pour décrire des relations combinatoires, des multiplexeurs et des décodeurs de manière claire et synthétisable.

Objectifs pédagogiques

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

  • expliquer pourquoi les instructions concurrentes décrivent un fonctionnement parallèle ;
  • distinguer l’ordre d’écriture du code de l’organisation du matériel obtenu ;
  • décrire une relation combinatoire avec une affectation simple ;
  • utiliser une affectation conditionnelle pour exprimer des choix prioritaires ;
  • utiliser une affectation sélectionnée pour des choix mutuellement exclusifs ;
  • identifier le multiplexeur inféré par une expression VHDL ;
  • employer correctement la clause others ;
  • éviter les descriptions incomplètes ou ambiguës ;
  • concevoir et simuler des multiplexeurs et des décodeurs ;
  • écrire des bancs de test exhaustifs avec assertions.

Prérequis

  • structure d’une entité et d’une architecture ;
  • types std_logic, std_logic_vector et unsigned ;
  • opérateurs logiques et relationnels ;
  • conversions avec IEEE.NUMERIC_STD ;
  • principes d’un banc de test VHDL.

Organisation du chapitre

Section

Contenu

Compétence principale

6.1Principe de concurrenceLire le code comme une structure matérielle parallèle
6.2Affectation simpleExprimer une équation logique directe
6.3Affectation conditionnelleDécrire un choix prioritaire
6.4Affectation sélectionnéeDécrire un choix selon une expression
TP 3Multiplexeurs et décodeursConcevoir, simuler et valider plusieurs circuits

 

Concept clé — Vision matérielle

Dans une architecture VHDL, chaque affectation concurrente représente un bloc de logique actif en permanence. Les relations sont réévaluées lorsqu’un signal lu par l’expression change.

 

6.1 Principe de concurrence

VHDL est un langage de description matérielle. Il ne décrit pas seulement une suite d’instructions à exécuter, mais un ensemble de composants et de relations fonctionnant simultanément. Cette concurrence est l’une des différences fondamentales entre une description matérielle et un programme logiciel classique.

6.1.1 Exécution parallèle des instructions

Trois affectations concurrentes  |  VHDL
architecture rtl of circuit is
begin
    s1 <= a and b;
    s2 <= c xor d;
    y   <= s1 or s2;
end architecture rtl;

 

Ces trois affectations représentent deux portes logiques suivies d’une porte OU. Elles sont actives en même temps. Lorsque a ou b change, s1 est recalculé ; lorsque c ou d change, s2 est recalculé ; lorsque s1 ou s2 change, y est recalculé.

Affectation

Matériel probable

Signaux lus

Signal piloté

s1 <= a and b;Porte ANDa, bs1
s2 <= c xor d;Porte XORc, ds2
y <= s1 or s2;Porte ORs1, s2y

 

6.1.2 L’ordre textuel n’impose pas l’ordre matériel

Même circuit, ordre différent  |  VHDL
architecture rtl of circuit is
begin
    y   <= s1 or s2;
    s2 <= c xor d;
    s1 <= a and b;
end architecture rtl;

 

Cette architecture décrit le même réseau combinatoire que l’exemple précédent. Le compilateur élabore les dépendances entre les signaux ; il ne transforme pas ces lignes en instructions exécutées successivement comme dans un programme procédural.

Bonne pratique — Lisibilité

Même si l’ordre n’affecte pas le matériel, il est conseillé d’écrire les expressions intermédiaires avant les sorties afin de faciliter la lecture humaine.

 

6.1.3 Différence avec un programme séquentiel

Programme logiciel

Description VHDL concurrente

Les instructions sont normalement exécutées l’une après l’autre.Les blocs matériels fonctionnent simultanément.
L’ordre des lignes modifie généralement le résultat.L’ordre des affectations concurrentes ne définit pas une chronologie.
Les variables sont modifiées immédiatement.Les signaux sont mis à jour selon le modèle de simulation.
Une seule unité de calcul peut exécuter plusieurs opérations successives.Plusieurs unités logiques peuvent être inférées en parallèle.
Le temps dépend du nombre d’instructions exécutées.Le temps dépend des chemins de propagation et de l’horloge.

 

6.1.4 Illustration logiciel/matériel

Pseudo-code séquentiel  |  Pseudo-code
s1 = a AND b
s2 = c XOR d
y  = s1 OR s2

 

Dans un logiciel, ces calculs peuvent être effectués successivement par un processeur. En VHDL, les trois équations correspondent à des ressources matérielles distinctes reliées par des signaux.

6.1.5 Relations entre signaux

Une affectation concurrente définit une relation permanente entre le signal cible et les signaux de l’expression. Elle peut être vue comme une équation logique ou un réseau de dépendances.

Relations entre signaux  |  VHDL
somme_logique <= a xor b xor retenue_entree;

retenue_sortie <= (a and b)
               or (a and retenue_entree)
               or (b and retenue_entree);

 

Cet exemple décrit les équations d’un additionneur complet. Le signal somme_logique et le signal retenue_sortie sont calculés en parallèle.

6.1.6 Événements et réévaluation

En simulation, une instruction concurrente est sensible aux signaux apparaissant dans son expression. Lorsqu’un événement survient sur l’un d’eux, l’expression est réévaluée et une nouvelle valeur est planifiée pour la cible.

Propagation sans retard explicite  |  VHDL
a <= '1';
b <= '1';

s <= a and b;

 

Même sans retard physique spécifié, la mise à jour peut nécessiter un ou plusieurs cycles delta. Les cycles delta permettent au simulateur de stabiliser les relations concurrentes sans avancer le temps réel de simulation.

6.1.7 Cycles delta simplifiés

Étape

Événement

Delta 0Les stimuli affectent a et b.
Delta 1L’expression a and b est réévaluée et une transaction est planifiée pour s.
Delta 2Le signal s prend sa nouvelle valeur ; les dépendances éventuelles sont réévaluées.
Temps physiqueAucun temps n’est nécessairement écoulé si aucun after n’est utilisé.

 

Simulation — Bancs de test

Après l’affectation de stimuli, un wait for 0 ns ou un faible délai est souvent utilisé avant une assertion afin de laisser les cycles delta se stabiliser.

 

6.1.8 Concurrence et processus

Un processus est lui-même une instruction concurrente. À l’intérieur du processus, les instructions sont séquentielles. Plusieurs processus et affectations directes fonctionnent néanmoins en parallèle.

Deux blocs concurrents  |  VHDL
architecture rtl of exemple is
begin
    y_combinatoire <= a and b;

    process(clk)
    begin
        if rising_edge(clk) then
            q <= d;
        end if;
    end process;
end architecture rtl;

 

Niveau

Nature

ArchitectureInstructions concurrentes
Affectation directeConcurrente
Processus entierConcurrent par rapport aux autres blocs
Instructions dans le processusSéquentielles

 

6.1.9 Pilotes de signaux

Chaque affectation concurrente crée un pilote pour son signal cible. Plusieurs affectations vers le même signal peuvent être légales si son type est résolu, mais elles décrivent plusieurs sources matérielles et peuvent produire des conflits.

Deux pilotes sur le même signal  |  VHDL
bus_partage <= donnee_a when autorisation_a = '1'
               else 'Z';

bus_partage <= donnee_b when autorisation_b = '1'
               else 'Z';

 

Attention — Éviter les conflits

Pour la logique interne courante, il est préférable qu’un signal possède un seul pilote. Plusieurs pilotes sont principalement utilisés pour les bus trois états ou des modèles de simulation.

 

6.1.10 Synthèse des formes concurrentes

Forme VHDL

Matériel inféré possible

y <= a and b;Porte logique
y <= a when sel='0' else b;Multiplexeur 2 vers 1
with sel select ...Multiplexeur à plusieurs entrées
y <= '1' when a=b else '0';Comparateur et logique de sortie
sortie <= entree(6 downto 0) & '0';Câblage de décalage
s <= resize(a,9)+resize(b,9);Additionneur

 

6.2 Affectation simple

L’affectation simple associe une expression à un signal cible. Elle est la forme la plus directe pour décrire des portes logiques, des opérations arithmétiques ou des connexions entre signaux.

6.2.1 Syntaxe générale

Forme générale  |   VHDL
signal_cible <= expression;

 

Le type et la longueur de l’expression doivent être compatibles avec le signal cible. L’expression peut contenir des opérateurs, des conversions, des appels de fonction, des tranches de vecteurs et des concaténations.

6.2.2 Exemple demandé : porte ET

Affectation simple  |  VHDL
s <= a and b;

 

a

b

s

000
010
100
111

 

6.2.3 Porte logique complexe

Équation combinatoire  |  VHDL
y <= (a and b) or (c and not d);

 

Le synthétiseur crée les portes nécessaires et optimise éventuellement l’équation selon la technologie cible.

6.2.4 Affectation d’un vecteur

Masquage bit à bit  |   VHDL
sortie <= donnees and masque;

 

Complément d’un bus  |   VHDL
sortie <= not entree;

 

6.2.5 Connexion directe

Copie d’un signal  |  VHDL
sortie <= entree;

 

Une connexion directe peut ne consommer aucune ressource logique ; elle correspond simplement à un câblage dans le réseau d’interconnexion.

6.2.6 Concaténation et extraction

Construction d’un octet  |  VHDL
octet <= poids_fort & poids_faible;

 

Extraction d’un champ  |  VHDL
opcode <= instruction(15 downto 12);

 

Extension non signée  |  VHDL
valeur_12bits <= "0000" & valeur_8bits;

 

6.2.7 Affectation arithmétique

Addition avec retenue  |  VHDL
somme <= std_logic_vector(
    resize(unsigned(a), somme'length)
    +
    resize(unsigned(b), somme'length)
);

 

Typage — Type numérique

Une affectation simple peut décrire des calculs complexes, mais les conversions et le dimensionnement du résultat doivent rester explicites.

 

6.2.8 Retard de simulation

Retard inertiel implicite  |  VHDL
s <= a and b after 5 ns;

 

Retard de transport  |  VHDL
s <= transport (a and b) after 5 ns;

 

Les retards explicites sont principalement utilisés dans les modèles de simulation. Ils ne représentent généralement pas une méthode portable pour imposer un retard physique après synthèse.

Attention — Synthèse

Pour les descriptions RTL destinées au FPGA, éviter les clauses after dans la logique fonctionnelle. Les retards réels sont déterminés par la synthèse, le placement et le routage.

 

6.2.9 Plusieurs affectations d’un même signal

Deux affectations concurrentes séparées créent deux pilotes, tandis que deux affectations séquentielles dans un même processus correspondent à un seul pilote. Cette distinction est essentielle.

Deux pilotes concurrents  |  VHDL
y <= a and b;
y <= c or d;

 

Avec std_logic, la fonction de résolution combine les deux valeurs. Si un pilote produit 0 et l’autre 1, y peut devenir X. Cette écriture ne correspond pas à un OU implicite.

Combinaison correcte en un seul pilote  |  VHDL
y <= (a and b) or (c or d);

 

6.2.10 Exemples d’inférence

Affectation

Interprétation matérielle

y <= not a;Inverseur
y <= a xor b;Porte XOR
y <= a(6 downto 0) & '0';Décalage fixe par câblage
egal <= '1' when a=b else '0';Comparateur d’égalité
parite <= d(3) xor d(2) xor d(1) xor d(0);Réseau XOR
s <= a + b;Additionneur, si les types sont numériques

 

6.3 Affectation conditionnelle

L’affectation conditionnelle choisit une valeur parmi plusieurs expressions selon des conditions booléennes. Les conditions sont testées de gauche à droite ; la première condition vraie détermine le résultat. Cette forme exprime donc une priorité.

6.3.1 Syntaxe élémentaire

Multiplexeur 2 vers 1  |   VHDL
y <= a when sel = '0'
     else b;

 

sel

y

0a
1b

 

Cette affectation infère un multiplexeur 2 vers 1. Le signal sel commande l’entrée transmise vers y.

6.3.2 Forme générale

Conditions successives  |  VHDL
cible <= expression_1 when condition_1
     else expression_2 when condition_2
     else expression_3 when condition_3
     else expression_par_defaut;

 

La dernière expression est obligatoire dans la forme combinatoire usuelle : elle définit le résultat lorsque toutes les conditions précédentes sont fausses.

6.3.3 Priorité des conditions

Encodeur prioritaire  |  VHDL
code <= "11" when entree(3) = '1'
   else "10" when entree(2) = '1'
   else "01" when entree(1) = '1'
   else "00";

 

Si plusieurs bits valent 1, le bit de plus fort indice est prioritaire, car sa condition apparaît en premier.

entree

code

Explication

"1000""11"La première condition est vraie
"1100""11"entree(3) est prioritaire sur entree(2)
"0110""10"entree(2) est prioritaire sur entree(1)
"0010""01"Seule la troisième condition est vraie
"0000""00"Valeur par défaut

 

Priorité — Ordre significatif

Dans une affectation conditionnelle à plusieurs branches, permuter deux conditions peut modifier le matériel et le comportement.

 

6.3.4 Multiplexeur à plusieurs entrées

Multiplexeur 4 vers 1 conditionnel  |  VHDL
y <= a when sel = "00"
     else b when sel = "01"
     else c when sel = "10"
     else d;

 

Les conditions sont ici mutuellement exclusives si sel ne contient que 0 et 1. La structure synthétisée est un multiplexeur 4 vers 1.

6.3.5 Valeurs inconnues du sélecteur

Si sel contient U, X ou Z, aucune comparaison binaire exacte ne peut être vraie. La branche finale est alors sélectionnée dans l’exemple précédent.

Traitement explicite des valeurs non valides   |  VHDL
y <= a when sel = "00"
     else b when sel = "01"
     else c when sel = "10"
     else d when sel = "11"
     else (others => 'X');

 

Diagnostic — Simulation défensive

Une branche finale à X peut révéler plus rapidement un sélecteur non initialisé. Pour la synthèse, vérifier le comportement attendu et la politique de sécurité du système.

 

6.3.6 Conditions relationnelles

Sélection selon une comparaison  |  VHDL
maximum <= a when unsigned(a) >= unsigned(b)
       else b;

 

Cette expression infère un comparateur et un multiplexeur.

6.3.7 Saturation

Limitation d’une valeur  |  VHDL
sortie <= x"FF"
     when valeur_interne > to_unsigned(255, valeur_interne'length)
     else std_logic_vector(valeur_interne(7 downto 0));

 

La condition commande un multiplexeur entre la valeur maximale et la valeur tronquée.

6.3.8 Activation d’un résultat

Sortie forcée à zéro si désactivée  |  VHDL
sortie <= resultat_interne
     when enable = '1'
     else (others => '0');

 

6.3.9 Conditions imbriquées et lisibilité

Expression difficile à lire  |  VHDL
y <= a when c1='1' else b when c2='1'
     else c when c3='1' else d;

 

Présentation recommandée  |  VHDL
y <= a when c1 = '1'
     else b when c2 = '1'
     else c when c3 = '1'
     else d;

 

  • Aligner les mots when et else.
  • Limiter le nombre de niveaux dans une seule expression.
  • Nommer les conditions complexes dans des signaux intermédiaires.
  • Documenter clairement la priorité.

6.3.10 Inférence de multiplexeurs prioritaires

Nombre de conditions

Structure probable

Une conditionMultiplexeur 2 vers 1
Deux conditions successivesChaîne prioritaire de multiplexeurs
Plusieurs conditions exclusivesMultiplexeur à plusieurs entrées, optimisable
Conditions complexesComparateurs/logique de commande + multiplexeurs

 

Performance — Chemin critique

Une longue chaîne prioritaire peut augmenter le chemin combinatoire. Lorsque les choix sont naturellement indexés par un sélecteur, une affectation sélectionnée ou une instruction case peut produire une structure plus régulière.

 

6.3.11 Affectation conditionnelle et latch

Une affectation conditionnelle concurrente comporte une expression finale et définit donc toujours la cible. Elle ne crée normalement pas de latch. Le risque de latch apparaît surtout dans un processus combinatoire dont certaines branches n’affectent pas la sortie.

Affectation combinatoire complète  |  VHDL
y <= a when sel = '0'
     else b;

 

6.4 Affectation sélectionnée

L’affectation sélectionnée choisit une expression selon la valeur d’une expression de sélection. Chaque choix doit être couvert une seule fois et l’ensemble des possibilités doit être complet, souvent grâce à others.

6.4.1 Syntaxe générale

Forme générale  |   VHDL
with expression_selection select
    cible <= expression_1 when choix_1,
             expression_2 when choix_2,
             expression_3 when choix_3,
             expression_defaut when others;

 

6.4.2 Exemple demandé : multiplexeur 4 vers 1

Affectation sélectionnée  |  VHDL
with sel select
    y <= a when "00",
         b when "01",
         c when "10",
         d when others;

 

sel

y

"00"a
"01"b
"10"c
"11"d
Autre valeur logiqued dans cette écriture

 

6.4.3 Sélection selon une expression

L’expression de sélection peut être un signal, une tranche, une concaténation ou une expression dont le type est discret.

Sélection par opcode  |  VHDL
with opcode select
    resultat <= a and b when "000",
                a or b  when "001",
                a xor b when "010",
                not a   when "011",
                (others => '0') when others;

 

Cette description infère une unité logique combinatoire suivie d’un multiplexeur, ou une logique équivalente optimisée.

6.4.4 Choix multiples

Plusieurs valeurs pour le même résultat  |  VHDL
with commande select
    actif <= '1' when "001" | "010" | "100",
             '0' when others;

 

Le symbole | regroupe plusieurs choix discrets ayant la même expression cible.

6.4.5 Utilisation de others

others couvre toutes les valeurs qui ne sont pas explicitement mentionnées. Il garantit la complétude du choix et est particulièrement utile avec std_logic_vector, dont chaque bit peut prendre neuf valeurs.

Valeur de sécurité  |  VHDL
with sel select
    y <= a   when "00",
         b   when "01",
         c   when "10",
         d   when "11",
         'X' when others;

 

Conception — Choisir la valeur par défaut

La branche others peut représenter un fonctionnement normal, une valeur sûre ou un indicateur d’erreur. Son choix doit être cohérent avec le cahier des charges.

 

6.4.6 Absence de priorité

Contrairement à l’affectation conditionnelle, les choix d’une affectation sélectionnée ne sont pas ordonnés par priorité. Ils doivent être mutuellement exclusifs.

Affectation conditionnelle

Affectation sélectionnée

Les conditions sont évaluées de gauche à droite.La valeur de sélection détermine directement un choix.
Une priorité est implicite.Aucune priorité entre les choix.
Les conditions peuvent être différentes et complexes.Tous les choix portent sur la même expression.
Convient aux encodeurs prioritaires.Convient aux multiplexeurs et tables de correspondance.

 

6.4.7 Recouvrement interdit

Deux choix ne doivent pas couvrir la même valeur. Un recouvrement rendrait le résultat ambigu et provoque une erreur d’analyse.

Exemple incorrect  |  VHDL
with sel select
    y <= a when "00",
         b when "00" | "01",
         c when others;

 

La valeur «00» apparaît dans deux alternatives.

6.4.8 Couverture complète

Couverture explicite sans others  |  VHDL
with sel select
    y <= a when "00",
         b when "01",
         c when "10",
         d when "11";

 

Cette forme peut être valide si le type de sel ne contient que ces quatre valeurs. Avec std_logic_vector, il existe de nombreuses combinaisons incluant U, X, Z, etc. La clause others est donc généralement nécessaire.

6.4.9 Décodeur 2 vers 4

Décodeur avec affectation sélectionnée  |  VHDL
with entree select
    sortie <= "0001" when "00",
              "0010" when "01",
              "0100" when "10",
              "1000" when "11",
              "0000" when others;

 

entree

sortie

"00""0001"
"01""0010"
"10""0100"
"11""1000"

 

6.4.10 Décodeur avec activation

Décodeur activé  |  VHDL
with (enable & entree) select
    sortie <= "0001" when "100",
              "0010" when "101",
              "0100" when "110",
              "1000" when "111",
              "0000" when others;

 

La concaténation enable & entree crée une expression de sélection sur trois bits. Lorsque enable vaut 0, la sortie est nulle.

6.4.11 Décodeur BCD vers sept segments

Un décodeur BCD traduit un chiffre de 0 à 9 en sept signaux commandant les segments a à g d’un afficheur. Le codage dépend de la polarité de l’afficheur.

Convention — Convention utilisée

Dans les exemples suivants, segments(6 downto 0) correspond à a b c d e f g et la valeur 1 allume un segment. Pour un afficheur actif à 0, il faut inverser les sorties.

 

BCD vers sept segments — actif à 1  |  VHDL
with bcd select
    segments <= "1111110" when "0000", -- 0
                "0110000" when "0001", -- 1
                "1101101" when "0010", -- 2
                "1111001" when "0011", -- 3
                "0110011" when "0100", -- 4
                "1011011" when "0101", -- 5
                "1011111" when "0110", -- 6
                "1110000" when "0111", -- 7
                "1111111" when "1000", -- 8
                "1111011" when "1001", -- 9
                "0000000" when others;

 

6.4.12 Inférence de multiplexeurs

Une affectation sélectionnée associe chaque valeur de sélection à une entrée. Le synthétiseur peut créer un multiplexeur équilibré, un réseau de portes ou exploiter une table de correspondance du FPGA.

Description

Structure probable

4 valeurs sélectionnées, données variablesMultiplexeur 4 vers 1
Valeurs de sortie constantesDécodeur ou LUT
Nombre élevé de choixArbre de multiplexeurs ou mémoire distribuée
Choix partiellement identiquesLogique simplifiée par optimisation

 

6.4.13 Affectation sélectionnée ou conditionnelle ?

Besoin

Forme conseillée

Sélection par un code ou un opcodeAffectation sélectionnée
Choix prioritairesAffectation conditionnelle
Conditions relationnelles différentesAffectation conditionnelle
Table de correspondance complèteAffectation sélectionnée
Multiplexeur indexéAffectation sélectionnée
Valeur de sécurité pour cas illégauxLes deux formes avec branche finale adaptée

 

6.4.14 Erreurs fréquentes

Erreur

Conséquence

Correction

Oublier others avec std_logic_vectorChoix incompletAjouter une alternative others
Répéter une valeur de choixRecouvrementRendre les choix mutuellement exclusifs
Mélanger des longueurs de sortieErreur de type ou de tailleUniformiser toutes les expressions
Utiliser une valeur par défaut dangereuseComportement inattendu en cas d’entrée invalideDéfinir une valeur sûre ou X en simulation
Confondre priorité et sélectionMatériel différent du besoinChoisir la forme adaptée

 

Méthode de conception d’un circuit concurrent

  1. Écrire la table de vérité ou la relation fonctionnelle.
  2. Identifier les entrées, les sorties et leurs types.
  3. Déterminer si le choix est prioritaire ou indexé par un sélecteur.
  4. Choisir entre affectation simple, conditionnelle ou sélectionnée.
  5. Définir une valeur pour tous les cas possibles.
  6. Vérifier les tailles et les conversions de types.
  7. Simuler les cas normaux, limites et invalides.
  8. Examiner le schéma RTL pour confirmer le matériel inféré.

Tableau de décision

Question

Réponse

Forme probable

Une seule expression logique ?OuiAffectation simple
Deux valeurs selon une condition ?OuiAffectation conditionnelle
Plusieurs conditions prioritaires ?OuiAffectation conditionnelle successive
Plusieurs valeurs d’un même sélecteur ?OuiAffectation sélectionnée
Table de correspondance constante ?OuiAffectation sélectionnée
Calcul séquentiel ou mémoire ?OuiProcessus, traité dans les chapitres suivants

 

Checklist de validation

  • Chaque signal cible possède-t-il un seul pilote, sauf nécessité justifiée ?
  • Toutes les branches produisent-elles des valeurs de même type et même longueur ?
  • Les cas inconnus U, X ou Z sont-ils traités de manière cohérente ?
  • La priorité des conditions est-elle volontaire et documentée ?
  • La branche others est-elle présente lorsque nécessaire ?
  • Le comportement observé dans le chronogramme correspond-il à la table de vérité ?
  • Le schéma RTL montre-t-il le multiplexeur ou le décodeur attendu ?

Travaux pratiques

TP 3 — Multiplexeurs et décodeurs

1. Objectifs du TP

  • décrire un multiplexeur 2 vers 1 avec une affectation conditionnelle ;
  • décrire un multiplexeur 4 vers 1 avec une affectation sélectionnée ;
  • réaliser un décodeur 2 vers 4 ;
  • réaliser un décodeur BCD vers sept segments ;
  • tester exhaustivement les combinaisons d’entrée ;
  • observer les sorties dans un simulateur et utiliser des assertions.

2. Organisation des fichiers

Arborescence proposée  |  Arborescence
tp3_multiplexeurs_decodeurs/
├── src/
│   ├── mux2.vhd
│   ├── mux4.vhd
│   ├── decodeur2_4.vhd
│   └── bcd_7segments.vhd
└── sim/
    ├── tb_mux2.vhd
    ├── tb_mux4.vhd
    ├── tb_decodeur2_4.vhd
    └── tb_bcd_7segments.vhd

 

3. Partie A — Multiplexeur 2 vers 1

Le multiplexeur transmet a lorsque sel = 0 et b lorsque sel = 1.

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

entity mux2 is
    port (
        a, b : in  std_logic;
        sel  : in   std_logic;
        y    : out std_logic
    );
end entity mux2;

architecture rtl of mux2 is
begin
    y <= a when sel = '0'
         else b;
end architecture rtl;

 

4. Banc de test du multiplexeur 2 vers 1

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

entity tb_mux2 is
end entity tb_mux2;

architecture simulation of tb_mux2 is
    signal a, b : std_logic := '0';
    signal sel  : std_logic := '0';
    signal y    : std_logic;
begin
    DUT : entity work.mux2(rtl)
        port map (
            a => a,
            b => b,
            sel => sel,
            y => y
        );

 

tb_mux2.vhd — Tests exhaustifs  |  VHDL
    stimuli : process
    begin
        for s in std_logic range '0' to '1' loop
            for va in std_logic range '0' to '1' loop
                for vb in std_logic range '0' to '1' loop
                    sel <= s;
                    a <= va;
                    b <= vb;
                    wait for 1 ns;

                    if s = '0' then
                        assert y = va
                            report "Erreur mux2 pour sel=0"
                            severity error;
                    else
                        assert y = vb
                            report "Erreur mux2 pour sel=1"
                            severity error;
                    end if;

                    wait for 9 ns;
                end loop;
            end loop;
        end loop;

        report "Test mux2 termine" severity note;
        stop;
        wait;
    end process;
end architecture simulation;

 

5. Partie B — Multiplexeur 4 vers 1

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

entity mux4 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;

architecture rtl of mux4 is
begin
    with sel select
        y <= a when "00",
             b when "01",
             c when "10",
             d when others;
end architecture rtl;

 

6. Banc de test du multiplexeur 4 vers 1

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

entity tb_mux4 is
end entity tb_mux4;

architecture simulation of tb_mux4 is
    signal a : std_logic_vector(7 downto 0) := x"11";
    signal b : std_logic_vector(7 downto 0) := x"22";
    signal c : std_logic_vector(7 downto 0) := x"44";
    signal d : std_logic_vector(7 downto 0) := x"88";
    signal sel : std_logic_vector(1 downto 0) := "00";
    signal y : std_logic_vector(7 downto 0);
begin
    DUT : entity work.mux4(rtl)
        port map (
            a => a, b => b, c => c, d => d,
            sel => sel,
            y => y
        );

 

tb_mux4.vhd — Partie 2  |  VHDL
    stimuli : process
    begin
        sel <= "00"; wait for 10 ns;
        assert y = x"11"
            report "Erreur selection a" severity error;

        sel <= "01"; wait for 10 ns;
        assert y = x"22"
            report "Erreur selection b" severity error;

        sel <= "10"; wait for 10 ns;
        assert y = x"44"
            report "Erreur selection c" severity error;

        sel <= "11"; wait for 10 ns;
        assert y = x"88"
            report "Erreur selection d" severity error;

        report "Test mux4 termine" severity note;
        stop;
        wait;
    end process;
end architecture simulation;

 

7. Partie C — Décodeur 2 vers 4

Une seule sortie vaut 1 pour chaque combinaison binaire valide de l’entrée.

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

entity decodeur2_4 is
    port (
        entree : in  std_logic_vector(1 downto 0);
        enable : in  std_logic;
        sortie : out std_logic_vector(3 downto 0)
    );
end entity decodeur2_4;

architecture rtl of decodeur2_4 is
begin
    with (enable & entree) select
        sortie <= "0001" when "100",
                  "0010" when "101",
                  "0100" when "110",
                  "1000" when "111",
                  "0000" when others;
end architecture rtl;

 

8. Banc de test du décodeur 2 vers 4

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

entity tb_decodeur2_4 is
end entity tb_decodeur2_4;

architecture simulation of tb_decodeur2_4 is
    signal entree : std_logic_vector(1 downto 0)
                    := "00";
    signal enable : std_logic := '0';
    signal sortie : std_logic_vector(3 downto 0);
begin
    DUT : entity work.decodeur2_4(rtl)
        port map (
            entree => entree,
            enable => enable,
            sortie => sortie
        );

 

tb_decodeur2_4.vhd — Partie 2  |  VHDL
    stimuli : process
        variable attendu : std_logic_vector(3 downto 0);
    begin
        enable <= '0';
        entree <= "00";
        wait for 10 ns;

        assert sortie = "0000"
            report "La sortie doit etre nulle si enable=0"
            severity error;

        enable <= '1';

        for i in 0 to 3 loop
            entree <= std_logic_vector(to_unsigned(i, 2));
            attendu := std_logic_vector(
                 shift_left(to_unsigned(1, 4), i)
            );
            wait for 10 ns;

            assert sortie = attendu
                report "Erreur decodeur pour entree "
                       & integer'image(i)
                severity error;
        end loop;

        report "Test decodeur2_4 termine" severity note;
        stop;
        wait;
    end process;
end architecture simulation;

 

9. Partie D — Décodeur BCD vers sept segments

La convention choisie utilise une sortie active à 1 avec segments(6 downto 0) = a b c d e f g.

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

entity bcd_7segments is
    port (
        bcd      : in   std_logic_vector(3 downto 0);
        segments : out std_logic_vector(6 downto 0)
    );
end entity bcd_7segments;

architecture rtl of bcd_7segments is
begin
    with bcd select
        segments <= "1111110" when "0000",
                    "0110000" when "0001",
                    "1101101" when "0010",
                    "1111001" when "0011",
                    "0110011" when "0100",
                    "1011011" when "0101",
                    "1011111" when "0110",
                    "1110000" when "0111",
                    "1111111" when "1000",
                    "1111011" when "1001",
                    "0000000" when others;
end architecture rtl;

 

10. Banc de test BCD vers sept segments

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

entity tb_bcd_7segments is
end entity tb_bcd_7segments;

architecture simulation of tb_bcd_7segments is
    signal bcd : std_logic_vector(3 downto 0)
                 := (others => '0');
    signal segments : std_logic_vector(6 downto 0);
begin
    DUT : entity work.bcd_7segments(rtl)
        port map (
            bcd => bcd,
            segments => segments
        );

 

tb_bcd_7segments.vhd — Table attendue  |  VHDL
    stimuli : process
        type table_segments_t is array (0 to 9)
            of std_logic_vector(6 downto 0);

        constant attendu : table_segments_t := (
            "1111110", "0110000", "1101101",
            "1111001", "0110011", "1011011",
            "1011111", "1110000", "1111111",
            "1111011"
        );
    begin

 

tb_bcd_7segments.vhd — Boucles de test  |  VHDL
        for i in 0 to 9 loop
            bcd <= std_logic_vector(to_unsigned(i, 4));
            wait for 10 ns;

            assert segments = attendu(i)
                report "Erreur pour le chiffre "
                       & integer'image(i)
                severity error;
        end loop;

        for i in 10 to 15 loop
            bcd <= std_logic_vector(to_unsigned(i, 4));
            wait for 10 ns;

            assert segments = "0000000"
                report "Un code BCD invalide doit eteindre les segments"
                severity error;
        end loop;

        report "Test BCD 7 segments termine"
            severity note;
        stop;
        wait;
    end process;
end architecture simulation;

 

11. Compilation avec GHDL

Compilation des composants  |  Terminal
ghdl -a --std=08 src/mux2.vhd
ghdl -a --std=08 src/mux4.vhd
ghdl -a --std=08 src/decodeur2_4.vhd
ghdl -a --std=08 src/bcd_7segments.vhd

 

Compilation des bancs de test  |  Terminal
ghdl -a --std=08 sim/tb_mux2.vhd
ghdl -a --std=08 sim/tb_mux4.vhd
ghdl -a --std=08 sim/tb_decodeur2_4.vhd
ghdl -a --std=08 sim/tb_bcd_7segments.vhd

 

Exemple de simulation  |  Terminal
ghdl -e --std=08 tb_mux4
ghdl -r --std=08 tb_mux4    --vcd=tb_mux4.vcd

gtkwave tb_mux4.vcd

 

12. Résultats à observer

  • Le multiplexeur 2 vers 1 transmet exactement l’entrée sélectionnée.
  • Le multiplexeur 4 vers 1 change de sortie à chaque valeur de sel.
  • Le décodeur 2 vers 4 active une seule sortie lorsque enable vaut 1.
  • Toutes les sorties du décodeur sont nulles lorsque enable vaut 0.
  • Le décodeur BCD produit les motifs corrects pour les chiffres de 0 à 9.
  • Les codes BCD 10 à 15 produisent le motif de sécurité défini.
  • Aucune assertion de niveau error n’apparaît.

13. Tableaux à compléter

Circuit

Entrée / sélection

Sortie observée

Sortie attendue

Conforme

MUX 2:1sel=0 a 
MUX 2:1sel=1 b 
MUX 4:1sel="00" a 
MUX 4:1sel="11" d 
Décodeur 2:4enable=1, entree="10" 0100 
BCD 7 segmentsbcd=5 1011011 

 

14. Questions d’analyse

1. Pourquoi le multiplexeur 2 vers 1 est-il naturellement décrit par une affectation conditionnelle ?

2. Pourquoi l’affectation sélectionnée est-elle adaptée au multiplexeur 4 vers 1 ?

3. Quelle différence existe entre priorité et sélection exclusive ?

4. Quel comportement obtient-on si sel contient X dans les descriptions proposées ?

5. Pourquoi la clause others est-elle importante avec std_logic_vector ?

6. Quel matériel est inféré pour le décodeur 2 vers 4 ?

7. Comment adapter le décodeur sept segments à un afficheur actif à 0 ?

8. Comment modifier le multiplexeur 4 vers 1 pour des mots de largeur générique ?

9. Pourquoi faut-il vérifier le schéma RTL après synthèse ?

15. Extensions proposées

  • Créer un multiplexeur 8 vers 1 paramétrable.
  • Ajouter une entrée enable aux multiplexeurs.
  • Créer un encodeur 4 vers 2 prioritaire.
  • Ajouter un point décimal au décodeur sept segments.
  • Afficher deux chiffres par multiplexage temporel.
  • Implanter le TP sur une carte FPGA avec interrupteurs et afficheur.
  • Comparer les ressources obtenues par affectation sélectionnée et processus case.

16. Barème indicatif

Critère

Points

Multiplexeur 2 vers 12
Multiplexeur 4 vers 13
Décodeur 2 vers 43
Décodeur BCD vers sept segments4
Bancs de test et couverture3
Assertions et diagnostic2
Analyse des chronogrammes2
Qualité du code et du compte rendu1
Total20

 

Synthèse du chapitre

Notion

Résumé

ConcurrenceLes blocs de l’architecture fonctionnent en parallèle.
Affectation simpleRelie directement une expression à un signal.
Affectation conditionnelleChoisit selon des conditions ordonnées et prioritaires.
Affectation sélectionnéeChoisit selon la valeur d’une expression unique.
othersCouvre tous les choix non explicitement listés.
MultiplexeurSélectionne une donnée parmi plusieurs entrées.
DécodeurActive une sortie ou produit un motif selon un code d’entrée.
Cycles deltaStabilisent les relations concurrentes sans avancer le temps physique.
SynthèseTransforme les relations en portes, LUT, comparateurs et multiplexeurs.

 

Autoévaluation

1. Les affectations concurrentes sont-elles exécutées dans l’ordre du fichier ?

Réponse : Non, elles décrivent des relations matérielles parallèles.

2. Que décrit s <= a and b ?

Réponse : Une porte ET ou une logique équivalente.

3. Quelle forme exprime naturellement une priorité ?

Réponse : L’affectation conditionnelle successive.

4. Quelle forme convient à une sélection par opcode ?

Réponse : L’affectation sélectionnée.

5. Quel est le rôle de others ?

Réponse : Couvrir les valeurs non explicitement mentionnées.

6. Que peut inférer y <= a when sel='0' else b ?

Réponse : Un multiplexeur 2 vers 1.

7. Plusieurs affectations concurrentes vers y créent-elles un OU implicite ?

Réponse : Non, elles créent plusieurs pilotes.

8. Pourquoi utiliser X dans une branche de simulation ?

Réponse : Pour révéler un cas invalide ou non initialisé.

9. Un processus est-il concurrent ?

Réponse : Le processus entier est concurrent ; ses instructions internes sont séquentielles.

10. Pourquoi tester tous les codes d’un décodeur ?

Réponse : Pour vérifier la couverture complète et les cas invalides.

Exercice de consolidation

Décrire un bloc qui sélectionne l’une de quatre opérations logiques sur deux mots de 8 bits : AND, OR, XOR ou XNOR. La sélection est effectuée par un signal operation sur 2 bits.

Correction proposée  |  VHDL
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity unite_logique_4ops is
    port (
        a, b      : in   std_logic_vector(7 downto 0);
        operation : in  std_logic_vector(1 downto 0);
        y         : out std_logic_vector(7 downto 0)
    );
end entity unite_logique_4ops;

architecture rtl of unite_logique_4ops is
begin
    with operation select
        y <= a and b  when "00",
             a or b   when "01",
             a xor b  when "10",
             a xnor b when others;
end architecture rtl;

 

Suite du cours — Transition vers la suite

Après les affectations concurrentes, le cours peut introduire les processus et les instructions séquentielles, utiles pour exprimer des conditions complexes, des boucles et des circuits cadencés.