VHDL · Chapter 12.4 · Generics
Generics with Generate Statements
Generics set sizes, and generate statements turn those sizes into structure. A for-generate whose bound is a generic replicates that many instances, building an N-stage pipeline, an array of processing elements, or a structural datapath, all from one body. An if-generate, and in VHDL-2008 a case-generate, conditionally includes logic based on a generic, giving you an optional output register when requested, a different implementation per mode, or special handling at the first or last index of a replicated array. Together, generic-driven generate is how you build designs whose very shape, meaning how many blocks and which blocks exist, becomes a parameter fixed at elaboration. This lesson combines generics with for-generate and if-generate to produce structurally parameterized hardware from a single source.
Foundation14 min readVHDLGenericsGenerateReplicationPipelineStructural
1. Engineering intuition — let a number decide the structure
So far a generic changed how wide a block is. Generate lets a generic change how many blocks there are and
which blocks exist. Think of a pipeline with STAGES stages: you do not want to copy a stage STAGES times by
hand — you want to say "make one of these for each stage" and let a generic set the count. That is for-generate.
And sometimes a piece of logic should exist only in certain configurations — an output register only when
requested, boundary handling only at the ends — which is if-generate. Generic-driven generate is how a single
source describes a family of differently-shaped circuits.
2. Formal explanation — for-generate and if-generate driven by generics
-- FOR-GENERATE: replicate N instances, N from a generic. Each iteration is elaborated structurally.
gen_stages : for i in 0 to STAGES-1 generate
u_stage : entity work.stage
generic map ( WIDTH => DATA_W )
port map ( clk => clk, d => pipe(i), q => pipe(i+1) ); -- index the array of signals
end generate;
-- IF-GENERATE: include logic only when a generic condition holds (e.g. optional output register).
gen_reg : if REG_OUT generate
process (clk) begin
if rising_edge(clk) then q <= y; end if; -- present only when REG_OUT = true
end process;
end generate;
gen_comb : if not REG_OUT generate
q <= y; -- otherwise combinational pass-through
end generate;A for-generate elaborates its body once per index over a range that can come from a generic — structural replication, with the index used to wire an array of instances/signals. An if-generate (and 2008 case-generate) elaborates its body only when a generic-based condition holds, conditionally including or omitting logic. Both are resolved at elaboration.
3. Production usage — an N-stage pipeline from a generic
entity delay_line is
generic ( STAGES : positive := 4; DATA_W : positive := 8 );
port ( clk : in std_logic;
d : in std_logic_vector(DATA_W-1 downto 0);
q : out std_logic_vector(DATA_W-1 downto 0) );
end entity;
architecture rtl of delay_line is
type slv_arr is array (0 to STAGES) of std_logic_vector(DATA_W-1 downto 0);
signal pipe : slv_arr; -- STAGES+1 taps
begin
pipe(0) <= d;
gen : for i in 0 to STAGES-1 generate -- STAGES registers, count from the generic
process (clk) begin
if rising_edge(clk) then pipe(i+1) <= pipe(i); end if;
end process;
end generate;
q <= pipe(STAGES);
end architecture;What hardware does this become? STAGES => 4 elaborates four register stages chained d → … → q (a
4-cycle delay line); STAGES => 16 elaborates sixteen. The for-generate produces real, distinct flip-flop
stages — one per index — wired through the pipe array. The number of stages is fixed at elaboration by the
generic, so the structure (how many registers) is parameterized while each stage is identical hardware.
4. Structural interpretation — a generic builds N stages
5. Why this is structural, not timing
Generic-driven generate is structural replication and conditional inclusion resolved at elaboration — it decides how many blocks and which blocks exist before any simulation — so a structure diagram, not a waveform, captures it. Once elaborated, the result is ordinary hardware (a 4-stage pipeline behaves like four chained registers, whose timing you already know); generate itself adds nothing at run time. The parameterization is in the shape of the netlist, a static property, which is precisely why it is shown as structure.
6. Debugging example — the generate that built the wrong shape
Expected: N stages wired in a chain. Observed: an index-out-of-range error, stages not connected, or
logic that should have been optional appearing/missing. Root cause: the signal array bounds did not match
the generate range (e.g. pipe declared 0 to STAGES-1 but indexed pipe(i+1) up to STAGES), the
for-generate range was off-by-one, or an if-generate condition was based on a value not known at
elaboration. Fix: size the connecting array to cover every index the loop uses (0 to STAGES for STAGES
stages with taps), keep the generate range consistent, and base if-generate conditions on generics/constants
(elaboration-time), never runtime signals. Engineering takeaway: generate replicates structurally at
elaboration — get the array bounds and loop range consistent, and gate if-generate on compile-time generics, not
runtime values.
-- BUG: array too small for the indices the generate uses → index out of range.
-- type a is array (0 to STAGES-1) of ...; -- but loop writes pipe(i+1) up to STAGES
-- FIX: size the array to cover every tap (0 .. STAGES).
type a is array (0 to STAGES) of std_logic_vector(DATA_W-1 downto 0);7. Common mistakes & what to watch for
- Off-by-one bounds. Match the connecting array size to the generate range (an N-stage chain needs N+1 taps); mismatches cause index errors.
- if-generate on a runtime value. Conditions must be elaboration-time (generics/constants); you cannot conditionally generate hardware from a signal.
- Forgetting generate labels. Generate statements and their inner instances need labels; they form part of the hierarchical name.
- Expecting a runtime-variable count. The number of generated instances is fixed at elaboration by the generic; it cannot change while running.
- Replicating instead of looping for pure logic. For simple per-bit logic a vectorized expression may be cleaner than a for-generate; use generate for instances/structure.
8. Engineering insight & continuity
Generic-driven generate makes a design's shape a parameter: a for-generate replicates N instances where N is a generic (pipelines, PE arrays, structural datapaths), and an if/case-generate includes or omits logic by a generic condition (optional registers, mode/boundary handling) — all resolved at elaboration into real hardware. Combined with width generics, you can now parameterize both size and structure from one source. The next lesson widens what a generic can be: beyond integers, Constant and Type Generics — passing configuration constants and even types as generics for still more flexible, reusable components.