Skip to content

[ImportVerilog] Fixup case statements that look exhaustive but are not #8626

@fabianschuiki

Description

@fabianschuiki

I've seen quite a bit of code like the following out in the wild:

module Foo (
  input  logic [1:0] a,
  output logic [3:0] z
);
  always_comb begin
    case (a)
      2'd0: z = 4'b0001;
      2'd1: z = 4'b0010;
      2'd2: z = 4'b0100;
      2'd3: z = 4'b1000;
    endcase
  end
endmodule

The intention clearly is to list all distinct values the input a can assume, and provide a unique output assignment for each. This case statement looks exhaustive, and it also is exhaustive in 2-state logic. But in SystemVerilog's 4-state logic type, this case-statement is non-exhaustive. If the input a contains an X or Z bit, none of the case items match and z remains unassigned, essentially modelling a latch.

Synthesis tools will often work around this by mapping the 4-state logic to 2-state logic, which makes case statements like this exhaustive. We need a similar workaround in CIRCT. For now, since the core dialects don't support 4-state logic, we can just assume that case statements that are exhaustive in 2-state logic need no else/default branch when we lower to IR.

The above produces the following IR:

hw.module @Foo(in %a : i2, out z : i4) {
  %c0_i3 = hw.constant 0 : i3
  %true = hw.constant true
  %0 = llhd.constant_time <0ns, 0d, 1e>
  %c0_i4 = hw.constant 0 : i4
  %c-1_i2 = hw.constant -1 : i2
  %c4_i4 = hw.constant 4 : i4
  %c-2_i2 = hw.constant -2 : i2
  %c2_i4 = hw.constant 2 : i4
  %c1_i2 = hw.constant 1 : i2
  %c1_i4 = hw.constant 1 : i4
  %c0_i2 = hw.constant 0 : i2
  %z = llhd.sig %c0_i4 : i4
  %1 = llhd.prb %z : !hw.inout<i4>
  %2 = comb.icmp ceq %a, %c0_i2 : i2
  %3 = comb.icmp ceq %a, %c1_i2 : i2
  %4 = comb.icmp ceq %a, %c-2_i2 : i2
  %5 = comb.icmp ceq %a, %c-1_i2 : i2
  %6 = comb.concat %5, %c0_i3 : i1, i3
  %7 = comb.xor %2, %true : i1
  %8 = comb.xor %3, %true : i1
  %9 = comb.and %8, %7, %4 : i1
  %10 = comb.mux %9, %c4_i4, %6 : i4
  %11 = comb.and %7, %3 : i1
  %12 = comb.mux %11, %c2_i4, %10 : i4
  %13 = comb.mux %2, %c1_i4, %12 : i4
  %14 = comb.or %2, %11, %9, %5 : i1
  llhd.drv %z, %13 after %0 if %14 : !hw.inout<i4>
  hw.output %1 : i4
}

The problematic part is the if %14 on the llhd.drv: if none of the four case items match, the drive does not take effect. This needs to be fixed.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions