Synchronize to posedge of clock - system-verilog

Is there any way to interrogate whether the simulation is at the #(posedge clk) event aside from using a named event that's triggered at the same time?
With the following code, I can make sure that I only do stuff at the posedge of a clock:
module tb;
bit clk;
always #2 clk = ~clk;
event pos_clk;
always #(posedge clk)
-> pos_clk;
initial begin
// stuff happens
#(posedge clk);
$display("[%0d] #(posedge clk)", $time());
// control is passed asynchronously to some task
// - since it's already at a posedge, it doesn't need to wait
some_task();
// other stuff happens
#1;
$display("[%0d] #1", $time());
// control is passed asynchronously to some task
// - since it's not at a posedge, it needs to catch the next one
some_task();
$finish();
end
task some_task();
wait (pos_clk.triggered);
$display("[%0d] wait (pos_clk.triggered)", $time());
// do relevant stuff
endtask
endmodule
Is there some other way I could do this without the extra named event?

This is what the ##0 construct does (See section 14.11 Cycle delay: ## of the 1800-2012 LRM). You do have to define a default clocking block, which means your task has to be defined inside a module or interface
module tb;
bit clk;
always #2 clk = ~clk;
default clocking cb #(posedge clk)
endclocking
initial begin
// stuff happens
#(cb) // when using clocking blocks, only use the clocking event
$display("[%0d] #(posedge clk)", $time());
// control is passed asynchronously to some task
// - since it's already at a posedge, it doesn't need to wait
some_task();
// other stuff happens
#1;
$display("[%0d] #1", $time());
// control is passed asynchronously to some task
// - since it's not at a posedge, it needs to catch the next one
some_task();
$finish();
end
task some_task();
##0;
$display("[%0d] wait (pos_clk.triggered)", $time());
// do relevant stuff
endtask
endmodule
My advice would be not to do either and figure out a way to keep the activation of some_task synchronous.

Related

Changing clocking block clock polarity on the fly

I am creating UVM VIP which is able to switch its clock polarity. Clocking block is used in the interface.
For example, a monitor should sample the data using posedge or negedge of incoming clock depending on UVM configuration - and this polarity change can happen on the fly.
This can be implemented as follows:
// In the interface, two clocking blocks are defined
// one for posedge (passive_cb), one for negedge (passive_cbn).
task wait_clock_event();
if (cfg.pol == 0) #vif.passive_cb;
else #vif.passive_cbn;
endtask
task sample_data();
if (cfg.pol == 0) pkt.data = vif.passive_cb.data;
else pkt.data = vif.passive_cbn.data;
endtask
task run();
wait_clock_event();
sample_data();
endtask
This seems to work but waste code lines and prone to error.
Is there any better solution?
Assuming the monitor has exclusive access to the clocking block, you could consider modifying clocking event in the interface with the iff qualifier.
bit pol;
clocking passive_cb #(posedge clk iff !pol, negedge clk iff pol);
input data;
endclocking
There is a potential race condition if pol changes in the same timestep as the target clock polarity.
Your monitor code would then include a set function and other tasks can be simplified to us only one clocking block.
function void set_vifcb_pol();
vif.pol = cfg.pol;
endfunction
task wait_clock_event();
#vif.passive_cb;
endtask
task sample_data();
pkt.data = vif.passive_cb.data;
endtask
task run();
set_vifcb_pol();
wait_clock_event();
sample_data();
endtask

Defining generated clock as synchronous in RTL simulation

I am generating a divided clock, something like this:
logic div_clk;
always_ff #(posedge clk or negedge rstb) begin
if(!rstb) div_clk <= 1'b0;
else div_clk <= !div_clk;
end
I then launch data on clk and capture on div_clk. Something like this:
always_ff #(posedge clk) begin
clk_data <= something;
end
always_ff #(posedge div_clk) begin
div_clk_data <= clk_data;
end
In my simulations I am getting a race condition since clk_data updates coincident with div_clk and the div_clk_data gets the wrong value.
In synthesis I define these two clocks to be synchronous by creating a generated clock:
create_clock -name CLK [get_ports clk]
create_generated_clock -name GEN_DIV_CLK -source [get_ports clk] -divide_by 2 [get_pins div_clk]
Is there something equivalent that I can put into my RTL, or something I can do to tell my simulator that div_clk is synchronous to clk and prevent the race condition from happening?
This is a case where NBA's should not be used. You should not have any NBA's in your clock tree (including gated clocks) if you want the clocks to remain synchronous.

system verilog expect behavior

I tried using expect with the following property
module tb;
logic a;
logic clk=0;
default clocking #(posedge clk); endclocking
always
#5ns clk = ~clk;
initial begin
$dumpfile("dump.vcd"); $dumpvars;
$display("START");
a = 0;
#100ns;
a = 1;
#100ns;
$finish;
end
initial begin
#10ns;
expect(#(posedge clk) 1 ##1 $changed(a) |-> 1) $display("SUCCESS"); else
$display("FAIL");
end
endmodule
Is the expect going to block until a change from 0 to 1 at 100ns ?
No, it will block until the second (posedge clk), regardless of the value of a, and will always pass.
The expect statement does not start evaluating the property until the first clk edge. The antecedent takes two cycle to either match or not match. Since the consequent is always true, the property passes on match. If there is no match, the property also passes, vacuously.

What is the difference between #(posedge clk) begin end.... and #(posedge clk);?

What is the difference between:
1
forever begin
**#posedge(clk) begin**
if(vif.sof == 1) begin
//some code here
end
end
end
2
forever begin
**#posedge(clk);**
if(vif.sof == 1) begin
//some code here
end
end
Does the begin..end that goes with #(posedge clk) make a difference ?
event_controls like # and # in procedural code are not statement by themselves; they are prefixes to the statements that follow. And a statement can be a simple statement, like an assignment, or a block like begin/end or fork/join. And a block is allowed wherever a single statement is allowed.
When you write #(posedge clk); it is really #(posedge clk) null_statement;
I should have given you enough information to answer your question, but here is another variation:
forever
#posedge(clk)
if(vif.sof == 1) begin
//some code here
end
Now there is a big difference if a semicolon follows #(posedge clk) or not.

SV assertion based on event trigger

Assume SV interface contains a concurrent assertion property.
Is it possible to enable this assertion only when an event is triggered? I tried writing property inside a task in interface file, but I ended up with error: near "property": syntax error, unexpected property.
Interface intf;
task e1();
-> e1;
endtask
wait(e1.triggered); // something like this, where property waits for trigger
property prop1;
#(posedge clk) a ##1 b;
endproperty
endinterface
Thank you.
I think you need to consider that properties are best written synchronously and are evaluated on every clock cycle. You property says that one cycle after every clock cycle where a occurs b occurs. I guess what you're after is something like:
if e1 occurs, then a should be true (on the next rising edge of
clk?) and then b should be true on the rising edge of clk after
that
So, one way of doing that would be to create an always block that generates a pulse one clock wide should e1 occur, eg:
always begin
#(e1);
#(posedge clk) e = 1'b1;
#(posedge clk) e = 1'b0;
end
property prop1;
#(posedge clk) e |-> a ##1 b;
endproperty
or some variation of that. I feel like I should be worried about races, however.