FPGA 版 FM 音源 (62) -- FPGA 版 EG (6)
EG スロット・メモリ・モジュール「opl3_EG_mem()」を回路図で表現したものを下に示します。
EG アキュムレータ 9 ビットと EG ステート・マシン 3 ビットの合計 12 ビット幅、(N_SLOT-1) 段のシフトレジスタの前に、メモリ初期化用のゲート回路を接続したものです。 N_SLOT = 1 の場合には D-FF はなく、ゲート回路のみとなります。
EG アキュムレータ・モジュール / EG コントロール・モジュール内のレジスタと合わせて、N_SLOT 個の要素を持つリング状のシフトレジスタとなり、1 サンプル周期内に N_SLOT 回発生するスロット・クロックでぐるっと 1 周します。
メモリの初期値としては、EG アキュムレータは最大の減衰量 96 dB に対応する 9'b1_1111_1111 を、EG ステート・マシンについては「ミュート状態」に対応する 3'b000 を発生させています。
Verilog で書いたものを下に示します。
"opl3_EG_mem.v"
// // opl3_EG_mem.v : OPL3 EG slot memory module // // 2017/01/13 Created by pcm1723 // module opl3_EG_mem( // // Input // reset, // async reset m_clk, // master clock slot_clk_en, // slot clock enable mem_init, // memory imitialize eg_acc_wr, // EG acc write data to slot mem. eg_state_wr, // EG state machine write data to slot mem. // // Output // eg_acc_rd, // EG acc read data from slot mem. eg_state_rd // EG state machine read data from slot mem. ); // parameter N_SLOT = 1; // Number of SLOTs // Input port input reset; input m_clk; input slot_clk_en; input mem_init; input [8:0] eg_acc_wr; input [2:0] eg_state_wr; // Output port output [2:0] eg_state_rd; output [8:0] eg_acc_rd; // wires wire [8:0] eg_acc; wire [2:0] eg_state; wire [11:0] eg_data; // // force (eg_acc = 9'b1_1111_1111) for (mem_init == 1) assign eg_acc = ( eg_acc_wr | {9{mem_init}} ); // force (eg_state = 3'b000) for (mem_init = 1) assign eg_state = ( eg_state_wr & {3{~mem_init}} ); generate if (N_SLOT == 1) // no memory required begin // direct output of gated input assign eg_acc_rd = eg_acc; assign eg_state_rd = eg_state; end else // (N_SLOT > 1) begin // build (N_SLOT-1) stage shift register integer i; // loop variable reg [11:0] eg_mem [0:N_SLOT-1]; // register file // combine eg_acc[8:0] and eg_state[2:0] to eg_data[11:0] assign eg_data = { eg_state, eg_acc }; // 12-bit wide (N_SLOT-1) stage shift register always @(posedge m_clk) // no async reset begin if (slot_clk_en) begin eg_mem[0] <= eg_data; // first stage for (i = 1; i < N_SLOT-1; i = i + 1) begin eg_mem[i] <= eg_mem[i-1]; // 1 slot time delay end // for end // if end // always // output data from last stage assign {eg_state_rd, eg_acc_rd} = eg_mem[N_SLOT-2]; end // if endgenerate // endmodule
N_SLOT が大きい場合に内部メモリを使った回路に置き換えられることを期待しているので、D-FF に対して非同期リセットは導入していません。
メモリ初期化の信号である「mem_init」をアサートし、1 サンプリング周期以上保持してリング状シフトレジスタ全体に初期値が書き込まれるようにします。
N_SLOT = 1 ではゲートのみ (FF なし) なので、当然、使用 LE (ロジック・エレメント) 数は 12 個のゲートに対応して 12 個となります。
N_SLOT = 2 では「ゲート + FF」の構成になりますが、これはひとつの LE の中におさまるので、使用 LE 数は 12 となり、N_SLOT = 1 の場合と同じになります。
N_SLOT = 1 および N_SLOT = 2 の場合のゲート・レベルのネットリストを下に示します。
青い「箱」ひとつが、ロジック・エレメントひとつに対応しています。
青い箱が 12 個あるので、LE 使用量は 12 個ということになります。
N_SLOT = 3 では FF が 2 段になるので、LE 使用量は倍になって 24 個となります。
その場合のネットリストを下に示します。
LE 使用量が 24 個であることが分かります。
N_SLOT = 4 以上の場合のネットリストを下に示します。
図の緑色の箱が内部の RAM (M4K) を使った「altshift_taps」メガファンクションの呼び出しで、D-FF によるシフトレジスタ部分の置き換えとして使用されています。
メガファンクションの使用により、LE 内の D-FF を使わなくなったので、LE 使用量は 20 に減っています。
Quartus II ハンドブックでは、HDL でシフトレジスタを記述した場合、
という条件を検出すると、「推論」により「altshift_taps」メガファンクションの呼び出しに変換すると書かれています。
さらに Cyclone デバイスでは、追加の条件として
- バス幅が1 (W = 1) の場合、タップ数とタップ間の長さを乗算した値が64 以上(N× L >= 64) であれば、altshift_taps が推測されます。
- バス幅が1 を超える場合 (W > 1)、バス幅、タップ数、各タップ間の長さを乗算した値が32 以上であれば (W× N × L >= 32)、altshift_taps が推測されます。
と記述されています。
N_SLOT = 4 の場合、バス幅 12、タップ数 1、タップ間の長さ 3 ですから、
12 × 1 × 3 = 36
となり上の条件を満たします。