Article #1014

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

前の記事で、ChatGPTのコード中に、busyなら受け付けないとあったのが気になったので確認します。

start_playに疑義があります。忙しかったらやらないのではプリエンプションを実装とはいえないのでは。

「ready は常に True」はハンドシェークの意味を成しません。

Producer が validをパルスで出したい場合、同サイクルにreadyが1でなければ 転送が成立しません。 そこで Consumer 側は「受け取った直後だけready=0に落とす」ことで 1 サイクル確実にハンドシェークを区切ります。

修正版 mkConsumer4_Preemptive

module mkConsumer4_Preemptive (ConsumerRaw);
   Reg#(Bool) busy       <- mkReg(False);   // 今まさに演奏中か
   Reg#(Bool) hasNewCmd  <- mkReg(False);   // 未処理コマンド保持
   Reg#(UInt#(4)) last   <- mkRegU;
   Reg#(Bool) ready_reg  <- mkReg(True);    // 出力する ready

   /* Producer から毎サイクル呼ばれるメソッド
      - always_ready/always_enabled: 条件文を書かない */
   (* always_ready, always_enabled *)
   method Action soundPreempt(UInt#(4) d);
      // 受信したサイクルで ready = 0 に落とす
      ready_reg  <= False;
      last       <= d;          // 最新コードを保持
      hasNewCmd  <= True;
   endmethod

   /* ready 出力メソッドは最後に置く */
   method Bool rdy_o();
      return ready_reg;
   endmethod

   /* 受信直後の次サイクルで ready を 1 に戻す */
   rule raise_ready (!ready_reg);
      ready_reg <= True;
   endrule

   /* 新コマンドがあればいつでも演奏を開始(busy を更新) */
   rule start_play (hasNewCmd);
      $display("%0t play %h", $time, last);
      busy       <= True;
      hasNewCmd  <= False;
   endrule

   /* ここでは 1 サイクルで演奏完了とする簡易例 */
   rule finish_play (busy && ready_reg);
      busy <= False;
   endrule
endmodule
 

挙動

サイクル Producer.valid Consumer.ready 動作
t 1 1 転送成立 → Consumer.ready を 0 へ
t+1 0 0→1 ready が復活。
busy が上がり演奏開始
busy中 1 1 新 valid が来れば上書きし即プリエンプト

このようにreadyを 1 サイクルだけ落とすことで

  • ハンドシェーク単位は厳密に 1 サイクル
  • それでもbusy中にいつでも新コードを受理し、即プリエンプション

が両立します。


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

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.