| 
                                         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です。
    
    
    
Leave a Comment