Exploiter les constantes et generic maps en VHDL pour un design de module flexible
Créer des modules réutilisables est une pierre angulaire du design VHDL efficace, mais de mineures variations demandent souvent du code dupliqué. Les génériques et generic maps résolvent cela en vous permettant de configurer les paramètres d'un module au moment de la compilation, gardant votre code DRY et maintenable.
Les constantes aident à éviter de coder en dur la même valeur répétitivement. Elles sont idéales pour définir les largeurs de vecteurs de signaux ou d'autres paramètres à la compilation, et peuvent même être mappées à des constantes génériques. Contrairement aux signaux ou variables, la valeur d'une constante est immuable après l'élaboration, assurant la cohérence à travers le design.
Cet article fait partie de la série Tutoriels VHDL de Base.
Dans notre tutoriel précédent, nous avons construit un multiplexeur 4 entrées avec une largeur de bus de 8 bits. Si vous avez maintenant besoin d'un MUX similaire avec une largeur différente, copier-coller le module entier n'est pas la seule option.
Au lieu de cela, déclarez une constante qui contient la largeur de bus désirée, puis passez cette constante au module via un générique. Le seul endroit où vous devez changer la largeur est la déclaration de constante dans votre testbench.
Voici la syntaxe pour déclarer une constante en VHDL :
constant <constant_name> : <type> := <value>;
Les constantes peuvent apparaître aux côtés des signaux dans la partie déclarative d'un fichier, ou avec les variables à l'intérieur d'un processus.
Pour exposer une constante à un module, utilisez le mot-clé generic dans la déclaration d'entité :
entity <entity_name> is
generic(
<entity_constant_name> : <type> [:= default_value];
...
);
port(
<entity_signal_name> : in|out|inout <type>;
...
);
end entity;
Instanciez le module générique ailleurs en utilisant un generic map et port map :
<label> : entity <library_name>.<entity_name>(<architecture_name>)
generic map(
<entity_constant_name> => <value_or_constant>,
...
)
port map(
<entity_signal_name> => <local_signal_name>,
...
);
Exercice
Dans ce tutoriel vidéo, nous allons parcourir la création et l'instanciation d'un module MUX 4 entrées générique en VHDL.
Testbench - MUX Générique
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity T16_GenericMapTb is
end entity;
architecture sim of T16_GenericMapTb is
constant DataWidth : integer := 8;
signal Sig1 : signed(DataWidth-1 downto 0) := x"AA";
signal Sig2 : signed(DataWidth-1 downto 0) := x"BB";
signal Sig3 : signed(DataWidth-1 downto 0) := x"CC";
signal Sig4 : signed(DataWidth-1 downto 0) := x"DD";
signal Sel : signed(1 downto 0) := (others => '0');
signal Output : signed(DataWidth-1 downto 0);
begin
i_Mux1 : entity work.T16_GenericMux(rtl)
generic map(DataWidth => DataWidth)
port map(
Sel => Sel,
Sig1 => Sig1,
Sig2 => Sig2,
Sig3 => Sig3,
Sig4 => Sig4,
Output => Output
);
process is
begin
wait for 10 ns;
Sel <= Sel + 1;
wait for 10 ns;
Sel <= Sel + 1;
wait for 10 ns;
Sel <= Sel + 1;
wait for 10 ns;
Sel <= Sel + 1;
wait for 10 ns;
Sel <= "UU";
wait;
end process;
end architecture;
Module MUX Générique
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity T16_GenericMux is
generic(DataWidth : integer);
port(
-- Entrées
Sig1 : in signed(DataWidth-1 downto 0);
Sig2 : in signed(DataWidth-1 downto 0);
Sig3 : in signed(DataWidth-1 downto 0);
Sig4 : in signed(DataWidth-1 downto 0);
Sel : in signed(1 downto 0);
-- Sortie
Output : out signed(DataWidth-1 downto 0)
);
end entity;
architecture rtl of T16_GenericMux is
begin
process(Sel, Sig1, Sig2, Sig3, Sig4) is
begin
case Sel is
when "00" => Output <= Sig1;
when "01" => Output <= Sig2;
when "10" => Output <= Sig3;
when "11" => Output <= Sig4;
when others => Output <= (others => 'X');
end case;
end process;
end architecture;
Forme d'onde ModelSim après l'exécution de la simulation (zoom sur la timeline) :

Analyse
En définissant DataWidth une fois dans le testbench, nous pouvons adapter le même MUX pour toute largeur de bus sans toucher au code du module. La forme d'onde confirme une fonctionnalité identique à la version codée en dur.

À retenir
- Les constantes éliminent les valeurs codées en dur répétitives, améliorant la lisibilité et réduisant les erreurs.
- Les génériques rendent les modules hautement configurables, améliorant la réutilisation à travers un design.
Passez au tutoriel suivant »
VHDL
- Exploiter les procédures in-process pour un design FSM VHDL plus propre
- Utilisation des fonctions impures en VHDL : Améliorer la lisibilité et la maintenabilité des FSM
- Maîtriser les fonctions VHDL : Guide pratique pour un design efficace
- Utilisation des procédures en VHDL : Simplifiez votre design avec du code réutilisable
- Exploiter les constantes et generic maps en VHDL pour un design de module flexible
- Maîtriser l'instanciation par port map en VHDL : Guide pratique
- Maîtriser l'instruction Case-When en VHDL : Conception efficace de multiplexeur
- Installation gratuite d'un simulateur et éditeur VHDL : guide étudiant
- Microcontrôleurs PIC18 : Caractéristiques, Performances et Utilisation