chisel
chisel copied to clipboard
Unexpected behaviour of connections for `Reg` defined within `when` context
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.
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.
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.
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 :=
.
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)