5

ここで簡略化されたサンプル コードを参照してください。

    process job[num_objs]; 
    // assume also, arr_obj1s (array of type obj1) and 
    // arr_obj2s (array of type obj2) are arrays of size 
    // num_objs, and the objects define a run() function
    foreach (arr_obj1s[i]) begin
        fork
            automatic int j = i;
            arr_obj1s[j].run(); // these run forever loops
            begin
                job[j] = process::self();
                arr_obj2s[j].run(); // these run finite logic
            end
        join_none
    end

    foreach (job[i]) begin
        wait (job[i] != null);
        job[i].await();
    end

    // How do we ever reach here?

私の混乱は、への呼び出しarr_obj1s[j].run()が決して返されないことです (それらは永遠にループを実行します)。そして、その呼び出しが begin/end ブロックの外側に配置されることの意味を完全には理解していません。永久run()に実行されるプロセスはどれですか?また、返されないawait()プロセスが実行されている場合、各呼び出しが返されるのはrun()どうしてでしょうか?

編集:ここにいくつかの詳細があります。完全なコードを投稿するとページとページになりますが、この余分なビットが役立つことを願っています.

obj1 のrun()関数は次のようになります。

virtual task run;
  fork
    run_a(); // different logically separated tasks
    run_b();
    run_c();
  join
endtask: run

例として、run_a基本的には次のようになります (すべて類似しています)。

virtual task run_a;
  // declare some local variables
  forever begin
    @(posedge clk)
    // ...
  end
endtask: run_a

しかし、obj2 のrun()関数は基本的に次のようになります。

virtual task run;
  fork
    run_d(); // different logically separated tasks
    run_e();
  join
endtask: run

例として、run_d()次のようになります。

virtual task run_d;
  while ((data_que.size() > 0)) begin
    // process a pre-loaded queue,
    // data will not be pushed on during the simulation
  end
endtask:run_d
4

2 に答える 2

7

このコード フラグメントは、プロセス制御を示しているように見えるので、何が起こっているかについての私の推測は次のとおりです。arr_obj1s と arr_obj2s にはプロセスのグループがあります。

  • arr_obj1s にあるものは永久に実行されるため、一度スポーンするだけでよく、忘れられます。
  • arr_obj2s にあるものは何らかのタスクを完了して戻るため、親プロセスはこれがいつ発生するかを知る必要があります。
  • すべてのプロセスが同じ親を持つ

私の混乱は、 arr_obj1s[j].run() への呼び出しが決して返されないことです (それらは永遠にループを実行します)。そして、begin/end ブロックの外にあるその呼び出しの配置の意味を完全には理解していません。

したがって、すべてのプロセスを生成するために必要なのは、fork..join_noneブロック内の 3 行のコードだけです。

foreach (arr_obj1s[i]) begin
  fork
    automatic int j = i; // Spawns process
    arr_obj1s[j].run();  // Spawns process
    arr_obj2s[j].run();  // Spawns process
  join_none
end

join_noneキーワードは、並列ブロックが完了した後も実行が継続されることを示します。したがって、foreach ループ全体が実行され、親プロセスは次の foreach ループに進みます。さらに、join_none は、親プロセスがブロッキング ステートメントに到達するまで、子プロセスが開始されないことも意味します。

ただし、子プロセスが変更する何らかの共有変数を持っていない限り、子プロセスがいつ完了するかを検出することはできません。そのコーディングを回避するために、SystemVerilog はプロセスへのハンドルを許可し、プロセスが完了したときにイベントをスケジュールできるようにします。ただし、単一のステートメントのハンドルを取得する機能は提供されません。プロセス ハンドルを取得するには、手続き型コンテキスト内で process::self() を使用する必要があります。したがって、これを fork-join ブロックに直接追加すると正しく機能しません。

foreach (arr_obj1s[i]) begin
  fork
    automatic int j = i;
    arr_obj1s[j].run();
    job[j] = process::self(); // Will return parent process
    arr_obj2s[j].run();
  join_none
end

これを修正するには、プロセス ハンドルを取得できる新しい順次手続き型コンテキストを作成し、そこから関数を実行する必要があります。

foreach (arr_obj1s[i]) begin
  fork
    automatic int j = i;
    arr_obj1s[j].run(); // Spawns a new process for those that don't complete
    begin               // Spawns a new process for those that complete
      job[j] = process::self(); // Saves handle to this begin..end process
      arr_obj2s[j].run();       // Process continues though here
    end
  join_none
end

最後の foreach ループは、ハンドルを持っているプロセスのみを待機します。永久に実行されるプロセスは無視されます。

于 2013-01-02T19:11:56.260 に答える
6

まず、Verilog で fork/join が機能する方法では、fork/join ブロック内の各ステートメントが同時に実行されます。開始/終了がない場合、各行はそれ自体がステートメントです。

したがって、あなたの例は、ループの反復ごとに少なくとも 2 つのプロセスをフォークしています。

    fork
        automatic int j = i;                               <= Statement 1 ??
        arr_obj1s[j].run(); // these run forever loops     <= Statement 2
        begin                                              \ 
            job[j] = process::self();                      |  <= Statement 3
            arr_obj2s[j].run(); // these run finite logic  |
        end                                                /
    join_none

automatic int jこの場合、 がどのように扱われるかを完全には理解していないので、少なくとも言います。

これが何が起こるかです。

ループの反復ごとに:

  1. arr_obj1s[j].run()開始されます。(これは永久ループを実行し、決して終了しません。)
  2. arr_obj2s[j].run()開始されます。(これは一定時間実行すると終了します。) これを開始したプロセスのプロセス ID は に格納されjob[j]ます。

呼び出しているコードはawait、への呼び出しを開始したプロセスのみを待機していますarr_obj2s[j].run()。有限のタスクを実行しているため、それらは完了します。

await呼び出しがすべて完了した後でも、永久ループは引き続き実行されます。

于 2013-01-02T19:08:57.080 に答える