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 でシフトレジスタを記述した場合、

  • 同じクロックおよびクロック・イネーブルを使用
  • 他のセカンダリ信号がない
  • タップがレジスタ3 個以上分離して等間隔に配置されている。

という条件を検出すると、「推論」により「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

となり上の条件を満たします。