Article #1018

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

実際のプログラムでは最上位は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 側(今の consumePut化)

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 側(produceGet化)


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

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.