Hi All,
I have 4-bit request signal which is an input to priority arbiter.
Suppose the 1st call to randomize() results in 4’b0001 ( highest index set is bit 0 )
Next call to randomize must be a value greater than 4’b0001 with the lsb set ( as highest index set in previous call to randomize() was bit 0 )
Expected values would be :: 4’b0011 / 4’b0111 / 4’b0101 / 4’b1111 / 4’b1001 / 4’b1101 / 4’b1011
If the 2nd call to randomize() gives 4’b0011 ( highest index set is bit 1 ) then 3rd call should have bit position 1 set
Expected values would be :: 4’b111x / 4’b011x / 4’b101x ( where lsb could be 0 / 1 )
The max chain that one could have would be 4’b0001 → 4’b0011 → 4’b0111 → 4’b1111.
After it reaches max value of 4’b1111 ( or any value where bit 3 is set ) there should be no constraint in terms of highest bit position set
i.e we can have any value with $countones( req ) >= 1 in the next call to randomize()
rand bit [3:0] req;
constraint no_of_ones { $countones(req) >= 1 ; }
constraint successive_values { ( const'(req[3]) != 1 ) -> req > const'(req); }
However constraint successive_values doesn’t guarantee that the same bit position is set b/w consecutive calls
Eg: If previous call gives req as 4’b0001 ( bit 0 is set ) then next call could possibly give me 4’b1000 ( bit 0 isn’t set ).
Any suggestions ?
EDIT: A friend suggested a solution using non-random variable that stores the highest bit set in post_randomize() and within constraint we simply use
(const'(req[3]) != 1) -> (req > const'(req) ) && (req[ind] == 1) .
Although this works as per intention, both of us are now looking for a possible solution using purely constraints ( w/o using helper variable ) for practice purposes
Thanks
You can use pre_randomize() to calculate the position of the MSB from the previous value.
class A;
rand bit[3:0] req;
bit [3:0] prev_req;
int msb;
constraint c {
req != '0; // must be non-zero
msb < 3 -> {
req > prev_req;
req[msb] == '1; // msb of previous value must be set
}
// attempt at a "better" distribution of values
1 dist { req==4'b0001 := 1, req[3:1]==3'b001 :=1, req[3:2]== 2'b01 :=1 , req[3]==1'b1 :=1 };
}
function void pre_randomize();
// req must never be 0
if (req==0) req = '1;
for (int i = $bits(req)-1; i >= 0; i--)
if (req[i]) begin
msb = i;
break;
end
prev_req = req;
endfunction
endclass
module top;
A h = new;
initial repeat(20) begin
assert(h.randomize());
$display("%b %d", h.req, h.msb);
end
endmodule
Apologies for editing my original post at the last moment Dave.
Would there exist a solution without using helper variable ?
Actually, I started my solution without using any helper variables, and found it less desirable. You can compare the two approaches to decide which one is more manageable for yourself
class A;
rand bit[3:0] req;
constraint c {
req != '0; // must be non-zero
fmsb(const'(req)) < 3 -> {
req > const'(req);
req[fmsb(const'(req))] == '1; // msb of previous value must be set
}
// attempt at a "better" distribution of values
1 dist { req==4'b0001 := 1, req[3:1]==3'b001 :=1, req[3:2]== 2'b01 :=1 , req[3]==1'b1 :=1 };
}
function void pre_randomize();
// req must never be 0
if (req==0) req = '1;
endfunction
function int fmsb(type(req) x);
// assume x is never 0
for (int i = $bits(req)-1; i >= 0; i--)
if (x[i]) return i;
endfunction
endclass
module top;
A h = new;
initial repeat(20) begin
assert(h.randomize());
$display("%b %d", h.req, h.fmsb(h.req));
end
endmodule
1 Like
When msb is 1 next randomization is any number but zero. I have used helper variable here. This is my approach
class req_txn;
rand bit [3:0] val;
bit [3:0] prev = 0;
constraint c1 {
if(prev[2]) (val[2]==1 && val[3]==1);
else if(prev[1]) (val[1] ==1 && (val[3] || val[2]));
else if(prev[0]) (val[0] ==1 && (val[3] || val[2] || val[1]));
}
constraint c2 { $countones(req) >=1; }
function void post_randomize;
prev = val;
endfunction
endclass
Last line needs to be else if(prev[0]) (val[0] ==1 && (val[3] || val[2] || val[1]));
If the bit-width of val is large, then it would be difficult to use this logic