Constraints error

Hello,

I am writing a constraint for the following condition:

An ALU takes the following instructions: ADD (takes 2 cycles), SUB (takes 3 cycles), MUL (takes 4 cycles) and DIV (takes 5 cycles). Say you want to build a system verilog queue of these instructions. When the ALU is working on one instruction, say ADD , for the next 2 clk cycles, it cannot take an ADD. So, two ADD instructions cannot go in the queue consecutively. Same way for SUB, since it takes 3 cycles, 3 SUB instructions cannot be there consecutively in the queue. Write a constraint to build one such queue such that queue has an even distribution of instructions.

I coded up the following:

typedef enum {ADD, SUB, MUL, DIV} instruction; 

class Example;
  
  
  rand instruction inst_q[$];
  
  //constraint c1 {inst_q.size() inside {[7:11]};}
  constraint c1 {inst_q.size() == 8;}
  constraint c2 {foreach(inst_q[i]) {
    inst_q[i] == ADD -> inst_q[i+1] != ADD && inst_q[i+2] != ADD;
    inst_q[i] == SUB -> inst_q[i+1] != SUB && inst_q[i+2] != SUB && inst_q[i+3] != SUB;
    inst_q[i] == MUL -> inst_q[i+1] != MUL && inst_q[i+2] != MUL && inst_q[i+3] != MUL && inst_q[i+4] != MUL;
    inst_q[i] == DIV -> inst_q[i+1] != DIV && inst_q[i+2] != DIV && inst_q[i+3] != DIV && inst_q[i+4] != DIV;}}
  constraint c3 {foreach(inst_q[i]) {
    i == inst_q.size()-1 && inst_q[i] == ADD -> inst_q[i-1] != ADD;
    i == inst_q.size()-1 && inst_q[i] == SUB -> inst_q[i-1] != SUB && inst_q[i-2] != SUB;
    i == inst_q.size()-1 && inst_q[i] == MUL -> inst_q[i-1] != MUL && inst_q[i-2] != MUL && inst_q[i-3] != MUL;
    i == inst_q.size()-1 && inst_q[i] == DIV -> inst_q[i-1] != DIV && inst_q[i-2] != DIV && inst_q[i-3] != DIV && inst_q[i-4] != DIV;}}  
                        
        
    function void post_randomize();
      $display("Size of inst_q = %0d \n", inst_q.size());
    endfunction
  


endclass

module TB;
  
  Example E;
  initial begin
    E = new();
    if(!(E.randomize()))
       $display("Randomization failed \n");
    for (int i = 0; i < E.inst_q.size(); i++) begin
      $display("inst_q[%0d] = %p \n", i, E.inst_q[i]);     
    end  
  end  
  
  
endmodule

The above does works (minimally); please see error below:

Error-[CNST-IAIE] Constraint illegal array index error
testbench.sv, 39
Constrained variable inst_q[8] is outside of the array size.
Please make sure variable inst_q[8] is within the array size.

Randomization failed

inst_q[0] = DIV

inst_q[1] = ADD

inst_q[2] = SUB

inst_q[3] = MUL

inst_q[4] = ADD

inst_q[5] = DIV

inst_q[6] = SUB

inst_q[7] = ADD

Question:

  1. I am not sure what condition I am not satisfying with the constraints that I see the error. Any insights appreciated.
  2. Is there a better way to do this? EDA playground gets stuck (hangs with VCS) if queue size is greater than 8. So, above solution is not scalable?

In reply to Verif Engg:


Loop through twice, and get the difference of index. 
class Example;
 
 typedef enum {ADD, SUB, MUL, DIV} instruction; 
 
  rand instruction inst_q[];
 
  //constraint c1 {inst_q.size() inside {[7:11]};}
  constraint c1 {
    inst_q.size() == 8 ;
    foreach(inst_q[i]) {
      foreach(inst_q[j]){
        if(i < j){
          if(inst_q[i] == ADD && inst_q[j] == ADD)  j - i == 2 ;
          if(inst_q[i] == SUB && inst_q[j] == SUB)  j - i == 3 ;
          if(inst_q[i] == MUL && inst_q[j] == MUL)  j - i == 4 ;
          if(inst_q[i] == DIV && inst_q[j] == DIV)  j - i == 5 ;
        
        
        }
      
      }
    } 
    
  }
     
 
endclass
 
module TB;
 
  Example E;
  initial begin
    E = new();
    if(!(E.randomize()))
       $display("Randomization failed \n");
    for (int i = 0; i < E.inst_q.size(); i++) begin
      $display("inst_q[%0d] = %p \n", i, E.inst_q[i]);     
    end  
  end  
 
 
endmodule


In reply to kddholak:

Thanks! It does help with the randomization error. But does not scale up. I increased the queue size to randomize between 20 to 30, and I see the following error:

Solver failed when solving following set of constraints

rand Example::instruction inst_q[1]; // rand_mode = ON
rand Example::instruction inst_q[15]; // rand_mode = ON
rand Example::instruction inst_q[17]; // rand_mode = ON
rand Example::instruction inst_q[18]; // rand_mode = ON
rand Example::instruction inst_q[19]; // rand_mode = ON
rand Example::instruction inst_q[20]; // rand_mode = ON
rand Example::instruction inst_q[21]; // rand_mode = ON
rand Example::instruction inst_q[22]; // rand_mode = ON
rand Example::instruction inst_q[23]; // rand_mode = ON

constraint c1 // (from this) (constraint_mode = ON) (testbench.sv:10)
{
((inst_q[15] == Example::instruction::ADD) && (inst_q[19] == Example::instruction::ADD)) → ((19 - 15) == 2);
((inst_q[15] == Example::instruction::ADD) && (inst_q[20] == Example::instruction::ADD)) → ((20 - 15) == 2);
((inst_q[15] == Example::instruction::ADD) && (inst_q[21] == Example::instruction::ADD)) → ((21 - 15) == 2);
((inst_q[15] == Example::instruction::SUB) && (inst_q[19] == Example::instruction::SUB)) → ((19 - 15) == 3);
((inst_q[15] == Example::instruction::SUB) && (inst_q[20] == Example::instruction::SUB)) → ((20 - 15) == 3);
((inst_q[15] == Example::instruction::SUB) && (inst_q[21] == Example::instruction::SUB)) → ((21 - 15) == 3);
((inst_q[15] == Example::instruction::MUL) && (inst_q[18] == Example::instruction::MUL)) → ((18 - 15) == 4);
((inst_q[15] == Example::instruction::MUL) && (inst_q[20] == Example::instruction::MUL)) → ((20 - 15) == 4);
((inst_q[15] == Example::instruction::MUL) && (inst_q[21] == Example::instruction::MUL)) → ((21 - 15) == 4);
((inst_q[15] == Example::instruction::MUL) && (inst_q[22] == Example::instruction::MUL)) → ((22 - 15) == 4);
((inst_q[15] == Example::instruction::MUL) && (inst_q[23] == Example::instruction::MUL)) → ((23 - 15) == 4);
((inst_q[15] == Example::instruction::DIV) && (inst_q[17] == Example::instruction::DIV)) → ((17 - 15) == 5);
((inst_q[15] == Example::instruction::DIV) && (inst_q[18] == Example::instruction::DIV)) → ((18 - 15) == 5);
((inst_q[15] == Example::instruction::DIV) && (inst_q[19] == Example::instruction::DIV)) → ((19 - 15) == 5);
((inst_q[15] == Example::instruction::DIV) && (inst_q[21] == Example::instruction::DIV)) → ((21 - 15) == 5);
((inst_q[15] == Example::instruction::DIV) && (inst_q[22] == Example::instruction::DIV)) → ((22 - 15) == 5);
((inst_q[15] == Example::instruction::DIV) && (inst_q[23] == Example::instruction::DIV)) → ((23 - 15) == 5);
((inst_q[17] == Example::instruction::ADD) && (inst_q[20] == Example::instruction::ADD)) → ((20 - 17) == 2);
((inst_q[17] == Example::instruction::ADD) && (inst_q[21] == Example::instruction::ADD)) → ((21 - 17) == 2);
((inst_q[17] == Example::instruction::ADD) && (inst_q[22] == Example::instruction::ADD)) → ((22 - 17) == 2);
((inst_q[17] == Example::instruction::SUB) && (inst_q[18] == Example::instruction::SUB)) → ((18 - 17) == 3);
((inst_q[17] == Example::instruction::SUB) && (inst_q[19] == Example::instruction::SUB)) → ((19 - 17) == 3);
((inst_q[17] == Example::instruction::SUB) && (inst_q[21] == Example::instruction::SUB)) → ((21 - 17) == 3);
((inst_q[17] == Example::instruction::SUB) && (inst_q[22] == Example::instruction::SUB)) → ((22 - 17) == 3);
((inst_q[17] == Example::instruction::SUB) && (inst_q[23] == Example::instruction::SUB)) → ((23 - 17) == 3);
((inst_q[17] == Example::instruction::MUL) && (inst_q[18] == Example::instruction::MUL)) → ((18 - 17) == 4);
((inst_q[17] == Example::instruction::MUL) && (inst_q[19] == Example::instruction::MUL)) → ((19 - 17) == 4);
((inst_q[17] == Example::instruction::MUL) && (inst_q[20] == Example::instruction::MUL)) → ((20 - 17) == 4);
((inst_q[17] == Example::instruction::DIV) && (inst_q[20] == Example::instruction::DIV)) → ((20 - 17) == 5);
((inst_q[17] == Example::instruction::DIV) && (inst_q[21] == Example::instruction::DIV)) → ((21 - 17) == 5);
((inst_q[17] == Example::instruction::DIV) && (inst_q[23] == Example::instruction::DIV)) → ((23 - 17) == 5);
((inst_q[18] == Example::instruction::ADD) && (inst_q[21] == Example::instruction::ADD)) → ((21 - 18) == 2);
((inst_q[18] == Example::instruction::ADD) && (inst_q[22] == Example::instruction::ADD)) → ((22 - 18) == 2);
((inst_q[18] == Example::instruction::ADD) && (inst_q[23] == Example::instruction::ADD)) → ((23 - 18) == 2);
((inst_q[18] == Example::instruction::SUB) && (inst_q[19] == Example::instruction::SUB)) → ((19 - 18) == 3);
((inst_q[18] == Example::instruction::SUB) && (inst_q[20] == Example::instruction::SUB)) → ((20 - 18) == 3);
((inst_q[18] == Example::instruction::SUB) && (inst_q[22] == Example::instruction::SUB)) → ((22 - 18) == 3);
((inst_q[18] == Example::instruction::SUB) && (inst_q[23] == Example::instruction::SUB)) → ((23 - 18) == 3);
((inst_q[18] == Example::instruction::MUL) && (inst_q[19] == Example::instruction::MUL)) → ((19 - 18) == 4);
((inst_q[18] == Example::instruction::MUL) && (inst_q[20] == Example::instruction::MUL)) → ((20 - 18) == 4);
((inst_q[18] == Example::instruction::MUL) && (inst_q[21] == Example::instruction::MUL)) → ((21 - 18) == 4);
((inst_q[18] == Example::instruction::DIV) && (inst_q[19] == Example::instruction::DIV)) → ((19 - 18) == 5);
((inst_q[18] == Example::instruction::DIV) && (inst_q[20] == Example::instruction::DIV)) → ((20 - 18) == 5);
((inst_q[18] == Example::instruction::DIV) && (inst_q[21] == Example::instruction::DIV)) → ((21 - 18) == 5);
((inst_q[18] == Example::instruction::DIV) && (inst_q[22] == Example::instruction::DIV)) → ((22 - 18) == 5);

In reply to Verif Engg:
If you write constraints like you initially tried, you need to guard against invalid indexes. Remember that a foreach loop gets unrolled into individual constraints. (See this example for more details).

Here is an alternate approach.

class Example;
 
 typedef enum {ADD, SUB, MUL, DIV} instruction; 
 
  rand instruction inst_q[];
 
//  constraint c1 {inst_q.size() inside {[7:11]};}
  constraint c1 {
    inst_q.size() == 60 ;
    foreach(inst_q[i])
      foreach(inst_q[j])
        if(i < j){
          if(inst_q[i] == ADD && inst_q[j] == ADD)  j - i > 1 ;
          if(inst_q[i] == SUB && inst_q[j] == SUB)  j - i > 2 ;
          if(inst_q[i] == MUL && inst_q[j] == MUL)  j - i > 3 ;
          if(inst_q[i] == DIV && inst_q[j] == DIV)  j - i > 4 ;
        }
   }          
endclass
 
module TB;
  Example E;
  initial begin
    E = new();
    assert (E.randomize()) else
       $display("Randomization failed \n");
    foreach (E.inst_q[i])
      $display("inst_q[%0d] = %p \n", i, E.inst_q[i]);     
  end  
endmodule