LoginSignup
1
0

More than 5 years have passed since last update.

[Systemverilog]foreverなタスクをkillして殺す。

Posted at

はじめに

以前、もっとキレイな記述をした記憶があるんですが、探しても見つからなかったため、メモ代わりです。

背景

テストの場合、always文は極力使わずforever文を使う自分ですが、いったんforever文で走らせたタスクのparameterをrandomizeし直したい時があります。
何を言っているんだお前は と言われそうですが、まあテスト担当として未熟なんで軽くやりたいんですよねホント。

processクラス

で、使うのがprocessクラスです。
これはSystemVerilogにビルドインされているクラスで、タスクで発生したスレッドの制御を行うことができます。主に、forkjoin..とかでタスクを並列実行させてる場合に有効です。とはいっても、これを使っている人、 あまり見たことない。
検索するとこの辺とか出てくるんですが、LRMのサンプルそのまんまなんですよね。

forkjoin..forever文が入ったタスクは、disable forkdisable label でうまく消すことができませんでした。ちょっと調べた限り、そんな例はない。たぶん 誰もやらない。 なので、このクラスのkill functionを使ってみます。

つまりforeverで走らせるんだけど、やりなおしたい、どうにもならない、なんでprocessクラスを使って
b4f3183d-s.jpg
ということになるんですな。

コード

クロック発生させてみました。周波数は1..100ns周期のランダムで始まり、500ns進むと、周波数がランダムに変わります。

kill.sv
`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ができそうな…。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0