Non blocking statements with delays - verilog

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.

Related

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.

SystemVerilog wait() statement

Is the following code is supported in SystemVerilog?
int cnt = 0;
wait( cnt == (cnt+1) )
Could any one point me the section in LRM?
This is supported. But the main question is, what will you get by such wait statement, as this statement will never be evaluated as "true".
May be I can help you, if you provide more details on, what you exactly want to do through this wait statement.
Meanwhile, here is the code, as per your wait statement, with it's output. This will help you to understand, what this wait statement will do:
// Sample code, as per your wait statement
module top();
int cnt;
bit clk;
always #5 clk = ~clk;
always # (posedge clk)
cnt <= cnt + 1;
initial
begin
$display("***** Before wait *****");
wait(cnt == (cnt + 1))
$display("***** After wait *****");
end
initial #100 $finish;
initial $monitor("cnt - %0d", cnt);
endmodule
// Output of this sample code
***** Before wait *****
cnt - 0
cnt - 1
cnt - 2
cnt - 3
cnt - 4
cnt - 5
cnt - 6
cnt - 7
cnt - 8
cnt - 9
cnt - 10
$finish called from file "testbench.sv", line 20.
$finish at simulation time 100
I guess the answer depends on what you mean by supported? You are certainly allowed to write expressions that make no sense and would always result in false (1'b0). That would cause the wait statement to hang and suspend whatever process executed it.
Yes it is supported. You would not get any compilation error even if logically you know it is going to hang. (If that was your intention while asking)
"wait" statement is level sensitive and will wait infinitely till the expression is evaluated to be true. It is usually used to wait for an event before executing another event or to delay the execution of the code till some event has occurred.
Since in systemverilog the threads are created dynamically, synchronization between events is necessary and that is where wait statements can be used.
LRM section where you can read more about wait statement: 9.4.3 (Level sensitive event control)
Instead of the uvm_event you could use SystemVerilog's own event type. This removes the dependency to the uvm_pkg.
class container;
event from_a;
task a();
...
-> from_a;
...
endtask
task b();
...
# from_a;
...
endtask
endclass
You can find a lot about interprocess communication (mailbox, semaphore, mutex, events) # LRM Chapter 15.

delayed attribute in VHDL

I'm trying to create a delayed version ('s_dlyd') of a signal ('s') using the 'delayed attribute in VHDL.
My code (below) compiles and simulates (using Xilinx webpack, ISIM) and 's' undergoes the expected '0/1' transitions.
s_dlyd simply sits at '1' however (i.e. it isn't a 5ns-delayed copy of 's' I'd (naively?!) expected.
I'm guessing I'm missing something fundamental about the way VHDL schedules transitions. I've tried numerous of variations of the code (splitting the line "s<=..." into 3; trying things like "s_dlyd <= s'delayed(5 ns) after 11 ns" etc.) but none give me a delayed copy of s.
Any help appreciated. Thankyou
architecture Behavioral of five_three is
signal s : STD_LOGIC := '1';
signal s_dlyd: STD_LOGIC;
begin
my_process : process is
begin
s <= '1', '0' after 10 ns, '1' after 20 ns;
s_dlyd <= s'delayed(5 ns);
wait for 50 ns;
s <= '0' ;
wait;
end process;
end architecture;
I expect s_dlyd to be '1' after 5 ns, previously 'U'.
A signal equivalent to signal S delayed T units of time. The value of
S'DELAYED(t) at time Tn is always equal to the value of S at time
Tn-t.
The current effective value of s will be assigned to s_dyld after 5 ns in this case. The current value of s (Now = 0 ns) is the default value ('1').
Your process is only going to get invoked once because of the wait statements (the last one wait ;).
The equivalent sequential signal assignment statement is
s_dyld <= transport s after 5 ns;
You can assign s_dyld in a separate process sensitive to s or as a concurrent signal assignment statement or restructure your current wait statement with more waits and more s_dyld assignments.

Why a delay of 1 clock period in simple counter

Below is a simple 3-bit counter.
When reset(rst) is 0, counter value is "000", else it increments by 1 for rising edge of each clock.
LIBRARY ieee;
USE ieee.std_logic_1164.all;
use IEEE.std_logic_unsigned.all;
use IEEE.numeric_std.all;
---------------------------------------------
ENTITY counter IS
PORT (clk : IN STD_LOGIC;
rst : in std_logic;
digit : out std_logic_vector (2 downto 0)
);
END counter;
---------------------------------------------
ARCHITECTURE counter OF counter IS
BEGIN
count: PROCESS(clk,rst)
VARIABLE temp : std_logic_vector(2 downto 0);
BEGIN
IF (clk'EVENT AND clk='1') THEN
if (rst = '1') then
temp := temp + "001";
else
temp := "000";
END IF;
END IF;
digit <= temp;
END PROCESS count;
END counter;
Below is the simulation result I got :
In the result, output is correct. But there is an one clock delay between the time rst = 1 and output='001'. ie counter doesn't increment instantaneously when rst = '1'.
As per my understanding, whenever a change in clk or rst happens, process is executed. So when rst changes from low to high, an event occurs. Process checks if rising edge of clk, YES. Then check if rst = 1, YES. So normally counter has to increment in that clk itself. But it doesn't.
Questions:
Why one clock period delay between reset = 1 and output = 001?
And what is wrong in my understanding?
The most likely cause in that "rst" is generated by a clocked process, clocked by the same "clk" signal.
So "rst" occurs one delta cycle after "clk". When "rst" changes it will wake the process up, but "clk'event" was on the previous delta cycle, therefore the "if" statement will not execute.
On the next clock edge, rst = 1 so the counter works as expected.
Three minor points:
it would be worth naming the reset signal rst_n to make it clearer that it is an
active-low reset!
rst really doesn't need to be in the sensitivity list
there is no need for parentheses around the boolean expressions
(Disclaimer: It's been long time since I programmed in VHDL, so this only answers to generic logic design.)
Anyway, one can't expect the result of addition to be ready immediately when a process is triggered. The point is, that calculating even the first bit of 000 + 001 is affected by the propagation delay equivalent to one xor operation. The second bit is calculated from the first bit's carry (if both bits were 1) and xor operation of the second bits. And so on.
If one would probe the 'temp' variable asynchronously, one would see something like this:
^ ________________
result_bit_0 __________|
0123456789
_____________
result_bit_1 ^ |____________
0123456789
____________ _____
result_bit_2 ^ |_| |________
0123456789abcde
________
clock: ________| |______|
The figure tries to illustrate in more detail the waveforms of a generic add operation.
At time 0 the process of adding is started.
After a small delay '2' the first bit stabilizes to 1.
At time '5' the second bit stabilizes to 0 and at time '9' the third bit stabilizes to 0.
But also it's quite common, that as in result_bit_2, the output toggles between various states.
It's the total / maximum delay of each temporary variable to take to stabilize, that determines the minimum clock period. At this case the time instant 'e' is that one, where we have decided that the result of counter increment is available.
Still, from the perspective result (which is a vector), everything happens instantly at the next clock cycle.
the "issue" is in the way you have described your "rst".
The way you did it would result in a "synchronous" reset, i.e. the reset would take effect only after a rising edge of the clock.
In general this is just a matter of coding style/preferences.
I usually prefer asynchronous reset (with maybe a reset synchronizer at top-level to avoid meta-stability when releasing the reset), but there is nothing wrong in adopting a synchronous reset approach.
In case of an asynchronous reset, you would need to change your code to something like this:
PROCESS (clk, rst_n) BEGIN
IF rst_n = '0' THEN
...
ELSIF rising_edge(clk) THEN
...
END IF;
END PROCESS;

Resources