chisel icon indicating copy to clipboard operation
chisel copied to clipboard

Unexpected behaviour of connections for `Reg` defined within `when` context

Open johnsbrew opened this issue 4 years ago • 4 comments

Type of issue: bug report Impact: unknown Development Phase: request Other information: see example below

If the current behavior is a bug, please provide the steps to reproduce the problem: Simple code example of a Reg defined and connected within a when context:

@chiselName
class BadWhenContext() extends MultiIOModule {
  val en = IO(Input(Bool()))
  val in = IO(Input(UInt(3.W)))
  val out = IO(Output(UInt(3.W)))
  
  val rin = Reg(chiselTypeOf(in))
  val rout = Reg(chiselTypeOf(in))
  
  
  when(en){
    i := in
    val inner1 = Reg(chiselTypeOf(i))
    inner1 := i + 1.U
    rout := inner1
  }
  out := rout
}

What is the current behavior? when context is ignored for embedded Reg connections as shown below (trimmed verilog):

reg [2:0] rin;
reg [2:0] rout;
reg [2:0] inner1;
assign out = rout;
always @(posedge clock) begin
  if (en) begin
    rin <= in;
  end
  if (en) begin
    rout <= inner1;
  end
  inner1 <= rin + 3'h1; // expecting this statement to also be surrounded with its own if(en) block
end

What is the expected behavior? when context applied to connections of embedded Reg, such as below (trimmed verilog):

reg [2:0] rin;
reg [2:0] rout;
reg [2:0] inner1;
assign out = rout;
always @(posedge clock) begin
  if (en) begin
    rin <= in;
  end
  if (en) begin
    rout <= inner1;
  end
  if (en) begin
    inner1 <= rin + 3'h1;
  end
end

Please tell us about your environment: - version: 3.4-20200728-SNAPSHOT - OS: Darwin 17.7.0 Darwin Kernel Version 17.7.0: Mon Aug 31 22:11:23 PDT 2020;

What is the use case for changing the behavior? Consistency: why isn't the when context applied to registers defined within himself?

Note: the actual use case is to be able to surround with a when context a function declaring and using Reg within its body.

johnsbrew avatar Nov 12 '20 12:11 johnsbrew

You may already have resolved this issue, but, just in case, as a reference, chipsalliance/firrtl#1862.

In summary, this is a expected behavior as firrtl spec (details at 5.10.2). I don't know whether this spec is appropriate or not though.

Soya-Onishi avatar Feb 03 '21 01:02 Soya-Onishi

Hi @Soya-Onishi

Sorry for this late answer, I missed the notification...!

I am quite sorry to read a definite answer about this, @jackkoenig to answer your comment:

what does it mean for the declaration of a register to be conditional?

it simply means that the condition (whenContext) of this register declaration is a pre-requisite to all affectation to this register.

Intended usage is quite simple : gate a whole block (typically a function) with a when(ready){ ... } If the block contains Reg declaration then the synchronization of other elements wouldn't be lost.

@Soya-Onishi to circumvent this limitation, in practice we use a custom transform to do exactly what I described above : all affectations to registers declared at a given whenContext are gated with this whenContext, simply &&-ed with existing conditions if any.

johnsbrew avatar Apr 29 '21 14:04 johnsbrew

I ran into this issue, and I am surprised that it is actually intended behavior since it is not intuitive. What worked for me is to create a method with the following general form:

def :@=(that: => Data): Unit = when(when.cond){data.:=(that)}

Now whenever I need an update to a locally defined Reg to respect all current when's, I use :@= instead of :=.

dbear496 avatar Mar 22 '22 01:03 dbear496

Nice hack @dbear496 It's a great use of when.cond which has been introduced by https://github.com/chipsalliance/chisel3/commit/cdb7bb27bd675a8a114701b97a45c56e26ef42b5 in January 2021 (a few months after I ran into this issue)

johnsbrew avatar Mar 24 '22 17:03 johnsbrew