Generics et generate
Paramétrer un bloc VHDL avec des generics et générer des structures répétées ou optionnelles.
Idée générale
Un generic permet de paramétrer un bloc VHDL avant la synthèse. Un generate permet de créer une structure répétée ou conditionnelle pendant l'élaboration du design.
La différence importante :
- un
ifdans unprocessdécrit un choix qui existe dans le matériel ; - un
if ... generatedécide si un bloc existe ou non dans le matériel.
Generic de largeur
Le cas le plus courant est la largeur d'un bus.
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;Ici, le même code peut produire un compteur 8 bits, 16 bits ou 32 bits. Le matériel final dépend de la valeur donnée au generic.
Instanciation avec generic map
u_counter_16 : entity work.counter
generic map (
g_WIDTH => 16
)
port map (
i_clk => i_clk,
i_rst => i_rst,
i_en => i_en,
o_cnt => w_count_16
);Comme pour les ports, l'association nommée est préférable : elle évite les erreurs quand l'ordre change.
for ... generate
for ... generate instancie plusieurs copies d'un même bloc à 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 is
begin
g_bits : for i in 0 to g_WIDTH - 1 generate
p_bit : process(i_clk)
begin
if rising_edge(i_clk)
Ce n'est pas une boucle à l'exécution. Le synthétiseur crée réellement g_WIDTH structures.
if ... generate
if ... generate rend un bloc optionnel.
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
Si g_REGISTER_OUTPUT = false, le registre n'existe pas dans le netlist.
Bonnes pratiques
- Donnez des valeurs par défaut raisonnables aux
generic. - Utilisez
positiveounaturalquand unintegerlibre n'est pas nécessaire. - Préférez
g_WIDTHàWIDTHpour distinguer les paramètres. - N'utilisez pas un
genericpour une valeur qui doit changer pendant l'exécution. - Labellisez les blocs
generate, surtout dans les designs structurés.
VHDL-2008 : generics plus avancés
VHDL-2008 permet aussi des generics de type, de sous-programme ou de package. C'est puissant, mais ce n'est pas nécessaire au début.
Exemple d'intention :
generic (
type t_data
);Ce style sert à créer des blocs très génériques, par exemple une FIFO capable de stocker différents types. Pour un parcours FPGA classique, les generics de largeur, de profondeur et d'activation de blocs sont déjà largement suffisants.
À retenir
| Besoin | Outil |
|---|---|
| Largeur paramétrable | generic g_WIDTH |
| Profondeur paramétrable | generic g_DEPTH |
| Répéter N instances | for ... generate |
| Activer ou retirer un bloc | if ... generate |
| Modifier à l'exécution | signal ou registre, pas generic |
📝 Tester mes connaissances - Quiz du chapitre