Search code examples
chisel

when-otherwise Statement vs. Mux Statement


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?


Solution

  • 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.