2010-12-08

[ZT][verilog]system function random a myth -28-3

来自: 这里

Now I tried to simulate with seed== 1 . Its interesting to know that some how the sequence is able to enter this chain which is formed with seed==0 and there is no seed value 1 in this chain and my simulation hanged. So aborted the simulation and parter results show that the initial seed = 1 with enter the chain formed by seed 0.

EXAMPLE:
module Tb();

    integer num,seed,j;
    reg [0:31] i;
   
    initial
    begin
        i = 0;
        seed = 0;
        while (seed != 1)
        begin
            if(i == 0)
                seed = 1;
            i = i + 1;
            num = $random(seed);
            if(seed < 20 && seed > 0)
                $display(" seed is %d after values %d ",seed,i);
        end
        $display(" seed is one after this number of random numbers %0d total numbers available are %d",i,{32'hffff_ffff});
    end
endmodule
RESULTS:
seed is 10 after values 357336117
seed is 17 after values 571497456
seed is 2 after values 674338909
seed is 12 after values 747729091
seed is 19 after values 856442278
seed is 3 after values 984423990
seed is 11 after values 1606429294
seed is 15 after values 2296752682
seed is 7 after values 2530823794
seed is 13 after values 2626733396
seed is 5 after values 2776665948
seed is 9 after values 2839232120
seed is 16 after values 3252885295
seed is 4 after values 3437575467
seed is 6 after values 3747632489
seed is 8 after values 3812077591
seed is 14 after values 3927407809
seed is 18 after values 4194899725
seed is 10 after values 357336117
seed is 17 after values 571497456
seed is 2 after values 674338909
seed is 12 after values 747729091
seed is 19 after values 856442278
seed is 3 after values 984423990

Verilog also has other system functions to generate random numbers. Each of these functions returns a pseudo-random number whose characteristics are described by the function name.
Following are the Verilog random number generator system functions:
      $random
      $dist_chi_square
      $dist_erlang
      $dist_exponential
      $dist_normal
      $dist_poisson
      $dist_t
      $dist_uniform
All parameters to the system functions are integer values. For the exponential , Poisson , chi-square , t , and erlang functions, the parameters mean, degree of freedom, and k_stage must be greater than 0 .
$dist_uniform(seed, min, max) is similar to min + {$random(seed)}%(max-min+1),the difference is that in $dist_uniform,the distribution is uniform. $dist_uniform returns a number between min and max. In the $dist_uniform function, the start and end parameters are integer inputs that bound the values returned. The start value should be smaller than the end value.
The mean parameter, used by $dist_normal, $dist_exponential, $dist_poisson, and $dist_erlang, is an integer input that causes the average value returned by the function to approach the value specified. The standard deviation parameter used with the $dist_normal function is an integer input that helps determine the shape of the density function. Larger numbers for standard deviation spread the returned values over a wider range.
The degree of freedom parameter used with the $dist_chi_square and $dist_t functions is an integer input that helps determine the shape of the density function. Larger numbers spread the returned values over a wider range.

EXAMPLE:
module Tb();
    integer num_1,num_2,seed;
   
    initial
    begin
        seed = 10;
        repeat(5)
        begin
            #1;
            num_1 = $dist_uniform(seed,20,25);
            num_2 = $dist_uniform(seed,50,55);
            $display("num_1 = %d,num_2 = %d",num_1,num_2);
        end
    end
endmodule
RESULTS:
num_1 = 20,num_2 = 50
num_1 = 23,num_2 = 55
num_1 = 22,num_2 = 54
num_1 = 25,num_2 = 51
num_1 = 23,num_2 = 55

As I discussed $random changes its seed , Lets see whether $dist_uniform is also doing the same.
EXAMPLE:
module Tb();
    integer num_1,num_2,seedd,seedr;
   
    initial
    begin
        seedd = 10;
        seedr = 10;
        repeat(5)
        begin
            #1;
            num_1 = $dist_uniform(seedd,20,25);
            num_2 = 20 + ({$random(seedr)} % 6);
            $display("num_1 = %d,num_2 = %d,seedd = %d seedr = %d",num_1,num_2,seedd,seedr);
        end
    end
endmodule
RESULTS:
num_1 = 20,num_2 = 22,seedd = 690691 seedr = 690691
num_1 = 20,num_2 = 20,seedd = 460696424 seedr = 460696424
num_1 = 23,num_2 = 22,seedd = -1571386807 seedr = -1571386807
num_1 = 25,num_2 = 21,seedd = -291802762 seedr = -291802762
num_1 = 22,num_2 = 23,seedd = 1756551551 seedr = 1756551551

Look at the results... Its interesting to note that $random and $dist_uniform have same seed sequence flow also.

As I mentioned ,$dist_uniform(seed, min, max) is similar to min + {$random(seed)}%(max-min+1). "similar" means they have some common functionality. $dist_uniform is having uniform distribution, $random for that range, is also uniformly distributed. Fallowing example ,demonstrates that $dist_uniform and $random are uniformly distributed.

EXAMPLE:
module Tb();
     integer num,seed;
     integer num_20,num_21,num_22,num_23,num_24,num_25;
    
     initial
     begin
         seed = 10;
         num_20 = 0;num_21 = 0;num_22 = 0;num_23 = 0;num_24 = 0;num_25 =0;
        
         repeat(6000)
         begin
        
             num = $dist_uniform(seed,20,25);
             if(num == 20 )
                 num_20 = num_20 + 1;
             if(num == 21)
                 num_21 = num_21 + 1;
             if(num == 22)
                 num_22 = num_22 + 1;
             if(num == 23)
                 num_23 = num_23 + 1;
             if(num == 24)
                 num_24 = num_24 + 1;
             if(num == 25)
                 num_25 = num_25 + 1;
        
         end
         $display("num_20 = %0d;num_21 = %0d;num_22 = %0d;num_23 = %0d;num_24 = %0d;num_25 = %0d",num_20,num_21,num_22,num_23,num_24,num_25);
     end
endmodule
RESULTS:
num_20 = 1014;num_21 = 983;num_22 = 946;num_23 = 1023;num_24 = 1014;num_25 = 1020

EXAMPLE:
module Tb();
    integer num;
    integer num_20,num_21,num_22,num_23,num_24,num_25;
   
    initial
    begin
        seed = 10;
        num_20 = 0;num_21 = 0;num_22 = 0;num_23 = 0;num_24 = 0;num_25 =0;
       
        repeat(6000)
        begin
       
             num = 20 +( {$random() } %6 );
             if(num == 20 )
                 num_20 = num_20 + 1;
             if(num == 21)
                 num_21 = num_21 + 1;
             if(num == 22)
                 num_22 = num_22 + 1;
             if(num == 23)
                 num_23 = num_23 + 1;
             if(num == 24)
                 num_24 = num_24 + 1;
             if(num == 25)
                 num_25 = num_25 + 1;
            
        end
        $display("num_20 = %0d;num_21 = %0d;num_22 = %0d;num_23 = %0d;num_24 = %0d;num_25 = %0d",num_20,num_21,num_22,num_23,num_24,num_25);
    end
endmodule
RESULTS:
num_20 = 996;num_21 = 999;num_22 = 959;num_23 = 996;num_24 = 1002;num_25 = 1048

As I mentioned ,$dist_uniform(seed, min, max) is similar to min + {$random(seed)}%(max-min+1). "similar" means they have some difference. The difference is that they generate different sequence.
EXAMPLE:
module Tb();
    integer num_1,num_2,seedd,seedr;
   
    initial
    begin
        seedd = 10;
        seedr = 10;
        repeat(5)
        begin
            #1;
            num_1 = $dist_uniform(seedd,20,25);
            num_2 = 20 + ({$random(seedr)} % 6);
            $display("num_1 = %d,num_2 = %d",num_1,num_2);
        end
    end
endmodule
RESULTS:
num_1 = 20,num_2 = 22
num_1 = 20,num_2 = 20
num_1 = 23,num_2 = 22
num_1 = 25,num_2 = 21
num_1 = 22,num_2 = 23

Till now what we have seen is $random has uniform distribution over integer values. It means that distribution should be uniform across all the bits in 32 bit vector also. The following example shows that bits positions 2,3,4,11,12,13 have equal probability of getting 0. For demonstration I showed some indexes only. Try out rest of them and see that results is same for all the bis.

EXAMPLE:
module Tb();
    integer num;
    integer num_2,num_3,num_4,num_11,num_12,num_13;
   
    initial
    begin
        seed = 10;
        num_2 = 0;num_3 = 0;num_4 = 0;num_11 = 0;num_12 = 0;num_13 =0;
       
        repeat(6000)
        begin
       
            num = $random();
            if(num[2] == 0 )
                num_2 = num_2 + 1;
            if(num[3] == 0)
                num_3 = num_3 + 1;
            if(num[4] == 0)
                num_4 = num_4 + 1;
            if(num[11] == 0)
                num_11 = num_11 + 1;
            if(num[12] == 0)
                num_12 = num_12 + 1;
            if(num[13] == 1)
                num_13 = num_13 + 1;
       
        end
        $display("num_2 = %0d;num_3 = %0d;num_4 = %0d;num_11 = %0d;num_12 = %0d;num_13 = %0d",num_2,num_3,num_4,num_11,num_12,num_13);
    end
endmodule
RESULTS:
num_2 = 3012;num_3 = 2964;num_4 = 3065;num_11 = 3001;num_12 = 2964;num_13 = 3025

The distribution is uniform for system function $random. Suppose if the requirement is to generate random numbers for more than one variable, and all the variables should have uniform distribution, then use different seeds for each variable. Otherwise distribution is distributed on all the variables as overall. But for lower bits, the distribution is same as shown in example.

EXAMPLE:
module Tb();
    integer seed;
    reg [1:0] var_1,var_2,var3,var4;
    integer num_2,num_3,num_1,num_0;
    integer cou_2,cou_3,cou_1,cou_0;
   
    initial
    begin
        seed = 10;
        num_2 = 0;num_3= 0;num_1= 0;num_0= 0;
        cou_2= 0;cou_3= 0;cou_1= 0;cou_0= 0;
       
       
        repeat(40000)
        begin
       
            var_1 = $random();
            var3 = $random();
            var4 = $random();
            var_2 = $random();
            if(var_1 == 0 )
               num_0 = num_0 + 1;
            if(var_1 == 1 )
               num_1 = num_1 + 1;
            if(var_1 == 2 )
               num_2 = num_2 + 1;
            if(var_1 == 3 )
               num_3 = num_3 + 1;
           
            if(var_2 == 0 )
               cou_0 = cou_0 + 1;
            if(var_2 == 1 )
               cou_1 = cou_1 + 1;
            if(var_2 == 2 )
               cou_2 = cou_2 + 1;
            if(var_2 == 3 )
               cou_3 = cou_3 + 1;
        end
        $display("num_2 = %0d;num_3= %0d;num_1= %0d;num_0= %0d;",num_2,num_3,num_1,num_0);
        $display("cou_2= %0d;cou_3= %0d;cou_1= %0d;cou_0= %0d;",cou_2,cou_3,cou_1,cou_0);
     end
endmodule
RESULTS:
num_2 = 9984;num_3= 10059;num_1= 10002;num_0= 9955;
cou_2= 10060;cou_3= 9934;cou_1= 10072;cou_0= 9934;



Use system time as seed, so the same TB simulated at different times have different random sequences and there is more probability of finding bugs. The following is c code useful in PLI to get system time in to verilog.

    #include
    #include
    char *get_time_string(int mode24);
    int get_systime() {
    time_t seconds;
    seconds = time (NULL);
    return seconds;
    }

Verilog 1995, every simulator has its own random number generation algorithm. Verilog 2001 , The standard made that every simulator has to follow same algorithm. So the same random number sequence can seen on different simulators for same seed.
Don't expect that the same sequence is generated on all the simulators. They are only following same algorithm. The reason is, race condition. Look at the following example, both the statements num_1 and num_2 are scheduled to execute at same simulation time. The order of execution is not known. Some simulators take num_1 as the first statement to execute and some other num_2 .If the TB is built without any race condition to $random function calls, then the same random sequence can be generated on different simulators.

EXAMPLE:
initial
# 10 num_1 = $random;
initial
#10 num_2 = $random;

本文地址:http://114er.blogspot.com/2010/12/ztverilogsystem-function-random-myth-28_1553.html
原创文章如转载,请注明链接: 转自Welcome Funny Guys

0 评论: