SystemVerilog wait() statement - verilog

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.

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.

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;

System verilog/verilog ---events

task monitorPush();
begin
bit [7:0] data = 0;
while (1) begin
# (posedge intf.clk);
if (intf.cb.wr_cs== 1 && intf.cb.wr_en== 1) begin
// # (posedge intf.clk);
data = intf.data_in;
sb.addItem(data);
$write("%dns : Write posting to scoreboard data = %x\n",$time, data);
end
end
end
endtask
How is the above code different from below code? As in how does shifting posedge clock from line 5 to 7 change the code? Thanks in advance
task monitorPush();
begin
bit [7:0] data = 0;
while (1) begin
// # (posedge intf.clk);
if (intf.cb.wr_cs== 1 && intf.cb.wr_en== 1) begin
# (posedge intf.clk);
data = intf.data_in;
sb.addItem(data);
$write("%dns : Write posting to scoreboard data = %x\n",$time, data);
end
end
end
endtask
The #(posedge intf.clk) waits for the posedge of the clk then continues execution.
Version 1 of your code waits for a clk (posedge) then performs the if statement.
Version 2: In the case of the failing if statement will execute continuously, inside the while true block, until the if becomes true then you will wait for the clk posedge.
In Version 2 you have the possibility of being stuck in a infinite loop because the simulator will get stuck evaluating the while loop and the if statement and won't switch to executing other parts of your code. In Version 1 the #(posedge intf.clk) will let the simulator jump to other parts of the code. In short, go with Version 1.
Version 2) will hang your simulation because you don't have an else condition for the if.
From the moment the monitor function is called and the first encounter of wr_cs/wr_en being zero will get stuck in the while(1) infinite loop as there is no else condition nor any timing event.
Version 1 is the right way to use.
Most of the times your control and data signals change with respect to clock.
In Version 1), you will sample the data for score board on the clock edge when the CS/WEN goes high
In version 2), you will sample the data one clock after the wr_cs/wr_en goes high.(as you wait for clock after seeing them high) You might end up getting a wrong data.

Resources