Paramétrer un bloc VHDL avec des generics et générer des structures répétées ou optionnelles.
Un générique fixe un paramètre à l'élaboration. Un generate utilise ces paramètres pour créer des instances ou sélectionner les blocs présents dans le design.
Fixer la taille d'une instance
La largeur d'un bus est un paramètre courant :
library
IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity counter is
generic (
g_WIDTH : positive := 8
);
port (
i_clk : in std_logic;
i_rst : in std_logic;
i_en : in std_logic;
o_cnt : out std_logic_vector(g_WIDTH - 1 downto 0)
);
end entity counter;
architecture rtl of counter is
signal r_cnt : unsigned(g_WIDTH - 1 downto 0);
begin
p_count : process(i_clk)
begin
if rising_edge(i_clk) then
if i_rst = '1' then
r_cnt <= (others => '0');
elsif i_en = '1' then
r_cnt <= r_cnt + 1;
end if;
end if;
end process p_count;
o_cnt <= std_logic_vector(r_cnt);
end architecture rtl;
Avec le même RTL, g_WIDTH peut produire un compteur de 8, 16 ou 32 bits. Chaque instance reçoit sa valeur par generic map :
L'association nommée rend ce choix visible et évite de dépendre de l'ordre des paramètres. Donne des valeurs par défaut raisonnables et utilise positive ou natural lorsque ces contraintes correspondent au besoin.
Répéter ou sélectionner des blocs
for / generate développe une structure répétée à l'élaboration :
entity reg_bank is generic ( g_WIDTH : positive := 8 ); port ( i_clk : in std_logic; i_d : in std_logic_vector(g_WIDTH - 1 downto 0); o_q : out std_logic_vector(g_WIDTH - 1 downto 0) );end entity reg_bank;architecture rtl of reg_bank isbegin g_bits : for i in 0 to g_WIDTH - 1 generate p_bit : process(i_clk) begin if rising_edge(i_clk) then o_q(i) <= i_d(i); end if; end process p_bit; end generate g_bits;end architecture rtl;
Cet extrait crée g_WIDTH registres. La répétition ne s'exécute pas comme une boucle logicielle dans le FPGA.
if / generate choisit une structure selon une condition statique :
entity pipeline_stage is generic ( g_REGISTER_OUTPUT : boolean := true ); port ( i_clk : in std_logic; i_a : in unsigned(7 downto 0); i_b : in unsigned(7 downto 0); o_y : out unsigned(8 downto 0) );end entity pipeline_stage;architecture rtl of pipeline_stage is signal w_sum : unsigned(8 downto 0); signal r_y : unsigned(8 downto 0);begin w_sum <= resize(i_a, w_sum'length) + resize(i_b, w_sum'length); g_registered : if g_REGISTER_OUTPUT generate p_reg : process(i_clk) begin if rising_edge(i_clk) then r_y <= w_sum; end if; end process p_reg; o_y <= r_y; end generate g_registered; g_comb : if not g_REGISTER_OUTPUT generate o_y <= w_sum; end generate g_comb;end architecture rtl;
Avec g_REGISTER_OUTPUT = false, seul le chemin combinatoire est utilisé ; le registre inutilisé peut être supprimé de la netlist. Avec true, la sortie est enregistrée.
Un if dans un process peut, lui, décrire une sélection à l'exécution lorsque sa condition dépend de signaux. Une condition constante peut aussi être simplifiée par l'outil.
Définir des paramètres réutilisables
Les génériques VHDL-2008 peuvent porter sur des types, des sous-programmes ou des packages :
generic ( type t_data);
Un type générique peut permettre à une FIFO d'accueillir différents types de données. Vérifie la compatibilité des outils avant de l'utiliser.
Préfixe les paramètres avec g_ et nomme les blocs generate pour faciliter la lecture de la hiérarchie. Pour une valeur qui doit changer pendant le fonctionnement, utilise un signal ou un registre de configuration.