How to use a "soft constraint" in OVM in sequence libary?

Hi:
with e language, we can use soft constraint which can be overwritten in higher level, does OVM/SV have similar mechanism?
my case is, in one sequence, I have a rand variable whose range is 0~255, by default, constraint its value to 5. if user use this sequence without define this rand variable, it will use this 5 value, if they define it, then honor to their vaule.
my purpose is : don’t run so long loop if user just run random case without defining value.
Thanks. P

Hi P,

The way that you would usually do this sort of thing in OVM is to define a “control knob” variable in your class whose value is used in the constraint. This variable will have a default value that can be overwritten either by:

a) setting its value for a particular object from a test, using its hierarchical name

or

b) using the OVM configuration mechanism (set_config_int, etc) before an object gets built.

The other possible approach is to create a derived class that overrides the constraint. However this is quite a lot of work if all you want to do is change the one value used in the constraint.

Hope that’s enough to give you some ideas!

Regards,
Dave

Well, because SV doesn’t have soft constraints :eek:, you cannot do exactly the same as in Specman. :mad:

You can mimic the behaviour by using a very improbable distribution.
For example, your requirement can be met via the following:
rand byte unsigned loop_length;
constraint loop_length_default {
loop_lenght dist { 5 := 9999999999999, [0:4] := 1, [6:255] := 1 };
}

The more generic form, where you cannot easily assign a dist directly to the field you’re controlling, needs you to add a control field, as follows:

rand bit set_loop_length;
rand int unsigned loop_length;
constraint loop_length {
set_loop_length dist { 0 := 9999999999, 1 := 1 };
set_loop_length == 1’b0 → loop_length == 5;
}

The user would have to constrain the 2 fields, but it does at least give you a more flexible system (e.g. loop_length could be assigned to some more complex expression).

The test writer would use:
constraint test_loop_size {
set_loop_length == 1’b1;
loop_length inside [100:150];
};

Or similar…

Hope this helps.
Steve.

thanks, Dave and Steve.
I still feel a little uncomfortable about this cuz I need to write extra codes (set_config_* before build, write more control handles in sequence …etc)to implement a “soft” function, this is just one simple line in e:(
anyway, thanks for your advices

one more question:
how could I use set_config_int or hierachy reference to set an iteration value? could you give me an example? I am not clear about how to define the inst_name, how to specify which sequence in sequencer I need to controll the variable?

like I have some sequences registed in one my sequencer, how should I refer to one sequence?
use m_sequencer.??
please advise
Thanks.P

Hi P,

Setting control knobs in a sequencefrom the component hierarchy cannot be done directly since sequence items are not part of the hierarchy. The set_config_int configuration is only applied to objects derived from ovm_component so this mechanism cannot be used directly either.

To get this to work with sequences, the trick is to place the control variables in the sequencer - this is part of the component hierarchy so these variables can be set using either hierarchical names or the OVM configuration mechanism.

The control variables can be picked up within a sequence by using the p_sequencer handle that points to the sequencer that creates it, e.g.

max_addr = p_sequencer.max_addr;

The p_sequencer handle is created by the `ovm_sequence_utils macro and is the same type as the sequencer class so can access all of its members.

If you only want to override constraint values in a sequence from a higher level sequence, that is much easier - make them rand members and set their values in the higher level sequence with in-line constraints, e.g.

class my_seq_item extends ovm_sequence_item;
  rand int addr;
  rand int max_addr;

 ...
 constraint c_addr { addr >= 0; addr < max_addr; }
endclass: my_seq_item

class my_sequence extends ovm_sequence #(my_seq_item);
  my_seq_item s_item;  //lower-level sequence or sequence item

  ...
  virtual task body();
   //override control knob values with in-line constraint
    `ovm_do_with(s_item, { max_addr == 1000; } )
  endtask: body
endclass: my_sequence

Hope that makes sense to you!

Regards,
Dave

Thanks, Dave. your example about sequencer/sequence is exact what I want to know.
:)

Hi,
Given the SV language support, OVM’s sequencer/sequence organization along with its macros turns out to be the convenient mechanism to override a simple constraint from a test case. However, thinking loud I must agree with you on:

thanks, Dave and Steve.
I still feel a little uncomfortable about this cuz I need to write extra codes (set_config_* before build, write more control handles in sequence …etc)to implement a “soft” function, this is just one simple line in e:(
Thanks.P

This is where AOP (as in E for instance) wins hands-down. IMHO a small extension/addition to SV can achieve this, but need few string users to push for it in the LRM committee. FWIW, Synopsys has been providing such extension (look for AOE in their manual), and I know few customers successfully using it as well. However I feel little uncomfortable with it as it is not slated to be part of LRM anytime in near future. It will be great to get one another EDA vendor support some sort of Aspects with SV (even if that means a slightly different syntax than VCS’s) - that would create enough momentum in the LRM committee to look at this practical requirements.

Regards
Srini
www.cvcblr.com

Hi Dave,

Can you give me example on this?

To get this to work with sequences, the trick is to place the control variables in the sequencer - this is part of the component hierarchy so these variables can be set using either hierarchical names or the OVM configuration mechanism.

The control variables can be picked up within a sequence by using the p_sequencer handle that points to the sequencer that creates it, e.g.

Code:

max_addr = p_sequencer.max_addr;

The p_sequencer handle is created by the `ovm_sequence_utils macro and is the same type as the sequencer class so can access all of its members.

Thanks,
Shashi

Hi Shashi,

Here is a more complete example that should give you the idea.

The transaction class has a random control variable

class my_transaction extends ovm_sequence_item;
  
    rand int data;
    rand int max_data;  //control variable

    constraint c_data { data >= 0; data < max_data; }

    //rest of class not shown
   ...
  endclass: my_transaction

The sequencer has a member that corresponds to the control variable that can be configured

class my_sequencer extends ovm_sequencer #(my_transaction);
    
    `ovm_sequencer_utils_begin(my_sequencer)
      `ovm_field_int(max_data, OVM_ALL_ON)
    `ovm_sequencer_utils_end
    
    function new(string name="", ovm_component parent=null);
      super.new(name, parent);
      `ovm_update_sequence_lib_and_item(my_transaction)
    endfunction: new
    
    //variable used to control max_data in sequence
    int max_data = 20;

  endclass: my_sequencer

A sequence that runs on the sequencer that constrains the control variable

class my_sequence extends ovm_sequence #(my_transaction);
    `ovm_sequence_utils(my_sequence, my_sequencer)
   
    my_transaction seq_item;

    function new(string name="");
      super.new(name);
    endfunction: new

    virtual task body();
     repeat(10)
       `ovm_do_with(seq_item,{max_data == p_sequencer.max_data; })
    endtask: body
 
  endclass: my_sequence

The sequencer variable and sequence are configured in the test

class my_test extends ovm_test;
    virtual function void build;
      super.build();
      
      set_config_int("m_env.*", "max_data", 40);
      set_config_string("*.m_sequencer0", "default_sequence", "my_sequence");
      
      $cast(m_env, create_component("my_env", "m_env") );
    endfunction: build

  //rest of class not shown
  ...
  endclass: my_test

Hope that all makes sense to you now!

Regards,
Dave

Thanks Dave.

Hi Dave,

The configuration you mentioned above is one time configuration for each test. set_config_int(“m_env.*”, “max_data”, 40); is in the build function and it is one time setting . Let say in the same test i want to change max_data to 5 different value. For each corresponding value i will be sending a sequence. How to do that?
Thanks,

Shashi

Hi Shashi,

See my reply to your question in this other thread about setting the control variables from the run task of a test (using ovm_top.find).

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

Regards,
Dave

I have a followup question on this.

I’m trying to do something very similar and example above shows almost exactly what I need. I have a sequence item parameter I want to change at runtime. So for the example above and looking at the other thread referenced, if I want to change the value of max_data at runtime, I would just do something like the following?

m_env.my_sequencer.max_data = 50;

My only question now is where is the best place to do something like this? Say I want to change max_data after every 100 test cases. Where in the hierarchy does it make sense to do this? It seems like it could be done a couple ways. I’m thinking either at the test level, wait a certain number cycles for 100 test cases to finish, then change max_data. Or maybe in the environment level, have a monitor signal when every 100 test cases have run and the environment redefines max_data.

Also, I just tried doing something similar to the example above in Questa and kept getting a runtime error:

example_sequence.sv(13): randomize() failed; solution graph size exceeds limit (SolveGraphMaxSize=10000)

OVM_WARNING @ 0: reporter [RNDFLD] Randomization failed in ovm_do_with action

Any reason it is giving this? I pretty much copied exactly what is in the example. Thanks!

Jeff

^^ Actually, nevermind on my above questions because I pretty much figured everything out on my own.

However I have another question on the sequence example. I’m trying to set more than one value with ovm_do_with, however the syntax from all the examples I’ve seen doesn’t work. For example:

ovm_do_with(seq_item,{max_data1 == 1; max_data2 == 2;  })

Even though it compiles, at runtime it fails. The examples I’m looking at have this way. Is there another way to do this? Thanks.

Hi Jeff,

Your syntax for `ovm_do_with looks ok to me - are
max_data1
and
max_data2
rand members of your sequence class?

With respect to your earlier question about how to best manage changing the control variables as the test proceeds, there are two common choices:

  1. Use an ad-hoc approach in the test’s run task. Set the sequence to run for the required length, change the variables and start the sequence again. Repeat as necessary.

  2. Use a virtual sequence in a System UVC (“Universal Verification Component”) to set the variables and run the sequence in an Interface UVC, as described in the Cadence OVM Multi-Language Methodology (see their OVM_ML download in the contributions section of OVM World). This is basically an extended version of the architecture described in the OVM user guide. An Interface UVC or OVC consists of an environment with sequencer + driver + monitor (typically in an agent) that connects to the DUT. This is instantiated in the environment of the System UVC together with a virtual sequencer. A virtual sequence runs on the virtual sequencer. Its body task runs sequences on the lower-level sequencer by calling e.g.

`ovm_do_on( m_sequence, p_sequencer.m_sequencer )

If you’re not sure how this hierarchical approach might work, I could post a simple example.

Regards
Dave

Thanks Dave.

However, I’m still having issues with the ovm_do_with.

If I do the following:

`ovm_do_with( seq_item,{mr_dist_0 == 1; mr_dist_1 == 1; })

It compiles, but at run time it gives this error message and no sequence items are generated:

OVM_WARNING @ 0: reporter [RNDFLD] Randomization failed in ovm_do_with action

If I change the code to the following, it works fine:

`ovm_do_with( seq_item,{mr_dist_0 == 1;})
`ovm_do_with( seq_item,{mr_dist_1 == 1;})

However, this isn’t functionally what I want since I need to set both values at the same time, not on separate sequence items. Actually I have a list variables I want to set this way, but I’m starting with trying to just set 2.

Thanks for your help. Your other answer on managing variable changes was very helpful.

Jeff

Edit: Well it seems I found a work around, but I don’t quite understand it. It seems to do with how I’m using the variables I’m setting. I’m using mr_dist_0 and mr_dist_1 as probability distributions (in a dist{} constraint). Just doing some experimenting, I created an int temp = 0. I then added temp to mr_dist_0 and mr_dist_1 when assigning probability in the dist{} statement. Doing this makes it work! Don’t really understand it, but for now it’s doing what I want.

  1. Use an ad-hoc approach in the test’s run task. Set the sequence to run for the required length, change the variables and start the sequence again. Repeat as necessary.

I’m tying to do this approach and running into problems. How do I tell it to start the sequence again after finishing? I initially tried it by changing the variables in the run() task while still in the middle of the sequence. It seems to work at first, but after a while it falls apart and I get undefined inputs.

I guess ideally I want the sequence to generate say 10 items, pause simulation, change variables in the sequencer, then start the sequence all over again. Then repeat this process many times. Any help is greatly appreciated.

In reply to dlong:

David, the link is now outdated and i am unable to reach. It goes to verificationacademy (i have a login but doesnt take me there. Could you please post the new link to the old thread http://ovmworld.org/forums/showthread.php?t=1254

thanks
Sameer