FPGA 版 FM 音源 (59) -- FPGA 版 EG (3)
EG クロック・プリスケーラ・モジュール「opl3_EG_psc()」を回路図で表現したものを下に示します。
Verilog で書いたものを下に示します。
"opl3_EG_psc.v"
// // opl3_EG_psc() : OPL3 EG prescaler module // // 2017/01/08 Created by pcm1723 // module opl3_EG_psc( // // Input // reset, // async. reset input m_clk, // master clock input fs_clk_en, // enable for sampling clock rate, // EG rate input rof_1, // rof[1] input rof_0, // rof[0] input // // Output // clk_en, // EG clock enable output sft_sel // EG shift select output ); // Input port input reset; input m_clk; input fs_clk_en; input [3:0] rate; input rof_1; input rof_0; // Output port output clk_en; output sft_sel; // wires wire hi_rate; // hi_rate flag wire [13:0] edge_det; // positive edge detction // wire [15:0] base; // base frequency pulses wire [15:0] div2; // base div 2 freq. pulses wire [15:0] div4; // base div 4 freq. pulses // regs reg [13:0] psc_cnt; // prescaler counter reg [13:0] psc_z1; // 1 sample delay // // hi_rate flag (rate >= 13) assign hi_rate = ( rate >= 13 ); // positive edge detection of prescaled clock assign edge_det = (psc_cnt & (~psc_z1)); // base frequency pulses assign base = {1'b0,edge_det[11:0],3'b000}; // base freq. div 2 pulses assign div2 = {1'b0,edge_det[12:1],3'b000}; // base freq. div 4 pulses assign div4 = {1'b0,edge_det[13:2],3'b000}; // EG clock enable signal assign clk_en = (hi_rate | base[~rate] | (rof_1 & div2[~rate]) | (rof_0 & div4[~rate])); // EG shift select signal assign sft_sel = ((hi_rate & rof_1 & (~psc_cnt[1])) | (hi_rate & rof_0 & psc_cnt[1] & psc_cnt[2])); // prescaler counter and 1 sample delay always @(posedge m_clk or posedge reset) begin if (reset) // async reset begin psc_z1 <= 14'h0000; psc_cnt <= 14'h0000; end else if (fs_clk_en) // fs clock begin psc_z1 <= psc_cnt; psc_cnt <= (psc_cnt + 1'b1); end else // hold begin psc_z1 <= psc_z1; psc_cnt <= psc_cnt; end // if ... end // always begin ... // endmodule // opl3_EG_psc()
このモジュールに限らず、すべてのモジュールで非同期リセットの「reset」入力を設けていますが、これは主にシミュレーション時に unknown だらけになるのを解消するためで、実際の回路では特に必要ありません。
各スロットの EG アキュムレータ / EG ステート・マシンの状態はメモリ (シフトレジスタ) として別に確保されているので、その内容を初期化する必要があり、「mem_init」という信号を用意しています。
EG クロック・プリスケーラ部は 1 回路だけ存在して、各スロットで共通に使用し、サンプリング周波数 fs のレートでのみ状態が更新されます。
周波数は数十 kHz と低くスピードは要求されないので、メタルゲート標準 CMOS ロジックで言えば CD4040B などの「リプル・カウンタ」でも十分ですが、実際の FPGA 回路としてはリプル・カウンタは好ましくなく、同期型カウンタにする必要があります。
また、カウンタの各ビットの立ち上がりを「微分」するのに FF を使わず「組み合わせゲート」だけで実現することも可能ですが、FPGA 回路としては FF を使った方が簡単になります。
EG クロック・プリスケーラ単体でのシミュレーション結果を下に示します。 (図をクリックすると拡大します)
図の下半分のシアン色のトレースがプリスケーラ・カウンタの各ビットの立ち上がりを「微分」した「edge_det[13:0]」の各ビットで、インデクスが 1 増えると周波数は 1/2 になり、なおかつ、お互いに重なり合わない位置にパルスが配置されています。