4

SystemVerilog では、disable構文を使用して名前付きブロックまたはタスクを終了できます。しかし今日、クラス インスタンス内のタスクを無効にすると、すべてのクラス インスタンス内のタスクのすべてのコピーに影響することがわかりました。

その中でいくつかのタスクが定義されているクラスを考えてみましょう。クラスの内部で への呼び出しがある場合、クラスのすべてのインスタンスでタスクのすべてのコピーdisable <taskname>が無効になります。これは私が期待した動作ではありませんが、LRM によれば正しい動作です。

タスクが複数回有効になっている場合、そのようなタスクを無効にすると、タスクのすべてのアクティブ化が無効になります。

クラスの特定のインスタンス内のタスクのみを無効にするメカニズムまたは回避策はありますか?

以下のコードは、私が直面している問題を強調しています。基本的に、他のイベントのために無効にしたいタイマータスクがあります。これはすべてクラス内に含まれています。私の検証環境では、このクラスの複数のインスタンスがあり、それらは完全に独立して動作します。したがって、1 つのインスタンス内でタイマーを無効にしても、他のインスタンスには影響しません。しかし、disableそれが機能する方法は、他のインスタンスに影響を与えています。

私は試しdisable this.timerましたが、それはコンパイルされませんでした。

この例でclass cは、タスクを含む2 つのインスタンスがありtimerます。disablerを呼び出す、並行して開始されるタスクがありますdisable timer。この例の目的はtimer、カウントの途中で無効にすることです。したがってc1は時間 5 でc2無効になり、時間 10 で無効になります。ただし、 でdisable timer発信された呼び出しが との両方でc1タスクを無効にするため、両方とも時間 5 で無効になります。c1c2

module top();

  class c;

    string name;
    int    count;

    function new(string _name, int _count);
      name  = _name;
      count = _count;
    endfunction

    task t1();
      timer();
      $display("%t %s timer completed", $time, name);
    endtask

    task run();
      fork
        t1();
        disabler();
      join
    endtask

    task timer();
      $display("%t %s starting timer with count=%0d", $time, name, count);
      repeat(count) #1;
    endtask

    task disabler();
      repeat(count/2) #1;
      disable timer;
    endtask

  endclass

  class ex;

    c c1;
    c c2;

    function new();
      c1 = new("c1", 10);
      c2 = new("c2", 20);
    endfunction

    task run();
      fork
        c1.run();
        c2.run();
      join_none
    endtask

  endclass

  ex e = new;

  initial begin
    e.run();
  end

endmodule

出力:

               0 c1 starting timer with count=10
               0 c2 starting timer with count=20
               5 c2 timer completed
               5 c1 timer completed

を使用せずにこれを書き直して動作させることができることはわかっていdisableますが、タスクを早期に終了するのは非常に簡単な方法であるため、欠けているものがあることを願っています。

4

3 に答える 3

3

これは不可能だと思います。名前付きブロックでdisableを使用しても、そのタスクのすべてのインスタンスが停止します。

自動タスクまたは自動タスク内のブロックを無効にすると、通常のタスクと同様に、タスクのすべての同時実行が実行されます。

プロセス クラスを使用してみることができます。私はそれらを自分で使用したことがないため、このコードにはエラーが含まれている可能性があります。

class c;
process p1;

task run();
  fork
    begin
      p1 = process::self(); //Get process of this begin..end block
      $display("%t %s starting timer with count=%0d", $time, name, count);
      repeat(count) #1;
    end
    disabler()
  join_none
endtask

task disabler();
  wait (p1 != null);
  repeat(count/2) #1;
  p1.kill();
endtask
于 2012-10-03T14:58:29.473 に答える
2
class a1; 
  process p1; 

  task timer();
    p1=process::self();
    begin
      while(1)
      begin
        $display("example data %t",$time);
        #10;
      end 
    end 
  endtask

  task timer2();
    for(int i = 0; i < 10; i ++) 
    begin
      #20;
      $display("shouldnot killed",i);
    end
  endtask

endclass

module example_kill;
  a1 ab,bc;
  initial begin 
    ab = new();
    bc= new();
    fork 
    ab.timer();
    ab.timer2();
    bc.timer();
    join_none
    #50; 
    ab.p1.kill();
    #100;
    bc.p1.kill();
    wait fork;
  end
endmodule
于 2013-11-25T13:41:31.737 に答える
0

タスクはスレッド内で分離できると思います。アイデアは、スレッド内でタスクを分離することです。特定の 1 つのインスタンスに対してのみ、ディセーブル フォークを適用する必要があります。したがって、私たちがいるインスタンスについて質問する必要があります。systemverilog では次のことが許可されていないため、問題が発生します。

fork begin yourtaskcall; end join_none if (class_instance_disable_member_id==1) begin disable fork; end その後、前のコードを再度ラップして、そのタスクの無効化フォークのみを分離できます。例えば

fork begin fork begin yourtaskcall; end join_none if (class_instance_disable_member_id==1) begin disable fork; end end join

最後に、無効にする特定のインスタンスの変数「 class_instance_disable_member_id」を 1 (デフォルト値 = 0 ) に設定する必要があります。これは、アウタークラスまたはトップクラスから実行できます。

例 top.class1.class_instance_disable_member_id=1;

タスクが呼び出されるまでに、タスクは無効になります。そのため、呼び出しが発生する前に「class_instance_disable_member_id=1 変数」を設定する必要があります。UVM を使用する場合は、フェーズ (実行フェーズの前にビルドまたは接続) を使用できます。単純な systemverilog の場合は、new() コンストラクターを使用して、その変数を先頭から正しいインスタンスに設定できます。

「その場で/動的に」タスクをアクティブ化/非アクティブ化する場合は、無効にするタスクが呼び出される前に、特定のインスタンスの「class_instance_disable_member_id」を変更する別のスレッド/タスクを上部に配置する必要があります。

次の基本ブロックを使用して、class_instance_disable_member_id の変更を検出して、途中でタスクを強制終了することもできます。

fork begin yourtaskcall; end begin if (class_instance_disable_member_id==0) begin @(posedge class_instance_disable_member_id); end end join_any if (class_instance_disable_member_id==1) begin disable fork; end

BRに役立つことを願っています

于 2016-10-12T07:36:33.040 に答える