Verilog - generate weighted random numbers

12,731

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

Share:
12,731
camillo_benso
Author by

camillo_benso

Updated on June 28, 2022

Comments

  • camillo_benso
    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