Reputation: 107
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
Upvotes: 3
Views: 15493
Reputation: 19114
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".
Upvotes: 9
Reputation: 11428
Something like:
wire R;
if ($random[7:0]>(40*255/100))
assign R = 1'b0;
else
assign R = 1'b1;
I'm assuming that the algorithm that $random
uses produces numbers that are equally random whatever bits you take from it.
Upvotes: 0
Reputation: 1
It seems not so hard at verilog.
reg [7:0] R;
reg rand_bit;
R = $random();
if (R < 76)
rand_bit = 1'b0;
else
rand_bit = 1'b1;
Here I assume that $random is pretty uniform. I think it should work :)
Upvotes: 0
Reputation: 1
Following Code Will Generate Random Variable as Per Your Requirement :
program top;
class Packet;
rand reg R;
constraint percentage {R dist {1:=60,0:=40};};
function void display;
$display("Random Reg : %0d",this.R);
endfunction
endclass
Packet P;
initial
begin
P = new;
repeat(10)
begin
P.randomize();
P.display;
end
end
endprogram
Upvotes: 0
Reputation: 42698
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
Upvotes: 1
Reputation: 20514
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
Upvotes: 3