-
Notifications
You must be signed in to change notification settings - Fork 368
Description
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.