Skip to content
DenseChip
Learn
PracticeCode labInterview

DenseChip

Navigate

Menu

LearnPracticeCode labInterview

Tools

All toolsSV editorCode repoResume
DenseChip

Practice, courses, and chip-design tools in one focused workspace.

LearnPracticeCode labInterviewToolsLearning paths

© 2026 DenseChip

AboutContactPrivacyTerms
Skip to lesson

Course contents

  • Start Here6
  • SystemVerilog Language Foundations35
    • SystemVerilog Data Types
    • Arrays: Packed, Dynamic, Queues & Associative
    • Procedural Code & Scheduling
    • Operators, Expressions & Width Rules
      • Signed & Unsigned Arithmetic
      • Equality, Case Equality & Wildcards
      • unique, unique0 & priority
      • Shifts, Concatenation & Streaming
      • Expression Width & Evaluation Rules
    • Packages, Typedefs & Compilation
    • Interfaces, Modports & Clocking Blocks
  • Object-Oriented SystemVerilog for Verification35
  • Constraint Randomization — Interview-Critical Deep Dive66
  • SystemVerilog Assertions — Interview-Critical Deep Dive63
  • Functional Coverage in SystemVerilog28
  • Testbench Architecture in SystemVerilog38
  • Advanced Language & Integration30
  • Senior & Interview Preparation34
  • Principal-Level Verification28
Loading lesson

‹Operators, Expressions & Width Rules
  1. Topics
  2. SystemVerilog
  3. SystemVerilog Language Foundations
  4. Operators, Expressions & Width Rules
  5. Equality, Case Equality & Wildcards

Part 1 · Language Foundations · Intermediate

Equality, Case Equality & Wildcards

== vs === vs ==?, casez vs casex dangers with X, case inside, and which to use in RTL versus testbench.

On this page

    Why this matters

    A check said if (got == exp) and passed while got was partly X. The comparison returned X, if treated it as false, and the else branch happened to print nothing alarming.

    After this lesson you can: choose between ==, === and ==? for a job, say what each returns with X present, and replace casex with case inside.

    Three equalities

    Four-state values force three comparisons. Logical == yields 0 if any known bits differ, and X when the known bits match but an X or Z bit leaves the answer open. An if treats that X as false.

    Case === matches X literally and always returns 0 or 1. Wildcard ==? treats X and Z in the right operand as don't-cares.

    Predict first a is 4'b1010 and b is 4'b10x0. What do a == b, a === b and a ==? b return?

    X, 0 and 1. == cannot decide because bit 1 of b is unknown; === sees that the bits differ literally; ==? treats the X in b as a don't-care, and the known bits match.

    a

    b

    a == b

    a === b

    a ==? b

    4'b1010

    4'b1010

    1

    1

    1

    4'b1010

    4'b10X0

    X (false)

    0

    1 (X in b is don't-care)

    4'b10X0

    4'b1010

    X (false)

    0

    X (false: X in a is not a wildcard)

    4'b10X0

    4'b10X0

    X (false)

    1

    1

    • `==` belongs in RTL. It synthesizes, but X results read as false in conditions.

    • `===` belongs in testbench X checks. It never synthesizes.

    • `==?` belongs in masked compares. Only the right operand wildcards.

    The asymmetry is deliberate. An X in the left operand at a compared position gives X, which an if treats as false, so masked checks of possibly corrupt outputs still fail.

    Case variants and case inside

    casez treats ? as don't-care in items and selector. casex also wildcards X, so an unknown selector takes the first overlapping branch.

    That first match on garbage hides uninitialized registers and bus contention. Most style guides ban casex outright.

    case inside uses ==? semantics with deliberate wildcards plus ranges. An X selector falls through to default, which makes it the replacement for both.

    The two decoders below give the same grants, one with casez wildcards and one with case inside ranges. Their items are disjoint; when items overlap, the first match wins, so keep intentional overlap under priority.

    grant_decode.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    module grant_decode (
      input  logic [3:0] req,
      output logic [3:0] grant
    );
      always_comb begin
        grant = 4'b0000;
        casez (req)
          4'b1???: grant = 4'b1000;
          4'b01??: grant = 4'b0100;
          4'b001?: grant = 4'b0010;
          4'b0001: grant = 4'b0001;
          default: grant = 4'b0000;
        endcase
      end
    endmodule
    
    module inside_decode (
      input  logic [3:0] req,
      output logic [3:0] grant
    );
      always_comb begin
        grant = 4'b0000;
        case (req) inside
          [4'b1000 : 4'b1111]: grant = 4'b1000;
          [4'b0100 : 4'b0111]: grant = 4'b0100;
          [4'b0010 : 4'b0011]: grant = 4'b0010;
          4'b0001: grant = 4'b0001;
          default: grant = 4'b0000;
        endcase
      end
    endmodule
    
    module tb_case_inside;
      logic [3:0] req, gz, gi;
      int errors = 0;
      grant_decode  dz (.req(req), .grant(gz));
      inside_decode di (.req(req), .grant(gi));
      initial begin
        for (int k = 0; k < 16; k++) begin
          req = k[3:0]; #1;
          if (gz !== gi) errors++;                     // both decoders agree on every value
        end
        req = 4'b0110; #1;
        if (gi !== 4'b0100) errors++;
        if (errors == 0) $display("PASS: casez and case inside gave the same grant for all 16 requests");
        else $fatal(1, "FAIL: %0d requests decoded differently", errors);
        $finish;
      end
    endmodule
    Terminal
    PASS: casez and case inside gave the same grant for all 16 requests

    Common mistakes

    Common pitfall

    Using casex in RTL lets an X selector silently match the first wildcard item and hide real bugs. Prefer case inside, keep === and ==? in testbenches, and never rely on == to detect X.

    Interview

    Likely questions: the difference between == and ===, why casex is dangerous, and what replaces it in new code.

    • `==` vs `===` is X handling: X result versus literal 4-state match, and === is testbench-only.

    • `casex` matches X in the selector and hides unknowns; casez only wildcards ?.

    • `case inside` is the replacement: deliberate wildcards, ranges, X-safe selector.

    Check yourself got holds 4'b10X0. Does (got == 4'b1010) enter the if branch?

    No. The X makes the result X, and if treats X as false. Use === in the testbench to name the unknown.

    Check yourself req reads 4'bXXXX under the casez decoder above. Which grant results?

    4'b0000 through default. casez wildcards only ? and Z, so no item matches. A casex would wrongly take the first branch.

    Testbench

    The equality table row by row, casez and casex facing an unknown selector, and a masked compare. X needs a 4-state simulator, so this bench runs on Icarus.

    design.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    module tb_equality;
      logic [3:0] a, b, sel, g;
      logic [31:0] got;
      int errors = 0;
    
      task automatic row(input logic [3:0] x, input logic [3:0] y,
                         input logic e_eq, input logic e_case, input logic e_wild);
        a = x; b = y;
        $display("a=%b b=%b   a==b: %b   a===b: %b   a==?b: %b", a, b, a == b, a === b, a ==? b);
        if ((a == b) !== e_eq || (a === b) !== e_case || (a ==? b) !== e_wild) errors++;
      endtask
    
      initial begin
        row(4'b1010, 4'b1010, 1'b1, 1'b1, 1'b1);
        row(4'b1010, 4'b10x0, 1'bx, 1'b0, 1'b1);   // X in b is a wildcard for ==?
        row(4'b10x0, 4'b1010, 1'bx, 1'b0, 1'bx);   // X in a is not
        row(4'b10x0, 4'b10x0, 1'bx, 1'b1, 1'b1);
    
        a = 4'b10x0;
        if (a == 4'b1010) errors++;                // X result: if takes the else branch
    
        sel = 4'bxxxx;                             // an unknown selector
        casez (sel)
          4'b1???: g = 4'b1000;
          default: g = 4'b0000;
        endcase
        if (g !== 4'b0000) errors++;               // casez: X matches no item
        casex (sel)
          4'b1???: g = 4'b1000;
          default: g = 4'b0000;
        endcase
        if (g !== 4'b1000) errors++;               // casex: X matches the first item
        $display("casez on X picks default; casex on X picks the first item");
    
        got = 32'hDEAD_BE42;
        if (!(got ==? 32'hDEAD_BExx)) errors++;    // low byte masked: match
        if (got ==? 32'hDEAD_BFxx) errors++;       // a known bit differs: no match
    
        if (errors == 0) $display("PASS: the equality table, casez and casex on X, and the masked compare all behaved as shown");
        else $fatal(1, "FAIL: %0d equality checks disagreed", errors);
        $finish;
      end
    endmodule
    Terminal
    a=1010 b=1010   a==b: 1   a===b: 1   a==?b: 1
    a=1010 b=10x0   a==b: x   a===b: 0   a==?b: 1
    a=10x0 b=1010   a==b: x   a===b: 0   a==?b: x
    a=10x0 b=10x0   a==b: x   a===b: 1   a==?b: 1
    casez on X picks default; casex on X picks the first item
    PASS: the equality table, casez and casex on X, and the masked compare all behaved as shown

    Remember

    • == returns X when an unknown bit leaves the answer open; if treats X as false.

    • === compares X and Z literally and returns only 0 or 1.

    • ==? and case inside use X in the right operand as a wildcard, never in the left.

    Rule of thumb: == in RTL, === to look for X in tests, case inside instead of casex.

    How this was checked

    Run on 2026-10-18 with no warnings: the equality bench on Icarus 13 (-g2012), because X needs a 4-state simulator, and the decoder bench on Verilator 5.048 (--binary --timing), because Icarus 13 has no case inside. Each printed the PASS line shown.

    Related topics

    • Next: unique, unique0 & priority

    Previous

    26 / 363

    Next: unique, unique0 & priority

    Up next

    Up nextunique, unique0 & priority

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • Shifts, Concatenation & Streaming
    • Expression Width & Evaluation Rules