Cours syntaxe vhdl et exemples pour la conception materielle

Cours syntaxe vhdl et exemples pour la conception materielle

Télécharger PDF

Introduction au VHDL

Ce document fournit une référence concise sur la syntaxe et les éléments fondamentaux du langage VHDL (VHSIC Hardware Description Language), essentiel pour la description de circuits électroniques numériques. Il présente la structure de base du langage, des exemples de code et les concepts clés de logique combinatoire et séquentielle.

Syntaxe VHDL

Le VHDL est un langage de description matérielle utilisé pour modéliser et simuler le comportement de systèmes électroniques numériques. Sa syntaxe permet une représentation précise et structurée du matériel.

Déclarations de Bibliothèque

LIBRARY <nom_de_la_librairie>;
USE <nom_de_la_librairie>.<nom_du_package>.ALL;

Ces instructions sont utilisées pour rendre disponibles des packages de fonctions et de types de données prédéfinis, tels que ceux de la bibliothèque IEEE standard, dans votre design.

Déclaration d'Entité (ENTITY)

ENTITY <nom_de_l_entite> IS
    PORT (
        <nom_du_signal> : <mode (in/out/inout/buffer)> <type>,...
    );
END <nom_de_l_entite>;

Une entité représente l'interface externe de votre bloc de conception, définissant ses ports d'entrée, de sortie, bidirectionnels ou de buffer.

Déclaration d'Architecture (ARCHITECTURE)

ARCHITECTURE <nom_de_l_architecture> OF <nom_de_l_entite> IS
    -- Section des déclarations
    TYPE <nom_du_type> IS <définition_du_type>;
    SUBTYPE <nom_du_sous_type> IS <définition_du_sous_type>;
    CONSTANT <nom_de_la_constante> : <type> := <valeur>;
    SIGNAL <nom_du_signal> : <type>;
    COMPONENT <nom_du_composant>
        PORT (
            <liste_des_signaux_du_port_du_composant>
        );
    END COMPONENT;
    USE <nom_du_package>.ALL; -- Utilisation de packages locaux ou externes

BEGIN
    -- Section des énoncés concurrents
    <label_d_instance_de_composant>: <nom_du_composant>
        PORT MAP(
            <signal_interne> => <signal_externe>,...
        );

    <signal_de_destination> <= <valeur_si_vrai> WHEN <condition> ELSE <valeur_si_faux>;

    WITH <expression> SELECT
        <nom_du_signal_de_destination> <=
            <valeur1_de_l_expression> WHEN <choix1>,
            <valeur2_de_l_expression> WHEN <choix2>,
            . . . ;

    -- Section des processus (énoncés séquentiels)
    <nom_du_processus>: PROCESS (<liste_de_sensibilite>)
        -- Déclarations locales au processus (variables)
    BEGIN
        -- Énoncés séquentiels
        WAIT UNTIL <condition>; -- Utilisé si aucune liste de sensibilité
        WAIT FOR <temps>;       -- Principalement pour les bancs de test

        <label>: WHILE <condition_de_continuation> LOOP
            <énoncés>
        END LOOP <label>;

        <label>: FOR <variable> IN <valeur_de_debut> TO <valeur_de_fin> LOOP
            <énoncés>
        END LOOP <label>;

        CASE <expression> IS
            WHEN <choix1 | choix2 | ...> =>
                <énoncés>
            WHEN <choix_n | ...> =>
                <énoncés>
        END CASE;

        IF <condition> THEN
            <énoncés>
        [ELSIF <condition> THEN
            <énoncés>]
        [ELSE
            <énoncés>]
        END IF;

        <nom_de_la_variable> := <valeur>; -- Affectation immédiate
        <nom_du_signal> <= <valeur_du_signal>; -- Affectation après la fin du processus

        -- ASSERTION pour les bancs de test (non synthétisable)
        ASSERT <condition_a_verifier>
            REPORT "<message_si_FAUX>"
            SEVERITY NOTE|WARNING|ERROR|FAILURE|FATAL;
    END PROCESS;
END <nom_de_l_architecture>;

L'architecture décrit le comportement interne de l'entité. Elle contient une section de déclarations (types, sous-types, constantes, signaux, composants) et une section d'énoncés. Les énoncés peuvent être concurrents (exécutés en parallèle) ou séquentiels (exécutés pas à pas dans un processus).

  • Les affectations de signaux concurrentes (<= avec WHEN ELSE, WITH SELECT) sont exécutées en parallèle.
  • Les processus encapsulent des énoncés séquentiels. La liste de sensibilité d'un processus détermine les signaux qui déclenchent son exécution.
  • Les variables (:=) sont mises à jour immédiatement, tandis que les signaux (<=) sont mis à jour après un délai ou à la fin du processus.
  • L'instruction ASSERT est utilisée pour la vérification de conditions durant les simulations, notamment dans les bancs de test.

Déclaration de Package (PACKAGE)

PACKAGE <nom_du_package> IS
    <déclarations de types, sous-types, constantes, signaux, composants, fonctions, procédures>
    <clause USE>
    FUNCTION <nom_de_la_fonction> ( <paramètre> ) RETURN <type_de_la_valeur_de_retour>;
    PROCEDURE <nom_de_la_procedure> ( <paramètres> );
END <nom_du_package>;

Les packages sont utilisés pour regrouper des déclarations réutilisables (types, composants, fonctions, procédures, etc.) afin de les partager entre différentes entités ou architectures, favorisant la modularité et la réutilisabilité du code.

Exemple VHDL Complet

Cet exemple illustre l'application des concepts VHDL pour la conception d'un bloc de logique numérique.

LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL; -- Pour le type STD_LOGIC
USE IEEE.NUMERIC_STD.ALL;    -- Pour les types SIGNED/UNSIGNED et leurs opérations arithmétiques

ENTITY TOPDESIGN IS
    PORT (
        CLOCK   : IN STD_LOGIC;
        RESET   : IN STD_LOGIC;
        IOBUS   : INOUT UNSIGNED (7 downto 0);
        DATAIN  : IN UNSIGNED (3 downto 0);
        FLAGS   : OUT UNSIGNED (0 TO 10)
    );
END TOPDESIGN;

ARCHITECTURE ARCHI0 OF TOPDESIGN IS
    -- Déclarations de types personnalisés
    TYPE MEM8BYTE_T IS ARRAY (0 to 15) OF UNSIGNED (7 downto 0);
    TYPE STATE_T IS (IDLE, FIRST, LAST, STANDBY);
    SUBTYPE BYTE IS UNSIGNED (7 downto 0);

    -- Déclaration de constante (ROM)
    CONSTANT ROM : MEM8BYTE_T := (X"FF", X"FE", others=>X"00");

    -- Déclaration de signal
    SIGNAL COUNT : UNSIGNED (7 downto 0);

    -- Déclaration de composant (MY_ROM)
    COMPONENT MY_ROM -- Similaire à la déclaration d'entité MY_ROM
        PORT (
            ADD : IN UNSIGNED (7 downto 0);
            OE  : IN STD_LOGIC;
            DB  : OUT UNSIGNED (7 downto 0)
        );
    END COMPONENT;

    USE WORK.MY_SMALL_PACKAGE.ALL; -- Utilisation d'un package défini dans la bibliothèque de travail

BEGIN
    -- Instanciation de composants (ROM0 et ROM1)
    ROM0: MY_ROM PORT MAP(
        ADD => COUNT,
        OE  => DATAIN(0),
        DB  => IOBUS
    );
    ROM1: MY_ROM PORT MAP(
        ADD => COUNT,
        OE  => DATAIN(1),
        DB  => IOBUS
    );

    -- Affectation concurrente conditionnelle
    FLAGS(0) <= '0' WHEN DATAIN = "1100" ELSE '1';

    -- Affectation concurrente avec sélection (WITH SELECT)
    WITH DATAIN SELECT
        FLAGS(1 TO 2) <=
            "00" WHEN "0001",
            "01" WHEN "0101",
            "11" WHEN OTHERS;

    -- Processus pour un compteur synchrone avec reset
    COUNTER_SR : PROCESS (CLOCK)
    BEGIN
        IF RISING_EDGE (CLOCK) THEN
            IF DATAIN(3) = '1' THEN
                COUNT <= (others => '0'); -- Reset synchrone
            ELSE
                COUNT <= COUNT + 1;
            END IF;
        END IF;
    END PROCESS COUNTER_SR;

    -- Processus de test (pour banc de test, non synthétisable)
    TEST : PROCESS
    BEGIN
        FLAGS(10) <= '0';
        WAIT FOR 10 NS; -- Pause de 10 nanosecondes
        FLAGS(10) <= '1';
        WAIT FOR 10 NS;
        ASSERT COUNT = 0
            REPORT "COUNT RESET FAILED"
            SEVERITY ERROR;
        WAIT FOR 10000 NS;
        ASSERT FALSE
            REPORT "END OF SIMULATION REACHED"
            SEVERITY ERROR;
    END PROCESS TEST;

END ARCHI0;

PACKAGE MY_SMALL_PACKAGE IS
    COMPONENT MY_AND -- Similaire à la déclaration d'entité MY_AND
        PORT (
            A, B : IN STD_LOGIC;
            Y    : OUT STD_LOGIC
        );
    END COMPONENT;
END MY_SMALL_PACKAGE;

Logique Combinatoire

La logique combinatoire est un type de logique numérique dont la sortie dépend uniquement des valeurs actuelles de ses entrées, sans état interne mémorisé.

Opérateurs Élémentaires (Portes Logiques)

  • not A : Inverse l'entrée A.
  • A and B : La sortie est vraie si A ET B sont vrais.
  • A or B : La sortie est vraie si A OU B sont vrais.
  • A xor B : La sortie est vraie si A OU B est vrai, mais pas les deux.
  • A nand B : L'inverse de (A ET B).
  • A nor B : L'inverse de (A OU B).

Fonction Combinatoire Générique

Une fonction combinatoire peut être décrite à l'aide d'une table de vérité. L'instruction WITH SELECT en VHDL est un moyen efficace de la modéliser.

-- Exemple de table de vérité (A est une entrée de 2 bits, Y une sortie de 3 bits)
-- A(in) | Y(out)
-- 00    | 010
-- 01    | 111 (correction: 'x' n'est pas une valeur assignable)
-- 10    | 010
-- 11    | 010 (pour le cas 'others', ajusté pour être valide)

WITH A SELECT
    Y <=
        "010" WHEN "00" | "10",
        "111" WHEN "01",
        "010" WHEN OTHERS;

Note : Dans l'exemple original, "1x1" et "01-" ne sont pas des valeurs valides pour une affectation directe à un signal de type STD_LOGIC_VECTOR. Le 'x' est souvent utilisé dans les tables de vérité pour "don't care", mais il doit être résolu en une valeur binaire concrète lors de l'affectation.

Décodeur/Démultiplexeur

Un décodeur convertit une entrée binaire en un signal de sortie unique correspondant à cette entrée. Un démultiplexeur a une entrée de données unique et une entrée de sélection qui achemine cette donnée vers une de ses multiples sorties.

-- Exemple de décodeur (1 vers N)
process(A, E)
    variable index : natural;
begin
    index := TO_INTEGER(A);
    Q <= (others => '0'); -- Initialise toutes les sorties à '0'
    Q(index) <= E;         -- Active la sortie sélectionnée par A
end process;

Ici, A est l'entrée de sélection binaire et E est une entrée d'activation.

Comparateur

Un comparateur logique compare deux entrées binaires et génère une sortie indiquant leur relation (égal, supérieur, etc.).

-- Exemples de comparaisons concurrentes
A_egal_B  <= '1' WHEN A = B ELSE '0';
A_sup_B   <= '1' WHEN A > B ELSE '0';
A_diff_B  <= '1' WHEN A /= B ELSE '0';

Multiplexeur

Un multiplexeur (MUX) sélectionne une de ses nombreuses entrées de données pour l'acheminer vers une seule ligne de sortie, en fonction d'une entrée de sélection.

-- Exemple de multiplexeur 2 vers 1
SORTIE <= ENTREE0 WHEN SELECTEUR = '0' ELSE ENTREE1;

-- Multiplexeur avec WITH SELECT
WITH SELECTEUR SELECT
    SORTIE <=
        ENTREE0 WHEN "00",
        ENTREE1 WHEN "01",
        ENTREE2 WHEN "10",
        ENTREE3 WHEN OTHERS; -- Pour un MUX 4 vers 1

Logique Séquentielle

La logique séquentielle diffère de la logique combinatoire par sa capacité à mémoriser des états, ce qui signifie que ses sorties dépendent non seulement des entrées actuelles mais aussi de l'historique des entrées (état passé).

Bascule D Transparente (D-Latch)

Une bascule D transparente propage l'entrée D vers la sortie Q lorsque l'entrée de validation (LE) est active. Lorsque LE est inactive, la sortie Q maintient sa dernière valeur.

Q <= D WHEN LE = '1';

Bascule D Synchrone (D-Flip-Flop)

Une bascule D synchrone ne change d'état qu'au front d'horloge (montant ou descendant), mémorisant la valeur de D au moment de ce front.

D_FLIP_FLOP : process (clk)
begin
    if RISING_EDGE(clk) then
        Q <= D;
    end if;
end process D_FLIP_FLOP;

Compteur Synchrone

Un compteur est un circuit séquentiel qui s'incrémente ou se décrémente à chaque impulsion d'horloge. Il peut être réinitialisé (reset) à une valeur prédéfinie.

COUNTER_SYNCHRONE : process (clk)
begin
    wait until RISING_EDGE(clk);
    -- Le signal 'count' est mis à jour à chaque front montant de 'clk'
    count <= count + 1;
end process COUNTER_SYNCHRONE;

Cet exemple montre un compteur simple qui s'incrémente à chaque front montant de l'horloge.

Registre à Décalage (Shift Register)

Un registre à décalage est un type de registre séquentiel qui permet de décaler des bits de données vers la gauche ou la droite, une position à la fois, à chaque impulsion d'horloge.

SHIFT_REG : process (clk)
    signal iQ : STD_LOGIC_VECTOR(3 downto 0); -- Signal interne pour le décalage
begin
    if RISING_EDGE(clk) then
        iQ(3 downto 1) <= iQ(2 downto 0); -- Décale les bits vers la gauche (du bit 0 vers le bit 1, etc.)
        iQ(0) <= Din;                    -- Insère une nouvelle donnée à la position la plus à droite (LSB)
    end if;
    Q <= iQ; -- La sortie Q prend la valeur du signal interne iQ
end process SHIFT_REG;

Registre à Décalage avec Reset Asynchrone

Un reset asynchrone permet de réinitialiser le registre immédiatement, indépendamment du signal d'horloge, dès que le signal de reset est actif.

SHIFT_REG_RESET_ASYNC : process (RESET_ASYNC, clk)
begin
    if RESET_ASYNC = '0' then -- Si RESET_ASYNC est actif (niveau bas)
        Q <= (others => '0');  -- Réinitialise toutes les sorties à '0'
    elsif RISING_EDGE(clk) then
        Q <= D; -- Comportement normal de bascule D
    end if;
end process SHIFT_REG_RESET_ASYNC;

Automate à États Finis (FSM - Modèle de Moore)

Un automate de Moore est une machine à états finis dont les sorties sont déterminées uniquement par l'état actuel de l'automate. Les transitions entre états sont généralement synchronisées par une horloge.

-- Déclaration des états possibles
TYPE ETAT_T IS (IDLE, FIRST, LAST);
SIGNAL ETAT : ETAT_T;

-- Logique de transition d'état (synchrone)
MOORE_TRANSITION : process (clock)
begin
    if RISING_EDGE (clock) then
        case ETAT is
            when IDLE =>
                if A = '1' then
                    ETAT <= FIRST;
                end if;
            when FIRST =>
                if A = '1' then
                    ETAT <= LAST;
                else
                    ETAT <= IDLE;
                end if;
            when LAST =>
                if A = '0' then
                    ETAT <= IDLE;
                end if;
            when others => -- Gestion des états non définis (bonne pratique)
                ETAT <= IDLE;
        end case;
    end if;
end process MOORE_TRANSITION;

-- Logique de sortie (combinatoire, basée sur l'état actuel)
decodage_sorties: with ETAT select
    Q <=
        "00" WHEN IDLE,
        "01" WHEN FIRST,
        "10" WHEN LAST,
        "11" WHEN OTHERS; -- Cas par défaut pour Q

Dans cet exemple, A est une entrée qui influence les transitions d'état, et Q est la sortie qui dépend directement de l'état actuel de l'automate.

Sorties Spéciales

Certains types de sorties nécessitent une description spécifique pour modéliser des comportements matériels particuliers.

Buffer Tristate

Un buffer tristate est un composant qui peut être dans l'un de trois états : haut (1), bas (0) ou haute impédance (Z). L'état haute impédance permet de déconnecter logiquement la sortie d'un bus, rendant ce type de buffer essentiel pour les bus partagés.

Y <= A WHEN OE = '1' ELSE 'Z';

Lorsque OE (Output Enable) est à '1', la sortie Y suit l'entrée A. Lorsque OE est à '0', la sortie Y est en haute impédance ('Z').

Collecteur Ouvert

Une sortie à collecteur ouvert (ou drain ouvert pour les FET) est un type de sortie qui peut tirer la ligne vers un niveau logique bas (0). Pour obtenir un niveau logique haut (1), une résistance de rappel (pull-up) externe est nécessaire.

Y <= '0' WHEN A = '0' ELSE 'Z';

Dans cet exemple, si l'entrée A est à '0', la sortie Y est à '0'. Sinon, elle est en haute impédance ('Z'), permettant à une résistance de rappel externe de la tirer vers '1'.

Questions Fréquentes (FAQ)

Quelle est la différence entre une affectation de variable (:=) et une affectation de signal (<=) en VHDL ?

Les variables sont des objets locaux à un processus ou à une fonction et sont affectées immédiatement; leur nouvelle valeur est disponible dès l'instruction suivante. Les signaux représentent les connexions physiques dans le matériel et sont affectés avec un délai; leur nouvelle valeur n'est visible qu'après un court délai (délai delta) ou à la fin de l'exécution du processus.

À quoi sert la liste de sensibilité dans un processus VHDL ?

La liste de sensibilité d'un processus spécifie quels signaux doivent déclencher l'exécution de ce processus. Pour un comportement combinatoire, elle doit inclure toutes les entrées du processus. Pour un comportement séquentiel, elle contient typiquement le signal d'horloge et tout signal de reset asynchrone, ce qui permet au processus de réagir aux changements pertinents de ces signaux.

Pourquoi utilise-t-on des packages en VHDL ?

Les packages en VHDL sont des conteneurs qui regroupent des déclarations réutilisables telles que des types de données personnalisés, des sous-types, des constantes, des déclarations de composants, ainsi que des fonctions et procédures. Ils améliorent la modularité et la réutilisabilité du code en permettant de partager ces éléments entre différentes entités et architectures, simplifiant ainsi le développement de grands projets.

Partagez vos remarques, questions ou propositions d'amélioration ici...

Enregistrer un commentaire (0)
Plus récente Plus ancienne

Publicité 1

Publicité 2