In Verilog, is begin-end block really sequential ? Stratified event queue model doesn't include any such concept - verilog

I can understand that in a begin-end block delays are addressed sequentially i.e. they are relative to previous statement. But does it mean that the begin-end block is sequential with respect to execution sequence aswell?
integer a;
initial
begin
a = 1; // statement_1
$display(a); // statement_2
a = 2; // statement_3
end
Since statified event queue model will put all of the above 3 statements in the Active queue of #0 timestamp. How can we assure sequential execution?

Answering "How can we assure sequential execution?"
Within a begin-end block, the following applies.
IEEE Std 1364-2005 section 11.4.1 Determinism
"This standard guarantees a certain scheduling order:
Statements within a begin-end block shall be executed in the order in which they appear in that begin-end block.
Execution of statements in a particular begin-end block can be suspended in
favor of other processes in the model; however, in no case shall the statements in a begin-end
block be executed in any order other than that in which they appear in the source."
The posted code should always print 1.
For this snip, all 4 simulators on EDA Playground print 1
module tb ();
integer a;
initial
begin
a = 1; // statement_1
$display(a); // statement_2
a = 2; // statement_3
end
endmodule
https://www.edaplayground.com/x/6W3Q

Related

Non blocking statements with delays

always#(a)
begin
#1 t<=a;
#1 c<=t;
end
I am analysing above verilog code with test bench as given below
a=0;
#5 a=1;
#5 a=0;
#5 a=1;
#5;
Here is my analysis:
From above test bench I can tell that 'a' is a clock signal of total 20ns length with OFF and ON time of 5ns both respectively.At 0th ns, 'a' is changed from X to 0. So always block gets triggered.since first statement inside block is having 1ns inter delay, it waits for 1ns. after 1ns compiler gets to know that it is non blocking statement so just evaluation will be done not assignment.hence 'a' value will be stored as temporary and parallelly it executes second statement.since second one also has inter delay,it waits for 1ns. and then evaluation is done.since both the evaluations are done, assignment will happen now.
time a t c
0ns 0 x x
1ns 0 x x
2ns 0 x x
3ns 0 0 x
4ns 0 0 x
is this analysis correct?
No, that is not what happens, non-blocking assignments work different then what you describe.
You are right in that the actual assignment of a non-blocking statement is deferred, executed "later". But when is "later"?
'non-blocking' events are processed when there are no more outstanding blocking events. But before processing delays. Thus as soon as the simulator sees that it has to process your #1, it first handles all non-blocking assignments and only then start processing the delay.
Which means even before it starts the #1 delay t already has received the value of a.
There is a whole chapter in the Verilog standard which describes in what order the various 'actions' should be performed.
It might help to re-write your always block into separate lines and sightly move the location of the begin/end blocks. This has no affect on behavior as everything is executed sequentially.
always // instantiate a procedural block
begin
#a // blocking event delay waits for a change on -a-
#1 // blocking time delay waits for 1 time unit
t <= a; // non-blocking assignment
// uses the current value of -a- one time unit after it changed
// and schedules an assignment to t
#1 // blocking time delay waits for 1 time unit
// since there is no more active things to do -a- gets updated
c <= a; // uses the updated value of t and schedules an assignment to c
end // now 2 time units after -a- was first changed
// goes back to the top of the block and waits for another change
// on -a-.
Note that any changes on a that happen while executing the block are missed. Here's a good presentation on non-blocking assignments.

Can a sequential always block be triggered by a short pulse from a combi block

Could a sequential always block be triggered by a short lived pulse coming from a combi block ?
I have tried to trigger the always block, by assigning a value and set the value back to 0 in an attempt to trigger the sequential always block but to no avail, below is the pseudo code
always_comb begin
...some code...
pulse_trigger = 1;
load_var= driver_var // assigning some values
pulse_trigger = 0;
...some code...
end
always #(pulse_trigger)begin
...some code part 2...
end
I expect by assigning 1 to pulse_trigger the "always#(pulse_trigger)" block to get activated, but in my VCS simulation this does not seem to be the case.
Maybe this is because the pulse trigger is assigned 1 and unassigned 1 in the same combi block, which takes 0 simulation time, so pulse_trigger might not appear to have changed values. Or this method should've triggered "always#(pulse_trigger)" and executed "...some code part 2..", because I am looking at the wrong values ?
In verilog simulation only a single always block can be evaluated at a time. So, until your always_comb finishes, no other always block can be evaluated. Therefore, no pulse_trigger change will be detected by simulation (because all changes happen inside a single always block.
You can do something like that by adding delays (assuming this is not a synthesizable code):
always #* begin
pulse_trigger = 1;
load_var= driver_var // assigning some values
#1 // << this will stop execution of the block for 1 time unit and allow others.
pulse_trigger = 0;
end
However, the above code is not synthesizable but it can be a part of a test bench.
Also, it is not allowed within always_comb.
The result is indeterminate. The SystemVerilog standard is written so that simulators are free to jump between independent processes at any point. But most wait for an event or time control to suspend the process before jumping to another one.
If you want to guarantee a trigger, use a non-blocking assignment in the second assignment to pulse_trigger or use a named event.
always #* begin
pulse_trigger = 1;
load_var= driver_var // assigning some values
pulse_trigger <= 0; // adds a delta cycle or <= #1 delay without blocking the process
end
Even better is replacing the second always # block with a function declaration, then calling the function instead of triggering an event.

What does <= operator do in this code?

module counter (clk,rst,enable,count);
input clk, rst, enable;
output [3:0] count;
reg [3:0] count;
always # (posedge clk or posedge rst)
if (rst) begin
count <= 0;
end else begin : COUNT
while (enable) begin
count <= count + 1;
disable COUNT;
end
end
endmodule
(Source: http://www.asic-world.com/verilog/verilog_one_day2.html#While)
From what I have learnt, <= is a relational operator and it will return 1 if true and 0 if false, but where does it return in this code?
In the context of your code, <= is not a relational operator, it is an assignment operator. There are two types of assignment in Verilog:
blocking : =
non-blocking : <=
In a Verilog design, you
always use blocking assignments for combinational logic
always use non_blocking assignments for sequential logic
If you do not, you simulation will be indeterminate - it will not necessarily behave the same way every time you run it. Which, of course, is not good.
So, why is that? Well, to start you must learn that Verilog has 4 scheduling regions:
from prev time step
|
ACTIVE
|
INACTIVE
|
NBA
|
POSTPONED
|
V
to next time step
Blocking assignments are executed in the ACTIVE region. However, while the right-hand side of a non-blocking assignment is evaluated in the ACTIVE region, the assignment does not occur until the NBA region. This is key to why you need to use them for sequential logic.
So, why do you need to use non-blocking assignments for sequential logic? The reason is because the delay between evaluation of the right-hand side and assignment of the left hand side enables a Verilog simulation to be determinate, ie to behave the same way every time you run it. This delay means that the behaviour of the simulation does not depend on the order in which the always blocks are executed, which it would if only blocking assignments were used.
A simple analogy to the delay between evaluating the right-hand side of a non-blocking assignment and assigning the left-hand side is the clock-to-Q delay of a real flip-flop. In a real flip-flop, there is always a small delay (clock-to-Q delay) between the D input being sampled (by the clock) and the Q output being driven. This is vital to the correct operation of real sequential logic. For example, if there were no clock-to-Q delay in a real flip-flop instead of it taking exactly 4 clocks for the D input of the first flip-flop in a 4-stage shift register to get to the Q output of the fourth flip-flop, it could take any number of clocks between 1 and 4: its behaviour would also be indeterminate.

Subroutines in Verilog (used by ModelSim)

I am having a problem getting subroutines working in Verilog. I am following several tutorials and I cannot get my verilog files to compile. Here is a shortened version of my code.
module name(/*stuff*/)
inputs /*stuff*/
outputs /*stuff*/
initial begin
/*stuff*/
end
//Simple reset task
task reset_module ();
reset[1] = 1;
#(`CLOCK_CYCLE*4)
reset[1] = 0;
#(`CLOCK_CYCLE*4)
endtask
endmodule
The compiler complains about the endtask keyword being unexpected.
You need to add semicolons to the end of the delay lines:
task reset_module();
reset[1] = 1;
#(`CLOCK_CYCLE*4);
reset[1] = 0;
#(`CLOCK_CYCLE*4);
endtask
A semi-colon is needed after the last delay construct. That's because the #(expression) construct is not really a complete statement, it's a statement modifier. Each statement can can have any number of delay constructs (like #(expr) #(expr) ) in front of it. If you need a delay construct at the end of a procedural block of statement, you need a null statement, which is just a semi-colon.

Verilog blocking and non-blocking in a sequence

I have the following in Verilog:
reg a;
always # (clk)
begin
a = 0;
a <= 1;
$display(a);
end
What value of literal 'a' would show me? Is that 0 or 1?
Verilog simulation occurs in 5 queues as stated in IEEE 1364-1995 § 5.3, IEEE 1364-2001 § 5.3, and IEEE 1364-2005 § 11.3:
Active Event (before #0)
Evaluate RHS of all non-blocking assignment
Evaluate RHS and change LHS of all blocking assignments
Evaluate RHS and change LHS of all continuous assignments
Evaluate inputs and change outputs of all primitives
Evaluate and print output from $display and $write
Inactive Event (after #0)
Evaluate RHS after #0 delay, otherwize same processes as Active Event
Callback procedures scheduled with PLI routines such as tf_synchronize()(deprecated in IEEE 1364-2005) and vpi_register_cb(cbReadWriteSynch)
NBA Update
Change LHS of all non-blocking assignments
Monitor Event
Evaluate and print output from $monitor and $strobe
Call PLI with reason_rosynchronize(deprecated in IEEE 1364-2005)
Future
Events to occur at some future simulation time
Since $display occurs before the non-blocking assignment is assigned , the value will be 0. Note the order of execution may change in each queue.

Resources