18 |
サウンドミキサーの開発 (2) |
サウンドミキサーの検証
bsvでモジュールを開発するに際して、正解値を出力するverilogモジュールを作成しました。それぞれのモジュールを駆動するテストベンチはbsvのステートマシン合成で簡単に作成できます。verilogの世界で統合するために、テストベンチの上位にverilogの最上位階層を設けます。なぜならbsvの最上位であるテストベンチ階層にはクロックもリセットも存在しないため、verilogの最上位階層を設けてクロックとリセットをテストベンチに供給してやる必要があるためです。
ここまでは通常のBSV⇒verilogシミュレーション手法ですが、最上位階層を統合して一つにすれば、その中に2つのbsvから生成されたverilogのステートマシンとそれに接続されるverilogモジュールが配置されることになります。
|
|
top階層からverilogモードによるC-c C-aで自動結合するには、自モジュール名とファイル名が一致する必要があります。
ここで最上位階層top.vを統合して一つにし、テストベンチを2つ配置します。これで正解値と比較してデバッグし以下のミキサーが完成しました。以下にコードを示します。
typedef Int#(8) Esound_t; typedef Int#(16) Lsound_t; interface Mixer_ifc; (* prefix="" *) method Lsound_t mout( Esound_t ch0, Esound_t ch1, Esound_t ch2, Esound_t ch3 ); // output (* prefix="" *) method Bool soundon( Bool son0, Bool son1, Bool son2, Bool son3 ); // output endinterface (* synthesize, always_enabled = "mout, soundon", no_default_clock, no_default_reset *) module mkMixer(Mixer_ifc); function Bit#(9) repeatBit(Bit#(1) b); Bit#(9) result = 0; for (Integer i = 0; i < 9; i = i + 1) begin result = result << 1; result[0] = b; end return result; endfunction method Lsound_t mout( Esound_t ch0, Esound_t ch1, Esound_t ch2, Esound_t ch3 ); // output let tmp0 = pack(ch0); let tmp1 = pack(ch1); let tmp2 = pack(ch2); let tmp3 = pack(ch3); Int#(16) itmp0 = unpack({repeatBit(~tmp0[7]),tmp0[6:0]}); Int#(16) itmp1 = unpack({repeatBit(~tmp1[7]),tmp1[6:0]}); Int#(16) itmp2 = unpack({repeatBit(~tmp2[7]),tmp2[6:0]}); Int#(16) itmp3 = unpack({repeatBit(~tmp3[7]),tmp3[6:0]}); Int#(16) tmp4 = itmp0 + itmp1 + itmp2 + itmp3; let tmp5 = tmp4 << 6; return tmp5; endmethod method Bool soundon( Bool son0, Bool son1, Bool son2, Bool son3 ); // output let sdon = son0 || son1 || son2 || son3; return sdon; endmethod endmodule
まずげた履き符号から2の補数表現に変換するために、MSBの反転を行います。次にそれを符号拡張し16ビット整数とします。それらを加え合わせてスケーリングを行います。
シミュレーションの結果、4つのチャネルにどんな値が入力されてもオーバーフローやアンダーフローが起きないことを検証しています。