`timescale 1ns / 1ps ////////////////////////////////////////////////////////////////////////////////// // // This file is part of the Next186 Soc PC project // http://opencores.org/project,next186 // // Filename: opl3seq.v // Description: Part of the Next186 SoC PC project, OPL3 Sequencer // Version 1.0 // Creation date: 13:55:57 02/27/2017 // // Author: Nicolae Dumitrache // e-mail: ndumitrache@opencores.org // ///////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2017 Nicolae Dumitrache // // This source file may be used and distributed without // restriction provided that this copyright statement is not // removed from the file and that any derivative work contains // the original copyright notice and the associated disclaimer. // // This source file is free software; you can redistribute it // and/or modify it under the terms of the GNU Lesser General // Public License as published by the Free Software Foundation; // either version 2.1 of the License, or (at your option) any // later version. // // This source is distributed in the hope that it will be // useful, but WITHOUT ANY WARRANTY; without even the implied // warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the GNU Lesser General Public License for more // details. // // You should have received a copy of the GNU Lesser General // Public License along with this source; if not, download it // from http://www.opencores.org/lgpl.shtml // /////////////////////////////////////////////////////////////////////////////////// // Additional Comments: // // It shares OPL3 structure (~1.7KB DP RAM) with the main processor. It drives 36 operators at 44100Hz, with at least 45Mhz clock /////////////////////////////////////////////////////////////////////////////////// // altera message_off 10030 `define LFO_AM_TAB_ELEMENTS 210 `define phase_modulation_o 0 // CH18 `define panA_o 6'd4 // CH18 `define panB_o 6'd8 // CH18 `define lfo_am_depth_o 12 // CH18 `define block_fnum_o 44 // SLOT0 `define chanout_o 6'd46 // SLOT0 `define Cnt_o 6'd4 `define Incr_o 6'd8 `define op1_out_o 6'd12 `define state_o 18 `define AMmask_o 20 `define volume_o 22 `define FB_o 24 `define mul_o 30 `define sl_o 32 `define vib_o 34 `define connect_o 36 `define eg_sh_ar_o 38 `define eg_sh_dr_o 40 `define eg_sh_rr_o 42 module opl3seq ( input clk, input reset, input rd, // clk synchronous pulse, read only while == 1 output reg [15:0] A, output reg [15:0] B, output reg ready, output reg ram_wr, output [11:0] ram_addr, input [15:0] ram_rdata, output reg [15:0] ram_wdata ); reg [13:0]lfo_am_cnt = 0; reg [4:0]r_lfo_am_cnt = 0; wire [13:0]lfo_am_cnt1 = lfo_am_cnt + 1'b1; reg [9:0]lfo_pm_cnt = 0; reg [4:0]LFO_AM; // unsigned reg [3:0]LFO_PM = 0; // unsigned reg [5:0]STATE = 0; reg [5:0]nextSTATE; reg [5:0]RET; reg [5:0]ram_offset; // OPL3Struct_base + (CHindex*96 + OPindex*48 + offset) reg [4:0]ram_CHindex; reg [4:0]s_ram_CHindex; wire s_ram_CHindex17 = s_ram_CHindex == 17; wire s_ram_CHindex18 = s_ram_CHindex == 18; wire [4:0]s_ram_CHindex1 = s_ram_CHindex + 1'b1; reg ram_OPindex; reg s_ram_OPindex; reg [15:0]ram_rdata_lo; reg [15:0]eg_cnt = 0; // reg [22:0]noise_rng = 1; reg [9:0]env; reg [12:0]sinaddr; reg [12:0]r_sinaddr; wire [12:0]op_calc1; wire signed [15:0]op_calc = {{3{op_calc1[12]}}, op_calc1}; reg [15:0]tmp1; wire [13:0]outshift1 = $signed(tmp1[13:0]) >>> ram_rdata[3:0]; wire [9:0]outshift = |ram_rdata[3:0] ? outshift1[9:0] : 10'b0000000000; reg [17:0]pan; reg signed [18:0]rAcc; wire [15:0]limAcc = rAcc > 32767 ? 16'h7fff : rAcc < -32768 ? 16'h8000 : rAcc[15:0]; // (~|rAcc[18:15] | &rAcc[18:15]) ? rAcc[15:0] : {rAcc[18], {15{!rAcc[18]}}}; reg [11:0]phmask;// = (1'b1 << ram_rdata[3:0]) - 1'b1; wire phtest = ~|(eg_cnt & phmask); reg cond; wire [15:0]eg_inc1 = eg_cnt >> ram_rdata[3:0]; wire [6:0]eg_inc = ram_rdata[14:8] + eg_inc1[2:0]; reg [2:0]r_eg_inc; wire [9:0]volume_attack1 = $signed(~ram_rdata[9:0]) >>> (~r_eg_inc[1:0]); wire [9:0]volume_attack = {1'b0, ram_rdata[8:0]} + (r_eg_inc[2] ? 10'h000 : volume_attack1); reg [9:0]r_volume; wire [2:0]exp_r_eg_inc = 3'b1 << r_eg_inc; wire [9:0]volume_dsr = ram_rdata[8:0] + exp_r_eg_inc; // new volume for decay/sustain/release reg signed [3:0]lfo_fn_table_index_offset; reg [11:0]inc_hi; reg [15:0]inc_lo; reg carry = 1'b0; reg cy; reg [2:0]phase; wire [25:0]mul1 = tmp1[9:0] * ram_rdata_lo; // tmp1 adder reg [3:0]tmp1op; reg [15:0]tmp1op1; reg [15:0]tmp1op2; // .addrb(OPL3Struct_offset + {1'b1, ram_CHindex, ram_OPindex, ram_offset[5:1]}) assign ram_addr = (ram_OPindex ? 12'd24 : 12'd0) + {ram_CHindex + {ram_CHindex, ram_offset[5]}, ram_offset[4:1]}; wire [4:0] lfo_am_table [`LFO_AM_TAB_ELEMENTS] = '{ 0,0,0,0,0,0,0, 1,1,1,1, 2,2,2,2, 3,3,3,3, 4,4,4,4, 5,5,5,5, 6,6,6,6, 7,7,7,7, 8,8,8,8, 9,9,9,9, 10,10,10,10, 11,11,11,11, 12,12,12,12, 13,13,13,13, 14,14,14,14, 15,15,15,15, 16,16,16,16, 17,17,17,17, 18,18,18,18, 19,19,19,19, 20,20,20,20, 21,21,21,21, 22,22,22,22, 23,23,23,23, 24,24,24,24, 25,25,25,25, 26,26,26, 25,25,25,25, 24,24,24,24, 23,23,23,23, 22,22,22,22, 21,21,21,21, 20,20,20,20, 19,19,19,19, 18,18,18,18, 17,17,17,17, 16,16,16,16, 15,15,15,15, 14,14,14,14, 13,13,13,13, 12,12,12,12, 11,11,11,11, 10,10,10,10, 9,9,9,9, 8,8,8,8, 7,7,7,7, 6,6,6,6, 5,5,5,5, 4,4,4,4, 3,3,3,3, 2,2,2,2, 1,1,1,1 }; wire signed [3:0]lfo_pm_table[128] = '{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,-1, 0, 0, 0, 1, 0, 0, 0,-1, 0, 0, 0, 2, 1, 0,-1,-2,-1, 0, 1, 1, 0, 0, 0,-1, 0, 0, 0, 3, 1, 0,-1,-3,-1, 0, 1, 2, 1, 0,-1,-2,-1, 0, 1, 4, 2, 0,-2,-4,-2, 0, 2, 2, 1, 0,-1,-2,-1, 0, 1, 5, 2, 0,-2,-5,-2, 0, 2, 3, 1, 0,-1,-3,-1, 0, 1, 6, 3, 0,-3,-6,-3, 0, 3, 3, 1, 0,-1,-3,-1, 0, 1, 7, 3, 0,-3,-7,-3, 0, 3 }; wire [2:0]eg_inc_tab[120] = '{ 4,0, 4,0, 4,0, 4,0, 4,0, 4,0, 0,0, 4,0, 4,0, 0,0, 4,0, 0,0, 4,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,1, 0,0, 0,2, 0,1, 0,1, 0,1, 0,1, 0,1, 1,1, 0,1, 1,1, 1,1, 1,1, 1,1, 1,1, 1,1, 1,2, 1,1, 1,2, 1,2, 1,2, 1,2, 1,2, 1,2, 2,2, 1,2, 2,2, 2,2, 2,2, 2,2, 2,2, 3,3, 3,3, 3,3, 3,3, 4,4, 4,4, 4,4, 4,4 }; // log tablle, 4 = log(0) sampler sampler_inst ( .clk(clk), .index(r_sinaddr), .ampl(env[8:0]), .sample(op_calc1) ); always @(posedge clk) begin STATE <= nextSTATE; s_ram_CHindex <= ram_CHindex; s_ram_OPindex <= ram_OPindex; r_sinaddr <= sinaddr; r_lfo_am_cnt <= lfo_am_table[lfo_am_cnt[13:6]]; ram_rdata_lo <= ram_rdata; r_eg_inc <= eg_inc_tab[eg_inc]; lfo_fn_table_index_offset <= lfo_pm_table[{ram_rdata[9:7], LFO_PM}]; //34 {carry, tmp1} <= tmp1op1 + tmp1op2 + cy; pan <= pan >> 1; if(pan[0]) rAcc <= rAcc + {{3{ram_rdata[15]}}, ram_rdata}; if(reset) STATE <= 0; else case(STATE) 0: begin if(lfo_am_cnt1[13:6] == `LFO_AM_TAB_ELEMENTS) lfo_am_cnt <= 14'h0000; else lfo_am_cnt <= lfo_am_cnt1; {LFO_PM[2:0], lfo_pm_cnt} <= {LFO_PM[2:0], lfo_pm_cnt} + 1'b1; eg_cnt <= eg_cnt + 1'b1; // noise_rng <= {noise_rng[0], noise_rng[22:1]} ^ (noise_rng[0] ? 9'h181 : 9'h000); end 1: begin LFO_AM <= r_lfo_am_cnt >> {!ram_rdata[0], 1'b0}; LFO_PM[3] <= ram_rdata[11]; RET <= 3; end 2: s_ram_CHindex <= s_ram_CHindex17 ? 5'd0 : s_ram_CHindex1; 3: s_ram_CHindex <= s_ram_CHindex; 7: RET <= 8; 8: begin s_ram_CHindex <= s_ram_CHindex; RET <= 18; end 10: s_ram_OPindex <= 1'b1; 13: env <= ram_rdata_lo[9:0] + ram_rdata[8:0] + (ram_rdata_lo[15] ? LFO_AM : 10'd0); // env = volume_calc(SLOT1); 15: {s_ram_CHindex, s_ram_OPindex} <= {s_ram_CHindex, s_ram_OPindex}; 17: {s_ram_CHindex, s_ram_OPindex} <= {s_ram_CHindex, s_ram_OPindex}; 18: s_ram_CHindex <= s_ram_CHindex1; 20: begin pan <= {ram_rdata[1:0], ram_rdata_lo}; s_ram_CHindex <= 1; rAcc <= 0; end 21: s_ram_CHindex <= s_ram_CHindex18 ? s_ram_CHindex : s_ram_CHindex1; 22: A <= limAcc; 23: begin pan <= {ram_rdata[1:0], ram_rdata_lo}; s_ram_CHindex <= 1; rAcc <= 0; end 24: s_ram_CHindex <= s_ram_CHindex18 ? 5'd0 : s_ram_CHindex1; 25: B <= limAcc; // advance 27: cond <= phtest; 28: r_volume <= tmp1[2] ? volume_attack : volume_dsr; 29: if(r_volume[9]) r_volume <= (tmp1[2:0] < 3) ? 10'd511 : 10'd0; // phase gen 32: inc_lo <= ram_rdata; 33: begin inc_hi <= ram_rdata[11:0]; s_ram_OPindex <= s_ram_OPindex; end 35: cond <= |lfo_fn_table_index_offset; 36: if(cond && ram_rdata[0]) {inc_hi, inc_lo} <= {mul1, 2'b00} >> ~tmp1[12:10]; 37,38: inc_lo <= {4'b0000, inc_hi}; 39: begin s_ram_OPindex <= !s_ram_OPindex; if(s_ram_OPindex) s_ram_CHindex <= s_ram_CHindex1; end endcase end always @(*) begin ram_offset = 6'b000000; ram_CHindex = s_ram_CHindex; ram_OPindex = s_ram_OPindex; ram_wdata = 16'h0000; ram_wr = 1'b0; nextSTATE = STATE + 1'b1; sinaddr = r_sinaddr; tmp1op = 4'b1111; // tmp1 <= tmp1, carry <= 0 cy = 1'b0; ready = 1'b0; case(STATE) 0: begin ram_offset = `lfo_am_depth_o; ram_CHindex = 18; ram_OPindex = 0; end 1: ram_CHindex = 0; 2: begin ram_offset = `chanout_o; ram_wr = 1'b1; nextSTATE = s_ram_CHindex17 ? 6'd3 : 6'd2; end // chan_calc 3: begin // chip.phase_modulation = 0; ram_CHindex = 18; ram_offset = `phase_modulation_o; ram_wr = 1'b1; end 4: ram_offset = `op1_out_o; // op1_out[0] 5: ram_offset = `op1_out_o+6'd2; // op1_out[1] 6: begin ram_offset = `FB_o; // read {FB, wavetable, x, x} tmp1op = 4'b0000; // tmp1 <= ram_rdata + ram_rdata_lo; // out = SLOT1->op1_out[0] + SLOT1->op1_out[1]; end 7: begin // SLOT->op1_out[0] = SLOT->op1_out[1]; ram_offset = `op1_out_o; ram_wdata = ram_rdata_lo; ram_wr = 1'b1; sinaddr = {ram_rdata[10:8], outshift}; // wavetable, out>>FB nextSTATE = 11; // call end 8: begin ram_CHindex = 18; ram_offset = `phase_modulation_o; end 9: begin ram_offset = `FB_o; // read {FB, wavetable, x, x} ram_OPindex = 1; end 10: begin // SLOT->op1_out[1] = op_calc ram_offset = `op1_out_o+6'd2; ram_OPindex = 0; ram_wdata = tmp1; ram_wr = 1'b1; sinaddr = {ram_rdata[10:8], ram_rdata_lo[9:0]}; // wavetable, phase_modulation end 11: ram_offset = `AMmask_o; // read {TLL, AMmask} 12: ram_offset = `volume_o; // read volume[15:0] 13: ram_offset = `Cnt_o+6'd2; 14: begin ram_offset = `connect_o; sinaddr[9:0] = sinaddr[9:0] + ram_rdata[9:0]; if(env >= 416) nextSTATE = RET; end 15: {ram_CHindex, ram_OPindex, ram_offset} = ram_rdata[11:0]; 16: ram_offset = `connect_o; 17: begin {ram_CHindex, ram_OPindex, ram_offset} = ram_rdata[11:0]; ram_wdata = ram_rdata_lo + op_calc;//tmp1; ram_wr = 1'b1; nextSTATE = RET; tmp1op = 4'b1110; // tmp1 <= op_calc; end 18: begin ram_offset = `panA_o; ram_OPindex = 0; ram_CHindex = 18; nextSTATE = s_ram_CHindex17 ? 6'd19 : 6'd3; end 19: ram_offset = `panA_o+6'd2; 20: begin ram_offset = `chanout_o; ram_CHindex = 0; end 21: begin ram_offset = s_ram_CHindex18 ? `panB_o : `chanout_o; nextSTATE = s_ram_CHindex18 ? 6'd22 : 6'd21; end 22: ram_offset = `panB_o+6'd2; 23: begin ram_offset = `chanout_o; ram_CHindex = 0; end 24: begin ram_offset = `chanout_o; nextSTATE = s_ram_CHindex18 ? 6'd25 : 6'd24; end // envelope 25: ram_offset = `state_o; 26: begin case(ram_rdata[2:0]) 3'd1: ram_offset = `eg_sh_rr_o; // release phase 3'd2: begin // sustain phase ram_offset = `eg_sh_rr_o; if(ram_rdata[8]) nextSTATE = 31; // if (!op->eg_type) end 3'd3: ram_offset = `eg_sh_dr_o; // decay phase 3'd4: ram_offset = `eg_sh_ar_o; // attack phase default: nextSTATE = 31; endcase tmp1op = 4'b1100; // tmp1 <= ram_rdata; // {eg_type, state} end 27: ram_offset = `volume_o; 28: ram_offset = `sl_o; 29: begin ram_offset = `state_o; ram_wdata = tmp1; case(tmp1[1:0]) 2'b00: if(r_volume[9]) ram_wdata[2:0] = 3'd3; // attack 2'b11: if(r_volume >= {1'b0, ram_rdata[8:0]}) ram_wdata[2:0] = 3'd2; // decay 2'b10:; // sustain 2'b01: if(r_volume[9]) ram_wdata[2:0] = 3'd0; // release endcase ram_wr = cond; end 30: begin ram_offset = `volume_o; ram_wdata[9:0] = r_volume; ram_wr = cond; end // phase gen 31: ram_offset = `Incr_o; 32: ram_offset = `Incr_o+6'd2; 33: begin ram_offset = `block_fnum_o; ram_OPindex = 0; end 34: ram_offset = `mul_o; 35: begin ram_offset = `vib_o; tmp1op = 4'b0001; //tmp1 <= ram_rdata_lo + lfo_fn_table_index_offset; end 36: ram_offset = `Cnt_o; 37: begin ram_offset = `Cnt_o+6'd2; tmp1op = 4'b0100; //{carry, tmp1} <= inc_lo + ram_rdata; end 38: begin ram_offset = `Cnt_o; ram_wdata = tmp1; ram_wr = 1'b1; tmp1op = 4'b0100; //{carry, tmp1} <= inc_lo + ram_rdata + carry; cy = carry; end 39: begin ram_offset = `Cnt_o+6'd2; ram_wdata = tmp1; ram_wr = 1'b1; if(!(s_ram_CHindex17 && s_ram_OPindex)) nextSTATE = 6'd25; end default: begin ready = 1'b1; nextSTATE = rd ? 6'd0 : 6'd40; end endcase case(tmp1op[1:0]) 2'b00: tmp1op1 = ram_rdata; 2'b01: tmp1op1 = lfo_fn_table_index_offset; 2'b10: tmp1op1 = op_calc; 2'b11: tmp1op1 = tmp1; endcase case(tmp1op[3:2]) 2'b00: tmp1op2 = ram_rdata_lo; 2'b01: tmp1op2 = inc_lo; default: tmp1op2 = 16'h0000; endcase case(ram_rdata[3:0]) // ((1 << ram_rdata[3:0]) - 1)[11:0] 4'h0: phmask = 12'h000; 4'h1: phmask = 12'h001; 4'h2: phmask = 12'h003; 4'h3: phmask = 12'h007; 4'h4: phmask = 12'h00f; 4'h5: phmask = 12'h01f; 4'h6: phmask = 12'h03f; 4'h7: phmask = 12'h07f; 4'h8: phmask = 12'h0ff; 4'h9: phmask = 12'h1ff; 4'ha: phmask = 12'h3ff; 4'hb: phmask = 12'h7ff; default: phmask = 12'hfff; endcase end endmodule module sampler ( input clk, input [12:0] index, input [8:0] ampl, output [12:0] sample ); reg [15:0] sin_tab[8191:0]; initial $readmemh("sin_tab_full.mem", sin_tab); reg [15:0] exp_tab[6655:0]; initial $readmemh("exp_tab.mem", exp_tab); reg [15:0] logsin; wire [13:0] ilog = logsin[13:0] + {ampl, 4'b0000}; reg log_rng; reg [15:0] isample; assign sample = log_rng ? isample[12:0] : 13'd0; always @(posedge clk) begin logsin <= sin_tab[index]; log_rng <= ilog < 6656; isample <= exp_tab[ilog[12:0]]; end endmodule