![]() |
9 |
BSVにおけるコマンドバッファ制御 (16) |
実際のプログラムでは最上位はConnectableにより直結しています。つまり上位のANDは生成されません。どうしたら良いか聞いてみます。
TopDirect.bsvにおいては、
rule connect; UInt#(4) x <- prod.produce; cons.consume(x); // 直ちに渡す $display("%0t: produce = %h", $time, x); recvCnt <= recvCnt + 1; endrule
このようになっている。これはcallerが2つのcalleeを呼び出すので、topにおいて2つのcalleeのrdyのANDがとられ、calleeのenableとなるはず。一方で、本来のGameFSM.bsv, SoundFSM.bsvは独立にコンパイルされ、topではconnectableで直接結線されるので、ANDは出てこない。つまり、上記のrule connectをconnectableに変更しても動作させるにはcalleeをどのようにしたら良いか?
なるほど、rule connect
をやめて Connectable で直結したいって話ですね。
その場合は、callee(Producer/Consumer)を標準の Get#/Put#
インタフェースで公開するのが王道です。そうすれば mkConnection
が内部で「両方readyなら転送」のルールを自動生成してくれるので、トップで2つの enable を同一ルールでANDする構造から卒業できます。
方針
- Producer:
Get#(T)
を出す(get
ガードで ready 表現) - Consumer:
Put#(T)
を受ける(put
ガードで ready 表現) - Top:
mkConnection(prod.out, cons.in)
で直結(rule connect
不要)
具体例
Consumer 側(今の consume
をPut
化)
import FIFO::*;
import GetPut::*; // ← これ必要
interface Consumer4Ifc;
interface Put#(UInt#(4)) in; // ← 受け口をPutに
// 必要なら状態確認用のmethodも追加可
endinterface
module mkConsumer4 (Consumer4Ifc);
Reg#(UInt#(4)) cnt <- mkReg(0);
Reg#(Bool) busy <- mkReg(False);
Reg#(Bool) play <- mkReg(False);
Reg#(UInt#(4)) lastVal <- mkRegU;
// timer は consume 中(=busy)は止める
rule timer (play && !busy);
if (cnt == 14) begin
cnt <= 0;
play <= False;
end
else
cnt <= cnt + 1;
endrule
rule clear_busy (busy);
busy <= False;
endrule
// これが元の consume 相当
interface Put in;
method Action put(UInt#(4) x) if (!busy);
lastVal <= x;
$display("%0t: consume = %h", $time, x);
busy <= True;
play <= True;
cnt <= 0;
endmethod
endinterface
endmodule
Producer 側(produce
を Get
化)
import GetPut::*;
interface Producer4Ifc;
interface Get#(UInt#(4)) out; // ← 出口をGetに
endinterface
module mkProducer4 (Producer4Ifc);
// 例:なんらかのソースから値を出す
Reg#(UInt#(4)) v <- mkReg(0);
// ready 条件をガードで表現(例:常にOKならガード無しでも可)
interface Get out;
method ActionValue#(UInt#(4)) get;
UInt#(4) x = v;
v <= v + 1;
return x;
endmethod
endinterface
endmodule
Top(直結)
import GetPut::*;
import Connectable::*; // ← これ必要
module mkTopDirect(...);
Producer4Ifc prod <- mkProducer4;
Consumer4Ifc cons <- mkConsumer4;
// 直結! これが rule connect の置き換え
mkConnection(prod.out, cons.in);
// もし recvCnt を増やしたいなら、Consumer 側でカウンタを増やすか、
// Consumer の put 内で RWire を叩いて Top で拾うなどの手もあります。
endmodule
補足(recvCnt
や$display
を Top でやりたい場合)
mkConnection
の中でput/get
が呼ばれるので、Top からはその瞬間が見えません。
Top で観測したいなら:
- Consumer の
put
内でRWire/PulseWire
に書く → Top でwget
を見てカウント・表示 - あるいは Consumer に「通知用のメソッド」を用意して Top から呼ぶ(設計次第)
これで Top に AND は出ず、Connectable
での疎結合が成立します。
既存のconsume
を崩したくないなら、薄いラッパーで Put#(T)
を包んで中で consume
を呼ぶだけでもOKです。