Class extension assuring coherence between variables of superclass and subclass

Let’s say we have a class defined as:


class basePacket;
   rand bit [15:0] frame;
endclass;

Such class could be part of a VIP library, thus can’t be modified. The basePacket could contain much more random variables which depend on frame variable (through constraints). It means, frame must be calculated during randomize() call, not in post_randomize().

We would like to extend this class to our specific application in order to make it more user-friendly. Let’s say that in our application frame contains address on MSBs and data on LSBs. Intentionally, we don’t want to define new variables like address and data in the derived class in order to avoid coherency problem between frame, address and data (ie. a UVM driver/monitor from the VIP uses only the base class and is not aware of fields from the derived class to be updated). Thus, the preferred method would be to use function calls, like


class myPacket extends basedPacket;
  function bit[7:0] address();
    return frame[15:8];
  endfunction
  
  function bit[7:0] data();
    return frame[7:0];
  endfunciton
endclass

It allows to avoid coherency issue, but has a problem with randomization: the randomize() call in the sequence below will fail ( 0==3 and 0==5 can’t be satisfied).


task body();
  myPacket packet = new();
  if ( ! packet.randomize() with {
     data() == 3;
     address() == 5;} )
    `uvm_fatal("RANDOMIZE_FAILURE", "mySequence::body()~myPacket")
endtask

It’s because, according to standard, chapter “18.5.12 Functions in constraints”:

Functions shall be called before constraints are solved, and their return values shall be treated as state variables.

Is there are any universal methodology for this kind of problems?

In reply to adrianf0:

If your driver accepted an abstract base class, where the driver used access methods to access the data. Then you would implement the rand data fields you want, and provide driver access by implementing the accessor methods. However, this also means giving up any constraints provided by a common base item.

In your extension you can however, add your own rand fields, tie them to the pre-existing class fields with constraints, and then use the solver to enforce coherence when you need it. You just need to restrict randomization to the fields you are worried are out-of-sync with the others.

In reply to warnerrs:

Thank you for your reply.

I think I was very specific in the description: the base class and the driver is given by the external VIP and can’t be modified. The idea is to inherit transaction class and extend it. As I also wrote in the description, constraints will not assure coherency between fields: a driver (response transaction) and/or a monitor fill only variables of the superclass and obviously don’t call randomize() which would update fields in the subclass.

In reply to adrianf0:

Maybe you need to wrap the IP, in which case you can ensure coherency is enforced in the wrapper.