always block triggered multiple times #1160
Replies: 15 comments 2 replies
-
How is your clock generated? Any chance there are any glitches on the clock signal? |
Beta Was this translation helpful? Give feedback.
-
Clock is clean. That was my first thought.
Terry Little
Principal Digital Design Engineer
…On Sat, Aug 24, 2024 at 10:29 PM Lars-Peter Clausen < ***@***.***> wrote:
How is your clock generated? Any chance there are any glitches on the
clock signal?
—
Reply to this email directly, view it on GitHub
<#1160 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/BH4EKT6BFEF4MDHCRRGLO4DZTFTUDAVCNFSM6AAAAABNCG7GSGVHI2DSMVQWIX3LMV43URDJONRXK43TNFXW4Q3PNVWWK3TUHMYTANBUGEYTKNY>
.
You are receiving this because you authored the thread.Message ID:
***@***.***>
|
Beta Was this translation helpful? Give feedback.
-
I can not reproduce this when using a simple clock generation. module test;
reg clk_i = 1'b0;
reg resetn_i = 1'b0;
always #10 clk_i <= ~clk_i;
always @(posedge clk_i) resetn_i <= 1'b1;
reg [4:0] tmr_a, tmr_b;
reg clear_tmr_a = 1'b0, clear_tmr_b = 1'b0;
always @(posedge clk_i or negedge resetn_i) begin
if(!resetn_i) begin
tmr_a <= 5'd1; // Offset of 1 is intentional
tmr_b <= 5'd1; // Offset of 1 is intentional
end else begin
$display("%0t: tmr_a = %d",$time, tmr_a);
if (tmr_a > 4) begin
$finish;
end
if(clear_tmr_a) begin
tmr_a <= 5'd1; // Offset of 1 is intentional
end else begin
tmr_a <= tmr_a + 5'd1;
end
if(clear_tmr_b) begin
tmr_b <= 5'd1; // Offset of 1 is intentional
end else begin
tmr_b <= tmr_b + 5'd1;
end
end // if resetn_i
end
endmodule Output
If there is a glitch on the clock where it changes multiple times at the same $time you might not see this in the waveforms. |
Beta Was this translation helpful? Give feedback.
-
Exactly. As I stated this snippet doesn't reproduce the problem. I will
continue to try and develop a test case. But, the problem disappears in
this small case. The problem also doesn't happen in microsim. This problem
does occur in other always blocks in the larger design though and is very
consistent.
Terry Little
Principal Digital Design Engineer
…On Sat, Aug 24, 2024 at 10:40 PM Lars-Peter Clausen < ***@***.***> wrote:
I can not reproduce this when using a simple clock generation.
module test;
reg clk_i = 1'b0;reg resetn_i = 1'b0;
always #10 clk_i <= ~clk_i;always @(posedge clk_i) resetn_i <= 1'b1;
reg [4:0] tmr_a, tmr_b;reg clear_tmr_a = 1'b0, clear_tmr_b = 1'b0;
always @(posedge clk_i or negedge resetn_i) begin
if(!resetn_i) begin
tmr_a <= 5'd1; // Offset of 1 is intentional
tmr_b <= 5'd1; // Offset of 1 is intentional
end else begin
$display("%0t: tmr_a = %d",$time, tmr_a);
if (tmr_a > 4) begin
$finish;
end
if(clear_tmr_a) begin
tmr_a <= 5'd1; // Offset of 1 is intentional
end else begin
tmr_a <= tmr_a + 5'd1;
end
if(clear_tmr_b) begin
tmr_b <= 5'd1; // Offset of 1 is intentional
end else begin
tmr_b <= tmr_b + 5'd1;
end
end // if resetn_iend
endmodule
Output
30: tmr_a = 1
50: tmr_a = 2
70: tmr_a = 3
90: tmr_a = 4
110: tmr_a = 5
If there is a glitch on the clock where it changes multiple times at the
same $time you might not see this in the waveforms.
—
Reply to this email directly, view it on GitHub
<#1160 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/BH4EKT2MG3NXBJSDFEM2P5DZTFU3BAVCNFSM6AAAAABNCG7GSGVHI2DSMVQWIX3LMV43URDJONRXK43TNFXW4Q3PNVWWK3TUHMYTANBUGEYTONI>
.
You are receiving this because you authored the thread.Message ID:
***@***.***>
|
Beta Was this translation helpful? Give feedback.
-
The double execution of the always block is almost guaranteed to be a clock or reset glitch that is triggering the always block twice. What Martin wrote should help figure out which is glitching. It is very unlikely this is a bug in the simulator, though we will do our best to figure this out if it is. Creating manual breakpoints using $stop and then enabling fileline tracing will generate a bunch of results, but can help identify the order block are executed, etc. Unfortunately they do not currently work for continuous assignment expressions. |
Beta Was this translation helpful? Give feedback.
-
So after adding the extra always blocks as described I end up with a very clear indication that the resetn_i signal is bouncing like crazy to trigger the scheduler, but the value sampled is always a '1'. I am tracking that reset signal now. It is generated from a statemachine in another block. It is a registered output so I am still confused about the "bouncing". I even tried changing the name from the statemachine through the entire hierarchy and no difference. I have confirmed that the issue goes away when I remove the resetn_i signal from the always sensitivity list. But, I need the negedge synchronous reset from the state machine since clk_i is a gated clock that is not always present (gating is disabled for everything here). Still confused..... The clk_i and resetn_i display statements are from separate blocks. always @(posedge clk_i) $display("clk_i at time %t, state = %d", $time, state); This is the always statement for tmr_a clk_i at time 3634250000, state = 4 |
Beta Was this translation helpful? Give feedback.
-
Any chance you can share how the reset signal is generated (or a simplified version of it). Do you use blocking or non-blocking assignments? Maybe something like Does your state machine block look maybe something like always @(...) begin
resetn = 1'b0;
if (....)
resetn = 1'b1;
end |
Beta Was this translation helpful? Give feedback.
-
very much like that. In creating the snippet below I found the problem. It
isn't a problem for Microsim or Xcelium so it may still be of interest to
Icarus.
always @(posedge clk or negedge rstn) begin
if ( !rstn) begin
resetn_i <= 1'b0;
end
else begin
resetn_i <= 1'b0; // *This is the problem line. When I remove it the
double trigger of the counter stops.*
case (s)
1: begin
resetn_i <= 1'b0;
end
2: begin
resetn_i <= 1'b1;
end
3: begin
resetn_i <= 1'b0;
end
default: begin
resetn_i <= 1'b0;
end
end
…On Mon, Aug 26, 2024 at 10:51 AM Lars-Peter Clausen < ***@***.***> wrote:
Any chance you can share how the reset signal is generated (or a
simplified version of it). Do you use blocking or non-blocking assignments?
Maybe something like
Does your state machine block look maybe something like
always @(...) begin
resetn = 1'b0;
if (....)
resetn = 1'b1;
end
—
Reply to this email directly, view it on GitHub
<#1160 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/BH4EKT73GA3EP3SEFYXTCTTZTNTJTAVCNFSM6AAAAABNCG7GSGVHI2DSMVQWIX3LMV43URDJONRXK43TNFXW4Q3PNVWWK3TUHMYTANBVGQ3DKNY>
.
You are receiving this because you authored the thread.Message ID:
***@***.***>
--
Terry Little
Principal Digital Design Engineer
|
Beta Was this translation helpful? Give feedback.
-
When you mentioned synchronous reset and the gated clock did you really intend to say asynchronous reset? You may want to read and understand the reset design papers by Cummings, et al. Lots of good stuff in those two papers. Like Martin mentioned earlier. In general the coding style you are using can be used as the input to a flip-flop, but it should not be used to code the flip-flop since it creates glitches that are unexpected. Those are usually benign on a flip-flop input, but as you have discovered are catastrophic when the output glitches. I believe Icarus is working properly and it could be possible that the simulator differences fall into the non-determinism that is allowed in simulators. The scheduling and non-blocking assignment sections of the standard cover this so if you find something we are not doing incorrectly let us know. Adding: Fundamentally it looks like the other simulators are suppressing the first non-blocking assignment in the block and only executing the second assignment while Icarus is executing both non-blocking assignments in the correct order as implied in the standard. The following is from 1800-2023 section 10.4.2 "The order of the execution of distinct nonblocking assignments to a given variable shall be preserved. In other words, if there is clear ordering of the execution of a set of nonblocking assignments, then the order of the resulting updates of the destination of the nonblocking assignments shall be the same as the ordering of the execution" |
Beta Was this translation helpful? Give feedback.
-
See below
On Mon, Aug 26, 2024 at 12:52 PM Cary R. ***@***.***> wrote:
When you mentioned synchronous reset and the gated clock did you really
intend to say asynchronous reset? You may want to read and understand the
reset design papers by Cummings, et al. Lots of good stuff in those two
papers.
As is often the case of picking up someone else code I have been struggling
to debug code that was done in a way I would never have done it. When I
code a state machine there is the async reset in the if block and the case
statement in the else block. I don't ever put anything else in the else
block with the case statement. The state machine driving the resetn_i
signal is synchronous with the clock in both the fsm and timer tmr_a block
that had the problem. So the fsm evaluates the resetn_i signal every clock
the fsm is not in reset (which is a real POR asynch reset). Even though the
generated resetn_i signal controlled by the fsm doesn't change value it is
still causing the tmr_a block to be triggered for some reason.
Like Martin mentioned earlier. In general the coding style you are using
can be used as the input to a flip-flop, but it should not be used to code
the flip-flop since it creates glitches that are unexpected. Those are
usually benign on a flip-flop input, but as you have discovered are
catastrophic when the output glitches.
The interesting part is that a block that has two triggers posedge clk_i
and negedge resetn_i, the clk_i trigger was working as expected. But, the
fsm created resetn_i signal which was changing value was still triggering
the negedge resetn_i input to the tmr_a always block and incrementing tmr_a
counter because the value of resetn_i hadn't actually changed.
I believe Icarus is working properly and it could be possible that the
simulator differences fall into the non-determinism that is allowed in
simulators. The scheduling and non-blocking assignment sections of the
standard cover this so if you find something we are not doing correctly let
us know.
I am not sure this is correct behavior, because the value of resetn_i never
changed in the fsm where it was generated. I think this issue is related to
the fsm being triggered and the signal being placed on the time wheel for
evaluation. Then that scheduling event passing through to other blocks in
which the resetn_i is used as a negedge trigger getting put on the time
wheel and those blocks getting erroneously executed since the value of
resetn_i never changed. The issue affected all the blocks that were being
"reset" by the resetn_i signal.
From a coding standpoint I think the fsm style of having a default value
assignment in the else block but out outside the case statement that
actually encodes the state machine is not best practice, but I don't see
why it shouldn't work.
Having said all this, I haven't reviewed (and unfortunately have interest,
but not time) so can't say exactly what the behavior should be per spec.
But it seems that since all the assignments are non-blocking and registered
there shouldn't be any glitches on the resetn_i signal in my design. I am
very interested to remain involved in this issue if work continues on it,
but tapeout is next week so I won't be able to for a little while.
Terry
… —
Reply to this email directly, view it on GitHub
<#1160 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/BH4EKT2E5UCLVITFWTN5USTZTOBQBAVCNFSM6AAAAABNCG7GSGVHI2DSMVQWIX3LMV43URDJONRXK43TNFXW4Q3PNVWWK3TUHMYTANBVGU3DMNY>
.
You are receiving this because you authored the thread.Message ID:
***@***.***>
--
Terry Little
Principal Digital Design Engineer
|
Beta Was this translation helpful? Give feedback.
-
Cary,
As soon as I sent that last email I realized something.
The fsm in a single clock trigger set the resetn_i signal to 1'b0 then
evaluates the case statement and sets it back to the signal determined by
the state of the fsm. So if the fsm is setting it to 1'b1, it get set to
1'b0 and then the fsm set it to 1'b1, so on a clk edge reference the value
never changed, but value of the signal resetn_i does change from 1 to 0 to
1 every clock cycle.
So I think you are right, this is possibly in the non-determinism that is
allowed in simulators. People often forget that multiple things happen on
the time wheel and that the order is not always deterministic. So I think
the way the fsm is coded will always require multiple assignments to the
signal on a single simulator step. I wonder how this synthesiser is dealing
with this. I think I will recode. the fsm.
Terry
…On Mon, Aug 26, 2024 at 1:17 PM Terry Little ***@***.***> wrote:
See below
On Mon, Aug 26, 2024 at 12:52 PM Cary R. ***@***.***> wrote:
> When you mentioned synchronous reset and the gated clock did you really
> intend to say asynchronous reset? You may want to read and understand the
> reset design papers by Cummings, et al. Lots of good stuff in those two
> papers.
>
As is often the case of picking up someone else code I have been
struggling to debug code that was done in a way I would never have done it.
When I code a state machine there is the async reset in the if block and
the case statement in the else block. I don't ever put anything else in the
else block with the case statement. The state machine driving the resetn_i
signal is synchronous with the clock in both the fsm and timer tmr_a block
that had the problem. So the fsm evaluates the resetn_i signal every clock
the fsm is not in reset (which is a real POR asynch reset). Even though the
generated resetn_i signal controlled by the fsm doesn't change value it is
still causing the tmr_a block to be triggered for some reason.
> Like Martin mentioned earlier. In general the coding style you are using
> can be used as the input to a flip-flop, but it should not be used to code
> the flip-flop since it creates glitches that are unexpected. Those are
> usually benign on a flip-flop input, but as you have discovered are
> catastrophic when the output glitches.
>
The interesting part is that a block that has two triggers posedge clk_i
and negedge resetn_i, the clk_i trigger was working as expected. But, the
fsm created resetn_i signal which was changing value was still triggering
the negedge resetn_i input to the tmr_a always block and incrementing tmr_a
counter because the value of resetn_i hadn't actually changed.
> I believe Icarus is working properly and it could be possible that the
> simulator differences fall into the non-determinism that is allowed in
> simulators. The scheduling and non-blocking assignment sections of the
> standard cover this so if you find something we are not doing correctly let
> us know.
>
I am not sure this is correct behavior, because the value of resetn_i
never changed in the fsm where it was generated. I think this issue is
related to the fsm being triggered and the signal being placed on the time
wheel for evaluation. Then that scheduling event passing through to other
blocks in which the resetn_i is used as a negedge trigger getting put on
the time wheel and those blocks getting erroneously executed since the
value of resetn_i never changed. The issue affected all the blocks that
were being "reset" by the resetn_i signal.
From a coding standpoint I think the fsm style of having a default value
assignment in the else block but out outside the case statement that
actually encodes the state machine is not best practice, but I don't see
why it shouldn't work.
Having said all this, I haven't reviewed (and unfortunately have interest,
but not time) so can't say exactly what the behavior should be per spec.
But it seems that since all the assignments are non-blocking and registered
there shouldn't be any glitches on the resetn_i signal in my design. I am
very interested to remain involved in this issue if work continues on it,
but tapeout is next week so I won't be able to for a little while.
Terry
> —
> Reply to this email directly, view it on GitHub
> <#1160 (comment)>,
> or unsubscribe
> <https://github.com/notifications/unsubscribe-auth/BH4EKT2E5UCLVITFWTN5USTZTOBQBAVCNFSM6AAAAABNCG7GSGVHI2DSMVQWIX3LMV43URDJONRXK43TNFXW4Q3PNVWWK3TUHMYTANBVGU3DMNY>
> .
> You are receiving this because you authored the thread.Message ID:
> ***@***.***>
>
--
Terry Little
Principal Digital Design Engineer
--
Terry Little
Principal Digital Design Engineer
|
Beta Was this translation helpful? Give feedback.
-
Yes, this is a classic zero width glitch and the part I copied from the standard seems to support generating the glitch. Since some simulators suppress these, there are other ways to generate close to zero width glitches deterministically. I do very exotic things with SystemVerilog so I have an intuitive understanding of the scheduler. The synthesizer often does the correct thing since it only has real gates, which is likely a reason other simulators filter the event queue. |
Beta Was this translation helpful? Give feedback.
-
Yes, that and the passage from 10.4.2 do imply the other simulators are doing the wrong thing. Of course the Cadence folks will claim the standard is incorrect or our interpretation is wrong ;-)! Verilog-XL was the reference at some point in time, but they shouldn't get to claim that forever and for any of their simulators without also fixing/clarifying the standard. |
Beta Was this translation helpful? Give feedback.
-
When I worked at AMD they called this kind of "compliance" as being "bug
compatible". Very common comment when talking about the 486 processors.
…On Mon, Aug 26, 2024 at 7:27 PM Cary R. ***@***.***> wrote:
Yes, that and the passage from 10.4.2 do imply the other simulators are
doing the wrong thing. Of course the Cadence folks will claim the standard
is incorrect or our interpretation is wrong ;-)! Verilog-XL was the
reference at some point in time, but they shouldn't get to claim that
forever for any of their simulators without also fixing/clarifying the
standard.
—
Reply to this email directly, view it on GitHub
<#1160 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/BH4EKT73KPVQ5QJVJ33EGWDZTPP2XAVCNFSM6AAAAABNCG7GSGVHI2DSMVQWIX3LMV43URDJONRXK43TNFXW4Q3PNVWWK3TUHMYTANBVG44DEMQ>
.
You are receiving this because you authored the thread.Message ID:
***@***.***>
--
Terry Little
Principal Digital Design Engineer
|
Beta Was this translation helpful? Give feedback.
-
@terrywwgit can you mark this as answered or close it when you have some time? |
Beta Was this translation helpful? Give feedback.
-
I have an always block that is somehow getting triggered twice on a single clock edge. I am working on a small test case to demonstrate but was hoping this is a known issue with a know fix even though I can't find it. Simulating just this snippet doesn't produce the problem, just hoping for an answer since I have built a fairly large regression suite and this is killing me.
In the vcd the waves do not have the tmr_a == 3 output using gtkwaves. You 1, 2, 4, 5
In the output below you can see that values 3 and 4 occur at the same time.
Anything would be helpful at this point. No other logic drives these timers.
OUTPUT:
5251000000: tmr_a = 1
5251500000: tmr_a = 2
5252000000: tmr_a = 3
5252000000: tmr_a = 4
5252500000: tmr_a = 5
Beta Was this translation helpful? Give feedback.
All reactions