systemverilog comparing two ways to wait signal; 1) #( clock iff condition), 2) while( ! condition) #(clock); - system-verilog

I am looking for some intuitive understanding of systemverilog method of waiting for certain signal on the interface for 1) capturing transaction in a monitor, or 2) driving a transaction in response to some signal from DUT. Let's assume that DUT is asserting ready signal and driver has to drive two data beats (values of 1 and 2) back to back while asserting valid signal so that DUT would know when to capture data.
There are two methods of waiting for the ready single from the DUT that I know of; 1) one is iff conditioned clock event, and the other is 2) consuming clock while some signal is not true (e.g., ready is low). The testbench code can be found EDA playground (line 37 of my_driver.sv).
The first method is using #(posedge dut_vif.clock iff(dut_vif.ready == 1));
and the second method is using while( ! dut_vif.ready) #(posedge dut_vif.clock); and there is single clock difference between two methods as shown in the waveform. My best understanding is --
#(posedge dut_vif.clock iff(dut_vif.ready == 1));
This method is waiting for the clock rise event 'on the condition' of ready == 1. Therefore, data and valid are driven high on 25ns.
while( ! dut_vif.ready) #(posedge dut_vif.clock);
On the other hand, this statement means that simulation should consume clock while ready is low. However this interpretation and the actual behavior of systemverilog is very different. At 15ns, ready signal goes high and the valid and data are driven at the same cycle. My understanding is that at 15ns, the ready should be still captured as low by the testbench, and simulation should consume one clock. Therefore, the second method should behave just like the first method.
Can I get some interpretation on how to make sense of this difference?
I am attaching waveform here.

The issue is because of hidden delta delay inside the call to get_next_item() Even though the time is still at 15, counter and thus ready now have their new values after returning from the call. Using iff gives you a clearer sampling of values w.r.t the clock edge. It also avoids problems when !ready is x because that evaluates to false.

#(event iff (expression));
is equivalent to
do #event; while (!expression);
not
while (!expression); #event;
as Dave mentioned at here, maybe he forget it. That's why you missed one clock cycle.

Related

Gate-level timing checks in SVA

I need to check the value of a signal after a certain amount of time a clock edge occurs. For example, I want to check that if signal b asserts to high 1ps after posedge clock occurs.
Does SVA provide a syntax for this?
system-verilog-assertions were not intended for use as gate-level timing checks. Verilog already provides a number of built-in and optimized timing checks like $setuphold and $skew. See section 31. Timing checks in the IEEE 1800-2017 SystemVerilog LRM.
Timing checks are usually expressed as limits—either assertion happens at least 1ps after the clock edge, or at most 1ps after the clock edge. Also, must b be asserted after every clock edge? Regardless of the answers to these questions, it's possible to use SVA to model timing check, but you will have to manually create equations based on the actual requirements. For example
property p;
realtime timestamp;
#(posedge c) ($rose(a), timestamp = $realtime) |=>
#(posedge b) $realtime - timestamp < 1ps;
endproperty

assertion for holding the reset for a long time

I see that assertions are always related to n number of cycles of a clock. Is there any way I can check the duration wrt timescale? Meaning
let's say I want to check if a reset is hold for 100ns or less, how do we write a assert statement for this?
Yes, conceptually you can write an assertion like this, using local variables in SVA.
It may look like this :
property reset_chk;
time current_time;
#(rst) (~rst, current_time = $time) |=> ($time - current_time == 100);
endproperty
But this type of assertions, should be avoided, as they are written not wrt clock.
Alternatively, one can always make a reference clock, fast enough to accommodate any such signal timings.
For local variables in assertion, you can read Local Variables in SVA
First I would consider whether SVA was the best way to check this at all.
If you think so, how about creating a dummy clock in the testbench with a suitable period and (via the power of hierarchical naming) use that. A suitable period might be
100ns if you were looking for a minimum pulse width
much faster if you were looking for a maximum pulse width (eg a 10ns period would allow you to check the pulse width was less than 110ns, ie 11 cycles).
Assertions are best done synchronously. That doesn't mean you cannot check asynchronous things, but you still need to sample the signals in question synchronously. So, this way you are sampling your asynchronous signal synchronously, using your dummy clock.
This is asynchronous check. The best way is to check it in traditional way or pure systemverilog instead of using SVA concurrent assertion.
If you want, you can still add immediate assertion for coverage purpose.
Quick sample code:
//
task assert_reset_hold_100ns();
fork : fk1
begin : blk1
#(reset);
$fatal;
end
begin : blk2
#100ns;
ASSERT_RESET_HOLD_100NS: assert(1);
end
join_any
disable fork;
endtask
// checker
initial forever begin
wait(reset === 0);
assert_reset_hold_100ns();
wait(reset === 1);
end
//

How to initialize clocking block signals at reset

I've been reading through UVM: illegal combination of driver and procedural assignment warning and paper attached in answer.
(Please consider paper linked in the question mentioned)
However drivers are implemented to drive reset values on interface signals instead of on clocking block signals, the clock is not guaranteed to be running at reset.
So how can I go about this scenario if interface signals are declared wires.
for e.g.
consider the code in linked question. General scenario would be
#(vif.cb);
vif.cb.opcode <= value;
This is correct even if opcode is declared net in interface cause clocking block will take care of correct assignment. However I can't say
#(vif.rst);
vif.cb.opcode <= init_value;
since I can't guarantee clock at reset. To accommodate this I'll have to change clock generation strategy.
Neither can I say
vif.opcode <= init_value;
cause its illegal to use procedural assignment with net type signals
The other way is gating signals declared as net with reset but I think for that I'll have to declare temporary signals in interface. Can anyone elaborate how can I achieve driving nets at reset ?
While it's illegal to assign nets from procedural code, it's legal to force values onto them. You can do the following:
#(negedge vif.rst);
force vif.opcode = 0;
Bonus: IMO you shouldn't have opcode defined as a wire. The illegal combination of procedural and continuous driver warning is wrong. The SV 2012 standard clearly states in 14.16.2 Driving clocking output signals:
It is possible to use a procedural assignment to assign to a signal associated with an output clockvar. When
the associated signal is a variable, the procedural assignment assigns a new value to the variable, and the
variable shall hold that value until another assignment occurs (either from a drive to a clocking block output
or another procedural assignment).

How do I compare two signals whose edges are almost in the same place?

I am verifying part of a design which generates pulses with precisely timed edges. I have a basic behavioral model which produces an output which is similar, but not exactly the same as the design. The differences between the two are smaller than the precision needed for the design, so my model is good enough. The problem is: how do I do a comparison between these two signals?
I tried:
assert(out1 == out1_behav);
But that fails since the two signals have edges which happen 1ps apart. The design only requires that the edges be placed with 100ps precision, so I want a pass in this situation.
I thought about using a specify block with $delay() timing checks, however this causes me other problems since I need to run with +no_timing_checks to keep my ram models from failing in this RTL sim.
Is there a simple way to check that these edges are "almost" the same?
With the design requirement for the the signals to match within 100ps you could add a compare logic will a 100ps transition delay to act as a filter.
bit match;
assign #100ps match = (out1 == out1_behav);
always #*
assert #0 (match==1);
Verilog has different ways of assigning delay: transition and transport. Transition delays control the rise, fall, and indeterminate/high-Z timing. They can act as a filter if a driving signal gives a pulse less then the delay. Transport delays will always follow the the driving signals with a time shift. When the delays are large transition and transport will look the same.
assign #delay transition = driver; // Transition delay
always #(rhs) transport <= #dealy driver; // Transport delay
example: http://www.edaplayground.com/s/6/878, click the run button to see the waveform.
If you are using Modelsim/Questa, you can still use +notimingchecks, and then use the tcl command tchech_set to turn on individual timing checks, like $fullskew
Otherwise you will have to write a behavioral block that records the timestamps of the rising and falling edges of the two signals and checks the absolute value of the difference.

Simulink: How to convert event based signal with zero duration values to a time based signal without losing information

I have a matlab function block (which is not relevant) whose input is his previous output (loop). For example, if in a sample period the output is X, his input in the next sample period will be X, and so on.
This image shows a simplification of my simulation. I initialize the input of my function for the first loop.
The problem is that matlab functions recieves an event based signal from de initialization block in the first sample period (zero-duration), which I must convert to a timed based signal (so I can apply the unit delay that avoids an inifite loop, and allows to generate the next input as explained before). So, when I do so, I lose the information contained in the event-based signal (due to the zero-duration values) and the loop does not work.
If there was a way to intialize the loop in the time-based domain (green part of the image) so, in the first sample time, it is not a zero-duration signal, it would avoid the problem.
Is there any way to do so? Or, a different approach for this problem?
Two approaches come to mind
The initial condition can be set in the Unit Delay block, so it's not clear from your simplified example why you need the specific Initialization block.
You could just use a persistent variable inside the MATLAB Function block to maintain the state from one execution of the block to the next (noting that since it is event driven the block may not get called at every time step, only at each event triggger).