0
\$\begingroup\$

Here is a verilog code: (This code is not for synthesis)

`timescale 1 ns / 1 ns

module test;
    reg r1, r2, r3, r4;
    reg clk_at_time, clk_from_clk;


    // Initialize signals 
    initial begin
      r1 <= 1;
      r2 <= 0;
      clk_at_time <= 1;
      #200
      $finish();
    end


    // Generating simple a clock (period time is 10ns)  (as expected)
    always #5
        clk_at_time <= ~clk_at_time;


    // Generating a clock based on the clk_at_time.
    // This clk_from_clk is always equals the clk_at_time (as expected)
    always @ clk_at_time
        clk_from_clk <= clk_at_time;


    // r1 and r2 inverted at all posedge event. (as expected)
    // r3 is constant 0 (as expected)
    always @(posedge clk_at_time) begin
        r1 <= r2;
        r2 <= r1;
        r3 <= clk_from_clk;
    end


    // r4 is constant 1  ???!!!??? HOW ???!!!???
    always @(posedge clk_from_clk) begin
        r4 <= clk_at_time;
    end

endmodule

And the waveform of the simulation: The waveform of the simulation

In the code there are two clock: first is the traditional clock generated by time always #5 the second is generated by this clock always @ clk_at_time The two clocks are always equal (as expected)

The strange thing that if I use the clk_from_clk in clk_at_time's block the previous value will be used of clk_from_clk. (OK), BUT if I use the clk_at_time in clk_from_clk's block the NEW value will be used of clk_at_time.

Clarify: See the waveform: clk_from_clk and clk_at_time are equals always.

See code: r3 and r4 are analog:

  • r3 is in clk_at_time's block and driven by clk_from_clk
  • r4 is in clk_from_clk's block and driven by clk_at_time

So if clk_from_clk and clk_at_time are really the same r3 and r4 should have be equal always. BUT See the waveform: r3 is always 0 and r4 is always 1

HOW? What is the rule?

\$\endgroup\$
1
  • 2
    \$\begingroup\$ This is something of an artefact of simulation - there is an ordering between "simultaneous" events, because you're simulating on a sequential processor. Try a delay: "clk_from_clk <= #1 clk_at_time;" \$\endgroup\$
    – pjc50
    Mar 1, 2017 at 13:43

1 Answer 1

1
\$\begingroup\$

clk_at_time leads clk_from_time and there is a zero-time delay between the two of them. You cannot see the offset in a wave form or a $monitor statement, but it is there. To understand your simulation results, you need to understand the Verilog process scheduler.

Verilog Schedular

The active region evaluates all assignments. In a procedural block, if blocking assignment (=) is used then the calculated value is applined to the variable immediately. If non-blocking assignment (<=) is used then the calculated value is applied to the variable in the NBA region. Any reverences references to the variable with non-blocking assignments before the NBA region is executed will use the old value (not the updated).

This are the steps through the scheduler your simulator is likely taking for your code:

  1. ACTIVE region
    • eval initial block and calculate but postpone update on r1, r2, clk_at_time
  2. NBA region
    • update r1, r2, clk_at_time (values calculated in step 1)
  3. ACTIVE region
    • eval always @ clk_at_time block (change 1'bx->1'b1) and calculate but postpone update on clk_from_time
    • eval always @(posedge clk_at_time) block (1'bx->1'b1 is posedge) and calculate but postpone update on r1, r2, r3
  4. NBA region
    • update r1, r2, r3, clk_from_time (values calculated in step 3)
  5. ACTIVE region
    • eval always @(posedge clk_from_time) block (1'bx->1'b1 is posedge) and calculate but postpone update on r4
  6. NBA region
    • update r4 (value calculated in step 5)
  7. #5 time progression
  8. ACTIVE region
    • eval ~clk_at_time and postpone clk_at_time update
  9. NBA region
    • update clk_at_time (values calculated in step 8)
  10. ACTIVE region
    • eval always @ clk_at_time block (change 1'b1->1'b0) and calculate but postpone update on clk_from_time
  11. NBA region
    • update clk_from_time (values calculated in step 10)
  12. #5 time progression
  13. ACTIVE region
    • eval always @ clk_at_time block (change 1'b0->1'b1) and calculate but postpone update on clk_from_time
    • eval always @(posedge clk_at_time) block (1'b0->1'b1 is posedge) and calculate but postpone update on r1, r2, r3
  14. NBA region
    • update r1, r2, r3, clk_from_time (values calculated in step 13)
  15. ACTIVE region
    • eval always @(posedge clk_from_time) block (1'bx->1'b1 is posedge) and calculate but postpone update on r4
  16. NBA region
    • update r4 (value calculated in step 15)
  17. Go back to step 7 until time progression is #200 then exit

How the propagation works should be easier for you to visualize of you change all <= to <= #1.


FYI: By definition Verilog (intentionally) does not specify the evaluation order between two always blocks activated at the same time. This mean if you change clk_from_clk <= clk_at_time; to clk_from_clk = clk_at_time; Then value that is assigned to r3 can be indeterminate because always @ clk_at_time and always @(posedge clk_at_time) are triggered in the same ACTIVE region. In practices you are unlikely to see the indeterminate behavior in simulation

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.