Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Chisel3: Verilog "default" case equivalent

Tags:

chisel

Is it possible to have a Chisel "is" condition which behaves similar to a Verilog "default" case in a Chisel "switch" statement? This is required to prevent latches being inferred for combinatorial outputs from an FSM.

Verilog Example:

module detector (clk, rstn, in1, in2, out1, out2);
input clk, rstn, in1, in2;
output reg out1, out2;

localparam [1:0] IDLE    = 2'b01;
localparam [1:0] GOT_IN1 = 2'b10;

reg [1:0] state, nxtState;

always @ (posedge clk or negedge rstn) begin
    if (!rstn) begin
         state <= IDLE;
    end else begin
         state <= nxtState;
    end
end

always @ (*) begin
        case (state)
            IDLE: begin
                if (in1) begin
                    out1     = 1'b1;
                    out2     = 1'b0;
                    nxtState = GOT_IN1;
                end else begin
                    out1     = 1'b0;
                    out2     = 1'b0;
                    nxtState = IDLE;
                end
            end            
            GOT_IN1: begin
                if (in2) begin
                    out1     = 1'b0;
                    out2     = 1'b1;
                    nxtState = IDLE;
                end else begin
                    out1     = 1'b0;
                    out2     = 1'b0;
                    nxtState = GOT_IN1;
                end
            end
            default: begin
                out1     = 1'b0;
                out2     = 1'b0;
                nxtState = IDLE;
            end
        endcase
end

endmodule

Chisel2 allowed this type of behavior as a default value could be assigned to out1 and out2 in the switch statement outside of an "is" condition.

switch (state) {
    io.out1 := UInt(0)
    io.out2 := UInt(0)
    is (IDLE) {
        when (io.in1 === UInt(1)) {
            io.out1 := UInt(1)
            io.out2 := UInt(0)
            state   := GOT_IN1
        } .otherwise {
            io.out1 := UInt(0)
            io.out2 := UInt(0)
            state   := IDLE
        }
    }
    is (GOT_IN1) {
        when (io.in2 === UInt(1)) {
            io.out1 := UInt(0)
            io.out2 := UInt(1)
            state   := IDLE
        } .otherwise {
            io.out1 := UInt(0)
            io.out2 := UInt(0)
            state   := GOT_IN1
        }
    }
}

Chisel3 doesn't support this default assignment syntax like Chisel2. A build error gets flagged:

◾exception during macro expansion: java.lang.Exception: Cannot include blocks that do not begin with is() in switch. at chisel3.util.switch

Chisel3 doesn't appear to have any method to prevent a latch from being inferred on the out1 and out2 outputs. I understand that out1 and out2 assignments can be moved outside of the switch statement and handled using a conditional assignment. However, from a code visibility standpoint it's clearer to handle the assignments within the case statement for large FSMs with dozens of states and combinatorial outputs.

like image 887
plenn08 Avatar asked Mar 04 '26 07:03

plenn08


1 Answers

You can add bracket deliberately to identify some code should be read together. Something like:

{ // state machine block
    io.out1 := UInt(0)
    io.out2 := UInt(0)
    when (state === IDLE) {
        when (io.in1 === UInt(1)) {
            io.out1 := UInt(1)
            io.out2 := UInt(0)
            state   := GOT_IN1
        } .otherwise {
            io.out1 := UInt(0)
            io.out2 := UInt(0)
            state   := IDLE
        }
    }
    when (state === GOT_IN1) {
        when (io.in2 === UInt(1)) {
            io.out1 := UInt(0)
            io.out2 := UInt(1)
            state   := IDLE
        } .otherwise {
            io.out1 := UInt(0)
            io.out2 := UInt(0)
            state   := GOT_IN1
        }
    }
}

I believe Chisel will never generate latches. The first assignment takes effect if no later assignment change is enabled.

like image 190
Wei Song Avatar answered Mar 07 '26 00:03

Wei Song