SystemVerilog calculations right before writing to clocking block - verilog

I have a task, whose job it is to drive data onto a bus via a clocking block. See snippet:
task effects_driver::ReadQueueData();
stream_intf_.cycles(); // clocking block event
if (sample_q_.size() >= 2) // check to see if there is enough data in the queue
begin
automatic bit [31:0] sample0, sample1;
sample0 = sample_q_.pop_front(); // read from queue
sample1 = sample_q_.pop_front(); // read from queue
stream_intf_.cb.AXIS_TDATA <= {sample1, sample0}; // drive two samples at once
stream_intf_.cb.AXIS_TVALID <= 1;
end
else
...
endtask
You'll notice that I need to read a couple of items out of a queue before writing it to the clocking block. Is this the correct way to do it? Am I guaranteed that the simulator will perform these blocking assignments to the automatic variable before writing it to the clocking block?
P.S. I run into this scenario semi-frequently--where I need to do some quick calculations on the fly right before writing to the clocking block.

I believe you meant to ask "Am I guaranteed that the simulator will perform these blocking assignments to the automatic variable before writing it to the clocking block?" because that is what your code is doing.
The answer to that is yes, blocking assignments are guaranteed to complete before executing the statement following it.
Also note that there is no need to declare sample0 and sample1 with automatic lifetimes because class methods always have automatic lifetimes. Variables declared within them are implicitly automatic.

Related

Execution order of initial and always blocks in Verilog

I'm new to Verilog programming and would like to know how the Verilog program is executed. Does all initial and always block execution begin at time t = 0, or does initial block execution begin at time t = 0 and all always blocks begin after initial block execution? I examined the Verilog program's abstract syntax tree, and all initial and always blocks begin at the same hierarchical level. Thank you very much.
All initial and all always blocks throughout your design create concurrent processes that start at time 0. The ordering is indeterminate as far as the LRM is concerned. But may be repeatable for debug purposes when executing the same version of the same simulation tool. In other words, never rely on the simulation ordering to make you code execute properly.
Verilog requires event-driven simulation. As such, order of execution of all 'always' blocks and 'assign' statements depends on the flow of those events. Signal updated one block will cause execution of all other blocks which depend on those signals.
The difference between always blocks and initial blocks is that the latter is executed unconditionally at time 0 and usually produces some initial events, like generation of clocks and/or schedule reset signals. So, in a sense, initial blocks are executed first, before other blocks react to the events which are produced by them.
But, there is no execution order across multiple initial blocks or across initial blocks and always blocks which were forced into execution by other initial blocks.
In addition, there are other ways to generate events besides initial blocks.
In practice, nobody cares, and you shouldn't either.
On actual hardware, the chip immediately after powering-up is very unstable because of the transient states of the power supply circuit, hence its initial states untrustworthy.
The method to ensure initial state in practice is to set them in the initial block as
always # (event) {
if(~n_reset) {
initial_state=0
} else {
do_something();
}
}

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.

Verilog task based TB issue

I am quite new to verilog, specially using it for TB coding and I am facing the following issue -
I am working on verifying round-robin (RR) arbiter and want to check the DUT grant with a TB modeled grant. I am writing a task to implement the TB model and then calling the task at every posedge of clock as follows -
always #(posedge clk or posedge reset) begin
if(reset) reset_state;//task to reset state
else begin
//Initialising req vector every cycle
req_vc = {req4, req3, req2, req1, req0};
for (index=0; index<5; index=index+1) begin
temp[index] = rr_pri_state[index];
end
chk_grant; //task that gives out checker grant
**if(gnt_id_checker != gnt_id)** begin//logic to compare checker grant with DUT grant (gnt_id) and end test if false
$display ("\tERROR!! Model grant and DUT grant IDs MISMATCH.\n\t\tModel grant = %d\n\t\tDUT grant = %d ", gnt_id_checker, gnt_id);
#1 $finish;
end
end
end
All my variables are globally defined
The issue is with the if comparison just after chk_grant task is called. When I simulate this I see that the values for gnt_id and gnt_id_checker used for comparison are not being updated to the latest one for that cycle. It is still performing comparison on old values. If i introduce #1 delay before if statement then everything works as expected with the correct values.
So I want to understand if this is expected or if I have approached this incorrectly?
Here is how my chk_grant task looks like for your reference. It basically finds out highest priority requestor and updated memory to reflect the new priority order
//task to calculate checker grant AND update priority state for next cycle
task chk_grant;
begin
i=0;
while (i<5) begin
req_index = rr_pri_state[i];
if(req_vc[req_index]) begin //we have found the req getting grant this cycle
gnt_id_checker = req_index;
k = 5-(i+1); //i+1 req will have the highest priority next cycle
for (j=0; j<k; j=j+1) begin
rr_pri_state[j] = temp[i+j+1];
end
for (j=0; j<=i; j=j+1) begin
rr_pri_state[j+k] = temp[j];
end
i=5;
end //end of if
i=i+1;
end //end of while loop
end
endtask
PS - I have no particular reason for using task here. If you think an event/function is better here please do let me know how and why so. Any other inputs for improving this would be much appreciated. Thanks!
Not sure if theres anything wrong with the approach you are taking (ie, doing the work in a separate task, which in my mind makes more sense than a function as you are updating a few globals, not just getting the gnt_id_checker. If it was just getting a single value out, I would use a function).
The reason you need a #1 is that when the design run, I assume gnt_id comes from a NBA (<=) from some register. Thus you are updating your gnt_id_checker in the current process right away (blocking assignment, =) but the assignment of gnt_id is delayed into the postponed region and thus not being used by the if-statement in performing the check. If it happens you are updating gnt_id combinationally, then theres a race condition between this block and that assigning gnt_id. Im assuming theres another block actually providing the stimulus to the design which is hard to tell without more information on your variables. If this same block is providing the stimulus, you definitely not giving your design a chance to run before checking the result (which it basically comes down to either way).
So to answer you directly, yes, this is expected and no, your general approach looks fine. Though for stylistic comments, I would suggest calling your checker a golden model as that is what you are doing. So, the task might be called run_golden instead (checkers are a thing in SystemVerilog as a separate concept). And would move temp into the task so the golden model is entirely contained within the task.

Use of Non-Blocking Assignment in Testbench : 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.

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.

Resources