FPGA 版 FM 音源 (73) -- FPGA 版 EG (17)
デュアル・ポート RAM を使ったレジスタ・アレイ・インターフェース部の Verilog ソースを下に示します。
"opl3_REG_eg.v"
// // opl3_REG_eg.v : OPL3 slot parameter register host interface (EG/OP) // // 2017/02/12 Created by pcm1723 // module opl3_REG_eg( // Input reset, // async. reset m_clk, // master clock slot_clk_en, // slot clock enable fs_clk_en, // fs clock enable wr_trig, // data write trigger wr_addr, // register address (9-bit) wr_data, // write data (8-bit) // Output ar, // AR (4-bit) dr, // DR (4-bit) sl, // SL (4-bit) rr, // RR (4-bit) ksl, // KSL (2-bit) tl, // TL (6-bit) am, // AM vib, // VIB egt, // EGT ksr, // KSR mult // MULT (4-bit) ); // parameter N_SLOT = 6; // input reset; input m_clk; input slot_clk_en; input fs_clk_en; input wr_trig; input [8:0] wr_addr; input [7:0] wr_data; // output [3:0] ar; output [3:0] dr; output [3:0] sl; output [3:0] rr; output [1:0] ksl; output [5:0] tl; output am; output vib; output egt; output ksr; output [3:0] mult; // wire [31:0] rd_data; // RAM read data wire wr_clk; wire wr_clk_en; wire wr_en; wire [8:0] wr_addr_remap; // re-mapped write address wire rd_clk; wire rd_clk_en; wire cs; // "chip select" // reg [6:0] rd_addr; // RAM read address reg [1:0] wr_trig_dly; // delay of wr_trig // // instantiate 2-port RAM // opl3_ram2p8 opl3_ram2p8_inst ( // write only port .wrclock ( wr_clk ), .wrclocken( wr_clk_en ), .wren ( wr_en ), .wraddress( wr_addr_remap ), .data ( wr_data ), // read only port .rdclock ( rd_clk ), .rdclocken( rd_clk_en ), .rdaddress( rd_addr ), .q ( rd_data ) ); // assign wr_clk = m_clk; assign wr_clk_en = wr_en; assign rd_clk = m_clk; assign rd_clk_en = slot_clk_en; assign { ar, dr, ksl, tl, am, vib, egt, ksr, mult, sl, rr} = rd_data; // // read address generation always @(posedge m_clk or posedge reset) begin if (reset) // async. reset begin rd_addr <= 7'h00; end else if (slot_clk_en) begin if (fs_clk_en) begin rd_addr <= 7'h00; end else begin rd_addr <= ( ((N_SLOT/2-1) == rd_addr[6:0]) ? {~rd_addr[6], 6'h00} : (rd_addr + 7'h01) ); end // if (fs_clk_en) end // if (slot_clk_en) else begin rd_addr <= rd_addr; end end // always // // write enable control always @(posedge m_clk or posedge reset) begin if (reset) // async. reset begin wr_trig_dly <= 2'b00; end else begin wr_trig_dly <= { wr_trig_dly[0], wr_trig }; end // if end // always // write enable = positive edge of wr_trig assign wr_en = ( cs & ( (~wr_trig_dly[1]) & wr_trig_dly[0] ) ); // "chip select" assign cs = ( wr_addr[7] ^ ( wr_addr[6] | wr_addr[5] ) ); // write address remap assign wr_addr_remap = { wr_addr[8], 1'b0, wr_addr[4:0], wr_addr[6:5] }; endmodule // opl3_REG_eg()
結果をコンパクトにして見やすくするために、スロット数 N_SLOT = 6 として、アレイ 0 およびアレイ 1 それぞれ 3 個のスロットで構成されるようにしてあります。
また、メガウィザードの実行で生成される 2 ポート RAM 自体の Verilog ファイルについては省略します。
下にシミュレーション結果を示します。 (図をクリックすると拡大します)
テストベンチ・プログラム中で、書き込み側のレジスタ・アドレス (wr_addr) は
20h→21h→22h→40h→41h→42h→60h→61h→62h→80h→81h→82h→120h→121h→122h→140h→141h→142h→160h→161h→162h→180h→181h→182h→20h→...
という順番で発生させ、レジスタに書き込むデータの値 (wr_data) は LFSR(Linear Feedback Shift Register) を使った周期 255 の M 系列によって発生させています。
読み出し側のレジスタ・アドレス (rd_addr) は
00h → 01h → 02h → 40h → 41h → 42h → 00h → ...
という順番で発生させています。