FPGA 版 FM 音源 (60) -- FPGA 版 EG (4)

EG アキュムレータ・モジュール「opl3_EG_acc()」を回路図で表現したものを下に示します。

「EG Accumulator」と書いてある部分は単なるレジスタで、外部のアダーなどと合わせてアキュムレータの機能を持たせています。
ミュート状態や、 AR = 15 の場合にレジスタに定数値をロードする必要があるので、バラした状態で書いてあります。
また、実際には「EG Accumulator」の入力部分で回路を切断して、スロット・メモリ・モジュールと接続しています。
スロット・メモリ (シフトレジスタ) から読み出した当該スロットのデータを EG アキュムレータでラッチし、レジスタ出力から組み合わせ回路で計算した次サンプル・データの結果をスロット・メモリに書き込みます。
スロット数 N_SLOT = 1 では、スロット・メモリ・モジュールの内部は「素通し」になり、結局は上の回路図と同等になります。
EG ステート・マシンの状態遷移の判断に使う EG アキュムレータ値の「コンパレータ」 3 種のうち、0 dB との比較と、95 dB との比較の 2 つだけを回路図に描いてあります。
回路図が手狭になったので、残りひとつのサステイン・レベルとの比較回路はコントロール・モジュールの回路に描いてあります。
Verilog で書いたものを下に示します。 サステイン・レベルとの比較回路も含まれています。
"opl3_EG_acc.v"

//
// opl3_EG_acc.v : OPL3 EG accumulator module
//
// 2017/01/09 Created by pcm1723
//
module opl3_EG_acc(
//
// Input
//
    reset,     // async reset input
    m_clk,     // master clock input
    slot_clk_en, // slot clock timing
    acc_clk_en,  // EG accum. clock timing
    sft_sel,   // EG fb shift select
    rate13,    // (rate == 13) flag
    rate15,    // (rate == 15) flag
    hi_rate,   // hi-rate flag
    A,         // Attack  state
    D,         // Decay   state
    R,         // Release state
    M,         // Mute    state
    sl,        // Sustain Level
    eg_acc_in, // EG accum. input (read from mem)
//
// Output
//
    eq_0dB,    // EG_acc == 0dB
    eq_95dB,   // EG_acc == 95dB  
    eq_slx,    // EG_acc == SL
    eg_acc_out // EG accum. output (write to mem)
  );
// Input port
  input        reset;
  input        m_clk;
  input        slot_clk_en;
  input        acc_clk_en;
  input        sft_sel;
  input        hi_rate;
  input        rate15;
  input        rate13;
  input        A;
  input        D;
  input        R;
  input        M; 
  input  [3:0] sl;
  input  [8:0] eg_acc_in;
// Output port  
  output       eq_0dB;
  output       eq_slx;
  output       eq_95dB;
  output [8:0] eg_acc_out; 
// constant
  localparam EG_0dB  = 9'b0_0000_0000;
  localparam EG_96dB = 9'b1_1111_1111;
// wires 
  wire [8:0] adder9;   // 9-bit adder  
  wire [6:0] shift1_a; // 1-bit shifter A
  wire [6:0] shift1_b; // 1-bit shifter B
  wire [8:0] acc_fb;   // acc feedback value
  wire       ar15;     // Attack_state & (rate == 15)
  wire [4:0] slx;      // decoded Sustain Level
// res
  reg  [3:0] sl_reg; // Sustain Level input latch
  reg  [8:0] eg_acc; // EG accumulator
//
  always @(posedge m_clk or posedge reset)  
    begin
      if (reset) // async reset
        begin
          sl_reg <= 4'b0000;
        end
      else if (slot_clk_en) // slot update timing
        begin
          sl_reg <= sl;
        end
      else // hold
        begin
          sl_reg <= sl_reg;
        end // if (reset) ...
    end // always @() ...
//	 
  always @(posedge m_clk or posedge reset)  
    begin
      if (reset) // async reset
        begin
          eg_acc <= EG_0dB; // 0 dB
        end
      else if (slot_clk_en) // acc update timing
        begin
          eg_acc <= eg_acc_in;
        end
      else // hold
        begin
          eg_acc <= eg_acc;
        end // if (reset) ...
    end // always @() ...
//	 
// decoded Sustain Level 
// 0..42 dB for SL=0..14, 93 dB for SL=15)	 
  assign slx = { (&sl_reg), sl_reg };
// (EG_state = Attack) and (rate == 15)
  assign ar15 = (A & rate15);
// compare EG_acc against 0dB  (9'b0_0000_0000)
  assign eq_0dB  = (~(|eg_acc));	 
// compare EG_acc against 95dB (9'b1_1111_11xx)
  assign eq_95dB = (&eg_acc[8:2]);	 
// compare EG_acc against Sustain Level
  assign eq_slx  = (eg_acc[8:4] == slx);	 
// EG_acc output
  assign eg_acc_out = ( {9{M}} | ( {9{~ar15}} & adder9) );
// 9-bit adder
  assign adder9 = ( { {2{acc_fb[8]}}, shift1_b} + eg_acc );
// 1-bit shifter B
  assign shift1_b = ( (rate13 | (~hi_rate)) ? { acc_fb[8], shift1_a[6:1] } : shift1_a );
// 1-bit shifter A
  assign shift1_a = ( (~(sft_sel | rate15)) ? acc_fb[7:1] : acc_fb[6:0] );
// acc feedback value (force 9'h000 for (acc_clk_en == 0))
  assign acc_fb = ( { 6'h00, (acc_clk_en & (D | R)), 2'h0 } | ( {9{A & acc_clk_en}} & { 1'b1, (~eg_acc[8:1]) } ) );
endmodule

N_SLOT = 1 の設定に相当する EG アキュムレータ・モジュール単体でのシミュレーション結果を下に示します。 (図をクリックすると拡大します。)

opl3_EG_acc_msim1.png

本来はプリスケーラ・モジュールからの「CLK_EN」信号や「SFT_SEL」信号で細かく制御されるのですが、アキュムレータ・モジュール単体のテストではバレル・シフタの 0 / 1 / 2 ビット・シフトに対応して 3 種のスロープが発生できるだけです。
また、コントロール回路もないので、シミュレーションのテストベンチでアタックとディケイだけの簡単な制御回路を作成してコントロールしています。