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:
I am not sure what condition I am not satisfying with the constraints that I see the error. Any insights appreciated.
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?
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
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