Generics and generate
Parameterize a VHDL block with generics and generate repeated or optional structures.
General idea
A generic parameterizes a VHDL block before synthesis. A generate statement creates repeated or conditional structure during design elaboration.
The important difference:
- an
ifinside aprocessdescribes a choice that exists in hardware; - an
if ... generatedecides whether a block exists in hardware at all.
Width generic
The most common case is bus width.
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;The same code can produce an 8-bit, 16-bit or 32-bit counter. The final hardware depends on the generic value.
Instantiation with 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
);As with ports, named association is preferred. It avoids mistakes when the order changes.
for ... generate
for ... generate instantiates several copies of the same block at elaboration.
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)
This is not a runtime loop. The synthesizer creates g_WIDTH real structures.
if ... generate
if ... generate makes a block optional.
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
If g_REGISTER_OUTPUT = false, the register is absent from the netlist.
Best practices
- Give every
generica reasonable default. - Use
positiveornaturalwhen a freeintegeris not needed. - Prefer
g_WIDTHtoWIDTHto distinguish parameters. - Do not use a
genericfor a value that must change while the circuit runs. - Label
generateblocks, especially in structural designs.
VHDL-2008: more advanced generics
VHDL-2008 also allows type, subprogram and package generics. This is powerful, but not required at the beginning.
Example intent:
generic (
type t_data
);This style is used to create very generic blocks, for example a FIFO that can store different types. For a classic FPGA path, width, depth and feature-enable generics are already enough.
Key takeaways
| Need | Tool |
|---|---|
| Parameterized width | generic g_WIDTH |
| Parameterized depth | generic g_DEPTH |
| Repeat N instances | for ... generate |
| Enable or remove a block | if ... generate |
| Change at runtime | signal or register, not generic |
📝 Test your knowledge - Chapter quiz