2010-12-08

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

来自: 这里

Verilog has system function $random ,which can be used to generate random input vectors. With this approach, we can generate values which we wouldn't have got, if listed manually. In this topic I would like to discuss what natural things happening behind $random and how we use it in different manners.

EXAMPLE:

module Tb_mem();
    reg clock;
    reg read_write;
    reg [31:0] data;
    reg [31:0] address;
   
    initial
    begin
        clock = 0;
        forever
           #10 clock = ~clock;
    end
   
    initial
    begin
        repeat(5)@(negedge clock)
        begin read_write = $random ; data = $random;address = $random; end
        $finish;
    end
   
    initial
        $monitor($time,"read_write = %d ; data = %d ; address = %d;",read_write,data,address);
   
endmodule
RESULT:
                 20read_write = 0 ; data = 3230228097 ; address = 2223298057;
                 40read_write = 1 ; data = 112818957 ; address = 1189058957;
                 60read_write = 1 ; data = 2302104082 ; address = 15983361;
                 80read_write = 1 ; data = 992211318 ; address = 512609597;

$random() system function returns a new 32-bit random number each time it is called. The random number is a signed integer; it can be positive or negative. The following example demonstrates random generation of signed numbers.

EXAMPLE:
module Tb();
    integer address;
   
    initial
    begin
        repeat(5)
        #1 address = $random;
    end
   
    initial
        $monitor("address = %d;",address);
   
endmodule
RESULT:
address = 303379748;
address = -1064739199;
address = -2071669239;
address = -1309649309;
address = 112818957;

We have seen how to generate random numbers. But the numbers range from - (2**32 -1) to 2 **32. Most of the time, the requirement don't need this range. For example, take a memory. The address starts from 0 to some 1k or 1m.Generating a random address which DUT is not supporting is meaningless. In verilog there are no constructs to constraint randomization. Fallowing example demonstrated how to generate random number between 0 to 10.Using % operation, the remainder of any number is always between 0 to 10.

EXAMPLE:
module Tb();
    integer add_1;
    initial
    begin
        repeat(5)
        begin
            #1;
            add_1 = $random % 10;
        end
    end
   
    initial
        $monitor("add_1 = %d",add_1);
endmodule
RESULT:
add_1 = 8;
add_1 = 4294967287;
add_1 = 4294967295;
add_1 = 9;
add_1 = 9;

OOPS!...... The results are not what is expected. The reason is $random generates negative numbers also. The following example demonstrates proper way of generating a random number between 0 to 10. Concatenation operator returns only bit vector. Bit vectors are unsigned, so the results are correct as we expected. Verilog also has $unsigned systemtask to convert signed numbers to signed number. This can also be used to meet the requirements. The following example shows the usage of concatenation operator and $unsigned.

EXAMPLE:
module Tb();
     integer add_2;
     reg [31:0] add_1;
     integer add_3;
    
     initial
     begin
         repeat(5)
         begin
             #1;
             add_1 = $random % 10;
             add_2 = {$random} %10 ;
             add_3 = $unsigned($random) %10 ;
         end
     end
    
     initial
     $monitor("add_3 = %d;add_2 = %d;add_1 = %d",add_3,add_2,add_1);
endmodule
RESULT:
add_3 = 7;add_2 = 7;add_1 = 8
add_3 = 7;add_2 = 7;add_1 = 4294967287
add_3 = 1;add_2 = 2;add_1 = 4294967295
add_3 = 7;add_2 = 8;add_1 = 9
add_3 = 9;add_2 = 2;add_1 = 9

The above example shows the generation of numbers from 0 to N.Some specification require the range to start from non Zero number. MIN + {$random} % (MAX - MIN ) will generate random numbers between MIN and MAX.

EXAMPLE:
module Tb();
    integer add;
   
    initial
    begin
        repeat(5)
        begin
            #1;
            add = 40 + {$random} % (50 - 40) ;
            $display("add = %d",add);
        end
    end
endmodule
RESULT:
add = 48
add = 47
add = 47
add = 47
add = 47

Now how to generate a random number between two ranges? The number should be between MIN1 and MAX1 or MIN2 and MAX2.The following example show how to generate this specification.

EXAMPLE:
module Tb();
    integer add;
   
    initial
    begin
        repeat(5)
        begin
            #1;
            if($random % 2)
                add = 40 + {$random} % (50 - 40) ;
            else
                add = 90 + {$random} % (100 - 90) ;
            $display("add = %d",add);
        end
    end
endmodule
RESULT:
add = 97
add = 47
add = 47
add = 42
add = 49

All the random number generates above generate numbers of 32 vector. Not always the requirements are 32 bit .For example, to generate a 5 bit and 45 bit vector random number, the following method can be used.

EXAMPLE:
module Tb();
    reg [4:0] add_1;
    reg [44:0] add_2;
    initial
    begin
        repeat(5)
        begin
            add_1 = $random ;
            add_2 = {$random,$random};
            $display("add_1 = %b,add_2 = %b ",add_1,add_2);
        end
    end
endmodule
RESULTS:
add_1 = 00100,add_2 = 111101000000110000100100001001101011000001001
add_1 = 00011,add_2 = 110110000110101000110110111111001100110001101
add_1 = 00101,add_2 = 100100001001000000000111100111110001100000001
add_1 = 01101,add_2 = 100010111011000011110100011011100110100111101
add_1 = 01101,add_2 = 101111000110001111100111111011110100111111001

Some protocols require a random number which is multiple some number. For example, Ethernet packet is always in multiples of 8bits,and PCIExpress packets are multiples of 4byts .Look at the following example. It generates a random number which is multiple of 3 and 5.

EXAMPLE:
module Tb();
    integer num_1,num_2,tmp;
    initial
    begin
        repeat(5)
        begin
            #1;
            tmp = {$random} / 3;
            num_1 = (tmp) * 3;
            tmp = {$random} / 3;
            num_2 = (tmp) * 5;
            $display("num_1 = %d,num_2 = %d",num_1,num_2);
        end
    end
endmodule
RESULT:
   num_1 = 303379746,num_2 = -1064739195
   num_1 = -2071669239,num_2 = -1309649305
   num_1 = 112818957,num_2 = 1189058955
   num_1 = -1295874969,num_2 = -1992863210
   num_1 = 15983361,num_2 = 114806025

All the above example show that the random numbers are integers only. In verilog there is not special construct to generate a random real number. The following method shows the generation of random real number.

EXAMPLE:
module Tb();
integer num_1,num_2,num_3;
real r_num;
   initial
   begin
       repeat(5)
       begin
           #1;
           num_1 = $random;
           num_2 = $random;
           num_3 = $random;
           r_num = num_1 + ((10)**(-(num_2)))*(num_3);
           $display("r_num = %e",r_num);
       end
   end
endmodule
RESULT:
    r_num = -2.071669e+03
    r_num = 2641.189059e+013
    r_num = 976361.598336e+01
    r_num = 57645.126096e+02
    r_num = 24589.097015e+0

To generate random real number , system function $bitstoreal can also be used.

EXAMPLE:
module Tb();
   real r_num;
   initial
   begin
       repeat(5)
       begin
          #1;
          r_num = $bitstoreal({$random,$random});
          $display("r_num = %e",r_num);
       end
   end
endmodule
RESULTS:
   r_num = 1.466745e-221
   r_num = -6.841798e-287
   r_num = 2.874848e-276
   r_num = -3.516622e-64
   r_num = 4.531144e-304


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

0 评论: