Article #1002

既に発行済みのブログであっても適宜修正・追加することがあります。
We may make changes and additions to blogs already published.
posted by sakurai on July 31, 2025 #1002

まず、ChatGPTに、BSVの2線ハンドシェイクアルゴリズムを尋ねてみます。

bluespecのモジュールでは自動的に2線方式のハンドシェークが行われるが、そのアルゴリズムを解説してください。


以下、Blu­e­s­pec がモジュール間/ルール間で自動的に挿入する「2線ハンドシェーク」の 正確なアルゴリズム をまとめ直します。

1. ハンドシェークの基本モデル

各メソッド呼び出し(あるいはルール起動)には、必ず以下の2本の信号が対応します。

信号 BSV上の名前 役割
Ready can_fire() Callee(呼ばれる側)が 実行可能 かを示す純組合せフラグ (ready)
Enable will_fire Caller(呼ぶ側)が 実際に起動 する1サイクルパルス (enable)
  • Ready (can_fire) は、FIFO なら !full、Register なら常に True、独自モジュールなら内部状態から算出される組合せ信号です。
  • Enable (will_fire) は後述のルール・スケジューラによって自動合成される一周期パルス信号で、これが Callee の *_enポートに接続されます。

2. ルール/メソッド呼び出し単位での合成フロー

2.1 各メソッドのcan_fire 取得

ルールの本文中で呼ぶメソッドが複数ある場合、まずそれぞれの Ready 信号を取り出します。

rule foo when (guard);
   let v  <- A.method1.can_fire;   // ①
       w  <- B.method2.can_fire;   // ②
   …
endrule

(実際は can_fire()はメソッド呼出子の後ろに自動で付く組合せロジックです)

2.2 ルール単位の can_fire_rule (= 全 Ready の AND)

ルールは「自分のガードが真 & すべての callee が Ready」で発火可能です。

wire can_fire_rule = guard && A_ready && B_ready;

2.3 スケジューラ仲裁 (scheduler_grant)

同じリソース(レジスタやポート)に対して競合する他ルールとの静的解析結果に基づき、 can_fire_rule 同士の優先度/排他を決める組合せロジックが入ります。

// 競合ルール同士なら priority_bits で排他
wire grant_rule = can_fire_rule & scheduler_logic(…);

2.4 will_fire(= 発火パルス)

上記 grant_ruleが 1 サイクルだけ 真になる「発火許可パルス」となり、 これが Enable 信号として扱われます。

wire will_fire = grant_rule;  // 1-cycle pulse

2.5 Callee への配線 (扇形ファンアウト)

得られた will_fire を、ルール本文で呼び出したすべてのメソッドの*_en(Enable)端子に繋ぎます。

assign A_en = will_fire;
assign B_en = will_fire;

2.6 レジスタ更新の en 端子

同じ will_fire をそのルール内のレジスタ書き込み *_en にも使うので、 レジスタ更新 も同一パルスでまとめて走ります。

3. 複数ルール/複数メソッドの競合回避

  • 同一リソースを書き換える複数ルール は、静的優先度ツリー(priority tree)で排他し、あるルールが will_fire すると他は偽になります。
  • 同一ルール内の複数メソッド呼び出し は、ひとつの will_fireで 同時に 起動。
  • 非競合ルール どうしは並列に will_fire可能。

合成後、以下のような MUX/OR ネットワークが作られます:

// レジスタ更新データの MUX(優先度付き)
assign reg_din =
      (rule2_will_fire) ? data2 :
      (rule1_will_fire) ? data1 :
                          reg_q;

// write-enable の OR
assign reg_en = rule1_will_fire | rule2_will_fire | … ;

4. まとめ:2線ハンドシェークの要点

  1. Ready (can_fire)

    • Callee が 組合せで「今受け入れられるか」を出力。
  2. Enable (will_fire)

    • ルール単位で「ガード & 全 Ready & スケジューラ許可」を合成し、
    • 1 サイクルだけ真になるパルスを自動生成。
  3. ファンアウト
    • そのパルスを該当するすべてのメソッド/レジスタの *_en に扇形配線。
  4. 競合解消
    • 複数ルール間の静的優先度/排他はコンパイラが生成。
  5. ユーザ記述不要
    • can_fire()以外はすべて BSC が自動で合成し、
    • 人手で AND/OR や MUX を書く必要はありません。

これが Bluespec SystemVerilog が内部的に繰り返す 「2 線方式ハンドシェーク」 の実装アルゴリズムです。


左矢前のブログ 次のブログ右矢

まず、ChatGPT に BSV の 2 線ハンドシェークを尋ねてみます。

> bluespec のモジュールでは自動的に 2 線方式のハンドシェークが行われるが、そのアルゴリズムを解説してください。


以下、Bluespec SystemVerilog がモジュール/ルール間に自動挿入する 2 線ハンドシェーク (Ready–Enable) のアルゴリズムを Producer(送り手) / Consumer(受け手) という固定役割だけで解説します。 階層が変わっても物理向きは一切反転しません。

1. ハンドシェークの基本

信号物理方向意味生成元
RDY_consumerConsumer → Producer「空きがあります」通知Consumer が組合せで出力(!full 等)
firewireRDY_consumer & Req_producerルールガードが組合せで生成
EN_producer / EN_consumerfire → 双方 (入力)fire 1 クロックストローブbsc が扇形配線
DATAProducer → ConsumerペイロードProducer が EN=1 サイクルで出力
※ RDY は常に Consumer から出る。
 EN は fire を入力で受ける

(Producer が単独で EN を駆動することはありません)

2. ルール内での合成フロー

<pre><code class="language-BSV"> rule send_when_ready (prod_req && cons.rdy); // RDY_consumer を参照 cons.en(data); // fire がここで 1 クロック生成 endrule </code></pre>

fire パルス (Verilog 展開例)

<pre><code class="language-verilog"> wire fire = prod_req & cons_rdy; // 組合せ AND assign EN_producer = fire; assign EN_consumer = fire; </code></pre>


3. 複数ルールの場合

bsc が同一リソースへ向かう fire を静的解析し、 優先度ツリー/排他 OR ネットを自動生成。 競合のないルールは並列発火可能。


4. 要点まとめ

  1. RDY ― Consumer が組合せで出力
  2. fire = RDY ∧ Req_producer ― ルールガードで生成
  3. EN ― fire を Producer / Consumer 双方の入力に扇形配線
  4. 競合解消は bsc ― ユーザは AND・MUX を手書き不要

これが BSV が内部で実装する純ハード視点の 2 線 Ready-Enable ハンドシェークです。 向きは常に
RDY : Consumer → Producer
EN : fire → 双方
で固定され、階層を跨いでも反転しません。


左矢前のブログ
次のブログ右矢

Leave a Comment

Your email address will not be published.

You may use Markdown syntax. If you include an ad such as http://, it will be invalidated by our AI system.

Please enter the numbers as they are shown in the image above.