Verilog Conditional Statements

Conditional statements control the flow of execution in procedural blocks. Understanding them properly is key to avoiding latches in synthesis.

if-else Statement

if-else Syntax
module priority_encoder (
    input  wire [3:0] req,
    output reg  [1:0] grant
);
    always @(*) begin
        if (req[3])
            grant = 2'd3;
        else if (req[2])
            grant = 2'd2;
        else if (req[1])
            grant = 2'd1;
        else if (req[0])
            grant = 2'd0;
        else
            grant = 2'd0;  // Default - CRITICAL!
    end
endmodule

Always Include else!

In combinational logic, missing else clause causes latch inference. Always assign a default value.

case Statement

case provides clean multi-way branching:

case Statement Example
module alu (
    input  wire [7:0]  a, b,
    input  wire [2:0]  op,
    output reg  [7:0]  result
);
    always @(*) begin
        case (op)
            3'b000: result = a + b;     // ADD
            3'b001: result = a - b;     // SUB
            3'b010: result = a & b;     // AND
            3'b011: result = a | b;     // OR
            3'b100: result = a ^ b;     // XOR
            3'b101: result = ~a;        // NOT
            3'b110: result = a << 1;    // SHL
            3'b111: result = a >> 1;    // SHR
            default: result = 8'd0;     // Default case
        endcase
    end
endmodule

casex and casez

These variants allow don't-care matching:

Statement Treats as don't-care Use Case
case Nothing Exact matching
casez z and ? Priority encoder, address decode
casex x, z, ? Avoid - X matching is dangerous
casez for Priority Encoding
module priority_enc_casez (
    input  wire [7:0] req,
    output reg  [2:0] grant
);
    always @(*) begin
        casez (req)
            8'b1???????: grant = 3'd7;
            8'b01??????: grant = 3'd6;
            8'b001?????: grant = 3'd5;
            8'b0001????: grant = 3'd4;
            8'b00001???: grant = 3'd3;
            8'b000001??: grant = 3'd2;
            8'b0000001?: grant = 3'd1;
            8'b00000001: grant = 3'd0;
            default:     grant = 3'd0;
        endcase
    end
endmodule

Prefer casez over casex

casex treats X as don't-care, which can mask bugs in simulation. Use casez instead.

Latch Inference Problem

Latches are inferred when outputs aren't assigned in all branches:

Latch Inference Example
// BAD: Creates a latch!
always @(*) begin
    if (enable)
        result = data;
    // Missing else: result holds old value = LATCH!
end
// GOOD: No latch
always @(*) begin
    if (enable)
        result = data;
    else
        result = 8'd0;  // Always assign!
end
// ALSO GOOD: Default at start
always @(*) begin
    result = 8'd0;  // Default
    if (enable)
        result = data;
end

Common Interview Questions

  1. What causes latch inference?

    Not assigning outputs in all branches of combinational always blocks (missing else or case default).

  2. What is the difference between casez and casex?

    casez treats only Z/? as don't-care; casex also treats X as don't-care, which can mask simulation bugs.

  3. Is if-else or case better?

    if-else implies priority (first match wins); case implies parallel evaluation. Use case for mux-like structures.