Skip to main content

Waiting on clocking block signals

Its a good practice to use the clocking blocks for creating verification components.

There are some scenarios, where you have to wait on change on some values. As an example, when DUT drives the valid signal, in monitor you wait for valid signal and then read other signal on next clock.

Lets say the DUT drives a valid signals and in your monitor you have to wait till valid is high and wait for two clocks. Then in your montior, you do something like this:

wait (interface.cb.valid == 1'b1);
@interface.cb;
@interface.cb;

What do you expect?
when valid happens, then wait for two clock cycles. But this may not happen. the first wait and then @interface.cb may happen in same cycle.
This is because the clocking block events are synchronous. The wait and the @() statement will execute in same delta.

Instead, the best way is to use this:

@(tif1.cb iff tif1.cb.data);

In this way, you wait every clock only if the cb.data is high.

Code: https://www.edaplayground.com/x/5Cev


interface tif(input clk);

logic data;

clocking cb@(posedge clk);
input data;

endclocking

endinterface

module test;

reg clk;
tif tif1(clk);

initial begin
    tif1.data = 1'b0;
    #12;
    tif1.data <= 1'b1;
end

initial begin
    //wait(tif1.cb.data == 1'b1);  //This happens on 15ns. (12ns assignment. 15ns on posedge of clock)
    @(tif1.cb iff tif1.cb.data);
    $display("[%t]:: After waiting for cb.data",$time); //Here time is 15ns.
    @(tif1.cb); //Expect this to happen at next clock edge
    $display("[%t]:: After waiting for cb",$time); //Here time is 15ns. //expect the time here to be 25ns. one posedge later.
end

initial
begin
#1000 $finish;
end
initial
begin
    clk <= 1'b0;
    forever
    begin
        #5;
        clk <= ~clk;
    end
end
endmodule

Be careful with when using @(clocking_block). This is not same as @(posedge clk)

  1. All samples and drives to clocking block inputs and outputs respectively must be synchronized to the clocking block event (cb). Do not use any other events or waits other than @cb or @(cb iff signal==1)
  2. The clock event used to trigger the clocking block must not come from a program. (we do not recommend using program blocks anyways)
  3. Once you start using clocking blocks in an interface, do not reference those signals from anything other than the clocking block in your testbench.

Comments

Popular posts from this blog

Verdi Uses - I

COVERAGE While going through some of the blog posts, i found that the Verdi supports even coverage right out of the box, but from the 2014 Version. Well till now, we relied on the URG reports and the DVE to review the coverage and apply waivers and create exclusion files. Looks verdi supports all the features.. I did not get any hands on the features of this option, soon i will find some time to play around with this option of coverage in Verdi. How to launch the verdi with coverage. $> verdi -cov -covdir <PATH_TO_TB>.simv.vdb -covdir <PATH_TO_TEST1>.simv.vdb -covdir <PATH_TO_TEST2>.simv.vdb...  You can pass multiple covdirs, where in all the results will be merged. References: SYNOPSYS SITE Think Verification  

Sequence Layering in UVM

What is Sequence Layering? Sequence layering is refered to as running sequences inside sequences.  So whats the big deal. There are virtual sequences we will use to run multiple sequences. A generic example of sequence layering. you have two sequences  Interrupt sequence register read write sequence. Generally when you have interrupt, we generally enter into interrupt service routine, which can be implemented as an interrupt sequence. So when you run an interrupt sequence, you might end up running register read /write sequence like polling or clearing interrupts. Well thats easy, just run one sequence in another. class top_seq extends uvm_sequence#(txn_item); //Two sequencers say.. sub sequences. sub_seq1 seq1; sub_seq2 seq2; ... task body(); seq1.start(some_seqr); seq2.start(some_seqr2); endtask endclass Killing sequences: That was great you are running nested sequences. But how to kill them when needed. UVM provides method cal

SystemVerilog: Mailboxes and Queues

Mailboxes and queues are couple of basic data constructs of system verilog language. Lets get to the definition of them: Queue: A Queue in system verilog function as the name suggests. But with a twist. Queue in system verilog is a list of similar elements. Queue is built on top of an array. Delcaration of a queue. < TYPE > < que_name >[ $ ]; Default Behaviour: The default size of the queue in system verilog is " Infinite ". The above declaration will create a que of infinite length. You can add elements to the que until your simulator crashes :) What if you want to create a queue of finite length. Just look at the declaration below: < TYPE > < que_name >[ $ :< LIMIT >]; The above declaration will create a queue of size " LIMIT+1 " Initializing queue with elements Accessing elements of a queue Methods in queue Inserting elements into queue Reoving elements from queue http://www.project-veripage.com/queue_1.ph