Use of Non-Blocking Assignment in Testbench : Verilog - verilog

I have two questions regarding the use of Non-Blocking assignments in testbench.
Can we use blocking assignment in always #(posedge clk) w.r.t testbench? I think we can use as we dont have to worry about hardware. But I need confirmation.
I have used the following code in my testbench but it doesn't work as expected.
always #(posedge clk)
begin
while((state==2'd3) && (x!=OUT_MAX_SIZE_32) && (count_done==4'd4))
begin
$display("a[%d] :%h, %d",l,a[l],x);
a[l] <= {b[x][31], b[x][30], b[x][29], b[x][28], b[x][27], b[x][26], b[x][25], b[x][24]};
a[l+1] <= {b[x][23], b[x][22], b[x][21], b[x][20], b[x][19], b[x][18], b[x][17], b[x][16]};
a[l+2] <= {b[x][15], b[x][14], b[x][13], b[x][12], b[x][11], b[x][10], b[x][9], b[x][8]};
a[l+3] <= {b[x][7], b[x][6], b[x][5], b[x][4], b[x][3], b[x][2], b[x][1], b[x][0]} ;
x <= x+1;
l <= l+4;
end
end
What is happening is x and l are not incrementing if I use non-blocking assignments. But if I use blocking assignments, it works as expected. I need help in analyzing it.

You can and should use non-blocking assignments in your testbench. A simulator does not know the difference between what is you design and your testbench. You need to code both in a way to prevent race conditions.
From the code that you show, I can't see why it would make any difference unless there are other assignments to x and l elsewhere that you are not showing.

Non-blocking assignments can always be used in test bench code. This becomes an infinite loop by use of non-blocking assignments.
Referring to SystemVerilog LRM 1800-2012 section 10.4.2,
The non blocking procedural assignment allows assignment scheduling without blocking the procedural flow.
Referring to section 4.9.4,
A non blocking assignment statement (see 10.4.2) always computes the updated value and schedules the update as an NBA update event, either in the current time step if the delay is zero or as a future event if the delay is nonzero.
Here, at the posedge of clock, lets say x=0 so it is assuming while loop is executed. The RHS of non-blocking assignments are evaluated in active region, while the actual assignments are done in NBA region.
So, increment of x to 1 is scheduled in NBA region of the same time-stamp. Also, since it is a non-blocking statement, the condition of while loop is checked again in active region without blocking anything (getting x=0 again). Again, x is scheduled to be incremented in NBA region and this loop goes on forever. Hence you are not able to increment x. Similar comments applies to l.
While, using blocking assignments, the value is immediately assigned to the LHS of expression, hence x/l increases.
Also, $display executed in Active region, so you'll not be able to get value of x as 1. Following image shall give you clear idea about this.
For more information on event regions, refer to CummingsSNUG2006Boston_SystemVerilog_Events paper.

Related

Verilog execution parallel or sequential if block along with another statement

The following is a verilog code
I'm trying to understand the working of statements inside an always block.
I know the rule that blocking statements are written using = and non blocking use <= in verilog.I know the working of these.
What will happen if an if statement(with blocking statements) come in between blocking statements?
always(#posedge clk)
begin
if(en1)
begin
out1=c; //statement 1
out2=c+1; //statement 2
if(out2>5)
begin
out3=out1+out2;//statement 3
end
else
out3=0;
out4=out1-out2;
end
end
The 'if statement' was synthesized into a multiplexer. Will it use the values updated in the previous statement1 ???Requirement is -The output should be such that the three statements were executed sequentially.
But when this is implemented in hardware the mux for ' if ' will be separate from the other adders.So I thought the if statement3 in between will work in parallel with statement 1 and 3.
I checked in simulation and the value taken is the latest value-ie as if it works sequentially.
My questions are
1.Is it correct to use 'if statements' in between other assignments.
or should I use another method of programming.Will it run sequentially when blocking statements are used?
2.Will this work in all conditions as if sequentially?
The story here is very simple. In simulation all statements inside an always block are always executed sequentially, as in any programming language. The if statement will be executed after the assignment, as in the order given below.
1> out1=c; //statement 1
2> out2=c+1; //statement 2
3> if(out2>5)
begin
3a> out3=out1+out2;//statement 3
end
else
3b> out3=0;
4> out4=out1-out2;
The above will work as in any generic programming language. The if will be taken if out1 > 5.
The confusion is in in the blocking/non-blocking assignments. Verilog has a very special semantic for the <=, non-blocking assignment. Actually it is just a simulation artifact. It means that the rhs value will not be assigned to the lhs inside this particular always block. It will be done later, after all always blocks are evaluated.
So, consider the following:
out1=c; //statement 1
out2 <= c+1; //<<<< non blocking, assignment here, statement 2
if(out2>5)
begin
Now, if c is 4 and the result of the rhs c+1 is 5, the if statement will still be taken, because out2 is not yet updated in this block. It will still have the previous value of 4. But the value of 5 will be assigned to it at the very end, after all the statements are evaluated. It will not be seen by the if statement till the next posedge of your clock.
1.Is it correct to use 'if statements' in between other assignments. or should I use another method of programming.Will it run sequentially when blocking statements are used?
it depend on what you are trying to achieve here. Could be correct or not
Will this work in all conditions as if sequentially?
As i explained above. You have to understand one thing though. Verilog is not a hardware description language. It is a language for describing desired behavior of hardware and gets interpreted by synthesis tools. Therefore you can run into a situation when your simulation results will not match behavior of the synthesized schematic. To minimize this possibility you should use verilog programming practices accepted in the industry. One of them: use non-blocking assignments for the real outputs of the edge-controlled blocks. There are compelling reasons for doing so. From this perspective your example is completely wrong.

Behaviour of Blocking Assignments inside Tasks called from within always_ff blocks

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.

register inferred by blocking assignment and races

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.

Non-blocking and blocking assignments don't work as expected

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?

About verilog flip flop delay

I want to buffer a single-bit signal "done" with two single-bit flip-flops. The done signal will rise for only one clock cycle in my design. So I wrote the following code.
//first level buffer done signal for one cycle to get ciphertext_reg ready
always #(posedge clk or posedge rst) begin
if(rst)
done_buf_1 = 1'b0;
else
done_buf_1 = done;
end
//second level buffer
always #(posedge clk or posedge rst) begin
if(rst)
done_buf_2 = 1'b0;
else
done_buf_2 = done_buf_1;
end
In functional simulation, I discover the done_buf_1 rises one cycle after done, but done_buf_2 rises at the same time as done_buf_1.
What is the explanation for this?
Thank you!
You've already got answers with the solution ("use non-blocking assignments"), but here's an attempt at why you need to do that.
Both of your always statements have the same event, so they could run in any order. What seems to be happening is that the first one is running first. When the line...
done_buf_1 = done;
... is hit, it will block until the assignment is complete (it's a "blocking" assignment). Therefore done_buf_1 takes the new value immediately. This differs from the non-blocking version...
done_buf_1 <= done;
... which says 'give done_buf_1 the value of done (which I'll evaluate now) at the end of the time slice'.
Now we move on, and done_buf_2 is assigned.
done_buf_2 = done_buf_1;
Now, if done_buf_1 was updated with a blocking assignment it already has the current value of done, and you'll see both signal rise at the same time. If it was a non-blocking assignment then done_buf_1 still has the previous value of done, as it won't be updated until the end of the time-slice, the result being a 2 cycle delay for done_buf_2.
There's also another problem though. Remember that I said that the always statements could be run in either order because the events were the same? Well if the second one was executed first the code would appear to work as intended (db2 = db1; db1 = done; No problem). So it's worth knowing that using blocking assignments like this gives erratic results especially between tools. That can lead to some subtle bugs.
You're using blocking assignments = to model synchronous logic. You need to use non-blocking assignments <=.
As others have said: don't use blocking assignments (=) for this.
The key point is that "this" is the job of communicating between different processes. The race conditions inherent in blocking assignments make this unpredictable. VHDL takes this so seriously that it separates these types of assignment such that you can't use the wrong one (as long as you keep away from shared variables).
Some interesting writings on the subject from Jan Decaluwe:
Verilog's major flaw
VHDL's crown jewel

Resources