Search code examples
verilogbitchisel

How to duplicate a single bit to a UInt in Chisel 3?


I'm looking for a Chisel way to do the following job:

wire [3:0] word;
wire bit;

assign word = {4{bit}};

I'm currently doing it like this:

val word = Wire(UInt(4.W))
val bit = Wire(Bool())

word := Cat(bit, bit, bit, bit)

However, this solution isn't very tidy when I need a bigger number:

val bigWord = Wire(UInt(32.W))

bigWord := Cat(bit, bit, bit, bit, bit, bit, bit, bit, bit, bit, bit, bit, bit, bit, bit, bit, bit, bit, bit, bit, bit, bit, bit, bit, bit, bit, bit, bit, bit, bit, bit, bit)
io.out := summon_cthulhu()

Is there a better way to do this? Like Verilog assign bigWord = {32{bit}}?


Solution

  • Qiu's comment is right. Using chisel3.util.Fill is the right way to go.

    To concretize this, the following Chisel:

    import chisel3._
    import chisel3.experimental.MultiIOModule
    import chisel3.util.Fill
    
    class FooModule(n: Int = 32) extends MultiIOModule {
      val a: UInt = IO(Input(Bool()))
      val b: UInt = IO(Output(UInt(n.W)))
      b := Fill(n, a)
    }
    

    Produces the following Verilog:

    module FooModule(
      input         clock,
      input         reset,
      input         a,
      output [31:0] b
    );
      assign b = a ? 32'hffffffff : 32'h0;
    endmodule
    

    Note that Fill will use a mux in the special case of filling by something with a width of one. Otherwise, this will do explicit concatenations in a tree.

    As an aside, if you choose to do the concatenations explicitly, FIRRTL actually has a dedicated transform called CombineCats that will try to clean this up for you. In the following, alternative example n - 1 temporaries are created where each bit is explicitly concatenated:

    class BarModule(n: Int = 32) extends MultiIOModule {
      val a: UInt = IO(Input(Bool()))
      val b: UInt = IO(Output(UInt(n.W)))
      b := Seq.fill(n)(a.asUInt).reduce(_ ## _)
    }
    

    You'll get the following Verilog:

    module BarModule(
      input         clock,
      input         reset,
      input         a,
      output [31:0] b
    );
      wire [9:0] _T_8;
      wire [18:0] _T_17;
      wire [27:0] _T_26;
      wire [30:0] _T_29;
      assign _T_8 = {a,a,a,a,a,a,a,a,a,a};
      assign _T_17 = {_T_8,a,a,a,a,a,a,a,a,a};
      assign _T_26 = {_T_17,a,a,a,a,a,a,a,a,a};
      assign _T_29 = {_T_26,a,a,a};
      assign b = {_T_29,a};
    endmodule
    

    You will not, however, get the benefits of concatenation in a tree structure. If you were instead to use a UInt(32.W) as the input, the latter would be much less efficient.