Calling randomize with arguments

Hi All,
I was trying following code ::

class seqa;
  bit [2:0] a1;
endclass  

class seqb extends seqa;
  bit [3:0] a2 = 10;
endclass

class seqc ;
 
 seqb seqb_h;

  task body();
 
     seqb_h = new();
     if( randomize(seqb_h.a1) with { seqb_h.a1 == 7; } )
         $display("seqb_h is %0p",seqb_h);

     if( seqb_h.randomize(a1) with { a1 == 5; } )
     $display("seqb_h is %0p",seqb_h);
  endtask

endclass  

module top;
 seqc  seqc_h;

 initial begin
   seqc_h = new();
   seqc_h.body();
 end  
endmodule

Why is it that the 1st call to randomize() result in constraint failure whereas 2nd call to randomize() is successful ?

I am aware that 1st call to randomize() calls randomize() within class ‘seqc’ whereas
2nd call to randomize call the randomize() within class ‘seqb’

The LRM specifies that the variables specified by the ‘with’ clause are scoped to the item being randomized. When you use ‘seqb_h.a1’ in the first randomize() call, the targeted variable is scoped as ‘seqb_h.seqb_h.a1’, which doesn’t exist.

The second call to randomize scopes works because ‘a1’ exists as ‘seqb_h.a1’.

When you use ‘seqb_h.a1’ in the first randomize() call, the targeted variable is scoped as ‘seqb_h.seqb_h.a1’, which doesn’t exist.

Shouldn’t this give a compilation error ( rather than run-time constraint failure ) in that case ?

Eg: Using the following gives a compilation error

f( randomize(seqb_h.a1) with { a1 == 7; } ) // 'a1' doesn't exist in Scope of class 'seqc'
         $display("seqb_h is %0p",seqb_h);

As per LRM

The scope for resolution of variable names referenced in an unrestricted constraint block begins with the randomize() with object class; that is, the class of the object handle used in the method call to randomize(). 
Then, if a name fails to resolve within the randomize() with object class, the name is resolved normally starting in the scope containing the inline constraint.

I also noticed that the 1st call to randomize() is successful if a1 is initialized during declaration to 7

class seqa;
  bit [2:0] a1=7; // Alternatively assign 7 prior to calling randomize() below
endclass
............
task body();
     seqb_h = new();
     if( randomize(seqb_h.a1) with { seqb_h.a1 == 7; } ) // No constraint failure
         $display("seqb_h is %0p",seqb_h);

     if( seqb_h.randomize(a1) with { a1 == 5; } )
     $display("seqb_h is %0p",seqb_h);
  endtask

My initial response was incorrect. I was looking at the expression inside the {} after the ‘with’ clause in the first randomize() call, instead of what is inside the () of the randomize() call.

If you run your example on EDA Playground, you will get compile time errors in 2 of the 4 simulators.

The LRM states that the arguments to randomize() must be local variables, and can’t be hierarchical paths. So you can use randomize(seqb_h) or seqb_h.randomize(), but you can’t use randomize(seqb_h.a1).

Some further explanation:

randomize(seqb_h.a1) with { seqb_h.a1 == 7;}  // Illegal because seqb_h.a1 is not a local variable
randomize(seqb_h) with {seqb_h.a1 == 7;}  // Legal because seqb_h is a local variable, but will fail since 'a1' is not declared rand. However, if 'a1' is initialized to 7, the randomization() call will pass as the constraints are validated
seqb_h.randomize(a1) with {a1 == 5;} // Legal as seqb_h is being randomized, and will succeed as specifying the variable inside () allows it to be randomized without requiring the 'rand' specifier
1 Like

Thanks cgales.

A final question on your comment
“The LRM states that the arguments to randomize() must be local variables, and can’t be hierarchical paths

Is this what the LRM means by the following quote from Section 18.11 ::

The scope of the arguments to the randomize() method is the object class. Arguments are limited to the names of properties of the calling object; expressions are not allowed

Is a hierarchical path considered an expression ?

The LRM is misleading here by not using consistent terminology. A class property by itself can be an expression, but expressions can contain more than just class properties. The point here is that the arguments to randomize() must be class properties, and more specifically, properties of the object being randomized.

1 Like

Hi Dave,
A few questions on calling randomize() w/o argument via hierarchical path.
For the following sample code
(1) As per LRM is the call to s_seqh.ext_h.randomize() with { .. } considered legal ?

(2) Is the scope for searching for variables p1/p2/p3 in the following order
ext → base → sub_seq → p_seq → module

(3) Assuming the hierarchical call to randomize() in (1) is legal,
does it make a difference if ‘ext_h’ is declared as rand or not ?

As long as ext_h holds a handle to a class, you can call any built-in or user-defined method of that class. It doesn’t matter if s_seqh is another class, structure, or module/interface instance.

If you mean p1/p2/p3 are names inside the randomize() with {expression} constraint, the search order is first the properties visible to the class variable which randomize is being called from. This is the same as class_variable.name. name. When class_variable holds a handle to a derived object, names declared in the derived object are not visible. If the names are not found inside class_variable, then the normal search rules for looking up identifier names apply at the place where the call to randomize() is made.

When calling class_name.randomize() it doesn’t matter if class_name is declared with a rand qualifier or not.