20 / 37 · Concept
generate: building static circuits with loops
Use genvar and generate-if to create named circuit instances and check bus lane placement.
Lessons are free to read. Enroll to save your learning progress.
A generate loop creates instances, not clock cycles
genvar and a generate loop describe repeated static structure. The elaborator creates all instances before execution. A loop inside always_comb describes a procedural computation whose hardware is determined by synthesis. Neither automatically means one iteration per clock. Serial processing requires explicit state and a clocked controller.
This example splits a packed input bus into LANES words, each W bits wide, and computes one parity bit per word. W and LANES must both be positive integers.
module lane_parity #(
parameter integer W = 8,
parameter integer LANES = 3
) (
input logic [W*LANES-1:0] data,
output logic [LANES-1:0] parity
);
genvar lane;
generate
for (lane = 0; lane < LANES; lane = lane + 1) begin : g_lane
wire [W-1:0] word_data;
assign word_data = data[lane*W +: W];
assign parity[lane] = ^word_data;
end
endgenerate
endmoduledata[base +: W] selects W bits starting at base and moving toward larger bit indices. W is constant for an elaborated instance. With W=8 and LANES=3, lane 0 receives bits 7:0, lane 1 bits 15:8, and lane 2 bits 23:16. The named block g_lane provides stable hierarchy such as g_lane[1].word_data for inspection.
Read the lane order from the declaration
For data=24'h03_01_80, lane values are 80,01,03 from lane 0 upward. Their parity bits are 1,1,0, so the displayed vector parity[2:0] is 3'b011. The leftmost hexadecimal byte is lane 2, not lane 0. Keep numerical indices, display order and transmission order separate.
All lanes compute concurrently. This design has no registered latency. A larger LANES value creates more combinational logic, not a longer sequence of cycles. Physical fanout, routing and timing still need their own implementation checks.
Generate-if chooses one fixed structure
A condition in generate-if must be constant during elaboration, such as a parameter choosing whether an optional register is included. A run-time signal must instead select behavior in a combinational or clocked block. Changing a configuration parameter from registered to unregistered also changes the valid-time contract, so it must be reflected in the port documentation and checker.
Do not use a parameter value of zero to “turn off” this bus. A range such as [−1:0] is not a safe zero-width object. Reject the unsupported setting or use an explicit generate branch whose external interface remains well-defined.
Practice · Detect lane swaps
Check the example above, then set exactly one bit in each lane in turn. Confirm that only the corresponding parity bit changes. Also test a word with two set bits: even parity must return 0. A test with identical words in every lane would fail to reveal swapped slices.
Use an independent checker that extracts a lane numerically and counts its set bits. Test W=1, W=8, LANES=1 and LANES=3. These cases expose assumptions about byte width, repeated hierarchy and minimum configuration.
Finally register the parity vector on a rising edge as a separate experiment. Specify reset, enable and whether the checker compares against the current bus or the bus sampled at the preceding edge.