I tried to generate the bath-tub curve distribution using the constraint posted on this verification academy page but got run-time error from the constraint used in it.
Here is the constraint used in the page
int a[5] = '{1, 11, 21, 31, 41};
int b[5] = '{10, 20, 30, 40, 50};
int c[5] = '{30, 15, 10, 15, 30};
constraint c_value { foreach (a[i])
value dist { [a[i]:b[i]] :/ c[i] };
}
And during runtime, I got the following errors.
"
**Solver failed when solving following set of constraints
solver failure because that code looks like this:
value has 5 different dist constraints and conflict to each other
constraint c_value {
value dist { [a[0]:b[0]] :/ c[0] };
value dist { [a[1]:b[1]] :/ c[1] };
value dist { [a[2]:b[2]] :/ c[2] };
value dist { [a[3]:b[3]] :/ c[3] };
value dist { [a[4]:b[4]] :/ c[4] };
}
and it seems compiler doesn’t support this yet.
so it’s tough to making bath-tub curve smooth (depending on giving dynamic array size, e.g. a/b/c size),
any good way to making long dist block short, I don’t have a good idea yet.
I believe the article was showing pseudo-code as a concept. You cannot use a dist constraint without a fixed list of values. There are other ways of constructing random distributions. One way is to select a random number to use in a series of implications where only one can be selected:
class A;
rand int value;
int a[5] = '{1, 11, 21, 31, 41};
int b[5] = '{10, 20, 30, 40, 50};
int c[5] = '{30, 15, 10, 15, 30};
int d[6] = {0, 30, 45, 55, 70, 100}; // could be computed from c
rand int range;
constraint c_range {range inside {[d[$low(d)]:d[$high(d)]-1]};
solve range before value; } // prevents c_value from skewing distribution
constraint c_value {foreach (a[ii])
range inside {[d[ii]:d[ii+1]-1]} ->
value inside {[a[ii]:b[ii]]};}
endclass
Very good idea.
Another method using $dist_normal(seed, mean, std);
By given range related config, then val will be a bath-tub curve in this range.
class A;
rand int norm;
// range config
int high = 100;
int low = 0;
int mean = 50;
int std = 20;
int val;
constraint c {
norm == normal(mean);
}
function int normal(int mean);
return $dist_normal($urandom(), mean, std);
endfunction
function void post_randomize();
if (norm inside {[low:high]}) begin
val = high - norm;
end
// val within designed range will be bath-tub
endfunction
endclass : A
I assume we could discard the val outside of the range from the caller.
if we really want to make all val within range, then just do the following:
function int normal(int mean);
do begin
normal = $dist_normal($urandom(), mean, std);
end while (!(normal inside {[low:high]}));
return normal;
endfunction
A while loop might work in this particular case, but you can get stuck into an infinite loop in other cases. That is why we feed our constraints to a constraint solver which has to prove a solution exists before generating a particular solution.
And I do not think your equation gives the desired curve. It simple flips the curve as a mirror image.
I just try to provide a solution to have more smooth curve without hardcoded a/b/c/d array definition. with a/b/c/d fixed array, we can’t have a smooth curve unless you want to define huge array.
if the user provides bad std/mean/seed, it might break $dist_normal for sure.
everything can be fixed, e.g. just put an iteration_count in while loop to catch this issue.
I have a question related to using ‘dist’ operator inside a foreach loop in a systemverilog constraint. I need to generate array elements with values according to a distribution pattern. But, I’m concerned if calling ‘dist’ operator for each element will cause unintended distribution. Can you help?
constraint value_c{
foreach(c1[i]){
(num == i) dist {1:=c1[i],0:=(100-c1[i])};
}
num inside {[0:($size(c1)-1)]};
solve num before value;
value inside {[a1[num]:b1[num]]};
Each element will have the intended distribution. The loop gets unrolled into individual constraints so that the distribution of one element has no effect on the distribution of another element.