Triggering Covergroup Sampling via SVA

Hi All ,

The intention of below code is to sample a coverpoint variable via an event triggered via SVA


   event  cg_trig ;

   bit    clk , SOP , EOP ;

   bit [3:0]  framelength ;

   covergroup  frame @( cg_trig ) ;

     coverpoint framelength ;  //  Generated  16  Auto bins !!

   endgroup

   function  void  trigger_cg ( input int length ) ; // input  Arg.  Same  type  as   Actual  Arg.  i.e  Local  variable ' cnt '

      framelength  = length ;  

      -> cg_trig ;             //  Trigger  Covergroup  Sampling 

   endfunction
   
  sequence  Detect_EOP;
     int  cnt ;
    
    ( 1 , cnt = 1 )  ##1 ( 1 , cnt++ )[*0:$]  ##1 ( $rose( EOP ) , $display("cnt is %0d ", cnt ) , trigger_cg( cnt ) )  ;
   
   endsequence

   property  SOP_2_EOP ;
     
     @( posedge clk )   $rose( SOP ) |->  Detect_EOP ;

   endproperty
   
     initial   forever  #5  clk  =  !clk ;
  
   frame  inst  = new () ;  //   Instantiate  the  Covergroup  !!
  
   assert  property ( SOP_2_EOP )  $display("Property  PASSes  at  %0t " , $time ) ;

   initial  begin
     
     #4  ; SOP  = 1 ; 

     #50 ; EOP  = 1 ;

      #6 ;
      $finish() ;
   end


With proper stimulus the code works fine , however I wanted to know if there is any alternative way to trigger the covergroup event ?

One possible solution is triggering from Pass action block

In above code the event is triggered from subroutine , can it be triggered from Sequence directly ?

In reply to Have_A_Doubt:

What you are doing is OK. You can also use the endpoint of a sequence.
For example,


// BAD: DO NOT USE .triggered, use the @(sequence_name)
// But a better approach is to have support logic generate the sampling trigger event
   covergroup  frame @(Detect_EOP.triggered ) ; ...
   sequence  Detect_EOP; ...

After further thoughts, it was a mistake to allow the trigger of the covergroup to also be @(seqquence_name).
The regions at which variables are updated affect the outcome.
One should not think of "regions"when writing code.

In reply to ben@SystemVerilog.us:

Thanks Ben ,

Need a little help with the following code :: Seq_Triggered

I observe the following ::

(1) Display statement "1st cnt at … " executes multiple times whereas the expectation is for it to be executed only once

(2) Although cnt is 5 , bin auto[0] is covered i.e value of framelength of 0 is being hit instead of value 5 .

**( Using  event  triggering  bin auto[5]  is  covered  )**

In reply to Have_A_Doubt:

  1. The .triggered can be used as a trigger for the cover group, but this is not going to work in this case because the framelength is computed within the sequences, and it’s value needs to be copied to the module variable.
  2. The reason Display statement "1st cnt at … " executes multiple times is because at every clocking event (the posedge clk) you start a new independent thread for the evaluation of the sequence Detect_EOP.
  3. On the multiple times, the issue is that you have a new thread at every clocking event.
# KERNEL:  1st cnt at 5 // First thread
# KERNEL: Property  PASSes  at  15 // 2nd new thread is vacuous (not a $rose(SOP))
// The PASS action block is displayed, assertion is vacuously TRUE
# KERNEL: Property  PASSes  at  25  // 3rd new thread is vacuous
# KERNEL: Property  PASSes  at  35  // 4th new thread is vacuous
# KERNEL: Property  PASSes  at  45  // 5th new thread is vacuous
# KERNEL: cnt is 1   // First thread is nonvacuously TRUE
// "cnt is 1" message is not the same as "1st cnt at" message
# KERNEL: Property  PASSes  at  55 // First thread passes nonvacuously
# KERNEL: Property  PASSes  at  55 // ?? don't know why the repeat here
#

Read my paper Understanding the SVA Engine (item 3 below)
Ben Cohen
http://www.systemverilog.us/ ben@systemverilog.us
** SVA Handbook 4th Edition, 2016 ISBN 978-1518681448

  1. SVA Package: Dynamic and range delays and repeats SVA: Package for dynamic and range delays and repeats | Verification Academy
  2. Free books: * Component Design by Example FREE BOOK: Component Design by Example … A Step-by-Step Process Using VHDL with UART as Vehicle | Verification Academy
  1. Papers:

Udemy courses by Srinivasan Venkataramanan (http://cvcblr.com/home.html)
https://www.udemy.com/course/sva-basic/
https://www.udemy.com/course/sv-pre-uvm/

In reply to ben@SystemVerilog.us:

Although cnt is 5 , bin auto[0] is covered i.e value of framelength of 0 is being hit instead of value 5 .
My guess is the SVG evaluation timing regions. Try the following and let me know what you get.


task trigger_cg (int length ) ; // input  Arg.  Same  type  as   Actual  Arg.  i.e  Local  variable ' cnt '
 
      framelength  = length ;  
      #1; // Delay to bring the value of framelength stable in a new evaluation cyle 
      -> cg_trig ;             //  Trigger  Covergroup  Sampling 
   endtask

In reply to ben@SystemVerilog.us:

Hi Ben ,

With the delay of #1 and using covergroup frame @( cg_trig ) , auto[5] is covered

A few questions regarding the previous reply

(1)

this is not going to work in this case because the framelength is computed within the sequences, and it’s value needs to be copied to the module variable.

Won’t ( Detect_EOP.triggered ) return 1’b1 only when the sequence completes ?
i.e function trigger_cg would have been called ( framelength would be updated with cnt 5 ) before the sequence completes

(2) Regarding the vacuous pass reporting when $rose(SOP) is false .

Does the LRM discuss this part ? i.e Pass action block being executed when antecedent is false OR it depends upon tool ( 2 tools I tried don’t report the Vacuous pass )

In reply to ben@SystemVerilog.us:

I updated the eda link :: edacode

The updated value of framelength via function trigger_cg isn’t reflected at the additional $display report at the end of the sequence as it’s preponed value is 0

Seems like tool issue since the $display() aren’t reported from left to right which impacts the value sampled .

In reply to Have_A_Doubt:

On item 1, I am asking some colleagues about it.
On item 2, The pass action block is active on any pass: Vacuous or nonvacuous.
A tool may have simulation switches to suppress the pass action block messages.

In reply to ben@SystemVerilog.us:

The PDF summarizes the results.
The event trigger works as expected.
The sequence_name.triggered or the @sequence_name does not provide the correct result.
I think it’s a race condition as to when the module var gets updated and when the trigger for the covergroup occurs

http://SystemVerilog.us/vf/coverpnt.sv






module  Cov_Trigger;  
   event  cg_trig;
   bit    clk, SOP, EOP;
   bit [3:0]  framelength;
   
   sequence  Detect_EOP;
     int  cnt;     
    @(posedge clk)
    (1, cnt = 1, $display(" 1st cnt at %0t ", $time))  ##1 
    (1, cnt++)[*0:$]  ##1 
    ($rose(EOP), $display("TIME:%0t cnt is %0d ", $time, cnt), trigger_cg(cnt)) ##0 
    (1, $display(" framelength  is  %0d ", framelength));
   endsequence 

  covergroup  frame @(cg_trig) ;  // line 15
    coverpoint framelength ;  //  Generated  16  Auto bins !!
  endgroup 
 
   /* covergroup  frame @(Detect_EOP.triggered); 
     coverpoint framelength;  //  Generated  16  Auto bins !! 
   endgroup */ 
 
   function void trigger_cg (input int length); // input  Arg.  Same  type  as   Actual  Arg.  i.e  Local  variable ' cnt '
     $display(" Within  function  trigger_cg "); 
      framelength  = length;  
     $display(" Within  function  trigger_cg, framelength  is  %0d ", framelength);
     -> cg_trig;         //  Trigger  Covergroup  Sampling 
   endfunction
 
  
 
   property  SOP_2_EOP; 
     @(posedge clk)   $rose(SOP) |->  Detect_EOP; 
   endproperty
   assert  property (SOP_2_EOP)  $display("Property  PASSes  at  %0t ", $time);

In reply to ben@SystemVerilog.us:

Errata and clarification
A colleague pointed out ot me why the use of sequence_name.triggered is
incorrect in triggering a covergroup.


covergroup  BAD_frame @(Detect_EOP.triggered); // BAD USE for the trigger 
     coverpoint framelength;  //  Generated  16  Auto bins !! 
endgroup

covergroup  GOOD_frame @(Detect_EOP); // GOOD use of sequence_name for the trigger 
     coverpoint framelength;  //  Generated  16  Auto bins !! 
endgroup 
 
  1. @(sequence.triggered) is not correct even though the compiler might accept it. It is a boolean briefly tru in the observed region. That is, it should trigger twice in the observed region, one on posedge and the other on negedge.
    The method seq.triggered is a Boolean, used either in the body of a sequence or w.g., wait statement. see e.g. 15.5.5.2 for an event E1.
    As Boolean it becomes true when the sequence matches and then becomes false at the end of the Observed region (or Reactive region, need to check 1800). In other words @(seq.triggered) should see two events due to the change from false to true and for true to false. Using it as an event is incorrect and @(seq) should be used, i.e. sensitive to the event of the match.
  2. @(sequence) triggers by the event corresponding to the match of sequence.

function void trigger_cg (input int length);
framelength  = length;
-> cg_trig;         //  Trigger  Covergroup  Sampling
endfunction
  1. The reason why triggering the covergroup by the sequence samples framelength of 0 is that the natch of the sequence occurs in the observed region which triggers the covergroup in the next round of active region execution or in the reactive region (not sure which but it does not matter. The task evaluation is scheduled in the reactive region - see clause 16.11.
    This means that it executes after the covergroup does its sampling. Therefore, framelength is still 0.
    If you use trigger an event in the function (or task) which then causes the cg to sample, it executes after framelength is assigned, hence cg sees the expected value.

In reply to ben@SystemVerilog.us:

Thanks for the detailed explanation Ben .

(1) Via @( Detect_EOP ) some tools correctly sample auto[5] while others still cover auto[0] unfortunately .

An alternative would be calling sample() function from the subroutine ( instead of triggering the event in subroutine )

This would mean there is no sampling event defined for covergroup i.e covergroup frame ;

(2)

Therefore, framelength is still 0.

LRM 16.11 mentions :: " Assertion evaluation does not wait on or receive data back from any attached subroutine. "

Does this mean the display at the end of the sequence ( "framelength is %0d " ) execute ( in Observed Region ) before the function ’ trigger_cg ’ is called ( in Reactive Region ) ?

( Although the subroutine call appears before the $display )

In reply to Have_A_Doubt:
If you have to worry about the event regions to correctly trigger a covergroup, then something is wrong in the methodology or approach. On
(1) Via @( Detect_EOP ) some tools correctly sample auto[5] while others still cover auto[0] unfortunately.


sequence  Detect_EOP;
     int  cnt;     
    @(posedge clk)
    (1, cnt = 1)  ##1 (1, cnt++)[*0:$]  ##1 
    ($rose(EOP), trigger_cg(cnt));
   endsequence
function void trigger_cg (input int length);   
    framelength  = length;  
    // -> cg_trig;         //  Trigger  Covergroup  Sampling 
endfunction
covergroup  GOOD_frame @(Detect_EOP); // GOOD use of sequence_name for the trigger 
     coverpoint framelength;  //  Generated  16  Auto bins !! 
endgroup 
 

1800: “The subroutines are scheduled in the Reactive region, like an action block.”
The way I see this is that the function is called in the Reactive region.
Thus at the endpoint of the assertion that uses that sequence, the triggers the
covergroup GOOD_frame @(Detect_EOP) occurs in the Observed region because of the @(Detect_EOP).
Following that trigger the function is called, and that function updates the framelength.
Thus, the value of the capture framelength is 0, set at the declaration by default.

An alternative would be calling sample() function from the subroutine ( instead of triggering the event in subroutine )
This would mean there is no sampling event defined for covergroup i.e covergroup frame ;

Yes, that is a better approach.
I did this in my paper SVA for statistical analysis of a weighted work-conserving prioritized round-robin arbiter.
https://verificationacademy.com/forums/coverage/sva-statistical-analysis-weighted-work-conserving-prioritized-round-robin-arbiter.


function automatic void setdelay(int delay, k);
        req2grant[k]=delay;
        cg_inst.sample();   // for covergroup
    endfunction

     property p_req2grant_delay; // Used to count the cycle delays 
        // from each req to each corresponding grant 
        // At the grant, the function call provides the sampling of the covergroup
        int delay;
        @(posedge clk) ($rose(req[j]), delay = 1)  |->  ##1 
           (!sc_grnt[j], delay++)[*0:$] ##1
           (sc_grnt[j], setdelay(delay, j)); 
     endproperty 

1800 addressing the triggering of the covergroup. I would hate to have to think about the inner-workings of SV regions to get the trigger correctly. Sorry!


// 17.6 Covergroups in checkers 
    bit [3:0] opcode_d1; 
    always_ff @(posedge clk) opcode_d1 <= opcode;
    
    covergroup cg_op; 
      cp_op : coverpoint opcode_d1;
    endgroup: 
    cg_op cg_op_1 = new(); 
    sequence op_accept; 
      @(posedge clk) vld_1 ##1
       (vld_2, cg_op_1.sample()); 
    endsequence cover property (op_accept);
    
    /* endchecker In this example, the coverpoint cp_op refers to the checker 
       variable opcode_d1 directly. It is triggered by a call to the default 
       sample() method from a sequence match item. This function call occurs 
       in the Reactive region, while nonblocking assignments to checker variables
       will occur in the Re-NBA region. As a result, the covergroup will sample 
       the old value of the checker variable opcode_d1. */
    //---------------------------
    //   It is also possible to define a custom sample() method for a 
    //   covergroup (see 19.8.1 ). The following is an example of this: */
    checker op_test (logic clk, vld_1, vld_2, logic [3:0] opcode); 
        bit [3:0] opcode_d1; 
        always_ff @(posedge clk) opcode_d1 <= opcode; 
        covergroup cg_op with function sample(bit [3:0] opcode_d1); 
            cp_op : coverpoint opcode_d1; 
        endgroup: cg_op 
        cg_op cg_op_1 = new(); 
        sequence op_accept; @(posedge clk) vld_1 ##1 
            (vld_2, cg_op_1.sample(opcode_d1)); 
        endsequence 
        cover property (op_accept); 
    endchecker 
    /* In this example, a custom sample() method has been defined for the 
       covergroup cg_op, and the coverpoint cp_op references the formal argument 
       of the custom sample() method. This custom method will be called in the 
       Reactive region upon a sequence match, but the sampled value of 
       the sequential checker variable opcode_d1 will be passed to the sample() 
       function. As a result, the covergroup will sample the value from 
        the Preponed region. */

In reply to ben@SystemVerilog.us:

Ben , need your thoughts on the following ::

LRM 9.4.2.4 says “The process executing the event control shall block until the specified sequence reaches its end point. A process resumes execution following the Observed region in which the end point is detected.”

LRM 16.11 says “The subroutines are scheduled in the Reactive region”

For ::

covergroup  frame @( Detect_EOP) ; 

@( Detect_EOP ) would unblock in Active region whereas framelength is updated in Reactive region

So at time : 55 when $rose( EOP ) is True there are 2 possibilities ::

(1) Via feedback from observed to active region , @( Detect_EOP ) unblocks and default value of framelength of 0 is sampled

   ( Reactive  region  hasn't  started  yet )

(2) Via feedback from Reactive to active region , first framelength is updated then @( Detect_EOP ) unblocks and samples updated value of 5

Since reactive occurs after observed region , sequence Detect_EOP has reached endpoint by then

So some tools follow (1) and sample auto[0] whereas some follow (2) and sample auto[5] .

In reply to Have_A_Doubt:

After further thoughts, it was a mistake to allow the trigger of the covergroup to also be @(seqquence_name).
The regions at which variables are updated affect the outcome.
One should not think of "regions"when writing code.
Use support logic to generate the sampling trigger event.

Actually, regardless of the mode of triggering, adding the following option to the covergroup definition would solve the problem.
type_option.strobe = 1; // sample at the end of the time slot