I was wondering whether there are any fundamental differences between using the Mux statement vs. using the when-otherwise statement?
For example:
when(read){
dataReg := inValue
}.otherwise{
dataReg := 0.U
}
Or
dataReg := Mux (read, inValue, 0.U)
Should there be any preferences for one of them?
You can think about when-otherwise
as a higher-level construct that is lowered to one or more Muxes
. Mux
is useful for simple cases (especially when you'd like the code to fit on 1 line), but there are a lot of things that are more convenient to express with when-otherwise
.
For example, when-otherwise
can be used to express bidirectional connections in a convenient way that Mux
does not allow.
val producer_1 = IO(Flipped(Decoupled(UInt(8.W))))
val producer_2 = IO(Flipped(Decoupled(UInt(8.W))))
val select = IO(Input(Bool()))
val consumer = IO(Decoupled(UInt(8.W)))
when(select) {
consumer <> producer_1
producer_2.ready := false.B
} .otherwise {
consumer <> producer_2
producer_1.ready := false.B
}
This generates:
assign producer_1_ready = select & consumer_ready;
assign producer_2_ready = select ? 1'h0 : consumer_ready;
assign consumer_valid = select ? producer_1_valid : producer_2_valid;
assign consumer_bits = select ? producer_1_bits : producer_2_bits;
(Executable example link: https://scastie.scala-lang.org/GVH1zA2MTQ2fhm4yENijbg)
In addition, when-otherwise
can be used for connections to multiple things at the same time:
val a = IO(Input(Bool()))
val b = IO(Input(Bool()))
val foo = IO(Input(UInt(8.W)))
val bar = IO(Input(UInt(8.W)))
val out = IO(Output(UInt(8.W)))
val reg1 = RegInit(0.U(8.W))
val reg2 = RegInit(0.U(8.W))
out := reg1
when (a) {
reg1 := foo
} .elsewhen (b) {
reg1 := bar
reg2 := foo
} .otherwise {
out := reg2
}
(Executable example link: https://scastie.scala-lang.org/q9WNZVDoSpufRCyBeukCEg)
Note that there are connections to reg1
, reg2
, and out
on the different paths, and none even show up in every single path.