Inline constraints with uvm_do_on_with macro

Hi,

i want to control one sequence from the test . When i am giving inline constraints with uvm_do_on_with macro, these constraints are not working.

class mem_sequence extends base_sequence;

function new(string name=“mem_sequence”);
super.new(name);
endfunction

uvm_object_utils(mem_sequence) uvm_declare_p_sequencer (abc_sequencer)

virtual task body;
`uvm_do_on_with(seq1, p_sequencer.seqr1,{
req.x inside [0,1,3,4];
req.y inside [2,6];
})
endtask

endclass

In my base_sequence which is virutal sequence class, i have instance of a sequence as seq1. x & y are the seq items for seq1. When i am trying to give inline constraints, the code is compile free. However, the constraints with uvm_do_on_with are not working. Can someone please help me figuring out why this is happening and how to make these constraints work.

In reply to 8Blades:

Is ‘req’ part of seq1? You don’t show the fields of seq1, but perhaps you meant for your constraint to be {seq1.x inside [0,1,3,4]; seq1.y inside [2,6]}?

In reply to cgales:

Yes, req is part of seq1.

class base_sequence extends uvm sequence ;
 
 'uvm_object_utils(base_sequence)

  mem_sequence seq1;
 
function new(string name="base_sequence");
 super.new(name);
 endfunction
 

 virtual task body;
`uvm_do_on_with(seq1, p_sequencer.seqr1,{ 
req.x inside [0,1,3,4];
req.y inside [2,6];
}) 
endtask
endclass

class mem_sequnece extends uvm_sequence #(mem_seq_item)
   `uvm_object_utils(mem_sequence)

    rand mem_seq_item req;

task body();
 `uvm_do(req);
endtask: body

endclass

x and y are random properties in mem_seq_item.

The issue is that your sub-sequence (mem_sequence) is also using the uvm_do() macro to create the mem_seq_item. The uvm_do() macro will create and randomize the item every time, which will ignore any constraints passed in.

This is a perfect example of why using the `uvm_do_* macros is bad. I recommend you review the UVM Cookbook chapter on sequences and use the sequence/sequence_item methods directly.

In reply to cgales:

So, what i conclude from you answer is that inline constraints cannot be used with `uvm_do macros.

However, one more thing i want to ask that if “inside” works in inline constraints.As of now, i have never seen any example where inside is used in inline constriants. I have doubt on its functionality as well.

In reply to 8Blades:

You need to make sure that you pass down the constraints properly:


class mem_sequence extends uvm_sequence #(mem_seq_item)
   `uvm_object_utils(mem_sequence)
 
    rand mem_seq_item req;
    rand int x,y;
 
task body();
  req = mem_seq_item::type_id::create("req");
  start_item(req);
  if (!req.randomize() with {x == local::x; y == local::y;})
    `uvm_error("randerr", "Error randomizing mem_seq_item");
  finish_item(req);
endtask: body
 
endclass

class base_sequence extends uvm sequence ;
 
 'uvm_object_utils(base_sequence)
 
  mem_sequence seq1;
 
  function new(string name="base_sequence");
    super.new(name);
  endfunction
 
  virtual task body;
    seq1 = mem_sequence::type_id::create("seq1");
    if !(seq1.randomize() with { 
       x inside [0,1,3,4];
       y inside [2,6];
    }) `uvm_error("randerr", "Can't randomize seq1");
    seq1.start(m_sequencer, this)
  endtask
endclass
 

In reply to cgales:

I’d suggest doing it slightly differently so that you can constrain all fields of ‘req’, not just the ones you export to the sequence:


class mem_sequence extends uvm_sequence #(mem_seq_item)
  rand mem_seq_item req;

  function void pre_randomize();
    req = mem_seq_item::type_id::create("req");
  endfunction
 
  task body();
    start_item(req);
    finish_item(req);
  endtask: body
  
  `uvm_object_utils(mem_sequence)
endclass

This way, ‘req’ gets randomized together with the sequence, so any inline constraints you apply when randomizing the sequence won’t get discarded by a second call to ‘req.randomize()’. Now, the code you showed us in the beginning should work:


class base_sequence extends uvm sequence ;
  mem_sequence seq1;
  
  function new(string name="base_sequence");
    super.new(name);
  endfunction
  
  virtual task body;
    `uvm_do_on_with(seq1, p_sequencer.seqr1,{ 
      req.x inside [0,1,3,4];
      req.y inside [2,6];
    }) 
  endtask

  'uvm_object_utils(base_sequence)
endclass

In reply to Tudor Timi:

I like your solution better. I would make one change to mem_sequence to prevent a possible null object. This doesn’t follow the just-in-time randomization recommendation, but since it is being generated without constraints, it shouldn’t matter.

class mem_sequence extends uvm_sequence #(mem_seq_item)
  rand mem_seq_item req;
 
  function void pre_randomize();
    req = mem_seq_item::type_id::create("req");
  endfunction
 
  task body();
    if (req == null) begin
      req = mem_seq_item::type_id::create("reg");
      if (!req.randomize())
        `uvm_error("randerr", "Unable to randomize mem_seq_item");
    end
    start_item(req);
    finish_item(req);
  endtask: body
 
  `uvm_object_utils(mem_sequence)
endclass

In reply to cgales:

Thanks Mr. Tudor Timi and Mr. Cgales for the soltution. This is working fine. However, i want to drive 10 packets here. Please have a look at below code.

class mem_sequence extends uvm_sequence #(mem_seq_item)
  rand mem_seq_item req;
  rand int loop;
 
  function void pre_randomize();
    req = mem_seq_item::type_id::create("req");
  endfunction
 
  task body();
    if (req == null) begin
      req = mem_seq_item::type_id::create("reg");
      if (!req.randomize())
        `uvm_error("randerr", "Unable to randomize mem_seq_item");
    end
    for(int i=0;i<loop;i++) begin
    start_item(req);
    finish_item(req);
    end
  endtask: body
 
  `uvm_object_utils(mem_sequence)
endclass
class base_sequence extends uvm sequence ;
  mem_sequence seq1;
 
  function new(string name="base_sequence");
    super.new(name);
  endfunction
 
  virtual task body;
    `uvm_do_on_with(seq1, p_sequencer.seqr1,{
      loop ==10; 
      req.x inside [0,1,3,4];
      req.y inside [2,6];
    }) 
  endtask
 
  'uvm_object_utils(base_sequence)
endclass

When i am trying like this, all 10 generated packets have the same data, which of course is expected as packet is randomized only once in base sequence.

I tried like taking loop variable in base sequence instead of mem_sequence, like below:

class base_sequence extends uvm sequence ;
  mem_sequence seq1;
  int no_of_packets;
  no_of_packets=10;
  function new(string name="base_sequence");
    super.new(name);
  endfunction
 
  virtual task body;
      for(int i=0;i<no_of_packets;i++)
     `uvm_do_on_with(seq1, p_sequencer.seqr1,{
                     req.x inside [0,1,3,4];
                     req.y inside [2,6];
    }) 
  endtask
 
  'uvm_object_utils(base_sequence)
endclass

It seems to be working fine. Is there any better way to implement this, in a way that i can have the control from mem_sequence ?