Search code examples
chisel

Is the behavior of the chisel standard library shift register correct for the enable line


I am trying to create a data path that involves a shift register, but I want the whole thing to be able to be stalled while waiting on a new input. I saw there was a shift register in the standard library with an enable line (although defaulted to true).

The issue is that when I try to use it, the compiled verilog doesn't seem to actually stall the shift register when enable is low.

Consider this chisel code:

package SR

import Chisel._

class SR extends Module {
  val io = new Bundle { 
    val in = UInt(INPUT, 8)
    val enable = Bool(INPUT)
    val out = UInt(OUTPUT, 8)
  }
  io.out:= ShiftRegister(io.in, 10, io.enable)
}

class SRTests(c: SR) extends Tester(c) {
}

object SR {
  def main(args: Array[String]): Unit = {
    val tutArgs = args.slice(1, args.length)
    chiselMainTest(tutArgs, () => Module(new SR())) {
      c => new SRTests(c) }
  }
}

I get the following verilog:

module SR(input clk,
    input [7:0] io_in,
    input  io_enable,
    output[7:0] io_out
);

  reg [7:0] R0;
  reg [7:0] R1;
  reg [7:0] R2;
  reg [7:0] R3;
  reg [7:0] R4;
  reg [7:0] R5;
  reg [7:0] R6;
  reg [7:0] R7;
  reg [7:0] R8;
  reg [7:0] R9;
  wire[7:0] T10;

`ifndef SYNTHESIS
  integer initvar;
  initial begin
    #0.002;
    R0 = {1{$random}};
    R1 = {1{$random}};
    R2 = {1{$random}};
    R3 = {1{$random}};
    R4 = {1{$random}};
    R5 = {1{$random}};
    R6 = {1{$random}};
    R7 = {1{$random}};
    R8 = {1{$random}};
    R9 = {1{$random}};
  end
`endif

  assign io_out = R0;
  assign T10 = io_enable ? io_in : R9;

  always @(posedge clk) begin
    R0 <= R1;
    R1 <= R2;
    R2 <= R3;
    R3 <= R4;
    R4 <= R5;
    R5 <= R6;
    R6 <= R7;
    R7 <= R8;
    R8 <= R9;
    if(io_enable) begin
      R9 <= io_in;
    end
  end
endmodule

It seems like the shift register is only holding the first value fixed rather than the whole thing. For example, if you wrote in 1,2,3,4,5 on successive clock cycles but only held enable high for the for 1,2,3, 3 would correctly be held but 1 and 2 would eventually shift out and the whole shift register would fill with the value 3.

I would like behavior like the shift register example seen in the chisel tutorial. The issue is that I need long, parameterizable shift registers so hand writing each register is not an option. I would be extremely grateful to an example of chisel code that implements a shift register with enable behavior like is seen in the chisel tutorial but parameterizale to different lengths like is seen in standard library.


Solution

  • You can see the source code of the ShiftRegister in src/main/scala/ChiselUtil.scala in the Chisel repository:

    object ShiftRegister
    {
      def apply[T <: Data](in: T, n: Int, en: Bool = Bool(true)): T =
      {
        // The order of tests reflects the expected use cases.
        if (n == 1) {
          RegEnable(in, en)
        } else if (n != 0) {
          RegNext(apply(in, n-1, en))
        } else {
          in
        }
      }
    }
    

    That's creating a recursive chain of RegNexts, but with the base-case creating a RegEnable. Example:

    RegNext(RegNext(RegNext(RegEnable(in, en))))
    

    You can copy that code into your hello world, rename it something like object MyShiftRegister, and then modify that loop to suit your needs.

    I think what you are looking for is:

    } else if (n != 0) {
      RegEnable(apply(in, n-1, en), en)
    } ...
    

    As a general strategy, I suggest writing out what the code would look like "un-rolled" and then think about how to "package it up" into a succinct and parameterizable piece of Scala code.