Chapitre 5 — Opérateurs et expressions VHDL
Objectif — Finalité du chapitre Maîtriser les opérateurs logiques, relationnels, arithmétiques, de décalage et de concaténation afin de construire des expressions VHDL correctes, lisibles et synthétisables, puis valider leur comportement par simulation. |
Objectifs pédagogiques
À la fin de ce chapitre, l’étudiant devra être capable de :
- utiliser les opérateurs logiques sur des signaux scalaires et vectoriels ;
- interpréter correctement les opérateurs relationnels et leurs types de résultat ;
- réaliser des opérations arithmétiques avec integer, signed et unsigned ;
- distinguer modulo et reste ;
- gérer les largeurs de résultat et les risques de débordement ;
- effectuer des décalages logiques, arithmétiques et des rotations ;
- utiliser shift_left et shift_right avec IEEE.NUMERIC_STD ;
- concaténer des bits et des vecteurs avec l’opérateur & ;
- construire une extension par zéro ou une extension de signe ;
- appliquer les règles de priorité des opérateurs et utiliser les parenthèses ;
- développer puis simuler une unité logique et arithmétique simple.
Prérequis
- types std_logic, std_logic_vector, signed et unsigned ;
- bibliothèques IEEE.STD_LOGIC_1164 et IEEE.NUMERIC_STD ;
- conversions entre vecteurs et types numériques ;
- entité, architecture, instructions concurrentes et banc de test.
Organisation du chapitre
Section | Contenu | Compétence |
|---|---|---|
| 5.1 | Opérateurs logiques | Exprimer des fonctions booléennes |
| 5.2 | Opérateurs relationnels | Comparer des valeurs compatibles |
| 5.3 | Opérateurs arithmétiques | Calculer et dimensionner les résultats |
| 5.4 | Décalages et rotations | Déplacer ou faire tourner les bits |
| 5.5 | Concaténation | Assembler et étendre des vecteurs |
| 5.6 | Priorité des opérateurs | Éviter les expressions ambiguës |
| TP 2 | Unité logique et arithmétique | Concevoir et vérifier un bloc complet |
Concept clé — Typage des expressions Un opérateur VHDL n’est disponible que si une définition compatible existe pour les types de ses opérandes. Deux symboles identiques peuvent avoir plusieurs surcharges, mais le compilateur doit pouvoir déterminer sans ambiguïté celle qui convient. |
5.1 Opérateurs logiques
Les opérateurs logiques combinent des valeurs booléennes ou logiques. Sur des vecteurs de même longueur, l’opération est généralement appliquée bit par bit. Ils sont utilisés pour traduire des équations de Boole, construire des masques et générer des signaux de commande.
5.1.1 Vue d’ensemble
Opérateur | Expression | Résultat pour bits | Interprétation |
|---|---|---|---|
| and | a and b | 1 si a=1 et b=1 | Conjonction |
| or | a or b | 1 si au moins une entrée vaut 1 | Disjonction inclusive |
| nand | a nand b | not(a and b) | ET nié |
| nor | a nor b | not(a or b) | OU nié |
| xor | a xor b | 1 si a et b sont différents | OU exclusif |
| xnor | a xnor b | 1 si a et b sont identiques | Équivalence |
| not | not a | Inverse la valeur | Négation unaire |
5.1.2 Opérateur and
L’opérateur and produit un niveau actif uniquement lorsque tous les opérandes concernés sont actifs.
| Porte ET à deux entrées | VHDL |
| y <= a and b; |
| Masquage d’un vecteur | VHDL |
| signal donnees : std_logic_vector(7 downto 0); signal masque : std_logic_vector(7 downto 0); signal sortie : std_logic_vector(7 downto 0); sortie <= donnees and masque; |
a | b | a and b |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 0 |
| 1 | 0 | 0 |
| 1 | 1 | 1 |
5.1.3 Opérateur or
L’opérateur or produit 1 lorsqu’au moins un opérande vaut 1.
| Combinaison de deux demandes | VHDL |
| demande_globale <= demande_a or demande_b; |
a | b | a or b |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 1 |
5.1.4 Opérateur nand
nand est la négation de and. Il produit 0 uniquement lorsque les deux entrées valent 1.
| Porte NAND | VHDL |
| y <= a nand b; -- Écriture équivalente y_equiv <= not (a and b); |
Lisibilité — Parenthèses recommandées Même lorsqu’un opérateur composé existe, l’écriture not (a and b) peut être plus explicite lors d’une démonstration. L’opérateur nand reste concis et directement synthétisable. |
5.1.5 Opérateur nor
nor est la négation de or. Il produit 1 uniquement lorsque toutes les entrées valent 0.
| Porte NOR | VHDL |
| y <= a nor b; -- Écriture équivalente y_equiv <= not (a or b); |
5.1.6 Opérateur xor
xor produit 1 lorsque les opérandes binaires sont différents. Il est utilisé dans les additionneurs, les calculs de parité et certains algorithmes de détection d’erreur.
| Porte XOR | VHDL |
| y <= a xor b; |
| Parité de quatre bits | VHDL |
| parite <= d(3) xor d(2) xor d(1) xor d(0); |
a | b | a xor b |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 0 |
5.1.7 Opérateur xnor
xnor est le complément de xor. Il produit 1 lorsque les entrées sont égales.
| Détection d’égalité bit à bit | VHDL |
| egaux_bit <= a xnor b; |
| Comparaison bit à bit d’un bus | VHDL |
| comparaison_bits <= bus_a xnor bus_b; |
Distinction — Vecteur xnor Sur un vecteur, xnor fournit un vecteur de résultats bit à bit. Pour tester l’égalité globale de deux mots, l’opérateur relationnel = est généralement plus direct. |
5.1.8 Opérateur not
not est un opérateur unaire. Il inverse un bit ou chaque élément d’un vecteur.
| Inversion scalaire et vectorielle | VHDL |
| n_a <= not a; complement <= not donnees; |
5.1.9 Opérations logiques sur std_logic
Lorsque les opérandes contiennent des valeurs telles que 'U', 'X' ou 'Z', le résultat suit les tables définies par IEEE.STD_LOGIC_1164. Une inconnue peut se propager, sauf lorsque le résultat est imposé par une valeur dominante.
Expression | Résultat | Explication |
|---|---|---|
| '0' and 'X' | '0' | Le zéro impose le résultat de l’ET |
| '1' and 'X' | 'X' | Le résultat dépend de l’inconnue |
| '1' or 'X' | '1' | Le un impose le résultat du OU |
| '0' or 'X' | 'X' | Le résultat dépend de l’inconnue |
| not 'Z' | 'X' | La haute impédance n’est pas un bit binaire connu |
5.1.10 Réduction logique
Pour déterminer si tous les bits d’un vecteur sont à 1 ou si au moins un bit est actif, on peut utiliser une boucle portable. VHDL-2008 introduit également des formes de réduction unaire selon les outils.
| Réduction AND portable | VHDL |
| process(donnees) variable tous_a_un : std_logic; begin tous_a_un := '1'; for i in donnees'range loop tous_a_un := tous_a_un and donnees(i); end loop; resultat <= tous_a_un; end process; |
| Réduction OR portable | VHDL |
| process(donnees) variable au_moins_un : std_logic; begin au_moins_un := '0'; for i in donnees'range loop au_moins_un := au_moins_un or donnees(i); end loop; resultat <= au_moins_un; end process; |
5.1.11 Exemple combiné
| Fonction logique à quatre entrées | VHDL |
| y <= ((a and b) or (c xor d)) and not inhibition; |
Bonne pratique — Décomposition utile Pour faciliter la simulation et le débogage, une expression complexe peut être divisée en signaux intermédiaires nommés. |
| Version décomposée | VHDL |
| signal terme_et : std_logic; signal terme_xor : std_logic; signal demande : std_logic; terme_et <= a and b; terme_xor <= c xor d; demande <= terme_et or terme_xor; y <= demande and not inhibition; |
5.2 Opérateurs relationnels
Les opérateurs relationnels comparent deux valeurs compatibles et produisent un résultat de type boolean. Ils sont utilisés dans les conditions if, les affectations conditionnelles et les assertions.
Opérateur | Signification | Exemple |
|---|---|---|
| = | Égal à | a = b |
| /= | Différent de | a /= b |
| < | Strictement inférieur | compteur < limite |
| <= | Inférieur ou égal | valeur <= maximum |
| > | Strictement supérieur | a > b |
| >= | Supérieur ou égal | temperature >= seuil |
5.2.1 Égalité =
| Test d’égalité | VHDL |
| if a = b then egaux <= '1'; else egaux <= '0'; end if; |
Pour std_logic_vector, l’égalité compare les éléments position par position. Les valeurs inconnues sont comparées comme des valeurs du type ; une égalité contenant 'X' n’a pas le même sens qu’une comparaison physique de niveaux binaires.
| Affectation conditionnelle | VHDL |
| egaux <= '1' when mot_a = mot_b else '0'; |
5.2.2 Différence /=
| Détection de modification | VHDL |
| modifie <= '1' when valeur_nouvelle /= valeur_ancienne else '0'; |
5.2.3 Relations d’ordre
Les opérateurs <, <=, > et >= dépendent du type. Sur unsigned, la comparaison est non signée ; sur signed, elle respecte le complément à deux ; sur integer, elle suit l’ordre numérique.
| Comparaison non signée | VHDL |
| signal a_u, b_u : unsigned(7 downto 0); a_superieur <= '1' when a_u > b_u else '0'; |
| Comparaison signée | VHDL |
| signal x_s, y_s : signed(7 downto 0); x_negatif_par_rapport_y <= '1' when x_s < y_s else '0'; |
Attention — Attention au symbole <= Dans une expression, <= peut être l’opérateur « inférieur ou égal ». Dans une instruction d’affectation, le même symbole sert à affecter un signal. Le contexte syntaxique permet au compilateur de les distinguer. |
5.2.4 Comparaison de std_logic_vector
Une comparaison directe de deux std_logic_vector suit l’ordre prédéfini des éléments du tableau et ne traduit pas nécessairement l’ordre numérique recherché. Pour une comparaison numérique portable et explicite, convertir les vecteurs en unsigned ou signed.
| Comparaison non signée de deux ports | VHDL |
| plus_grand <= '1' when unsigned(a_slv) > unsigned(b_slv) else '0'; |
| Comparaison signée de deux ports | VHDL |
| plus_petit <= '1' when signed(a_slv) < signed(b_slv) else '0'; |
5.2.5 Exemple montrant l’impact du signe
Bits | Interprétation unsigned | Interprétation signed |
|---|---|---|
| "11111111" | 255 | -1 |
| "10000000" | 128 | -128 |
| "01111111" | 127 | 127 |
Ainsi, comparer «11111111» et «00000001» donne vrai pour la relation > en unsigned, mais faux en signed.
5.2.6 Comparaisons avec des constantes
| Comparaison avec un entier | VHDL |
| signal compteur : unsigned(7 downto 0); fin <= '1' when compteur = to_unsigned(99, compteur'length) else '0'; |
| Comparaison simplifiée autorisée par numeric_std | VHDL |
| if compteur >= 100 then compteur <= (others => '0'); end if; |
Conseil — Portabilité Même lorsque la surcharge avec un entier naturel est acceptée, une conversion explicite peut rendre la largeur et l’intention plus visibles dans un support pédagogique. |
5.2.7 Comparaison dans une instruction assert
| Vérification automatique | VHDL |
| assert resultat = attendu report "Le resultat calcule est incorrect" severity error; |
5.3 Opérateurs arithmétiques
Les opérateurs arithmétiques manipulent des types numériques. Avec IEEE.NUMERIC_STD, les types signed et unsigned peuvent être additionnés, soustraits, multipliés et comparés. La division et les opérations mod/rem doivent être utilisées avec prudence en synthèse en raison du coût matériel.
5.3.1 Addition
| Addition d’entiers | VHDL |
| signal a, b : integer range 0 to 100; signal s : integer range 0 to 200; s <= a + b; |
| Addition unsigned avec retenue | VHDL |
| signal a, b : unsigned(7 downto 0); signal s : unsigned(8 downto 0); s <= resize(a, s'length) + resize(b, s'length); |
| Addition signed | VHDL |
| signal x, y : signed(7 downto 0); signal r : signed(8 downto 0); r <= resize(x, r'length) + resize(y, r'length); |
Dimensionnement — Largeur du résultat Pour conserver une retenue, le résultat d’une addition de deux mots non signés de N bits doit généralement disposer de N+1 bits. Pour une addition signée, un bit supplémentaire évite le débordement pour la plage complète. |
5.3.2 Soustraction
| Soustraction signed | VHDL |
| signal a, b : signed(7 downto 0); signal d : signed(8 downto 0); d <= resize(a, d'length) - resize(b, d'length); |
| Soustraction d’unsigned pouvant être négative | VHDL |
| signal a, b : unsigned(7 downto 0); signal d : signed(8 downto 0); d <= signed('0' & a) - signed('0' & b); |
5.3.3 Multiplication
Le produit de deux opérandes de N et M bits peut nécessiter jusqu’à N+M bits. Les FPGA disposent souvent de blocs DSP optimisés pour cette opération.
| Multiplication unsigned | VHDL |
| signal a, b : unsigned(7 downto 0); signal p : unsigned(15 downto 0); p <= a * b; |
| Multiplication signée | VHDL |
| signal x, y : signed(11 downto 0); signal p : signed(23 downto 0); p <= x * y; |
Attention — Troncature Affecter un produit à un vecteur trop court peut supprimer les bits de poids fort ou provoquer une erreur de taille. Toujours définir explicitement la politique de conservation, d’arrondi ou de saturation. |
5.3.4 Division
La division entière calcule le quotient sans partie fractionnaire. Elle est synthétisable dans certains contextes, mais une division par une valeur variable peut consommer beaucoup de ressources et réduire la fréquence maximale.
| Division entière | VHDL |
| signal nombre : unsigned(15 downto 0); signal quotient : unsigned(15 downto 0); quotient <= nombre / 10; |
| Division par une puissance de deux | VHDL |
| -- Division non signée par 8 quotient <= shift_right(nombre, 3); |
Matériel — Optimisation Une division non signée par 2^k peut être réalisée par un décalage logique vers la droite de k positions. Pour les nombres signés, il faut vérifier la règle d’arrondi souhaitée. |
5.3.5 Modulo mod
L’opérateur mod fournit un résultat dont le signe suit le second opérande. Il est utile pour le comptage cyclique, l’indexation et les calculs périodiques.
| Modulo positif | VHDL |
| reste_cycle <= compteur mod 10; |
Expression | Résultat |
|---|---|
| 17 mod 5 | 2 |
| -17 mod 5 | 3 |
| 17 mod -5 | -3 |
| -17 mod -5 | -2 |
5.3.6 Reste rem
L’opérateur rem fournit un reste dont le signe suit le premier opérande. Il diffère donc de mod lorsqu’un opérande est négatif.
| Calcul du reste | VHDL |
| r <= a rem b; |
Expression | Résultat |
|---|---|
| 17 rem 5 | 2 |
| -17 rem 5 | -2 |
| 17 rem -5 | 2 |
| -17 rem -5 | -2 |
Distinction — mod ou rem Avec des opérandes non négatifs, mod et rem donnent le même résultat. La différence devient visible avec des valeurs négatives. |
5.3.7 Valeur absolue abs
abs est un opérateur unaire qui retourne la valeur absolue d’un nombre. Il s’applique notamment à integer et signed selon les surcharges disponibles.
| Valeur absolue d’un entier | VHDL |
| signal erreur : integer range -255 to 255; signal amplitude : integer range 0 to 255; amplitude <= abs erreur; |
| Valeur absolue signée | VHDL |
| signal x : signed(7 downto 0); signal amplitude : signed(7 downto 0); amplitude <= abs x; |
Cas limite — Valeur minimale signée La valeur la plus négative d’un mot signé, par exemple -128 sur 8 bits, n’a pas d’équivalent positif représentable sur la même largeur. Une extension du résultat peut être nécessaire. |
5.3.8 Puissance et opérateurs unaires
L’opérateur ** calcule une puissance, tandis que les signes unaires + et - indiquent respectivement une valeur inchangée ou opposée. Leur synthèse doit être évaluée selon les constantes et l’outil.
| Exemples | VHDL |
| carre <= valeur ** 2; oppose <= -valeur_signee; |
5.3.9 Coût matériel des opérations
Opération | Matériel généralement inféré | Coût relatif |
|---|---|---|
| Addition / soustraction | Chaîne de retenue, additionneur | Faible à modéré |
| Multiplication | Bloc DSP ou réseau logique | Modéré |
| Division par constante simple | Décalages et additions optimisées | Variable |
| Division par opérande variable | Diviseur combinatoire ou séquentiel | Élevé |
| mod/rem par puissance de deux | Sélection de bits | Faible |
| abs signé | Test de signe et négation conditionnelle | Faible à modéré |
5.4 Opérateurs de décalage
Les décalages déplacent les bits d’un vecteur. Ils servent à multiplier ou diviser par des puissances de deux, à extraire des champs, à construire des registres à décalage et à réaliser des communications série.
5.4.1 Décalage logique
Un décalage logique introduit des zéros dans les positions libérées.
| Décalage logique manuel à gauche | VHDL |
| signal a : std_logic_vector(7 downto 0); signal y : std_logic_vector(7 downto 0); y <= a(6 downto 0) & '0'; |
| Décalage logique manuel à droite | VHDL |
| y <= '0' & a(7 downto 1); |
5.4.2 Fonctions shift_left et shift_right
IEEE.NUMERIC_STD fournit shift_left et shift_right pour signed et unsigned. Le deuxième argument indique le nombre de positions.
| Décalages sur unsigned | VHDL |
| signal a : unsigned(7 downto 0); signal gauche, droite : unsigned(7 downto 0); gauche <= shift_left(a, 2); droite <= shift_right(a, 3); |
Pour unsigned, les positions libérées sont remplies avec des zéros.
5.4.3 Décalage arithmétique
Le décalage arithmétique vers la droite d’un nombre signed conserve le signe en recopiant le bit de poids fort. Il correspond approximativement à une division par une puissance de deux, avec une règle d’arrondi dépendant de la représentation.
| Décalage arithmétique vers la droite | VHDL |
| signal x : signed(7 downto 0); signal y : signed(7 downto 0); y <= shift_right(x, 2); |
Règle — signed et shift_right Avec un opérande signed, shift_right remplit les bits libérés à gauche avec le bit de signe. Avec unsigned, les bits ajoutés valent zéro. |
5.4.4 Décalage arithmétique vers la gauche
Un décalage vers la gauche introduit généralement des zéros à droite. Il multiplie la valeur par 2^k tant qu’aucun bit significatif n’est perdu.
| Multiplication par quatre | VHDL |
| resultat <= shift_left(valeur, 2); |
Attention — Débordement Un décalage ne crée pas automatiquement de bits supplémentaires. Pour préserver la valeur complète, redimensionner avant le décalage. |
| Décalage avec extension préalable | VHDL |
| signal a : unsigned(7 downto 0); signal y : unsigned(9 downto 0); y <= shift_left(resize(a, y'length), 2); |
5.4.5 Rotation
Une rotation réintroduit à l’autre extrémité les bits qui sortent du vecteur. Aucun bit n’est perdu.
| Rotation gauche manuelle d’un bit | VHDL |
| rotation_gauche <= a(6 downto 0) & a(7); |
| Rotation droite manuelle d’un bit | VHDL |
| rotation_droite <= a(0) & a(7 downto 1); |
| Opérateurs rol et ror | VHDL |
| rotation_gauche <= a rol 2; rotation_droite <= a ror 3; |
Portabilité — Compatibilité des outils Les opérateurs de rotation et de décalage du langage peuvent être pris en charge selon la version VHDL et l’outil. Les fonctions numeric_std sont souvent privilégiées pour les calculs signed et unsigned. |
5.4.6 Registre à décalage
| Registre à décalage série-parallèle | VHDL |
| process(clk) begin if rising_edge(clk) then if enable = '1' then registre <= registre(registre'high-1 downto 0) & entree_serie; end if; end if; end process; |
5.4.7 Décalage variable
Lorsque le nombre de positions est variable, le synthétiseur peut inférer un barrel shifter, un réseau de multiplexeurs capable de décaler en un cycle.
| Décalage commandé | VHDL |
| signal decalage : natural range 0 to 7; sortie <= shift_left(entree, decalage); |
5.4.8 Exemple numérique
Entrée | Opération | Résultat sur 8 bits |
|---|---|---|
| "00110101" | shift_left(...,1) | "01101010" |
| "00110101" | shift_right(...,2) | "00001101" |
| "10110001" | rol 1 | "01100011" |
| "10110001" | ror 1 | "11011000" |
5.5 Concaténation
L’opérateur & assemble des valeurs compatibles afin de former un tableau plus long. Il est utilisé pour construire des mots, ajouter des bits, regrouper des champs et effectuer des décalages manuels.
5.5.1 Utilisation de l’opérateur &
| Assemblage de deux demi-octets | VHDL |
| signal poids_fort : std_logic_vector(3 downto 0); signal poids_faible: std_logic_vector(3 downto 0); signal octet : std_logic_vector(7 downto 0); octet <= poids_fort & poids_faible; |
5.5.2 Assemblage de bits et de vecteurs
| Ajout de bits de contrôle | VHDL |
| trame <= start_bit & donnees & parite & stop_bit; |
| Création d’un mot à partir de bits | VHDL |
| commande <= enable & lecture & ecriture & valide; |
5.5.3 Concaténation répétée
Un agrégat avec others est souvent plus clair pour remplir plusieurs bits identiques.
| Extension par quatre zéros | VHDL |
| mot_12bits <= "0000" & mot_8bits; -- Variante générique mot_12bits <= (3 downto 0 => '0') & mot_8bits; |
5.5.4 Extension d’un mot non signé
L’extension par zéro ajoute des zéros à gauche afin de conserver la valeur d’un nombre non signé.
| Extension par zéro | VHDL |
| signal a8 : unsigned(7 downto 0); signal a12 : unsigned(11 downto 0); a12 <= "0000" & a8; |
| Extension générique recommandée | VHDL |
| a12 <= resize(a8, a12'length); |
5.5.5 Extension de signe
Pour un nombre signé, les nouveaux bits de poids fort doivent reproduire le bit de signe.
| Extension de signe manuelle | VHDL |
| signal s8 : signed(7 downto 0); signal s12 : signed(11 downto 0); s12 <= (3 downto 0 => s8(7)) & s8; |
| Extension de signe avec resize | VHDL |
| s12 <= resize(s8, s12'length); |
Bonne pratique — Privilégier resize resize évite les erreurs de calcul du nombre de bits et applique automatiquement une extension par zéro pour unsigned ou une extension de signe pour signed. |
5.5.6 Construction d’une somme avec retenue
| Ajout d’un zéro avant l’addition | VHDL |
| signal a, b : unsigned(7 downto 0); signal s : unsigned(8 downto 0); s <= ('0' & a) + ('0' & b); |
5.5.7 Extraction et réassemblage de champs
| Découpage d’une instruction | VHDL |
| opcode <= instruction(15 downto 12); registre_a<= instruction(11 downto 8); registre_b<= instruction(7 downto 4); immediat <= instruction(3 downto 0); |
| Réassemblage | VHDL |
| instruction <= opcode & registre_a & registre_b & immediat; |
5.5.8 Sens et dimensions
La longueur du résultat d’une concaténation est la somme des longueurs des opérandes. L’opérande de gauche devient la partie gauche du résultat.
Expression | Longueur | Résultat |
|---|---|---|
| "10" & "0110" | 6 | "100110" |
| '1' & "001" | 4 | "1001" |
| "101" & '0' | 4 | "1010" |
5.6 Priorité des opérateurs
La priorité détermine l’ordre dans lequel les opérateurs sont regroupés lorsque les parenthèses sont absentes. Toutefois, la lisibilité d’une description matérielle est aussi importante que sa validité syntaxique : les parenthèses doivent rendre l’intention évidente.
5.6.1 Principes généraux
- Les expressions entre parenthèses sont évaluées en premier.
- Les opérateurs unaires et de puissance ont une priorité élevée.
- Les multiplications, divisions, mod et rem précèdent généralement les additions et soustractions.
- La concaténation appartient à la famille des opérateurs d’addition dans la grammaire VHDL.
- Les opérateurs de décalage sont évalués avant les relations.
- Les opérateurs relationnels produisent un boolean.
- Les opérateurs logiques sont évalués après les relations, selon leur classe.
5.6.2 Tableau pédagogique de priorité
Niveau approximatif | Famille | Opérateurs ou constructions |
|---|---|---|
| 1 — le plus élevé | Parenthèses / primaire | (expression), littéraux, appels de fonction |
| 2 | Divers unaire / puissance | **, abs, not, signe unaire |
| 3 | Multiplicatif | *, /, mod, rem |
| 4 | Additif / concaténation | + , - , & |
| 5 | Décalage | sll, srl, sla, sra, rol, ror |
| 6 | Relationnel | =, /=, <, <=, >, >= |
| 7 — le plus faible | Logique | and, or, nand, nor, xor, xnor |
Prudence — Tableau d’apprentissage Ce tableau sert à guider la lecture des expressions usuelles. Pour éviter toute dépendance à une mémorisation imparfaite ou à des restrictions syntaxiques entre versions, ajouter des parenthèses dès que plusieurs familles d’opérateurs sont combinées. |
5.6.3 Ordre d’évaluation
| Expression arithmétique | VHDL |
| resultat <= a + b * c; -- Interprétation recherchée resultat <= a + (b * c); |
| Expression logique | VHDL |
| y <= a and b or c; -- Forme explicitement documentée y <= (a and b) or c; |
Même lorsqu’une expression est légalement interprétée par le compilateur, la version parenthésée est généralement préférable pour une équipe de développement.
5.6.4 Utilisation des parenthèses
| Expression claire | VHDL |
| y <= ((a xor b) and enable) or (reset and not inhibition); |
| Calcul numérique clair | VHDL |
| somme_moyenne <= (resize(a, 10) + resize(b, 10)) / 2; |
5.6.5 Prévention des ambiguïtés de typage
Une ambiguïté ne vient pas seulement de la priorité. Elle peut provenir de plusieurs surcharges possibles ou d’une taille de résultat non déterminée.
| Expression potentiellement ambiguë | VHDL |
| resultat <= a + 1; |
Si a est unsigned, le littéral 1 peut être résolu par numeric_std, mais une conversion explicite améliore parfois la compréhension.
| Version explicite | VHDL |
| resultat <= a + to_unsigned(1, a'length); |
5.6.6 Parenthèses et conversions
| Conversion de l’ensemble du résultat | VHDL |
| s_slv <= std_logic_vector( resize(unsigned(a_slv), 9) + resize(unsigned(b_slv), 9) ); |
Les parenthèses indiquent que l’addition est effectuée sur des unsigned et que seule la somme finale est convertie en std_logic_vector.
5.6.7 Erreurs fréquentes
Erreur | Conséquence | Correction |
|---|---|---|
| Oublier les parenthèses autour d’une condition composée | Intention difficile à lire | Regrouper explicitement chaque sous-condition |
| Mélanger signed et unsigned | Aucune surcharge compatible | Convertir les deux opérandes vers un type commun |
| Additionner deux std_logic_vector | Opérateur + introuvable avec numeric_std | Convertir en unsigned ou signed |
| Sous-dimensionner le résultat | Perte de bits ou erreur de taille | resize ou destination élargie |
| Utiliser un décalage après une conversion mal placée | Décalage appliqué au mauvais type | Parenthéser la conversion et l’opération |
| Confondre <= relationnel et affectation | Lecture incorrecte du code | Identifier le contexte ou reformuler |
5.6.8 Recommandations de style
- Une expression complexe ne doit pas tenir sur une seule ligne si sa lecture devient difficile.
- Nommer les résultats intermédiaires significatifs.
- Utiliser des conversions proches des données auxquelles elles s’appliquent.
- Dimensionner explicitement les additions, produits et décalages.
- Ajouter un commentaire lorsque l’opération réalise une optimisation matérielle.
- Tester les valeurs limites, les nombres négatifs et les débordements.
Travaux pratiques
TP 2 — Opérations logiques et arithmétiques
1. Objectifs du TP
- réaliser une unité logique simple sélectionnée par un code d’opération ;
- additionner deux nombres binaires non signés en conservant la retenue ;
- comparer deux mots et produire trois indicateurs ;
- effectuer des décalages logiques commandés ;
- vérifier les résultats dans un simulateur ;
- construire un banc de test auto-vérifiant avec assertions.
2. Cahier des charges
Le composant reçoit deux opérandes a et b sur 8 bits, un code operation sur 3 bits et une quantité de décalage sur 3 bits. Il produit un résultat sur 9 bits ainsi que les indicateurs egal, inferieur, superieur et retenue.
Code operation | Fonction | Résultat |
|---|---|---|
| "000" | AND bit à bit | 0 & (a AND b) |
| "001" | OR bit à bit | 0 & (a OR b) |
| "010" | XOR bit à bit | 0 & (a XOR b) |
| "011" | NOT de a | 0 & (NOT a) |
| "100" | Addition a + b | Somme sur 9 bits |
| "101" | Soustraction a - b | Résultat sur 9 bits signés ou politique définie |
| "110" | Décalage gauche de a | Décalage logique |
| "111" | Décalage droit de a | Décalage logique |
3. Organisation proposée
| Arborescence du projet | Arborescence |
| tp2_operateurs/ ├── src/ │ └── unite_ops.vhd └── sim/ └── tb_unite_ops.vhd |
4. Entité de l’unité
| unite_ops.vhd — Entité | VHDL |
| library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; entity unite_ops is port ( a, b : in std_logic_vector(7 downto 0); operation : in std_logic_vector(2 downto 0); decalage : in unsigned(2 downto 0); resultat : out std_logic_vector(8 downto 0); retenue : out std_logic; egal : out std_logic; inferieur : out std_logic; superieur : out std_logic ); end entity unite_ops; |
5. Architecture — déclarations
| unite_ops.vhd — Signaux internes | VHDL |
| architecture rtl of unite_ops is signal a_u : unsigned(7 downto 0); signal b_u : unsigned(7 downto 0); signal somme_u : unsigned(8 downto 0); signal resultat_u: unsigned(8 downto 0); begin a_u <= unsigned(a); b_u <= unsigned(b); somme_u <= resize(a_u, 9) + resize(b_u, 9); |
6. Architecture — comparaisons
| Indicateurs relationnels | VHDL |
| egal <= '1' when a_u = b_u else '0'; inferieur <= '1' when a_u < b_u else '0'; superieur <= '1' when a_u > b_u else '0'; |
7. Architecture — sélection des opérations
| Processus combinatoire — Partie 1 | VHDL |
| process(a_u, b_u, operation, decalage, somme_u) begin resultat_u <= (others => '0'); case operation is when "000" => resultat_u <= '0' & (a_u and b_u); when "001" => resultat_u <= '0' & (a_u or b_u); when "010" => resultat_u <= '0' & (a_u xor b_u); when "011" => resultat_u <= '0' & (not a_u); |
| Processus combinatoire — Partie 2 | VHDL |
| when "100" => resultat_u <= somme_u; when "101" => resultat_u <= resize(a_u, 9) - resize(b_u, 9); when "110" => resultat_u <= shift_left( resize(a_u, 9), to_integer(decalage) ); when others => resultat_u <= shift_right( resize(a_u, 9), to_integer(decalage) ); end case; end process; |
| Affectations finales | VHDL |
| resultat <= std_logic_vector(resultat_u); retenue <= somme_u(8) when operation = "100" else '0'; end architecture rtl; |
Limite à analyser — Soustraction non signée La soustraction proposée travaille sur unsigned. Si a < b, le résultat s’enroule modulo 2^9. Une extension du TP peut ajouter une sortie signed ou un indicateur emprunt afin de représenter explicitement un résultat négatif. |
8. Banc de test — déclarations
| tb_unite_ops.vhd — Partie 1 | VHDL |
| library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; use STD.ENV.ALL; entity tb_unite_ops is end entity tb_unite_ops; architecture simulation of tb_unite_ops is signal a, b : std_logic_vector(7 downto 0) := (others => '0'); signal operation : std_logic_vector(2 downto 0) := (others => '0'); signal decalage : unsigned(2 downto 0) := (others => '0'); signal resultat : std_logic_vector(8 downto 0); signal retenue : std_logic; signal egal : std_logic; signal inferieur : std_logic; signal superieur : std_logic; begin |
9. Banc de test — instanciation
| Instanciation du composant | VHDL |
| DUT : entity work.unite_ops(rtl) port map ( a => a, b => b, operation => operation, decalage => decalage, resultat => resultat, retenue => retenue, egal => egal, inferieur => inferieur, superieur => superieur ); |
10. Banc de test — opérations logiques
| Tests AND, OR et XOR | VHDL |
| stimuli : process begin a <= x"55"; b <= x"0F"; operation <= "000"; wait for 10 ns; assert resultat = ('0' & x"05") report "Erreur operation AND" severity error; operation <= "001"; wait for 10 ns; assert resultat = ('0' & x"5F") report "Erreur operation OR" severity error; operation <= "010"; wait for 10 ns; assert resultat = ('0' & x"5A") report "Erreur operation XOR" severity error; |
11. Banc de test — addition
| Test de l’addition et de la retenue | VHDL |
| a <= std_logic_vector(to_unsigned(200, 8)); b <= std_logic_vector(to_unsigned(100, 8)); operation <= "100"; wait for 10 ns; assert unsigned(resultat) = to_unsigned(300, 9) report "Erreur addition 200 + 100" severity error; assert retenue = '1' report "Retenue incorrecte" severity error; |
12. Banc de test — comparaisons
| Tests relationnels | VHDL |
| a <= x"14"; -- 20 b <= x"1E"; -- 30 wait for 10 ns; assert egal = '0' report "Indicateur egal incorrect" severity error; assert inferieur = '1' report "Indicateur inferieur incorrect" severity error; assert superieur = '0' report "Indicateur superieur incorrect" severity error; |
13. Banc de test — décalages
| Tests de décalage | VHDL |
| a <= "00010110"; -- 22 decalage <= to_unsigned(2, decalage'length); operation <= "110"; wait for 10 ns; assert unsigned(resultat) = to_unsigned(88, 9) report "Erreur decalage gauche" severity error; operation <= "111"; wait for 10 ns; assert unsigned(resultat) = to_unsigned(5, 9) report "Erreur decalage droit" severity error; |
14. Fin du banc de test
| Clôture de la simulation | VHDL |
| report "Tous les tests du TP 2 sont termines" severity note; stop; wait; end process; end architecture simulation; |
15. Compilation avec GHDL
| Analyse, élaboration et simulation | Terminal |
| ghdl -a --std=08 src/unite_ops.vhd ghdl -a --std=08 sim/tb_unite_ops.vhd ghdl -e --std=08 tb_unite_ops ghdl -r --std=08 tb_unite_ops --vcd=tb_unite_ops.vcd |
| Ouverture du chronogramme | Terminal |
| gtkwave tb_unite_ops.vcd |
16. Observations demandées
- Relever les valeurs de a, b, operation et resultat pour chaque scénario.
- Vérifier que les opérations logiques sont effectuées bit par bit.
- Observer le neuvième bit lors de l’addition 200 + 100.
- Comparer les indicateurs egal, inferieur et superieur.
- Observer les zéros introduits lors des décalages.
- Identifier le résultat obtenu pour une soustraction avec a < b.
- Confirmer qu’aucune assertion de niveau error n’est affichée.
17. Tableau de résultats à compléter
a | b | Opération | Décalage | Résultat observé | Indicateurs |
|---|---|---|---|---|---|
| 0x55 | 0x0F | AND | — | ||
| 0x55 | 0x0F | OR | — | ||
| 0x55 | 0x0F | XOR | — | ||
| 200 | 100 | ADD | — | ||
| 20 | 30 | Comparaison | — | ||
| 22 | — | SHIFT LEFT | 2 | ||
| 22 | — | SHIFT RIGHT | 2 |
18. Questions d’analyse
- Pourquoi les entrées a et b sont-elles converties en unsigned ?
- Pourquoi la somme comporte-t-elle neuf bits ?
- Que représente le bit resultat(8) pour les opérations logiques ?
- Quelle différence existerait si a et b étaient interprétés comme signed ?
- Quel matériel peut être inféré lorsque decalage est variable ?
- Pourquoi une valeur par défaut est-elle affectée à resultat_u au début du processus ?
- Comment modifier le circuit pour signaler un emprunt lors d’une soustraction ?
- Comment ajouter une opération de rotation gauche ?
- Pourquoi les parenthèses et resize sont-ils importants dans les expressions numériques ?
19. Extensions proposées
- Ajouter les opérations NAND, NOR et XNOR.
- Ajouter une rotation gauche et une rotation droite.
- Produire un indicateur zero lorsque le résultat est nul.
- Produire un indicateur negatif pour une version signed.
- Ajouter un mode de saturation pour l’addition.
- Créer une unité arithmétique signée distincte.
- Implanter le composant sur FPGA avec interrupteurs, LED et afficheurs.
20. Barème indicatif
Critère | Points |
|---|---|
| Entité et types des ports | 2 |
| Opérations logiques | 3 |
| Addition et gestion de la retenue | 3 |
| Comparaisons | 2 |
| Décalages | 2 |
| Processus combinatoire complet | 2 |
| Banc de test et assertions | 3 |
| Analyse des résultats | 2 |
| Qualité du code et du compte rendu | 1 |
| Total | 20 |
Synthèse du chapitre
Notion | Résumé |
|---|---|
| and, or, nand, nor | Combinaisons logiques de base |
| xor, xnor | Différence ou équivalence logique |
| not | Négation d’un bit ou d’un vecteur |
| =, /=, <, <=, >, >= | Comparaisons produisant un boolean |
| +, -, *, / | Opérations arithmétiques dépendant du type et de la largeur |
| mod et rem | Deux définitions du reste, différentes avec des nombres négatifs |
| abs | Valeur absolue d’un nombre |
| shift_left/right | Décalages normalisés pour signed et unsigned |
| rol, ror | Rotations sans perte des bits |
| & | Concaténation de bits et de vecteurs |
| resize | Extension par zéro ou extension de signe |
| Parenthèses | Moyen principal d’expliciter l’ordre et le typage |
Autoévaluation
1. Quel opérateur réalise un OU exclusif ?
Réponse : xor.
2. Quel opérateur teste la différence ?
Réponse : /=.
3. Quelle largeur minimale peut conserver la somme de deux unsigned de 8 bits ?
Réponse : 9 bits.
4. Quelle différence existe entre mod et rem ?
Réponse : Le signe du résultat : mod suit le diviseur, rem suit le dividende.
5. Quelle fonction décale un unsigned vers la droite ?
Réponse : shift_right.
6. Comment effectuer une extension de signe sûre ?
Réponse : Avec resize sur un signed.
7. Que fait l’opérateur & ?
Réponse : Il concatène des éléments ou des vecteurs.
8. Pourquoi utiliser des parenthèses ?
Réponse : Pour expliciter l’ordre d’évaluation et éviter les ambiguïtés.
9. Comment comparer numériquement deux std_logic_vector non signés ?
Réponse : Les convertir en unsigned.
10. Que faut-il vérifier avant une multiplication ?
Réponse : La largeur du produit et le coût matériel.
Exercice de consolidation
Écrire une expression VHDL produisant un résultat de 11 bits correspondant à la somme d’un mot unsigned de 8 bits et de sa version décalée de deux positions vers la gauche. Justifier pourquoi 11 bits sont nécessaires pour conserver tous les résultats possibles.
| Correction proposée | VHDL |
| signal a : unsigned(7 downto 0); signal resultat : unsigned(10 downto 0); resultat <= resize(a, resultat'length) + shift_left( resize(a, resultat'length), 2 ); |
Suite du cours — Transition vers le chapitre suivant Après la maîtrise des opérateurs et expressions, le cours peut aborder les affectations concurrentes conditionnelles et sélectionnées, qui permettent de décrire efficacement multiplexeurs, décodeurs et autres circuits combinatoires. |