1
0
mirror of https://github.com/Gehstock/Mist_FPGA.git synced 2026-02-08 17:11:24 +00:00
Files
Gehstock.Mist_FPGA/common/Sound/opl3/opl3seq.sv
2020-05-16 06:42:10 +02:00

483 lines
14 KiB
Systemverilog

`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 <ready> == 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