Managing constraints from the test case

I’m verifying a chip that processes multi-layered protocol traffic and requires a significant amount of configuration (e.g. routing tables) for system level tests. The transactions have been abstracted up to a very high level. Consequently, there are random elements several layers down into the transaction hierarchy. What is the best approach for managing (from the test case level) the constraints of a transaction hierarchy?

In our current approach, we use knobs to control the constraints and we hierarchically modify the knobs from the test case.

class a;
   rand int addr;
   int min, max;    // constraint knobs
   
   constraint c { addr >= min && addr <= max; }
   
   function new();
      min = 0;
      max = 10;
   endfunction
   
endclass

// test case code (after transaction hierarchy is built but before it is randomized)
x.y.a.min = 5;
x.y.a.max = 7;   

d.e.a.min = 24;
d.e.a.max = 32;

This approach solves the problem of controlling the constraints from the test case, but it is not ideal since the test case is tied to the transaction hierarchy and the hierarchy must be built before the knobs are adjusted.

In our environment there are several instances of “a” down in the transaction hierarchy so moving the constraints up to the higher levels of transactions seems wasteful.

Also, the complexity of the transaction hierarchy and the large number of constraints rules out the use of “randomize with”.

I understand the factory pattern and overriding constraints in extended classes. If we go down that road, it seems as though we’ll end up with a lot of these extended classes and the test writers will need to be more knowledgeable about the verification environment.

Are there any other ideas for complex stimulus generation?

It would be nice if we could use set_config_* on the knobs to break the hard dependency of the test case to the transaction hierarchy, but that would require an enhancement to OVM.

Are there any plans for incorporating a methodology into OVM to solve this problem?

Thanks in advance.

I read about the use of external constraint definitions as an alternative solution. The transaction class contains a constraint declaration.

class my_trans;
   rand int addr;
   constraint addr_c;
endclass

The body of the constraint could be defined from the test.

class my_test;
   constraint my_trans::addr_c { addr > 0 && addr < 10; }
endclass

I tried this approach with Questa and I got the “*Invalid package scope specified for constraint block”*compile error. Does anyone have a working example of this idea?

Thanks.

The external constraint should be outside the class scope. i.e.

constraint my_trans::addr_c { addr > 0 && addr < 10; }

HTH
Srini
www.cvcblr.com

Hi Jesse,

One thing I do not understand in your request is how would you use set_config without knowing the underlying transaction hierarchy? How would you distiguish the x.y constraint from the d.e constraint?

Dave

Srini,
I was hoping I could declare the constraint from another class, but I found another thread that explains the external constraint block must be in the same scope.

http://www.ovmworld.org/forums/showthread.php?t=605

Dave,
You are correct that you still must know someof the hierarchy. The wildcard feature of set_config would allow you to hide some of the hierarchy. It would also allow you to setup knobs for multiple transactions , say if there is a dynamic array of transactions in the hierarchy. This may not seem very useful for block level testing involving fairly generic transactions. But it would be very useful in our application where we are dealing with system level tests. Our transactions are abstracted at a very high level and require significant initialization in the DUT. This results is a complex transaction hierarchy and is driving my original question.

Thanks,
Jesse

In reply to jesseprusi:

Hi Jesse,

I am also having similar situation as you described above. Do you have a solution for this?

Thanks
sb

Hi All
I am facing this problem of complex stimuli and abstraction levels im my actual tasks.
What I’m doing is:

  • Declare the sequences with many control knobs, so I can have a high control degree outside it.
  • Start the sequences directly from test using seq.start() method.
  • I have a configuration class inside test, this cfg class is passed to all sequences instances in the test.build() method. This way the cfg class automatically pass parameters from test to sequences, that will influence in the randomization.
  • I also have a lot of test tasks that execute especific sequences with special control on its randomization.

This scheme has been doing the job very well!!
Ask for more details if someone got interested in that!

In reply to vaciloto:

Thanks vaciloto for your reply.

I was curious in this statement. Can you please give or point me to a small example?

Start the sequences directly from test using seq.start() method.

Thanks
sbatta

In reply to sbatta:

Hi sbattta
All sequence has this start() method. THis method execute the sequence in the sequencer you put as argument. There are several examples on that in the OVM User Manual. If you instantiate the sequence inside the test, you can call this method from the test’s run() method. You can also find examples on past threads of this blogs.

In reply to vaciloto:

Thanks vaciloto.