always @(clk) begin #10 clk <= ~clk;end //works
always @(clk) begin #10 clk = ~clk;end //doesn't work
Works means execution re-enters the always block, behaves like a oscillator.
Does not work mean it execute only once.
I've read Scheduling semantics part in Verilog Standard, as I understand it now, in a time step, all statements in the process are placed in the hierarchical event queue at the same time, until the process is suspended when the timing control statement in the process is encountered. The statements are then sorted and sorted. If the statements are in a begin end block, the statements need to be sorted in the order in which they appear.
As I understand it, both blocking and non-blocking assignments can generate a flapping clock because the timing control statement in the process is detected before the assignment is updated.
Is the evaluation of events in a time step done sentence by sentence? Or there's something wrong with my understanding.
Why can a non-blocking update event trigger a sensitive event at the same time step? Could You tell me how evaluation and update events enter the hierarchical event queue?
To better understand this, you need to unroll the statement in the always
loop.
initial #0 clk = 0; // I'm assuming you have this code already.
initial begin
@(clk) #10 clk <= ~clk;
@(clk) #10 clk <= ~clk;
@(clk) #10 clk <= ~clk;
...
end
This works because clk
is set to 0 after encountering the first @clk
. It waits 10 time units and then executions the nonblocking assignment statement. The next @(clk)
is encountered before the nonblocking assignment updates the value of clk
.
In the second case,
initial #0 clk = 0; // I'm assuming you have this code already.
initial begin
@(clk) #10 clk = ~clk;
@(clk) #10 clk = ~clk;
@(clk) #10 clk = ~clk;
...
end
Again,clk
is set to 0 after encountering the first @clk
. But since you now have a blocking assignment statement, the update to clk
occurs first, and then you encounter the @(clk)
. So it waits for a change on clk
that never happens.
The key thing about event controls they have to be encountered in the procedural thread of execution before any change to the event expression happens. Note that I added a #0
to make sure the the @
is seen first. Without the delay, there is a race condition. There is still a race condition when the original code was modeled with an always
construct, but most users do not see this because simulators tend to start always
processes before initial
processes.
In your case, there is no need for an event control. You can simply write:
always #10 clk = ~clk;
Even better is
initial begin
clk = 0; // make sure that a posedge does not occur at time 0.
forever #10 clk = ~clk;
end