9 |
Pongの開発 (4) |
疑似乱数生成器
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の中に入れます。
Leave a Comment