when
statements are essentially just shorthand ways to help construct mux trees. For example:
class SimpleWhen extends Module {
val io = IO(new Bundle {
val cond = Input(Bool())
val a = Input(UInt(32.W))
val b = Input(UInt(32.W))
val z = Output(UInt(32.W))
})
when (io.cond) { io.z := io.a }
.otherwise { io.z := io.b }
}
If we generate Verilog from this we get (in Chisel 3):
module SimpleWhen(
input clock,
input reset,
input io_cond,
input [31:0] io_a,
input [31:0] io_b,
output [31:0] io_z
);
wire _T_11;
wire [31:0] _GEN_1;
assign io_z = _GEN_1;
assign _T_11 = io_cond == 1'h0;
assign _GEN_1 = _T_11 ? io_b : io_a;
endmodule
As one would expect, this module essentially just muxes between a
and b
based on the condition cond
.
For your more interesting use case of registers with enable:
class RegEnableTest extends Module {
val io = IO(new Bundle {
val en = Input(Bool())
val a = Input(Valid(UInt(32.W)))
val b = Input(Valid(UInt(32.W)))
val out = Output(UInt(32.W))
})
val regNext = Wire(UInt(32.W))
val myReg = Reg(UInt(32.W))
when (io.en) { myReg := regNext }
regNext := myReg
when (io.a.valid) { regNext := io.a.bits }
when (io.b.valid) { regNext := io.b.bits }
io.out := myReg
}
Here we have a register myReg
that is only updated when the input en
is high. The generated Verilog is:
module RegEnableTest(
input clock,
input reset,
input io_en,
input io_a_valid,
input [31:0] io_a_bits,
input io_b_valid,
input [31:0] io_b_bits,
output [31:0] io_out
);
wire [31:0] regNext;
reg [31:0] myReg;
reg [31:0] _GEN_1;
wire [31:0] _GEN_0;
wire [31:0] _GEN_2;
assign io_out = myReg;
assign regNext = _GEN_2;
assign _GEN_0 = io_en ? regNext : myReg;
assign _GEN_2 = io_b_valid ? io_b_bits : io_a_bits;
// ... Randomization removed for clarity ...
always @(posedge clock) begin
if (io_en) begin
myReg <= regNext;
end
end
endmodule
myReg is only updated when io.en
is high. This code can be made somewhat more concise by using RegEnable (https://chisel.eecs.berkeley.edu/api/index.html#chisel3.util.RegEnable$)