Verilog - generate weighted random numbers
Solution 1
The SystemVerilog solution has a distribution method within randomize
called dist
. Weights are assigned by value_or_range := weight
or value_or_range :/ distributed_weight
. This exert from the IEEE Std 1800-2012 § 18.5.4 page 476 gives a clear example:
When weights are applied to ranges, they can be applied to each value in the range, or they can be applied to the range as a whole. For example:
x dist { [100:102] := 1, 200 := 2, 300 := 5}
means x is equal to 100, 101, 102, 200, or 300 with a weighted ratio of 1-1-1-2-5, and
x dist { [100:102] :/ 1, 200 := 2, 300 := 5}
means x is equal to one of 100, 101, 102, 200, or 300 with a weighted ratio of 1/3-1/3-1/3-2-5.
dist
is used in randomization so it needs to be mare of a randomize() with
(or a class constraint
). randomize
returns a success bit, therefore it should be in called within an assert
, void'()
, or the RHS of an assignment.
In your we can set the weight of 0 to 6 and the weight of 1 to 4, creating a total weight of 10 with a 60/40 distribution. Example:
reg R;
initial begin
assert( randomize(R) with { R dist { 0 := 6, 1 := 4 }; } );
end
From more about dist
see IEEE Std 1800-2012 § 18.5.4 "Distribution".
Solution 2
Create a random integer then based on Value return 1 or 0; NB you may want to seed your random number, for repeatability use the same seed. This way when a test fails it can be debugged.
$urandom
works a little different to $random
it doe not update the seed value so should only be seeded the first time it is called in a thread (always block). It is also thread safe, each always block works independently.
initial begin
$urandom(seed);
$urandom;
$urandom;
end
integer temp;
reg r ;
always @ ... begin
temp = $urandom; //Range: +2_147_483_647 -2_147_483_648
// weighting; 0 would be 50:50
// real weighting is (0.1 + 0.5), 0.5 inherent from positive number.
r = (temp > (2_147_483_647*0.1);
end
NB: the random functions are not synthesizable and should only be used for testbenches. if you want a random number for synthesis check out this Question
Solution 3
For Verilog you can always so something like:
integer R;
R = ($dist_uniform(0,100) < 60) : $dist_uniform(0,5) : $dist_uniform(6,10)
and this in SystemVerilog would be the same as:
std::randomize(R) with {R dist {[0:5] :/60, [6:10] :/ 40} ;};
You could also do this procedural code: randcase 60: R = 1; 40: R = 0; endcase
camillo_benso
Updated on June 28, 2022Comments
-
camillo_benso almost 2 years
I am trying to generate random single bits and this is simple as long as you want a normal randomization:
wire R; assign R = $random % 2;
What I am looking for is a sort of weighted probability like:
wire R; assign R = 60%(0) || 40%(1);
Forgive me if it is not conform to standard Verilog code, it is just to give an idea of what I want. Can anyone help me out? Thank you