Constraints weird behaviour

Hi, I’m trying to understand why I get a correct waveform for this code (A correct waveform means that data_in is created exactly according to the constraint rules):

class transaction_pd extends transaction;
  rand int window_start;
  rand int window_end;
  rand logic [11:0] data_in[$];
  
  
  function new(string inst = "transaction_pd");
    super.new(inst);
    `uvm_info("TRANS_PD","trans_pd_built",UVM_LOW)
  endfunction
  
  constraint window{
    window_start inside {[0:10]};
    window_end inside {[11:20]};   
  }
  
  constraint p_data{
    foreach(data_in[i]){
      if(i inside {[10:20]})
        data_in[i]==1;
      else
        data_in[i]==0;
    }    
  }
  `uvm_object_utils_begin(transaction_pd)
  `uvm_field_int(window_start,UVM_ALL_ON)
  `uvm_field_int(window_end,UVM_ALL_ON)
 `uvm_field_queue_int(data_in,UVM_ALL_ON)
  `uvm_object_utils_end
endclass

But for this code I get a wrong waveform(data_in is changed from 0 to 1 without connection to the constraint rules):

class transaction_pd extends transaction;
  rand int window_start;
  rand int window_end;
  rand logic [11:0] data_in[$];
  
  
  function new(string inst = "transaction_pd");
    super.new(inst);
    `uvm_info("TRANS_PD","trans_pd_built",UVM_LOW)
  endfunction
  
  constraint window{
    window_start inside {[0:10]};
    window_end inside {[11:20]};   
  }
  
  constraint p_data{
    foreach(data_in[i]){
      if(i inside {[window_start:window_end]})
        data_in[i]==1;
      else
        data_in[i]==0;
    }    
  }
  `uvm_object_utils_begin(transaction_pd)
  `uvm_field_int(window_start,UVM_ALL_ON)
  `uvm_field_int(window_end,UVM_ALL_ON)
 `uvm_field_queue_int(data_in,UVM_ALL_ON)
  `uvm_object_utils_end
endclass

Why when I use window_start and window_end with the “inside” keyword in the foreach loop it creates a mess?

Do not re-declare your class member variables when extending into a derived class. The whole point of inheritance is “inheriting” all the members of the base class. Redeclaring member variables with the same creates 2 sets of variables and hides the variables in the base class from references in the extended class.

What is probably happening is you are constructing a transaction_pd type object and storing its handle in a transaction type class variable. That class variable can only reference the set of variables declared in transaction.

class transaction_pd extends transaction;
  `uvm_object_utils(transaction_pd)
  function new(string inst = "transaction_pd");
    super.new(inst);
    `uvm_info("TRANS_PD","trans_pd_built",UVM_LOW)
  endfunction
  constraint p_data{
    foreach(data_in[i]){
      if(i inside {[window_start:window_end]})
        data_in[i]==1;
      else
        data_in[i]==0;
    }    
  }
endclass

All you need to do is override the constraint p_data. When overriding a constraint in an extended class, you disable the same-named constraint in the base class.

Hello,
I think the reason for not correct waveform (i.e incorrect data_in values) could be that the order of solving window_start, window_end and data_in.

In the first case, for constraint p_data, you are using constant range ([10:20]) making easier for constraint solver.

But in the second case, you are using dynamic range ([window_start:window_end]). But what is the order these constraints resolved?

if data_in[] is solved earlier than window_start or window_end, then you could see unexpected results, which is what is happening in your case.

data_in[] has dependency on both window_start and window_end, which are solved by some other constraint. SO you have to use “solve before”

Try with the following:

constraint solve_order {
solve winow_start before data_in;
solve window_end before data_in;
}

You will get wanted results.

Hope this helps.

Kranthi

@kranthikiranufl1, your reply is incorrect. solve before never changes the solution space, on the distribution of random value selected.

Hi Dave.

  1. I moved the transaction_pd members to transaction.
  2. I don’t have the p_data constraint in transaction. its only existing in transaction_pd.

Still, same results.
But, I tried another thing because I suspected that the problem connected to the ‘inside’ key word. Try to explain this to me:

Is there any reason that get I get a correct waveform for this code (A correct waveform means that data_in is created exactly according to the constraint rules):

class transaction_pd extends transaction;
  `uvm_object_utils(transaction_pd)
  
  function new(string inst = "transaction_pd");
    super.new(inst);
    c=pd;
    `uvm_info("TRANS_PD","trans_pd_built",UVM_LOW)
  endfunction
  

  constraint p_data{
    foreach(data_in[i]){
      if(i inside {[10:20]})
        data_in[i]==1;
      else
        data_in[i]==0;
    }
    
  } 
endclass

and for this code not?:

class transaction_pd extends transaction;
  `uvm_object_utils(transaction_pd)
	int x=10;
  	int y=20;

  
  function new(string inst = "transaction_pd");
    super.new(inst);
    c=pd;
    `uvm_info("TRANS_PD","trans_pd_built",UVM_LOW)
  endfunction
  

  constraint p_data{
    foreach(data_in[i]){
      if(i inside {[x:y]})
        data_in[i]==1;
      else
        data_in[i]==0;
    }
    
  } 
endclass

I just changed the numbers in the ‘inside’ range to int objects and the data is created wrong. why?

You need to show us a minimal,complete reproducible example. You have not sized the queue data_in explicitly or using a constraint. Try showing us a small example of your situation without UVM.