$urandom/$urandom_range
1. $randomと$urandomの違い
$urandomは、SVで追加されたランダム関数です。符号なしのランダム関数になりますが、次表の通り、その中身は、随分違います。
$random | $urandom/$urandom_range | |
符号 | signed | unsigned |
戻り値 | integer 32bit (4値 ただしzxが返ることはない) | int 32bit (2値) |
引数(seed option) | 次回seed値が、書き戻される仕様のために 引数は、integeral variable(記憶のある変数タイプ)でなければならない |
seed値について特に型の制限はない(次回seed値は書き戻されない。) |
ランダムシーケンス | LRMで規定されている。Vendor間で互換あり | 実装依存。Vendor間の互換はない |
適用 | グローバル | スレッドローカル |
階層Seed | グローバルのためにそういう概念はない | スレッド生成時に親スレッドからSeed値をもらう つまり子スレッドのランダムシーケンスは、親スレッドに依存する |
使い方 | bit [23:0] rand; rand = $random % 60;//-59から59まで 符号付のために注意が必要。符号なしが欲しい場合、例えば{}もしくは $unsigned($random)で、符号なしにする。 bit [23:0] rand; rand = {$random} % 60;//0から59まで |
rand=$urandom_range(59);//0から59まで rand=$urandom_range(59,0);//0から59まで rand=$urandom_range(0,59);//0から59まで |
1.1 $urandomは、実装依存
$randomは、Verilog2001のLRMにCソースが掲載されており、これに基づいて実装されているために、各Vendor間で互換があります。$urandomは、実装依存です。各Vendor間の互換はありません。
1.2 $urandomシーケンスは、$randomとは無関係
$randomがどのように動こうと、$urandomのランダムシーケンスは、影響を受けません。反対もまたしかりです。
1.3 $randomの問題
テストベンチの開発において、しばしば悩ましいのは、$randomは、グローバルに効いてしまうことです。 テストベンチでは、他のスレッドの影響を受けない独立したランダムシーケンスが欲しい場合が多いのですが、$randomは、どこにあっても影響してしまいます。 テストベンチの開発過程においては、コードの追加削除は日常茶飯事ですので、その度に$randomシーケンスが変化すると余計なデバッグの手間が増えてしまいます。テストベンチの開発効率に影響してしまいます。
1.4 seed でランダムシーケンスを制御できる
module urandom_test3;
initial begin
repeat (10) $display("initial1: %8x",$urandom());
$display("");
end
initial begin
repeat (10) $display("initial2:%8x",$urandom());
end
endmodule
***** Veritak SV6464 Engine Version 0.440 Build Dec.13.2011 ***** initial1: c6d422b3 initial1: 6cfac2aa initial1: 9ce97ec5 initial1: ab657674 initial1: 54c90b67 initial1: 8b07d88e initial1: fe3ecd19 initial1: 1b2fdb78 initial1: f74aec5b initial1: c61f05b2 initial2:c6d766b0 initial2:16f72ab3 initial2:e2b1aaaa initial2:8964c6c5 initial2:7d139e74 initial2:9a5e9367 initial2:0a67408e initial2:0fc09519 initial2:b7ca8378 initial2:2e1af45b ---------- シミュレーションを終了します。time=0nsinitial1とinitial2 のランダムシーケンスが異なることが分かります。これに同じseed、例えば0を追加してみます。
module urandom_test4;
initial begin
$urandom(0);
repeat (10) $display("initial1: %8x",$urandom());
$display("");
end
initial begin
$urandom(0);
repeat (10) $display("initial2:%8x",$urandom());
end
endmodule
***** Veritak SV6464 Engine Version 0.440 Build Dec.13.2011 *****
initial1: 1e278e7a
initial1: d2f65b55
initial1: 098520c4
initial1: a2974c77
initial1: 2e15555e
initial1: 20ad96a9
initial1: 7e1dbec8
initial1: a8d2826b
initial1: 77948382
initial1: 96dd9c3d
initial2:1e278e7a
initial2:d2f65b55
initial2:098520c4
initial2:a2974c77
initial2:2e15555e
initial2:20ad96a9
initial2:7e1dbec8
initial2:a8d2826b
initial2:77948382
initial2:96dd9c3d
---------- シミュレーションを終了します。time=0ns
1.5 $urandomは、スレッドローカル
上の反省versionが、$urandomです。スレッドとは、他のスレッドに一旦行っても、自分のコンテキストを復元して戻ってこれるプログラム単位のことです。
verilog HDLでは、次が、スレッドで実装されます。
従って、これらのステートメント上にある、$urandomは、独立したランダムシーケンスを持ちます。(2^32ビット周期のシーケンスとしてみると一つですが、異なる
Seedを与えることによって、短い期間でみると異なるランダムシーケンスに見えます。)
module urandom_test5;
initial
fork
begin
repeat(3) begin
#($urandom_range(10));
$display(" I1UT1 %x %d",$urandom(),$time);
end
end
begin
repeat(3) begin
#($urandom_range(1000));
$display(" I1UT1 %x %d",$urandom(),$time);
end
end
join
endmodule
***** Veritak SV6464 Engine Version 0.440 Build Dec.13.2011 *****
I1UT1 12700ff6 1
I1UT1 66bc0e20 5
I1UT1 28010d9a 12
I1UT2 dd93a09a 924
I1UT2 a32ec3e4 1305
I1UT2 32d1117e 1926
---------- シミュレーションを終了します。time=1926ns
module urandom_test6;
initial
fork
begin
repeat(3) begin
#($urandom_range(10));
$display(" I1UT1 %x %d",$urandom(),$time);
end
end
begin
repeat(3) begin
#($urandom_range(10));
$display(" I1UT1 %x %d",$urandom(),$time);
end
end
join
endmodule
上側のプロセスは、下側のプロセス$urandomの影響を受けずに、前の結果と同じであることが分かります。
***** Veritak SV6464 Engine Version 0.440 Build Dec.13.2011 ***** I1UT2 dd93a09a 0 I1UT1 12700ff6 1 I1UT1 66bc0e20 5 I1UT2 a32ec3e4 7 I1UT1 28010d9a 12 I1UT2 32d1117e 12
スレッド自身が、$urandomオブジェクト領域を持っており、他のスレッドの影響を受けずに独立したシーケンスを保てます。
1.6 階層Seed
子どもスレッド生成時、親スレッドのseedを元に子どものseedが決定されます。(どのように決定されるかは実装依存)。この時点で親スレッドのランダムシーケンスは、一つ進むことになります。いずれにしても、子どもの$urandom値は、seedを指定しない限り、親スレッドに依存することになります。言い換えると、親のルートのseedを変えてやれば、その子どもスレッド全体に影響は波及することになります。これによりコントロール可能なランダムシーケンスが実現できます。
次のソースでは、
と起動されますが、t2までは、子スレッドです。f1/f2は、t2のurandomオブジェクトを操作します。しかしながら、このランダムシーケンスは、最初の$urandom(0)で
制御されていることに注意してください。このinitial プロセスをコピペしても同じランダムシーケンス結果になります。また、例えば、$urandom(1)とすれば、違うランダムシーケンスとなります。
module urandom_test8;
initial begin
$display("%x ",$urandom(0));
fork
begin
// $urandom(0);
repeat(3) begin
#($urandom_range(10));
t1;
$display(" I1UT1 %x %d",$urandom(),$time);
end
end
begin
// $urandom(0);
repeat(3) begin
#($urandom_range(1000));
t1;
$display("I1UT2 %x %d",$urandom(),$time);
end
end
join
end
function f1;
$display("f1:%x",$urandom());
f2();
endfunction
function f2;
$display("f2:%x",$urandom());
endfunction
task t1;
$display("t1:%x",$urandom());
t2;
endtask
task t2;
$display("t2:%x",$urandom());
f1();
endtask
endmodule
***** Veritak SV6464 Engine Version 0.440 Build Dec.13.2011 ***** 00269ec3 t1:d8f9f0c3 t2:fc95bc34 f1:04ff3a27 f2:6b104c4e I1UT1 d8f9f0c3 5 t1:72f67ec5 t2:dd0bee22 f1:5ea9dc5d f2:97c8bdac I1UT1 72f67ec5 5 t1:cca120fb t2:10fe4a3c f1:3797b00f f2:b4508a96 I1UT1 cca120fb 14 t1:a71b0a9d t2:ee53438a f1:1dbb7c25 f2:e85cfe54 I1UT2 a71b0a9d 484 t1:8bb2c0c3 t2:df966c34 f1:9abd2a27 f2:ed967c4e I1UT2 8bb2c0c3 1338 t1:08b46ec5 t2:2fde7e22 f1:04722c5d f2:cbafcdac I1UT2 08b46ec5 1938 ---------- シミュレーションを終了します。time=1938ns
1.7 $urandom_range
$urandomと同じで、スレッドローカルです。
内部宣言は、
function int unsigned $urandom_range( int unsigned maxval,int unsigned
minval = 0 );
で、
val = $urandom_range(7,0); $urandom_range(7); $urandom(0,7);は、どれも同じ意味で0から7までを返します。
1.8 $urandomの速度
$randomは、浮動小数を使った確率分布に基づいた関数になっています。(LRM) 一方$urandomは、実装依存なので一概には言えないのですが、$randomに比べれば、数倍以上速いと思います。