Posts Issued on November 9, 2023

Pongの開発 (4)

posted by sakurai on November 9, 2023 #693

疑似乱数生成器

ChatGPTにLFSRのアルゴリズムを持つ疑似乱数生成器を記述してもらいました。以下の完成したモジュールはそれを手直ししたものです。

interface Randomizer_ifc;
  method ActionValue#(Bit#(1)) random_01();
endinterface

//(* synthesize *) モジュールをインライン化するためコメントアウト
module mkRandomizer(Randomizer_ifc);
    Reg#(Bit#(16)) lfsr <- mkReg(16'hACE1); // 適当な非ゼロの初期値

  method ActionValue#(Bit#(1)) random_01();
       Bit#(1) newBit = lfsr[15] ^ lfsr[13] ^ lfsr[12] ^ lfsr[10];
       lfsr <= {lfsr[14:0], newBit};
       return lfsr[15];
  endmethod

endmodule

ActionValueメソッドの呼び出し方

作成した疑似乱数生成器の呼び出しが少々難しかったのでまとめておきます。BSVにおいてはモジュールインタフェース内に記述されるメソッドの型は

  • Value Method
  • ActionValue Method
  • Action Method

の3種類があります。それぞれ入力、入出力、出力ポートに対応しますが、ActionValueの呼び出し方に少々困難がありました。単純にメソッドを変数に入れることができないためです。

特にFSMを構成するseqブロック内で、あるレジスタwにValueメソッドの戻り値を代入するだけなら、

seq
   :
   w <= random_01();
   :
endseq

等とすれば良いのですが、この場合のrandom関数は内部状態を持ち、それが呼び出しにより更新されるという副作用を持つため、ActionValueメソッドとして呼び出します。この呼び出し法が少々難しく、"<-"を用いてインスタンスした上で、かつ単純にseqの中で呼ぶことはできず、actionブロックを構成してその中でのみ有効な値となります。

実例を挙げると、

import Randomizer::*;
Randomizer_ifc randomizer <- mkRandomizer;
   :
    seq
        action
   :
           Bit#(1) w <- randomizer.random_01();
   :
        endaction
    endseq

のように、actionブロックの中で"<-"を用いて関数を呼び出します。特にactionブロックを構成することになかなか気づきませんでした。

追記:
この場合の変数wはaction - endactionのスコープ内でしか有効でないことが後日判明したので、それを回避する方法を追記します。action - endactionのスコープ内でコピー変数にコピーするだけです。

    Reg#(Bit#(1)) ww <- mkRegU; // wをactionスコープの外で使用するコピー変数
   :
    seq
        action
   :
           let w <- randomizer.random_01();  // Bit#(1)宣言でなくてletでも良い
           ww <= w;
   :
        endaction
    endseq

なお、関数がマルチサイクルの場合はこれでうまく行かない場合もあり、その場合はruleの中に入れます。


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