Skip to content
VLSI Mentor

Verilog · Chapter 14.5.3 · Behavioural Modeling

Multiway Advanced Techniques in Verilog — full_case, parallel_case & Priority vs Parallel

This lesson closes the branching section with the advanced patterns and the synthesis pragmas, along with the discipline of mostly avoiding them. The full-case pragma tells synthesis that a case statement covers every possible value, so it need not infer a latch for unlisted ones, and the parallel-case pragma tells it the branches are mutually exclusive, so it can build a parallel mux rather than a priority cascade. Both are dangerous, because they make promises to the synthesizer that the simulator does not honour, creating a mismatch when the promise is false and an unlisted value is actually hit or cases actually overlap. The modern discipline is to avoid the pragmas and instead write a real default and genuinely non-overlapping cases, so simulation and synthesis agree by construction. This page also covers the choice between priority and parallel structures and how to handle don't-care values.

Foundation13 min readVerilogfull_caseparallel_casePriorityParallelSynthesis Pragma

Chapter 14 · Section 14.5.3 · Behavioural Modeling

1. The Engineering Problem

Synthesis pragmas like full_case and parallel_case promise the synthesizer things about a case — but the simulator ignores them, so a false promise makes RTL simulation and hardware disagree:

full_case/parallel_case make promises to synthesis that the simulator does not honour — if the promise is false, sim and synth diverge. The discipline is to avoid the pragmas and instead write a real default and non-overlapping cases.

This page drills the pragmas, their dangers, the priority-vs-parallel choice, and the avoidance discipline.

2. Mental Model — Pragmas Promise Synthesis What the Simulator Ignores

3. The full_case Pragma

full_case tells synthesis all values are covered:

Azvya Education Pvt. Ltd.VLSI Mentor
full-case.v
   // RISKY — full_case promises completeness:
   always @(*)
       case (sel)  // synopsys full_case
           2'd0: y = a;
           2'd1: y = b;
           2'd2: y = c;
           // 2'd3 NOT listed; full_case says "treat as don't-care"
       endcase

   // BETTER — a real default:
   always @(*)
       case (sel)
           2'd0: y = a;
           2'd1: y = b;
           2'd2: y = c;
           default: y = 8'h00;     // explicit, sim and synth agree
       endcase

With full_case, synthesis treats 2'd3 as a don't-care (no latch), but simulation (which ignores the pragma) leaves y unassigned for 2'd3, holding the old value — a latch-like behaviour that differs from the synthesized hardware. A real default makes both agree.

4. The parallel_case Pragma

parallel_case tells synthesis cases are mutually exclusive:

Azvya Education Pvt. Ltd.VLSI Mentor
parallel-case.v
   // RISKY — parallel_case promises mutual exclusion:
   casez (req)  // synopsys parallel_case
       4'b1???: grant = 3;        // these patterns OVERLAP (1100 matches both)
       4'b?1??: grant = 2;
   endcase

If the patterns actually overlap (e.g. 4'b1100 matches both), simulation uses priority (first match wins) while parallel_case makes synthesis build a parallel structure that may pick differently — a mismatch. If you want priority, write overlapping casez patterns without the pragma (simulation and synthesis both treat it as priority). If you want parallel, write genuinely non-overlapping cases. The pragma is unnecessary and dangerous either way.

5. Priority vs Parallel — The Real Choice

The deliberate structural choice, without pragmas:

  • Priority (first match wins): use if/else if/else, or a case/casez with overlapping patterns. Synthesizes to a priority cascade. For prioritized decisions (interrupts, error handling).
  • Parallel (mutually exclusive): use a plain case with non-overlapping values. Synthesizes to a parallel mux/decoder. For value selection (opcodes, states).
Azvya Education Pvt. Ltd.VLSI Mentor
priority-vs-parallel.v
   // PARALLEL — non-overlapping case → parallel mux:
   case (op)  2'd0: y=a; 2'd1: y=b; 2'd2: y=c; default: y=d; endcase

   // PRIORITY — overlapping casez patterns → priority encoder:
   casez (req)
       4'b1???: g=3; 4'b01??: g=2; 4'b001?: g=1; default: g=0;
   endcase

The structure follows from how you write the cases — non-overlapping for parallel, overlapping (or if/else) for priority — so the code expresses the intent, and simulation and synthesis agree. No pragma needed.

Visual A — pragmas vs real code

Pragma promises vs honest code

data flow
Pragma promises vs honest codefull_case /parallel_casepromise to synthesisonlysim ignores →mismatch riskif promise is falsereal default +non-overlapsim and synth agree
full_case/parallel_case bias synthesis but are ignored by simulation, so a false promise causes a sim/synth mismatch. Writing a real default (for completeness) and genuinely non-overlapping cases (for parallelism) makes the intent explicit in the code, so simulation and synthesis agree by construction — the modern discipline.

6. Common Mistakes

  1. Using full_case/parallel_case — risk of sim/synth mismatch; use a real default and non-overlapping cases (§2-§4, DebugLab 1).
  2. Relying on a pragma instead of a default — the simulator still infers latch-like behaviour (§3).
  3. parallel_case on overlapping patterns — sim priority vs synth parallel disagree (§4).
  4. Not choosing priority vs parallel deliberately — let the case structure express intent (§5).

7. Debugging Lab

One advanced-branching debug post-mortem

Pitfall — full_case hides a sim/synth mismatch
Buggy Code
module sel (input [1:0] s, [7:0] a, b, c, output reg [7:0] y);
  // full_case promises all values covered — but s=2'd3 is not listed.
  always @(*)
      case (s)  // synopsys full_case
          2'd0: y = a;
          2'd1: y = b;
          2'd2: y = c;
      endcase
endmodule

// Synthesis treats s=2'd3 as a don't-care (no latch, optimized). Simulation
// IGNORES the pragma, so for s=2'd3 y is unassigned and holds its old value
// (latch-like). RTL sim and synthesized hardware behave differently for
// s=2'd3 — a hidden sim/synth mismatch.
Symptom

A design behaves correctly in synthesis but a gate-level / RTL comparison shows divergence for the unlisted select value (s=2'd3): RTL simulation holds a stale value while the synthesized logic produces an optimized (don't-care-based) result. The mismatch only appears for the uncovered input.

Root Cause

The full_case pragma tells SYNTHESIS that all case values are covered, so it treats the unlisted s=2'd3 as a don't-care and does not infer a latch. But the SIMULATOR ignores the pragma and follows standard semantics: for s=2'd3 no branch assigns y, so y holds its previous value (latch-like). The two disagree — a sim/synth mismatch caused by a pragma promise the simulator does not honour.

The fix is to remove the pragma and write a real default, which makes simulation and synthesis agree (both assign y for the uncovered value).

Fix
module sel (input [1:0] s, [7:0] a, b, c, output reg [7:0] y);
  always @(*)
      case (s)
          2'd0: y = a;
          2'd1: y = b;
          2'd2: y = c;
          default: y = 8'h00;    // real default — sim and synth agree
      endcase
endmodule

// A real default achieves completeness without a pragma, and there is no
// sim/synth mismatch. Avoid full_case/parallel_case.

8. Interview Q&A

9. Exercises

Exercise 1 — Replace the pragma

Rewrite a case that uses // synopsys full_case to be complete without the pragma.

Exercise 2 — Priority or parallel?

For (a) a 4:1 mux on a 2-bit select and (b) a priority interrupt decoder, state whether you want a priority or parallel structure and how to write it without a pragma.

Exercise 3 — Spot the mismatch

Explain how // synopsys parallel_case on a casez with overlapping patterns causes a sim/synth mismatch.

10. Summary

Advanced branching is mostly about avoiding the synthesis pragmas:

  • full_case/parallel_case promise completeness/mutual-exclusion to synthesis, but the simulator ignores them — a false promise causes a sim/synth mismatch.
  • The discipline — avoid the pragmas; write a real default (completeness) and non-overlapping cases (parallelism), so sim and synth agree.
  • Priority vs parallel is a deliberate choice expressed by the code: if/else or overlapping case/casez for priority; non-overlapping case for parallel.

Multiway branching complete

This closes Chapter 14.5 Multiway Branching — if/else (priority, 14.5.1), case/casez/casex (parallel, 14.5.2), and the advanced pragmas and priority/parallel choice (14.5.3) — unified by the latch-avoidance discipline: assign every output on every path in combinational blocks.

The chapter now turns to iteration: Chapter 14.6 Loops drills for, while, repeat, and forever — the looping constructs of behavioural code.

Standards & specifications

Governing standard
IEEE Std 1364 (Verilog)(opens IEEE in a new tab)

Defines the Verilog language and its simulation semantics, including the event scheduling model. Synthesis support is defined by tools, not by this standard.

This page also covers RTL structure, verification approach and debugging technique. Those are engineering practice built on the standard, not requirements the standard itself imposes.

Where this fits

Part of the Verilog HDL curriculum.