31 |
BSVにおけるコマンドバッファ制御 (2) |
まず、ChatGPTに、BSVの2線ハンドシェイクアルゴリズムを尋ねてみます。
bluespecのモジュールでは自動的に2線方式のハンドシェークが行われるが、そのアルゴリズムを解説してください。
以下、Bluespec がモジュール間/ルール間で自動的に挿入する「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線ハンドシェークの要点
Ready (
can_fire
)- Callee が 組合せで「今受け入れられるか」を出力。
Enable (
will_fire
)- ルール単位で「ガード & 全 Ready & スケジューラ許可」を合成し、
- 1 サイクルだけ真になるパルスを自動生成。
- ファンアウト
- そのパルスを該当するすべてのメソッド/レジスタの
*_en
に扇形配線。
- そのパルスを該当するすべてのメソッド/レジスタの
- 競合解消
- 複数ルール間の静的優先度/排他はコンパイラが生成。
- ユーザ記述不要
can_fire()
以外はすべて BSC が自動で合成し、- 人手で AND/OR や MUX を書く必要はありません。
これが Bluespec SystemVerilog が内部的に繰り返す 「2 線方式ハンドシェーク」 の実装アルゴリズムです。
caller/calleeが分かりにくかったですが、callerは最上位、calleeがモジュールで、この場合は両FSMとなります。