I know that an always block will be trigger on a change in any of the elements in its sensitivity list however, my question is what happens if a change in sensitivity list happens while the statements inside the always blocks are still being executed (due to a previous trigger). Does the always block begin execution again in a parallel thread or is triggering blocked until execution finishes first?
Many people do not realize that # is a statement modifier, not construct by itself. It says to delay the statement that follows until there is an event. #(A or B) means wait until there is a change in the value of A or B (not to be confused with a change in the result of A|B). #* means look at the statement that follows, and build an implicit sensitivity list of signals to wait for a change.
always #(A or B) C = A + B;
always begin
#(A or B) C = A + B;
end
always begin
#* C = A + B;
end
always_comb
begin
C = A + B;
end
These 4 always blocks have identical behavior with the exception of the last always_comb also triggers at time 0 regardless of any change on A or B.
If you look at the code that follows the always as a procedural sequence of executing statements, it might be easier to see the # construct as part of that procedural sequence, and the change has to occur while you are executing the construct. Just adding another delay will show this concept (not synthesizable)
always #(A or B) begin
#10 C = A + B;
end
This says "wait for a change on A or B, then wait 10 more time units, then make an assignment to C with the current values of A + B". If A or B changes during the 10 time unit wait, that change is missed. You have to wait for another change on A or B after those 10 time units.
As soon as an always block is triggered, it will be executed from the beginning to the end. Verilog is a single-thread simulation engine, therefore only one block can be executed at a time. Nothing else could happen while an always block is executed, unless it contains delay statements or waits on events. In the latter case it will just yield
to allow other blocks to being executed, then it continues.
If an always block changes its inputs by the end of the execution, then next simulation behavior depends on the type of the block:
all v95/v2k always blocks (e.g. always #*) will be re-triggered,
system verilog blocks (e.g, always_comb) will not be re-triggered in the current delta cycle.
With v2k/v95 always blocks you can end up with a zero-delay loop if you are not careful. In other words simulation can hang.
With SystemVerilog blocks you can get an interesting read-before-write condition (when a variable is read before it is written in the same block). This can potentially create simulation/synthesis mismatch.
Each always block is a single thread (unless it contains a fork-join). So, if it's executing, it won't retrigger if something in the sensitivity list changes. (If it does contain a fork-join then it splits into multiple threads once triggered, but again won't retrigger).
Related
I am facing some doubts regarding the nondeterminism in Verilog Scheduling Semantics mentioned in the Verilog LRM. Below is the excerpt which I am unable to understand:
"Another source of nondeterminism is that statements without time-control constructs in behavioral blocks do not have to be
executed as one event. Time control statements are the # expression
and # expression constructs (see 9.7). At any time while evaluating a
behavioral statement, the simulator may suspend execution and place
the partially completed event as a pending active event on the event
queue. The effect of this is to allow the interleaving of process
execution. Note that the order of interleaved execution is
non-deterministic and not under control of the user."
The only inference I could make was that statements in a behavioral block may be paused for the execution of other behavioral blocks (which are active in the same timestep) so as to interleave process execution though I am not sure.
Also, I don't understand the line "statements without time-control constructs in behavioral
blocks do not have to be executed as one event". What does the LRM mean by saying it doesn't execute as one event and what would happen if a behavioral block would contain all time-controlled statements?
Can anyone please explain this with the help of some examples? Thanks in advance.
The only thing which simulation guarantees is that all statements in the always blocks will be executed sequentially. Say, as in the following block:
always #(b,c,e,f) begin
a = b | c;
d = e & f;
g = a ^ d ^ x;
...
end
However, the simulator can decide to execute first 2 statements in a row, but then stop execution of this block before the last statement and let other blocks to continue. Then it will return to the last statement. In this sense you have a non-deterministic order of the execution of the statements.
Guess what?! Value of x can definitely change while it is waiting. a and d can potentially also change while other statements are executed. So, result of g could be non-deterministic. Good programming will help to remove this type of non-determinism: list all events in the sensitivity list, do not multiply-drive signals, ... The simulator then will do the best to avoid those situations.
The need for this interleave simulation is to allow simulators to do better optimization for performance reasons and allow other blocks to progress in case of the very long and loopy statements.
Answering the comment about time and event controls
In the above block a simulator can decide when to break the execution. From the point of view of the programmer, it is non-deterministic. You do not know when it can happen. The only thing that is known that it would happen in the same simulation (time) tick. A good simulator will try its best to avoid any side effect of this.
Timing and delay controls provide deterministic stops. For example,
always #(b,c,e,f) begin
a = b | c;
d = e & f;
#1 g = a ^ d ^ x;
...
end
In the above statement with #1 you actually tell the simulator to stop execution of the statements and wait till the next time tick.
always #(b,c,e,f) begin
a = b | c;
d = e & f;
#(posedge clk)
g = a ^ d ^ x;
...
end
Here it will stop execution and wait for the posedge clk event.
Note that above examples are not synthesizable and should be used in behavioral code (test bench) only. For synthesis you have to stick with the very first example and make sure that your code is written in accordance to the good Verilog coding practices.
Consider the below example:
module test;
reg a;
initial begin
a = 1'b1;
end
initial begin
wait(a) $display("wait(a): %b", a);
$display("wait(a)");
end
initial begin
#a $display("#a: %b", a);
$display("#a");
end
endmodule
When I run it, I always get this output:
wait(a): 1
wait(a)
Which confuses me. My understanding of the code is like this:
the default value for a is x.
all initial blocks start in parallel at time 0.
the first initial block does a block assignment while at the same time the wait and #a event controls read a.
since there is no determinism in the sequencing among the three, the blocking assignment a=1'b1, may be executed before or after the wait(a) or #a.
if the blocking assignment is executed before wait(a) and #a, no output should be displayed since wait(a) and #a will not detect any change in a.
if, however, the blocking assignment a=1'b1 is executed after the read of a in wait(a) and #a, which both will read as x, then the output from both should be displayed after the blocking assignment completes.
But, as I pointed out above, the output I see is always the output from wait(a). Can someone please explain to me:
What is going on and the defect in my understanding?
And more generally, and outside of the example above:
What exactly happens when the simulator encounters a wait(a) and #a?
wait(a) and #a detect level and edge changes (in the example, level and edge change are identical). When we say "change" in this case, does it mean a change after the last read of the variables involved in the event controls (in this example a)?
You are correct up until point 5.
If a=1'b1 gets executed before the wait(a), then it has no effect—it does not suspend the process. If the reverse order, the wait(a) suspends the process and resumes after the assignment a=1'b1. In your example, you always see the output from the second initial block regardless of the order.
But the ordering is very important for the third initial block. The #a must execute before any change to a, otherwise it suspends until it sees another change. Although you should not rely on it, most tools executed initial blocks in source code order. But optimizations and ordering between initial blocks in different modules can never guarantee ordering.
Have looked for an answer to this question online everywhere but I haven't managed to find an answer yet.
I've got a SystemVerilog project at the moment where I've implemented a circular buffer in a separate module to the main module. The queue module itself has a synchronous portion that acquires data from a set of signals but it also has a combinatorial section that responds to an input. Now when I want to query the state of this queue in my main module a task, inside an always_ff block sets the input using a blocking assignment, then the next statement reads the output and acts on that.
An example would look something like this in almost SystemVerilog:
module foo(clk, ...)
queue = queue(clk, ...)
always_ff#(posedge clk)
begin
check_queue(...)
end
task check_queue();
begin
query_in = 3;
if (query_out == 5)
begin
<<THINGS HAPPEN>>
end
end
endtask
endmodule
module queue(clk, query_in, query_out)
always_comb
begin
query_out = query_in + 2;
end
endmodule
My question essentially comes down to, does this idea work? In my head because the queue is combinatorial it should respond as soon as the input stimulus is applied it should be fine but because it's within a task within an always_ff block I'm a bit concerned about the use of blocking assignments.
Can someone help? If you need more information then let me know and I can give some clarifications.
This creates a race condition and most likely will not work. It has nothing to do with your use of a task. You are trying to read the value of a signal (queue_out) that is being assigned in another concurrent process. Whether it gets updated or not by the time you get to the If statement is a race. U?se a non-blocking assignment to all variable that go outside of the always_ff block and it guarantees you get the previous value.
in order to figure out the stuff, you can just mentally inline the task inside the always_ff. BTW, it really looks like a function in your case. Now, remember that execution of any always block must finish before any other is executed. So, the following will never evaluate to '5' at the same clock edge:
query_in = 3;
if (query_out == 5)
query_out will become 5 after this block (your task) is evaluated and will be ready at the next clock edge only. So, you are supposed to get a one cycle delay.
You need to split it into several always blocks.
I am new to verilog and have a doubt concerning the race conditions in the following code which is taken from FPGA Prototyping by Veriloog Examples by Pong P. Chu. The code is:
always #(posedge clk)
a = b;
always #(posedge clk)
b = a;
This will infer races depending on which always block gets executed first. But always blocks should get executed in parallel. Correct me if I am wrong. I know there is blocking assignment but how does it affect the first statement of the block, which is the always statement?
The second code using the non-blocking assignment is:-
always #(posedge clk)
begin //b(entry) = b
a <= b; //a(exit) = b(entry)
end //a = a(exit)
always #(posedge clk)
begin //a(entry) = a
b <= a; //b(exit) = a(entry)
end //b = b(exit)
This will work fine according to the book but I couldn't understand why? Is it because the always blocks are executed in parallel in this case because of non-blocking assignment?
Because the Verilog "stratified event queue" has different regions, the type of assignment operator used makes a difference in how the code is executed. The details can be found in section 5 of the IEEE Verilog standard, but in terms of your question, it boils roughly down to this:
The blocking assignments (in your first example) are evaluated immediately, i.e. when the always block they're in is activated. Since both blocks are parallel, order of their activation is undefined.
The non-blocking assignments are not executed immediately but rather scheduled after all blocks of the same time step have finished executing.
So when encountering a rising clk edge, in your first example a simulator would
Pick at random one of the always blocks
Find that the assignment is a blocking one and execute it immediately, therefore changing the left-hand variable in that assignment.
Pick the other always block and do the same, at which point the value of the first variable was already changed.
In your second example, the simulator would
Pick at random one of the always blocks
Find that the assignment is a non-blocking one and therefore
evaluate the right-hand side of the = sign and schedule the value it found there as a non-blocking assign update event to the variable left of the =.
Pick the other always block and do the same. Note that both variables still have their values from before the rising clk edge.
Since all blocks are done executing, update all variables which were scheduled for non-blocking assign update events, effectively swapping their values.
I'm having problems with understanding such a simply looking thing: blocking and non-blocking assignments.
I created a small test bench just to simulate the behavior of this code:
module ATest(clk, out);
input wire clk;
output reg [7:0] out;
reg [7:0] A;
initial begin
A <= 8'b0;
end
always #(posedge clk) begin
A = A + 1;
out = A;
end
endmodule
After simulation, I got this wave:
I expected the same value under both A and out, as I assigned values to them sequentially. Why is out "don't care" during the first clock?
Then I tried to use non-blocking assignment. I changed a part of my code into:
always #(posedge clk) begin
A <= A + 1;
out <= A;
end
And I got this wave:
I didn't expect anything here, because non-blocking statements are kind of mystery to me. Why is both A and out set to "don't care"?
Also, I found different names on every page I got to, so please help me out:
Are blocking and non-blocking interchangeable with sequential and concurrent as terms? Which one is right: non-blocking statement or concurrent statement?
Without diving too deep into the simulation cycles used by Verilog Simulators, you can think of non-blocking vs blocking assignment simply as this:
Blocking assignment happens inline at the time the given assignment is executed, so that means if I have a line like A = A + 1, that means we take the present value of A, add 1 and assign A that new value. So, the assignment "blocks" execution until it is done.
Non-blocking assignment (NBA) happens at a time slightly later than while the line is executed. You can think of non-blocking assignments as lines telling the simulator to schedule this assignment for a little bit later (note, later is still with the same simulation time step, so all of this is still happening in simtime t). So, if you have something like A <= A + 1, this means take the value of A at the time of executing this line, add 1 and schedule A to be updated to that value in a little bit, but keep moving on with the lines following that one. So, if the next line after is out = (A == 1) ? 1 : 0, this line will execute using the old value of A, not the incremented one. Once the simulator finished with the active code, it can move on to perform all the non-blocking assignments. Now, A will get the incremented value and all other non-blocking assignments will take effect.
So, to your examples. In case one, we see the delayed effect of NBA. In the initial block, A is assigned to 0, which means A will take on the value of 0 a little bit later (still within sim time 0 remember); ie the assignment is scheduled to take place after all blocking assignments have run (Not strictly true but it works in this case). Also, you have the clock's posedge happen so the always block runs. Here, A takes on the value A + 1, but remember, the assignment of A to 0 hasnt happened, so A still has its initial value of 8'bx. so, A + 1 is also 8'bx. And since this is a blocking assignment, it happens right away. So, A doesnt change from don't care. Continuing on, out gets the current value of A, which is 8'bx. So, we get the don't cares on out. After these and other blocking assignments are done, now we finish up the NBAs, in this case, A to become 0. So, still within sim time 0, A becomes 0 and we are done. At the next posedge of the clock, A is 0, out is don't care and your always block runs as expected, incrementing A and assignment out to the same value.
If you change the always block to use NBA (which it should if it is suppose to be a register), things change slightly. The initial block still results in a NBA scheduled for A to become 0. But now, the always block does something different. Now, A <= A + 1 instead of assigning A to don't cares right away, it schedules A to become 8'bx (remember, the right-hand side expression for what value to assign is evaluated inline, so A + 1 still uses A as don't care just as before; whats changed is when A takes on this new value) and this is scheduled after A to become 0. So, both the NBAs of A are set up, but the one telling A to be 0 happens first and is wiped out by the later assignment of A to 8'bx. out is similarly scheduled to take on 8'bx but now, A never becomes 0. As such, both A and out get stuck at 8'bx.
You can look through the Verilog or SystemVerilog LRM's to get a better understanding of sim cycles and what really goes on, but I hope this helps you better understand the difference!
Your issue come from using a non-blocking assignment in your initial block. Use initial A = 8'b0; instead.
The casue for this is likely how the two assignments are processed. = assignments are done incrementally, with any new values being available to subsequent assignments. Changes made via <= assignments are only available once all assignments have been processed.
Because your first edge is at t = 0 (when intial blocks are processed), in the first example A is assigned 0, but that 0 isn't available to out until after it is processed. That's while the first cycle looks weird, but everything else is OK. In the second, A is assigned both 0 and A+1, so the simulator uses the always block instead of the initial, going with A+1, when A is still an unknown value. As such, the values for A and out are never known.
The terms are equivalent. "Blocking" is the same as "sequential" because "blocking" means that the assignment must be done before the simulator moves to the next line (in sequence). "Non-Blocking" means that all the lines may be done at once. As everything with Verilog, it helps to imagine the hardware intended, so you may think of it as "parallel" vs. "serial" sometimes.
Is there a positive clock edge at time 0 in your simulation?