UPGRADE YOUR BROWSER

We have detected your current browser version is not the latest one. Xilinx.com uses the latest web technologies to bring you the best online experience possible. Please upgrade to a Xilinx.com supported browser:Chrome, Firefox, Internet Explorer 11, Safari. Thank you!

cancel
Showing results for 
Search instead for 
Did you mean: 
3,962 Views
Registered: ‎07-22-2013

Vivado 2013.2 simulator: Signal delayed by one cycle due to a wire?

I'm having some problems with a complex design, but after looking at it for a few days, I'm wondering if the problem is in the Vivado simulator?  I've simplified it into a simple test case.  See below.  When I set load to 1 in the testbench, the registers a1 and a3 flip to 1 in the *same* cycle.  However, the register a2 flips to 1 on the next cycle.  See the attached simulator screen shot.  The only difference is that a2 goes through one extra wire.  Shouldn't a1, a2, and a3 all be updated at the same time?

 

module my_pain(

    input clk,

    input load, // data is available

    );

    

    reg a1;

    wire a1_in;

    

    assign a1_in = load;

 

    always @(posedge clk) begin

        a1 <= a1_in;

    end

 

    reg a2;

    wire a2_in;

    wire this_screws_everything_up;

    

    assign this_screws_everything_up = load;    

   

    assign a2_in = this_screws_everything_up;

 

    always @(posedge clk) begin

        a2 <= a2_in;

    end

    

    reg a3;

    

    always @(posedge clk) begin

        a3 <= load;

    end

 

endmodule

 

Screen Shot 2013-09-22 at 4.45.51 PM.png
0 Kudos
3 Replies
Guide avrumw
Guide
3,960 Views
Registered: ‎01-23-2009

Re: Vivado 2013.2 simulator: Signal delayed by one cycle due to a wire?

Welcome to the world of Verilog non-determinism...

 

You didn't tell us how clk and load are generated, but based on the observed results I can guess.

 

In essence, you have a race. Presumably the rising edge of clk and the transition of load from 0->1 are done at the same "time", and using the same type of assignment.  For example

 

reg load=0;

reg clk=0;

 

always

  #10 clk = !clk;

 

initial begin

  @(posedge clk);

  @(posedge clk);

  load = 1;

end

 

In this case, the rising edges of clock are at times 10, 30, and onward.

 

The initial process waits for the first edge at time 10, then for the 2nd edge at time 30, and then sets load to 1.

 

Thus, at time 30, clk rises, and load changes from a 0 to 1. Which comes first? From this code, we see that the rising edge of clk causes the 0->1 transition on load, and hence we would like to think that the rising edge of clk comes first. But, it doesn't really.

 

In reality, this is what happens...

 

At time 30, the #10 in the always for the clk expires, and hence that process executes. It causes a 0->1 transition on clk.

 

The change on clock triggers all (posedge clk) statements in both your testbench and code

    - the execution of the 2nd @(posedge clk) in the initial

    - the posedge clk in your module for a1

    - the posedge clk in your module for a2

    - the posedge clk in your module for a3

 

Which goes first? The official answer is "it is not deterministic".

 

From your behavior it seems that the 2nd @posedge clk in the initial goes first. It changes load.

 

Since load has changed, it schedules anything that is dependent on the change in load; this is the assign to a1_in and the change to this_screws_everything_up. These get scheduled.

 

All the remaining events, though, are of equal priority - the 3 remaining @posedge clks and the two assigns.

 

Apparently the two assigns go next.

 

This changes the value on this_screws_everything_up so schedules a change on a2_in;

 

Again, all the remaining events are of equal priority, so can be done in any order.

 

Apparently, the three @posedge clk statements in your module go next. This causes a1 and a3 to take the new value, but a2 is looking at a2_in, which hasn't yet been updated, so it takes the old value.

 

Then the last event, the update to a2_in occurs. But, since the update of a2 has already occurred, this update doesn't affect a2 until the next rising edge of clock.

 

(this is a little simplified, since there are additional events for the propagation through the ports of your module, but the essence remains)

 

This is Verilog. You have coded an intrinsic 0 time race condition in your code, and when you do so, the order of execution is non-deterministic.

 

The solution is to be more careful in your testbench (which is presumably where your load signal comes from). Never change testbench inputs on the edge of your clock using a blocking assignment - either do it before or after, or use a non-blocking assignment. In this case, if you had the initial be

 

initial begin

  @(posedge clk);

  @(posedge clk);

  #1 load = 1;

end

 

or

 

initial begin

  @(posedge clk);

  @(posedge clk);

 load <= 1;

end

 

 

Then the load would assert cleanly after the rising edge of clock, and all three FFs would not take the new value until the next edge of clock (the one at 50ns in my example). A non-blocking assignment is guaranteed to be done after all active events in the current time tick - therefore the NBA on load would occur after all other active events - all posedge clk statement as well as all continuous assign statements.

 

This is not a bug in the simulator - its a bug in the testbench coupled with the normal event processing mechanism in Verilog.

 

Avrum

Highlighted
3,934 Views
Registered: ‎07-22-2013

Re: Vivado 2013.2 simulator: Signal delayed by one cycle due to a wire?

Thanks for the explanation.

 

My testbench is even simpler than the one you suggested.  It literally looks like this:

 

initial begin

        #5 clk <= 1;

        load <= 1;

        #5 clk <= 0;

        #5 clk <= 1;

        load <= 0;

        #5 clk <= 0;

end

 

There's a little more to it but that's the important part.  I imagine that it has the same problem as your example in terms of the ambiguous order of events.

 

It occurred to me that the test doesn't really reflect reality.  The test has clk and load going to 1 at the same moment.  But in the actual circuit, load will already be 1 when clk goes to 1.  I've written a bunch of other tests in this same manner, and they all work as expected, so I was reluctant to just change the test to make it work without understanding what was going on.

 

So is the solution just to set load to 1 a few nanoseconds before setting clk to 1?  

 

Thanks,

W

 

 

0 Kudos
Historian
Historian
3,928 Views
Registered: ‎02-25-2008

Re: Vivado 2013.2 simulator: Signal delayed by one cycle due to a wire?


@willisblackburn wrote:

Thanks for the explanation.

 

My testbench is even simpler than the one you suggested.  It literally looks like this:

 

initial begin

        #5 clk <= 1;

        load <= 1;

        #5 clk <= 0;

        #5 clk <= 1;

        load <= 0;

        #5 clk <= 0;

end

 

There's a little more to it but that's the important part.  I imagine that it has the same problem as your example in terms of the ambiguous order of events.

 

It occurred to me that the test doesn't really reflect reality.  The test has clk and load going to 1 at the same moment.  But in the actual circuit, load will already be 1 when clk goes to 1.  I've written a bunch of other tests in this same manner, and they all work as expected, so I was reluctant to just change the test to make it work without understanding what was going on.

 

So is the solution just to set load to 1 a few nanoseconds before setting clk to 1?  

 

Thanks,


Remember that if signals in the design are synchronous to a clock, they should change only with the clock, perhaps in an always block sensitive to the clock, perhaps in an always or initial block after a posedge(clk). 

 

This is all about the event model. Adding the assignment delays doesn't make a signal synchronous.

----------------------------Yes, I do this for a living.
0 Kudos