scalachisel

How to use this built-in shiftRegister from Chisel3.util properly?


I tried to compare this built-in shiftRegister with some common shift registers in the chisel-tutorial. But this one seems not actually shifting the bits? https://github.com/freechipsproject/chisel3/blob/9f620e06bacc2882068adfd4972ec2e9a87ea723/src/main/scala/chisel3/util/Reg.scala#L33

class MyShiftRegister_chisel[T <: Data](val init: Int = 1) extends Module {
  val io = IO(new Bundle {
    val in  = Input(Bool())
    val out = Output(UInt(4.W))
  })

  val state = ShiftRegister(io.in, 1, true.B)
//     val next_state = RegNext(UInt(4.W), state)
//      val nextState = Cat(state(2,0), io.in)
//   state := nextState
  io.out := state
}
println(getVerilog(new MyShiftRegister_chisel()))

And I got the following verilog:

[info] [0.000] Elaborating design...
[info] [0.070] Done elaborating.
Total FIRRTL Compile Time: 28.7 ms
module MyShiftRegister_chisel(
  input        clock,
  input        reset,
  input        io_in,
  output [3:0] io_out
);
  reg  state; // @[Reg.scala 15:16]
  reg [31:0] _RAND_0;
  assign io_out = {{3'd0}, state}; // @[cmd94.sc 11:10]
`ifdef RANDOMIZE_GARBAGE_ASSIGN
`define RANDOMIZE
`endif
`ifdef RANDOMIZE_INVALID_ASSIGN
`define RANDOMIZE
`endif
`ifdef RANDOMIZE_REG_INIT
`define RANDOMIZE
`endif
`ifdef RANDOMIZE_MEM_INIT
`define RANDOMIZE
`endif
`ifndef RANDOM
`define RANDOM $random
`endif
`ifdef RANDOMIZE_MEM_INIT
  integer initvar;
`endif
initial begin
  `ifdef RANDOMIZE
    `ifdef INIT_RANDOM
      `INIT_RANDOM
    `endif
    `ifndef VERILATOR
      `ifdef RANDOMIZE_DELAY
        #`RANDOMIZE_DELAY begin end
      `else
        #0.002 begin end
      `endif
    `endif
  `ifdef RANDOMIZE_REG_INIT
  _RAND_0 = {1{`RANDOM}};
  state = _RAND_0[0:0];
  `endif // RANDOMIZE_REG_INIT
  `endif // RANDOMIZE
end
  always @(posedge clock) begin
    state <= io_in;
  end
endmodule

So my question is, how to properly use this built-in ShiftRegister from Chisel3.util?


Solution

  • From your link with the ScalaDoc comment:

      /** Returns the n-cycle delayed version of the input signal.
        *
        * @param in input to delay
        * @param n number of cycles to delay
        * @param en enable the shift
        *
        * @example {{{
        * val regDelayTwo = ShiftRegister(nextVal, 2, ena)
        * }}}
        */
      def apply[T <: Data](in: T, n: Int, en: Bool = true.B): T = { ...
    

    The ShiftRegister delays the input data in, n cycles. It is generic as to the type being shifted in and out. I suspect you're referring to the stereotypical shift register which shifts in and out 1 bit of data per-cycle. You can easily do that with this construct by making the input type Bool:

    class Foo extends Module {
      val io = IO(new Bundle {
        val in = Input(Bool())
        val out = Output(Bool())
      })
    
      io.out := ShiftRegister(io.in, 4)
    }
    

    Gives

    module Foo(
      input   clock,
      input   reset,
      input   io_in,
      output  io_out
    );
      reg  _T; // @[Reg.scala 15:16]
      reg [31:0] _RAND_0;
      reg  _T_1; // @[Reg.scala 15:16]
      reg [31:0] _RAND_1;
      reg  _T_2; // @[Reg.scala 15:16]
      reg [31:0] _RAND_2;
      reg  _T_3; // @[Reg.scala 15:16]
      reg [31:0] _RAND_3;
      assign io_out = _T_3; // @[main.scala 13:10]
    // ...
      always @(posedge clock) begin
        _T <= io_in;
        _T_1 <= _T;
        _T_2 <= _T_1;
        _T_3 <= _T_2;
      end
    endmodule
    

    Note that the construct hides the underlying flops from you, it returns the output of the final flop which is the "shifted out value" each cycle.