Calling a function within assert property

Hi ,
I was trying an alternative solution to va_link using subroutine :


module top;
  logic a=1'bX;
 
  function automatic logic sample(); // Called in Observed Region
    return a ; // Updated value sampled . The value could have even been updated in NBA
  endfunction

  //   Without declaring local variable we have used return value of function :    
  x_prop_on_d_assert2 : assert property (@(a) !$isunknown( sample() )) else $display("%t proprIs unknown in a", $realtime);
  
  initial begin 
    a=1'bX; 
    #20 a=1; 
    #20 a=1'bZ; 
    #20 a=0;
    #20 a=1'bX;
    #20 a=0;
    #20 a=1;
    #20 a=0;
    #30; 
   end 
endmodule 

Although the code works and does act as an alternative solution to Ben’ solution using always block , I am a little confused on it’s syntax .

Generally we call a subroutine from within a property / sequence as part of sequence_match_item ( term used by LRM Syntax 16-15 )
Now in the above case I don’t declare a property / sequence ( so that I may declare a local variable within it ) .
Also notice that I call the subroutine without an always true sequence_expr ( i.e ( 1 , sequence_match_item ) , yet it works

The idea behind the solution was :
Since the function returns a value , it’s called in Observed Region . Hence the value returned by the function is the updated value post the respective assignment . Hence we are able to check whether the updated value has X/Z .

In reply to ben@SystemVerilog.us:

Hi Ben ,
As per your 2nd reply in vathread :

If you have a function that return a value, e.g., (seq, v=f(v)), the f(v) is considered
an expression and is evaluated in the Observed Region. If the function is void,
e.g., (seq, f_void(v) then f_void is executed in the Reactive Region. The task or void function
once started can complete after the assertion that called is done.

The same is confirmed in LRM Section 16.10 Local variables :

Initialization assignments shall be performed in the Observed region in the order that they appear in the sequence or property declaration. 

In the above case as the function returns a value , won’t the function execute in Observed region ?

The returned value is checked via $isunknown( return_value ) which also executes in Observed region ( since property/sequence is evaluated in Observed region )

[2] A better solution logically ( w/o worrying about SV regions ) would be :


      function automatic logic sample();  // Called in Observed Region
       return a ; // Updated value sampled even if 'a' were assigned in NBA region
     endfunction
    property prop;
      logic val ;
     @( a ) ( 1 , val = sample() ) ##0 !$isunknown( val );
   endproperty  
   x_prop_on_d_assert3 : assert property ( prop ) 
                  else $display("%t proprIs3 unknown in a", $realtime);  
     

As the subroutine returns a value , sample() is called in Observed region .
After local variable ‘val’ is assigned in Observed region, !$isunknown( val ) executes ( in Observed Region as well )

In reply to ben@SystemVerilog.us:

Hi Ben ,
I get your point but Section 16.11 of the LRM also tells us that subroutine calls are always attached to a sequence expression.
However we are able to call system function $isunknown without attaching it to a sequence_expr .Eg : ( 1 , $isunknown( sig ) )
So according to definition in Section 16.11 , $isunknown shouldn’t be considered a subroutine , right ?
Whereas system task $display can’t be called without attaching it to a sequence expression , hence $display would be considered a subroutine.

In reply to MICRO_91:
Sounds right.


  always(@(posdge clk) begin 
    if($isunknown(a)) ...; // $isunknown executes in the Active region
    am_unk: assert(($isunknown(a)); 
      // I believe that $isunknown executes in the Active region.                               


In reply to ben@SystemVerilog.us:
OK, when I am wet, I AM WET!
My apologies for making a mistake. Here are my conclusions after
a discussion with a colleague:

1800 pg. 591
Bit vector system functions (20.9) **
$countbits $countones $onehot $onehot0 $isunknown**
Those are functions evaluated when they are seen, there is no scheduling
in the Reactive region as I incorrectly surmised.

Also, with
x_prop_on_d_assert2 : assert property (@(a) !$isunknown( sample() ))
passfn=passfn+1; else
failfn=failfn+1;
the sample() evaluates in the Observed region where “a” is now ==1
That explains the difference between
(@(a) !$isunknown( sample() )) // a==value in Observed
(@(a) !$isunknown( a )) // a==sampled value
Ben

In reply to ben@SystemVerilog.us:

Thanks Ben .

The function is essentially called in Observed region , is it because :
(1) As it returns a value the subroutine gets called in Observed region ( However there is no local variable to which the returned value is assigned )
[OR]
(2) As the expression is evaluated in Observed region hence the function also gets called in Observed region .
This 2nd case has nothing to do with Section 16.11 of the LRM , it’s a simple function call

1800: 16.11 Calling subroutines on match of a sequence
Tasks, task methods, void functions, void function methods, and system tasks can be called at the end of a successful nonempty match of a sequence.
…Assertion evaluation does not wait on or receive data back from any attached subroutine. The subroutines are scheduled in the Reactive region, like an action block.

Thus, Tasks, task methods, void functions, void function methods, and system tasks (e.g., $display()) execute in the Reactive region.

If I write an implicit void function, is it also executed in the Reactive region.
1800 does not care about side effects, function is a function… But it may flag your non-void function if it does not return anything.
e.g., function f(); sig=1; endunction // In Reactive region
If it is not void, but has a side effect? // Since non-void then processed where seen

function bit f(a); 
   sig=1; 
  return !a; 
endunction

Ben

In reply to ben@SystemVerilog.us:

My apologies Ben , I wasn’t clear with the statement : " The function is essentially called in Observed region."
I meant to say : The function ‘sample()’ is essentially called in Observed region

Does sample() still identify as sequence_match_item ? Since it isn’t attached to sequence_expression

Also in the following case : function f(); sig=1; endfunction
Shouldn’t the function be called in Observed region due to default return-type as 1-bit logic ?

LRM Section 13.2 says :


"A nonvoid function can be used as an operand in an expression; the value of that operand is the value returned by the function."

So my 2nd thought was that sample() doesn’t identify as sequence_match_item ,
it is simply used to return a value which is used as an operand of expression : $isunknown( return_val );

As the property expression is evaluated in Observed region , sample() gets called in Observed region .

Section 16.11 discusses about subroutines as part of sequence_match_item i.e they are always attached to sequence expression .
However in our code there is no sequence expression , so I feel section 16.11 doesn’t apply to our case .
Rather our code could be related to Section 13.2 where the sample() function’s return value is used as an expression.

In reply to MICRO_91:

So my 2nd though was that sample() doesn’t identify as sequence_match_item ,
it is simply used to return a value which is used as an operand of expression : $isunknown( return_val );

I believe you are correct. But a user should not be concerned about these regions.
The only concern a user should pay attention the value of the variables used since assertions are executed outside (or after) the NBA region where the values of variables most likely may have changed. There is a possibility of no change if the variables used in the Observed region are those that are affected by changes in an action block.
Ben