##はじめに
以前、もっとキレイな記述をした記憶があるんですが、探しても見つからなかったため、メモ代わりです。
##背景
テストの場合、always
文は極力使わずforever
文を使う自分ですが、いったんforever
文で走らせたタスクのparameterをrandomizeし直したい時があります。
何を言っているんだお前は と言われそうですが、まあテスト担当として未熟なんで軽くやりたいんですよねホント。
##processクラス
で、使うのがprocessクラスです。
これはSystemVerilogにビルドインされているクラスで、タスクで発生したスレッドの制御を行うことができます。主に、fork
~join..
とかでタスクを並列実行させてる場合に有効です。とはいっても、これを使っている人、 あまり見たことない。
検索するとこの辺とか出てくるんですが、LRMのサンプルそのまんまなんですよね。
fork
~join..
でforever
文が入ったタスクは、disable fork
やdisable
label でうまく消すことができませんでした。ちょっと調べた限り、そんな例はない。たぶん 誰もやらない。 なので、このクラスのkill functionを使ってみます。
つまりforeverで走らせるんだけど、やりなおしたい、どうにもならない、なんでprocessクラスを使って
ということになるんですな。
##コード
クロック発生させてみました。周波数は1..100ns周期のランダムで始まり、500ns進むと、周波数がランダムに変わります。
`timescale 1ns/1ps
interface my_if;
logic clk;
endinterface
class clk_period;
real period;
rand bit[63:0] bit_period;
bit[63:0] max_period = $realtobits(100.0);
bit[63:0] min_period = $realtobits(1.0);
process p;
virtual my_if v_myif;
constraint c_period{ (bit_period > min_period) && (bit_period < max_period) ; }
function new(virtual my_if m);
v_myif = m;
endfunction
function void post_randomize();
period = $bitstoreal(bit_period);
$display("CLK PERIOD == %f", period);
endfunction
function logic init_clk(logic clk);
clk = '0;
return clk;
endfunction
task clkgen(real period);
v_myif.clk = init_clk(v_myif.clk);
forever #(period/2.0) v_myif.clk = ~v_myif.clk;
endtask
task killer(int ptime);
wait(p != null);
#ptime;
p.kill();
endtask
task run(int ptime);
fork
begin
p = process::self();
clkgen(period);
end
killer(ptime);
join_none
endtask
endclass
module tb();
my_if myif();
clk_period cp;
initial begin
cp = new(myif);
if(cp.randomize())
cp.run(500);
#500;
cp = new(myif);
if(cp.randomize())
cp.run(500);
#500;
$finish(1);
end
endmodule
先に書いたようにprocessクラスはSystemVerilogのビルドインなので、コードの中では強調されてませんが、process
で宣言します。
ぐっと下がって、runタスクにあるself()関数を使い、リソースをゲットします。selfはスコープ演算子を使います。あとはclkgenタスクとkillerタスクが平行で実行されます。
clkgenタスクはクロック発生器です。
killerタスクは、リソースのゲットを待ち、ゲットされたらptime経過後、プロセスを無理やり全部killします。つまりclkgenタスクも消滅します。
##おわりに
コードが全体的に、昔記憶していたものと比べて汚い気がします。
というか、processクラス使わなくても、これくらいならdisable forkができそうな…。