Skip to content

Verilog · Chapter 14.7.3 · Behavioural Modeling

Generate case in Verilog — Selecting Structure Variants by Parameter

The generate case construct picks one hardware implementation from several, chosen by a parameter when the design is elaborated. It is the multi-way version of generate if. Instead of including or excluding a single block, generate case lets you select among variants, such as a fast multiplier versus a small one, a vendor primitive versus a plain behavioural model, or a different datapath per mode. Only the matching variant is built, so the others produce no gates at all. This makes it the natural tool for implementation and platform selection in parameterized, portable RTL, letting one module choose the right structure for its configuration. This lesson walks through the syntax, how selection works, and common variant patterns.

Foundation10 min readVeriloggenerate caseVariant SelectionParameterPortable RTL

Chapter 14 · Section 14.7.3 · Behavioural Modeling

1. The Engineering Problem

A parameterized module needs to pick one of several implementations by configuration — a fast vs small multiplier, a vendor primitive vs a behavioural model. generate case selects the variant:

generate case selects among structural variants based on a parameter, at elaboration — only the chosen variant is built. The multi-way counterpart to generate if.

This page drills generate case and its variant-selection use.

2. Mental Model — Select One Structure Variant by Parameter

3. The generate case

generate-case.v
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   generate
       case (IMPL)
           "FAST":  begin : gen_fast
               fast_mult u (.a(a), .b(b), .y(y));      // single-cycle multiplier
           end
           "SMALL": begin : gen_small
               iterative_mult u (.a(a), .b(b), .clk(clk), .y(y));
           end
           default: begin : gen_default
               behavioural_mult u (.a(a), .b(b), .y(y));
           end
       endcase
   endgenerate

The IMPL parameter selects which multiplier structure to build — fast, small, or default. Only the chosen variant is elaborated; the others produce no hardware. This picks an implementation per configuration. (Name the generate blocks for hierarchy, 14.7.1.)

4. Platform and Implementation Variants

The canonical generate case use — selecting structure by platform or implementation:

variants.v
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   // platform primitive selection (Xilinx / Altera / ASIC):
   generate
       case (VENDOR)
           "XILINX": begin : g xilinx_ram u (...); end
           "ALTERA": begin : g altera_ram u (...); end
           default:  begin : g behavioural_ram u (...); end
       endcase
   endgenerate

Selecting a vendor primitive (a Xilinx BRAM vs an Altera memory vs a portable behavioural model) by a VENDOR parameter — one source that targets multiple platforms, building only the matching primitive. This is how portable, parameterized IP adapts its structure to its target. (Related to the `ifdef VENDOR_* build-target pattern of 7.4, but parameter-driven at the language level.)

Visual A — generate case selects a variant

generate case — one variant by parameter

data flow
generate case — one variant by parametercase (IMPL)parameter selectorFAST → fast_multone variantSMALL →iterative_multanother variantonly chosen builtothers: no hardware
generate case selects one structural variant by a parameter at elaboration: IMPL chooses among implementations (fast, small, default), and only the matching variant's structure is built — the others produce no hardware. Used for implementation and platform selection in parameterized, portable RTL.

5. Common Mistakes

  1. Runtime selector in generate case — the selector must be a parameter/constant (like generate if, §2).
  2. Using a runtime case for variant structure — builds all variants as mux inputs; use generate case to build only one (14.5.2 vs here).
  3. Unnamed generate blocks — name them for hierarchy (14.7.1).

6. Debugging Lab

One generate-case debug post-mortem

Pitfall — an unexpected parameter value silently builds the wrong variant
Buggy Code
module mult #(parameter IMPL = "FAST") (input [7:0] a, b, output [15:0] p);
  generate
      case (IMPL)
          "FAST":  fast_mult     u (a, b, p);   // single-cycle DSP variant
          "SMALL": iterative_mult u (a, b, p);  // multi-cycle area-saving variant
          default: fast_mult     u (a, b, p);   // fallback
      endcase
  endgenerate
endmodule

// A top-level instantiation overrides IMPL but with a value that matches NO
// case item:
//     mult #(.IMPL("LOW_POWER")) u_mult (...);   // typo / wrong string
//
// 'generate case' selects STRUCTURE at elaboration by exact parameter match.
// "LOW_POWER" matches neither "FAST" nor "SMALL", so the DEFAULT variant
// (fast_mult) is built — silently. There is no runtime "wrong opcode" to
// catch; the elaborated hardware is simply the default, not the intended
// low-power block. The design synthesizes cleanly and simulates, but the
// WRONG hardware variant is in the chip — a configuration bug that no
// functional test of the (working) default variant will reveal.
Symptom

A configurable module is instantiated with a particular implementation parameter, but the synthesized/elaborated design uses a different variant than intended (here, the default fast multiplier instead of a low-power one). The design works functionally — it just isn't the variant that was asked for — so area/power/timing come out wrong and the mismatch is found late, in synthesis reports or silicon characterization, not in simulation.

Root Cause

generate case selects a STRUCTURE by EXACT parameter match at ELABORATION, and falls through to 'default' for any unmatched value. The override value "LOW_POWER" matches no case item, so the default variant is elaborated. Unlike a runtime case (where an unexpected selector might drive an output to a defined-but-wrong value you could observe), a generate-case mismatch is an elaboration-time decision: the wrong block is simply built, with no runtime signal to flag it. A permissive 'default' that silently accepts unknown configurations therefore hides typos and unsupported settings.

generate case selects STRUCTURE, not BEHAVIOUR — so getting the parameter wrong does not produce a runtime error; it produces the wrong hardware.

Fix
module mult #(parameter IMPL = "FAST") (input [7:0] a, b, output [15:0] p);
  generate
      case (IMPL)
          "FAST":  fast_mult     u (a, b, p);
          "SMALL": iterative_mult u (a, b, p);
          // No silent default: fail loudly on an unsupported configuration.
          default: $error("mult: unsupported IMPL=%s", IMPL);
      endcase
  endgenerate
endmodule

// Replace the permissive fallback with an elaboration-time assertion
// ($error / $fatal in the default) so an unrecognized IMPL stops the build
// instead of quietly selecting a variant. Now "LOW_POWER" (or any typo) is
// caught at elaboration, naming the offending value — the configuration bug
// surfaces immediately instead of shipping the wrong variant.

7. Interview Q&A

8. Exercises

Exercise 1 — Variant selection

Write a generate case that selects between a ripple_adder and a cla_adder instance based on an ADDER_TYPE parameter.

Exercise 2 — generate case vs runtime case

Why does generate case build only one variant while a runtime case builds all branches?

9. Summary

The generate case selects a structural variant by parameter:

  • Parameter-driven, elaboration-time — picks one variant; only it is built, the rest produce no hardware.
  • The multi-way generate if — for choosing among several implementations.
  • Use for implementation selection (fast/small) and platform/vendor variants in portable IP.

The last generate sub-topic combines techniques: Chapter 14.7.4 Generate Advanced Techniques covers nested generate, named scopes and hierarchy, and combining for/if/case.