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.1 | Principe de concurrence | Lire le code comme une structure matérielle parallèle |
| 6.2 | Affectation simple | Exprimer une équation logique directe |
| 6.3 | Affectation conditionnelle | Décrire un choix prioritaire |
| 6.4 | Affectation sélectionnée | Décrire un choix selon une expression |
| TP 3 | Multiplexeurs et décodeurs | Concevoir, 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 AND | a, b | s1 |
| s2 <= c xor d; | Porte XOR | c, d | s2 |
| y <= s1 or s2; | Porte OR | s1, s2 | y |
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 0 | Les stimuli affectent a et b. |
| Delta 1 | L’expression a and b est réévaluée et une transaction est planifiée pour s. |
| Delta 2 | Le signal s prend sa nouvelle valeur ; les dépendances éventuelles sont réévaluées. |
| Temps physique | Aucun 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 |
|---|---|
| Architecture | Instructions concurrentes |
| Affectation directe | Concurrente |
| Processus entier | Concurrent par rapport aux autres blocs |
| Instructions dans le processus | Sé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 |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 0 |
| 1 | 0 | 0 |
| 1 | 1 | 1 |
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 |
|---|---|
| 0 | a |
| 1 | b |
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 condition | Multiplexeur 2 vers 1 |
| Deux conditions successives | Chaîne prioritaire de multiplexeurs |
| Plusieurs conditions exclusives | Multiplexeur à plusieurs entrées, optimisable |
| Conditions complexes | Comparateurs/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 logique | d 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 variables | Multiplexeur 4 vers 1 |
| Valeurs de sortie constantes | Décodeur ou LUT |
| Nombre élevé de choix | Arbre de multiplexeurs ou mémoire distribuée |
| Choix partiellement identiques | Logique simplifiée par optimisation |
6.4.13 Affectation sélectionnée ou conditionnelle ?
Besoin | Forme conseillée |
|---|---|
| Sélection par un code ou un opcode | Affectation sélectionnée |
| Choix prioritaires | Affectation conditionnelle |
| Conditions relationnelles différentes | Affectation conditionnelle |
| Table de correspondance complète | Affectation sélectionnée |
| Multiplexeur indexé | Affectation sélectionnée |
| Valeur de sécurité pour cas illégaux | Les deux formes avec branche finale adaptée |
6.4.14 Erreurs fréquentes
Erreur | Conséquence | Correction |
|---|---|---|
| Oublier others avec std_logic_vector | Choix incomplet | Ajouter une alternative others |
| Répéter une valeur de choix | Recouvrement | Rendre les choix mutuellement exclusifs |
| Mélanger des longueurs de sortie | Erreur de type ou de taille | Uniformiser toutes les expressions |
| Utiliser une valeur par défaut dangereuse | Comportement inattendu en cas d’entrée invalide | Définir une valeur sûre ou X en simulation |
| Confondre priorité et sélection | Matériel différent du besoin | Choisir la forme adaptée |
Méthode de conception d’un circuit concurrent
- Écrire la table de vérité ou la relation fonctionnelle.
- Identifier les entrées, les sorties et leurs types.
- Déterminer si le choix est prioritaire ou indexé par un sélecteur.
- Choisir entre affectation simple, conditionnelle ou sélectionnée.
- Définir une valeur pour tous les cas possibles.
- Vérifier les tailles et les conversions de types.
- Simuler les cas normaux, limites et invalides.
- 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 ? | Oui | Affectation simple |
| Deux valeurs selon une condition ? | Oui | Affectation conditionnelle |
| Plusieurs conditions prioritaires ? | Oui | Affectation conditionnelle successive |
| Plusieurs valeurs d’un même sélecteur ? | Oui | Affectation sélectionnée |
| Table de correspondance constante ? | Oui | Affectation sélectionnée |
| Calcul séquentiel ou mémoire ? | Oui | Processus, 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:1 | sel=0 | a | ||
| MUX 2:1 | sel=1 | b | ||
| MUX 4:1 | sel="00" | a | ||
| MUX 4:1 | sel="11" | d | ||
| Décodeur 2:4 | enable=1, entree="10" | 0100 | ||
| BCD 7 segments | bcd=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 1 | 2 |
| Multiplexeur 4 vers 1 | 3 |
| Décodeur 2 vers 4 | 3 |
| Décodeur BCD vers sept segments | 4 |
| Bancs de test et couverture | 3 |
| Assertions et diagnostic | 2 |
| Analyse des chronogrammes | 2 |
| Qualité du code et du compte rendu | 1 |
| Total | 20 |
Synthèse du chapitre
Notion | Résumé |
|---|---|
| Concurrence | Les blocs de l’architecture fonctionnent en parallèle. |
| Affectation simple | Relie directement une expression à un signal. |
| Affectation conditionnelle | Choisit selon des conditions ordonnées et prioritaires. |
| Affectation sélectionnée | Choisit selon la valeur d’une expression unique. |
| others | Couvre tous les choix non explicitement listés. |
| Multiplexeur | Sélectionne une donnée parmi plusieurs entrées. |
| Décodeur | Active une sortie ou produit un motif selon un code d’entrée. |
| Cycles delta | Stabilisent les relations concurrentes sans avancer le temps physique. |
| Synthèse | Transforme 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. |