1
0
mirror of https://github.com/Gehstock/Mist_FPGA.git synced 2026-01-11 23:43:09 +00:00

add YM3526

This commit is contained in:
Marcel 2022-10-11 15:43:41 +02:00
parent e3e8b4ca55
commit 676202ae97
31 changed files with 3461 additions and 0 deletions

View File

@ -0,0 +1,28 @@
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtopl_acc.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtopl_csr.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtopl_div.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtopl_lfo.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtopl_pm.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtopl_eg_cnt.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtopl_eg_comb.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtopl_eg_ctrl.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtopl_eg_final.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtopl_eg_pure.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtopl_eg_step.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtopl_eg.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtopl_exprom.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtopl_logsin.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtopl_mmr.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtopl_op.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtopl_pg_comb.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtopl_pg_inc.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtopl_pg_sum.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtopl_pg_rhy.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtopl_pg.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtopl_reg.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtopl_sh_rst.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtopl_sh.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtopl_single_acc.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtopl_timers.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtopl_noise.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtopl.v]

253
common/Sound/ym3526/jtopl.v Normal file
View File

@ -0,0 +1,253 @@
/* This file is part of JTOPL.
JTOPL is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JTOPL 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with JTOPL. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 10-6-2020
*/
module jtopl #(parameter OPL_TYPE=1)
(
input wire rst, // rst should be at least 6 clk&cen cycles long
input wire clk, // CPU clock
input wire cen, // optional clock enable, it not needed leave as 1'b1
input wire [ 7:0] din,
input wire addr,
input wire cs_n,
input wire wr_n,
output wire [ 7:0] dout,
output wire irq_n,
// combined output
output wire signed [15:0] snd,
output wire sample
);
//parameter OPL_TYPE=1;
wire cenop;
wire write;
wire [ 1:0] group;
wire [17:0] slot;
wire [ 3:0] trem;
// Timers
wire flag_A, flag_B, flagen_A, flagen_B;
wire [ 7:0] value_A;
wire [ 7:0] value_B;
wire load_A, load_B;
wire clr_flag_A, clr_flag_B;
wire overflow_A;
wire zero; // Single-clock pulse at the begginig of s1_enters
// Phase
wire [ 9:0] fnum_I;
wire [ 2:0] block_I;
wire [ 3:0] mul_II;
wire [ 9:0] phase_IV;
wire pg_rst_II;
wire viben_I;
wire [ 2:0] vib_cnt;
// envelope configuration
wire en_sus_I; // enable sustain
wire [ 3:0] keycode_II;
wire [ 3:0] arate_I; // attack rate
wire [ 3:0] drate_I; // decay rate
wire [ 3:0] rrate_I; // release rate
wire [ 3:0] sl_I; // sustain level
wire ksr_II; // key scale rate - affects rates
wire [ 1:0] ksl_IV; // key scale level - affects amplitude
// envelope operation
wire keyon_I;
wire eg_stop;
// envelope number
wire amen_IV;
wire [ 5:0] tl_IV;
wire [ 9:0] eg_V;
// Global values
wire am_dep, vib_dep, rhy_en;
// Operator
wire [ 2:0] fb_I;
wire [ 1:0] wavsel_I;
wire op, con_I, op_out, con_out;
wire signed [12:0] op_result;
assign write = !cs_n && !wr_n;
assign dout = { ~irq_n, flag_A, flag_B, 5'd6 };
assign eg_stop = 0;
assign sample = zero;
jtopl_mmr #(.OPL_TYPE(OPL_TYPE)) u_mmr(
.rst ( rst ),
.clk ( clk ),
.cen ( cen ), // external clock enable
.cenop ( cenop ), // internal clock enable
.din ( din ),
.write ( write ),
.addr ( addr ),
.zero ( zero ),
.group ( group ),
.op ( op ),
.slot ( slot ),
.rhy_en ( rhy_en ),
// Timers
.value_A ( value_A ),
.value_B ( value_B ),
.load_A ( load_A ),
.load_B ( load_B ),
.flagen_A ( flagen_A ),
.flagen_B ( flagen_B ),
.clr_flag_A ( clr_flag_A ),
.clr_flag_B ( clr_flag_B ),
.flag_A ( flag_A ),
.overflow_A ( overflow_A ),
// Phase Generator
.fnum_I ( fnum_I ),
.block_I ( block_I ),
.mul_II ( mul_II ),
// Operator
.wavsel_I ( wavsel_I ),
// Envelope Generator
.keyon_I ( keyon_I ),
.en_sus_I ( en_sus_I ),
.arate_I ( arate_I ),
.drate_I ( drate_I ),
.rrate_I ( rrate_I ),
.sl_I ( sl_I ),
.ks_II ( ksr_II ),
.tl_IV ( tl_IV ),
.ksl_IV ( ksl_IV ),
.amen_IV ( amen_IV ),
.viben_I ( viben_I ),
// Global Values
.am_dep ( am_dep ),
.vib_dep ( vib_dep ),
// Timbre
.fb_I ( fb_I ),
.con_I ( con_I )
);
jtopl_timers u_timers(
.rst ( rst ),
.clk ( clk ),
.cenop ( cenop ),
.zero ( zero ),
.value_A ( value_A ),
.value_B ( value_B ),
.load_A ( load_A ),
.load_B ( load_B ),
.flagen_A ( flagen_A ),
.flagen_B ( flagen_B ),
.clr_flag_A ( clr_flag_A ),
.clr_flag_B ( clr_flag_B ),
.flag_A ( flag_A ),
.flag_B ( flag_B ),
.overflow_A ( overflow_A ),
.irq_n ( irq_n )
);
jtopl_lfo u_lfo(
.rst ( rst ),
.clk ( clk ),
.cenop ( cenop ),
.slot ( slot ),
.vib_cnt ( vib_cnt ),
.trem ( trem )
);
jtopl_pg u_pg(
.rst ( rst ),
.clk ( clk ),
.cenop ( cenop ),
.slot ( slot ),
.rhy_en ( rhy_en ),
// Channel frequency
.fnum_I ( fnum_I ),
.block_I ( block_I ),
// Operator multiplying
.mul_II ( mul_II ),
// phase modulation from LFO (vibrato at 6.4Hz)
.vib_cnt ( vib_cnt ),
.vib_dep ( vib_dep ),
.viben_I ( viben_I ),
// phase operation
.pg_rst_II ( pg_rst_II ),
.keycode_II ( keycode_II ),
.phase_IV ( phase_IV )
);
jtopl_eg u_eg(
.rst ( rst ),
.clk ( clk ),
.cenop ( cenop ),
.zero ( zero ),
.eg_stop ( eg_stop ),
// envelope configuration
.en_sus_I ( en_sus_I ), // enable sustain
.keycode_II ( keycode_II ),
.arate_I ( arate_I ), // attack rate
.drate_I ( drate_I ), // decay rate
.rrate_I ( rrate_I ), // release rate
.sl_I ( sl_I ), // sustain level
.ksr_II ( ksr_II ), // key scale
// envelope operation
.keyon_I ( keyon_I ),
// envelope number
.fnum_I ( fnum_I ),
.block_I ( block_I ),
.lfo_mod ( trem ),
.amsen_IV ( amen_IV ),
.ams_IV ( am_dep ),
.tl_IV ( tl_IV ),
.ksl_IV ( ksl_IV ),
.eg_V ( eg_V ),
.pg_rst_II ( pg_rst_II )
);
jtopl_op #(.OPL_TYPE(OPL_TYPE)) u_op(
.rst ( rst ),
.clk ( clk ),
.cenop ( cenop ),
// location of current operator
.group ( group ),
.op ( op ),
.zero ( zero ),
.pg_phase_I ( phase_IV ),
.eg_atten_II( eg_V ), // output from envelope generator
.fb_I ( fb_I ), // voice feedback
.wavsel_I ( wavsel_I ), // sine mask (OPL2)
.con_I ( con_I ),
.op_result ( op_result ),
.op_out ( op_out ),
.con_out ( con_out )
);
jtopl_acc u_acc(
.rst ( rst ),
.clk ( clk ),
.cenop ( cenop ),
.zero ( zero ),
.op_result ( op_result ),
.op ( op_out ),
.con ( con_out ),
.snd ( snd )
);
endmodule

View File

@ -0,0 +1,52 @@
/* This file is part of JTOPL.
JTOPL is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JTOPL 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with JTOPL. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 10-10-2021
*/
module jtopl2(
input wire rst, // rst should be at least 6 clk&cen cycles long
input wire clk, // CPU clock
input wire cen, // optional clock enable, it not needed leave as 1'b1
input wire [ 7:0] din,
input wire addr,
input wire cs_n,
input wire wr_n,
output wire [ 7:0] dout,
output wire irq_n,
// combined output
output wire signed [15:0] snd,
output wire sample
);
`define JTOPL2
jtopl #(.OPL_TYPE(2)) u_base(
.rst ( rst ),
.clk ( clk ),
.cen ( cen ),
.din ( din ),
.addr ( addr ),
.cs_n ( cs_n ),
.wr_n ( wr_n ),
.dout ( dout ),
.irq_n ( irq_n ),
.snd ( snd ),
.sample ( sample )
);
endmodule

View File

@ -0,0 +1,48 @@
/* This file is part of JTOPL.
JTOPL program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JTOPL program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with JTOPL. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 20-6-2020
*/
module jtopl_acc(
input wire rst,
input wire clk,
input wire cenop,
input wire signed [12:0] op_result,
input wire zero,
input wire op, // 0 for modulator operators
input wire con, // 0 for modulated connection
output wire signed [15:0] snd
);
wire sum_en;
assign sum_en = op | con;
// Continuous output
jtopl_single_acc u_acc(
.clk ( clk ),
.cenop ( cenop ),
.op_result ( op_result ),
.sum_en ( sum_en ),
.zero ( zero ),
.snd ( snd )
);
endmodule

View File

@ -0,0 +1,77 @@
/* This file is part of JTOPL.
JTOPL program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JTOPL program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with JTOPL. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 17-6-2020
*/
module jtopl_csr #(
parameter LEN=18, W=34
) ( // Circular Shift Register + input mux
input wire rst,
input wire clk,
input wire cen,
input wire [ 7:0] din,
output wire [W-1:0] shift_out,
input wire up_mult,
input wire up_ksl_tl,
input wire up_ar_dr,
input wire up_sl_rr,
input wire up_wav,
input wire update_op_I,
input wire update_op_II,
input wire update_op_IV
);
wire [W-1:0] regop_in;
jtopl_sh_rst #(.width(W),.stages(LEN)) u_regch(
.clk ( clk ),
.cen ( cen ),
.rst ( rst ),
.din ( regop_in ),
.drop ( shift_out )
);
wire up_mult_I = up_mult & update_op_I;
wire up_mult_II = up_mult & update_op_II;
wire up_mult_IV = up_mult & update_op_IV;
wire up_ksl_tl_IV = up_ksl_tl & update_op_IV;
wire up_ar_dr_op = up_ar_dr & update_op_I;
wire up_sl_rr_op = up_sl_rr & update_op_I;
wire up_wav_I = up_wav & update_op_I;
assign regop_in[31:0] = { // 4 bytes:
up_mult_IV ? din[7] : shift_out[31], // AM enable
up_mult_I ? din[6:5] : shift_out[30:29], // Vib enable, EG type, KSR
up_mult_II ? din[4:0] : shift_out[28:24], // KSR + Mult
up_ksl_tl_IV? din : shift_out[23:16], // KSL + TL
up_ar_dr_op ? din : shift_out[15: 8],
up_sl_rr_op ? din : shift_out[ 7: 0]
};
// `ifdef JTOPL2
// assign regop_in[33:32] = up_wav_I ? din[1:0] : shift_out[33:32];
// `endif
endmodule // jtopl_reg

View File

@ -0,0 +1,48 @@
/* This file is part of JTOPL.
JTOPL is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JTOPL 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with JTOPL. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 10-6-2020
*/
module jtopl_div #(parameter OPL_TYPE=1)
(
input wire rst,
input wire clk,
input wire cen,
output reg cenop // clock enable at operator rate
);
//parameter OPL_TYPE=1;
localparam W = 2; // OPL_TYPE==2 ? 1 : 2;
reg [W-1:0] cnt;
`ifdef SIMULATION
initial cnt={W{1'b0}};
`endif
always @(posedge clk) if(cen) begin
cnt <= cnt+1'd1;
end
always @(posedge clk) begin
cenop <= cen && (&cnt);
end
endmodule

View File

@ -0,0 +1,203 @@
/* This file is part of JTOPL.
JTOPL is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JTOPL 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with JTOPL. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 17-6-2020
*/
module jtopl_eg (
input wire rst,
input wire clk,
input wire cenop,
input wire zero,
input wire eg_stop,
// envelope configuration
input wire en_sus_I, // enable sustain
input wire [3:0] keycode_II,
input wire [3:0] arate_I, // attack rate
input wire [3:0] drate_I, // decay rate
input wire [3:0] rrate_I, // release rate
input wire [3:0] sl_I, // sustain level
input wire ksr_II, // key scale
// envelope operation
input wire keyon_I,
// envelope number
input wire [9:0] fnum_I,
input wire [2:0] block_I,
input wire [3:0] lfo_mod,
input wire amsen_IV,
input wire ams_IV,
input wire [5:0] tl_IV,
input wire [1:0] ksl_IV,
output reg [9:0] eg_V,
output reg pg_rst_II
);
parameter SLOTS=18;
wire [14:0] eg_cnt;
jtopl_eg_cnt u_egcnt(
.rst ( rst ),
.clk ( clk ),
.cen ( cenop & ~eg_stop ),
.zero ( zero ),
.eg_cnt ( eg_cnt)
);
wire keyon_last_I;
wire keyon_now_I = !keyon_last_I && keyon_I;
wire keyoff_now_I = keyon_last_I && !keyon_I;
wire cnt_in_II, cnt_lsb_II, step_II, pg_rst_I;
wire [2:0] state_in_I, state_next_I;
reg attack_II, attack_III;
wire [4:0] base_rate_I;
reg [4:0] base_rate_II;
wire [5:0] rate_out_II;
reg [5:1] rate_in_III;
reg step_III;
wire sum_out_II;
reg sum_in_III;
wire [9:0] eg_in_I, pure_eg_out_III, eg_next_III, eg_out_IV;
reg [9:0] eg_in_II, eg_in_III, eg_in_IV;
reg [3:0] keycode_III, keycode_IV;
wire [3:0] fnum_IV;
wire [2:0] block_IV;
jtopl_eg_comb u_comb(
///////////////////////////////////
// I
.keyon_now ( keyon_now_I ),
.keyoff_now ( keyoff_now_I ),
.state_in ( state_in_I ),
.eg_in ( eg_in_I ),
// envelope configuration
.en_sus ( en_sus_I ),
.arate ( arate_I ), // attack rate
.drate ( drate_I ), // decay rate
.rrate ( rrate_I ),
.sl ( sl_I ), // sustain level
.base_rate ( base_rate_I ),
.state_next ( state_next_I ),
.pg_rst ( pg_rst_I ),
///////////////////////////////////
// II
.step_attack ( attack_II ),
.step_rate_in ( base_rate_II ),
.keycode ( keycode_II ),
.eg_cnt ( eg_cnt ),
.cnt_in ( cnt_in_II ),
.ksr ( ksr_II ),
.cnt_lsb ( cnt_lsb_II ),
.step ( step_II ),
.step_rate_out ( rate_out_II ),
.sum_up_out ( sum_out_II ),
///////////////////////////////////
// III
.pure_attack ( attack_III ),
.pure_step ( step_III ),
.pure_rate ( rate_in_III[5:1] ),
.pure_eg_in ( eg_in_III ),
.pure_eg_out ( pure_eg_out_III ),
.sum_up_in ( sum_in_III ),
///////////////////////////////////
// IV
.fnum ( fnum_IV ),
.block ( block_IV ),
.lfo_mod ( lfo_mod ),
.amsen ( amsen_IV ),
.ams ( ams_IV ),
.ksl ( ksl_IV ),
.tl ( tl_IV ),
.final_keycode ( keycode_IV ),
.final_eg_in ( eg_in_IV ),
.final_eg_out ( eg_out_IV )
);
always @(posedge clk) if(cenop) begin
eg_in_II <= eg_in_I;
attack_II <= state_next_I[0];
base_rate_II<= base_rate_I;
pg_rst_II <= pg_rst_I;
eg_in_III <= eg_in_II;
attack_III <= attack_II;
rate_in_III <= rate_out_II[5:1];
step_III <= step_II;
sum_in_III <= sum_out_II;
eg_in_IV <= pure_eg_out_III;
eg_V <= eg_out_IV;
keycode_III <= keycode_II;
keycode_IV <= keycode_III;
end
jtopl_sh #( .width(1), .stages(SLOTS) ) u_cntsh(
.clk ( clk ),
.cen ( cenop ),
.din ( cnt_lsb_II),
.drop ( cnt_in_II )
);
jtopl_sh #( .width(4), .stages(3) ) u_fnumsh(
.clk ( clk ),
.cen ( cenop ),
.din ( fnum_I[9:6] ),
.drop ( fnum_IV )
);
jtopl_sh #( .width(3), .stages(3) ) u_blocksh(
.clk ( clk ),
.cen ( cenop ),
.din ( block_I ),
.drop ( block_IV )
);
jtopl_sh_rst #( .width(10), .stages(SLOTS-3), .rstval(1'b1) ) u_egsh(
.clk ( clk ),
.cen ( cenop ),
.rst ( rst ),
.din ( eg_in_IV ),
.drop ( eg_in_I )
);
jtopl_sh_rst #( .width(3), .stages(SLOTS), .rstval(1'b1) ) u_egstate(
.clk ( clk ),
.cen ( cenop ),
.rst ( rst ),
.din ( state_next_I ),
.drop ( state_in_I )
);
jtopl_sh_rst #( .width(1), .stages(SLOTS), .rstval(1'b0) ) u_konsh(
.clk ( clk ),
.cen ( cenop ),
.rst ( rst ),
.din ( keyon_I ),
.drop ( keyon_last_I )
);
endmodule // jtopl_eg

View File

@ -0,0 +1,44 @@
/* This file is part of JTOPL.
JTOPL is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JTOPL 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with JTOPL. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 17-6-2020
*/
module jtopl_eg_cnt(
input wire rst,
input wire clk,
input wire cen,
input wire zero,
output reg [14:0] eg_cnt
);
always @(posedge clk, posedge rst) begin : envelope_counter
if( rst ) begin
eg_cnt <=15'd0;
end
else begin
if( zero && cen ) begin
// envelope counter increases at each zero input
// This is different from OPN/M where it increased
// once every three zero inputs
eg_cnt <= eg_cnt + 1'b1;
end
end
end
endmodule

View File

@ -0,0 +1,131 @@
/* This file is part of JTOPL.
JTOPL is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JTOPL 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with JTOPL. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 17-6-2020
*/
module jtopl_eg_comb(
input wire keyon_now,
input wire keyoff_now,
input wire [ 2:0] state_in,
input wire [ 9:0] eg_in,
// envelope configuration
input wire en_sus, // enable sustain
input wire [ 3:0] arate, // attack rate
input wire [ 3:0] drate, // decay rate
input wire [ 3:0] rrate,
input wire [ 3:0] sl, // sustain level
output wire [ 4:0] base_rate,
output wire [ 2:0] state_next,
output wire pg_rst,
///////////////////////////////////
// II
input wire step_attack,
input wire [ 4:0] step_rate_in,
input wire [ 3:0] keycode,
input wire [14:0] eg_cnt,
input wire cnt_in,
input wire ksr,
output wire cnt_lsb,
output wire step,
output wire [ 5:0] step_rate_out,
output wire sum_up_out,
///////////////////////////////////
// III
input wire pure_attack,
input wire pure_step,
input wire [ 5:1] pure_rate,
input wire [ 9:0] pure_eg_in,
output wire [ 9:0] pure_eg_out,
input wire sum_up_in,
///////////////////////////////////
// IV
input wire [ 3:0] lfo_mod,
input wire [ 3:0] fnum,
input wire [ 2:0] block,
input wire amsen,
input wire ams,
input wire [ 5:0] tl,
input wire [ 1:0] ksl,
input wire [ 3:0] final_keycode,
input wire [ 9:0] final_eg_in,
output wire [ 9:0] final_eg_out
);
// I
jtopl_eg_ctrl u_ctrl(
.keyon_now ( keyon_now ),
.keyoff_now ( keyoff_now ),
.state_in ( state_in ),
.eg ( eg_in ),
// envelope configuration
.en_sus ( en_sus ),
.arate ( arate ), // attack rate
.drate ( drate ), // decay rate
.rrate ( rrate ),
.sl ( sl ), // sustain level
.base_rate ( base_rate ),
.state_next ( state_next ),
.pg_rst ( pg_rst )
);
// II
jtopl_eg_step u_step(
.attack ( step_attack ),
.base_rate ( step_rate_in ),
.keycode ( keycode ),
.eg_cnt ( eg_cnt ),
.cnt_in ( cnt_in ),
.ksr ( ksr ),
.cnt_lsb ( cnt_lsb ),
.step ( step ),
.rate ( step_rate_out ),
.sum_up ( sum_up_out )
);
// III
wire [9:0] egin, egout;
jtopl_eg_pure u_pure(
.attack ( pure_attack ),
.step ( pure_step ),
.rate ( pure_rate ),
.eg_in ( pure_eg_in ),
.eg_pure( pure_eg_out ),
.sum_up ( sum_up_in )
);
// IV
jtopl_eg_final u_final(
.fnum ( fnum ),
.block ( block ),
.lfo_mod ( lfo_mod ),
.amsen ( amsen ),
.ams ( ams ),
.tl ( tl ),
.ksl ( ksl ),
.keycode ( final_keycode ),
.eg_pure_in ( final_eg_in ),
.eg_limited ( final_eg_out )
);
endmodule // jtopl_eg_comb

View File

@ -0,0 +1,87 @@
/* This file is part of JTOPL.
JTOPL is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JTOPL 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with JTOPL. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 17-6-2020
*/
module jtopl_eg_ctrl(
input wire keyon_now,
input wire keyoff_now,
input wire [2:0] state_in,
input wire [9:0] eg,
// envelope configuration
input wire en_sus, // enable sustain
input wire [3:0] arate, // attack rate
input wire [3:0] drate, // decay rate
input wire [3:0] rrate,
input wire [3:0] sl, // sustain level
output reg [4:0] base_rate,
output reg [2:0] state_next,
output reg pg_rst
);
localparam ATTACK = 3'b001,
DECAY = 3'b010,
HOLD = 3'b100,
RELEASE= 3'b000; // default state is release
// wire is_decaying = state_in[1] | state_in[2];
wire [4:0] sustain = { &sl, sl}; //93dB if sl==4'hF
always @(*) begin
pg_rst = keyon_now;
end
always @(*)
casez ( { keyoff_now, keyon_now, state_in} )
5'b01_???: begin // key on
base_rate = {arate,1'b0};
state_next = ATTACK;
end
{2'b00, ATTACK}:
if( eg==10'd0 ) begin
base_rate = {drate,1'b0};
state_next = DECAY;
end
else begin
base_rate = {arate,1'b0};
state_next = ATTACK;
end
{2'b00, DECAY}: begin
if( eg[9:5] >= sustain ) begin
base_rate = en_sus ? 5'd0 : {rrate,1'b0};
state_next = en_sus ? HOLD : RELEASE;
end else begin
base_rate = {drate,1'b0};
state_next = DECAY;
end
end
{2'b00, HOLD}: begin
base_rate = 5'd0;
state_next = HOLD;
end
default: begin // RELEASE, note that keyoff_now==1 will enter this state too
base_rate = {rrate,1'b1};
state_next = RELEASE; // release
end
endcase
endmodule // jtopl_eg_ctrl

View File

@ -0,0 +1,70 @@
/* This file is part of JTOPL.
JTOPL is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JTOPL 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with JTOPL. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 17-6-2020
*/
module jtopl_eg_final(
input wire [3:0] lfo_mod,
input wire [3:0] fnum,
input wire [2:0] block,
input wire amsen,
input wire ams,
input wire [5:0] tl,
input wire [1:0] ksl, // level damped by pitch
input wire [3:0] keycode,
input wire [9:0] eg_pure_in,
output reg [9:0] eg_limited
);
reg [ 5:0] am_final;
reg [11:0] sum_eg_tl;
reg [11:0] sum_eg_tl_am;
reg [ 8:0] ksl_dB;
reg [ 6:0] ksl_lut[0:15];
reg [ 7:0] ksl_base;
always @(*) begin
ksl_base = {1'b0, ksl_lut[fnum]}- { 1'b0, 4'd8-{1'b0,block}, 3'b0 };
if( ksl_base[7] || ksl==2'b0 ) begin
ksl_dB = 9'd0;
end else begin
ksl_dB = {ksl_base[6:0],2'b0} >> ~ksl;
end
end
always @(*) begin
am_final = amsen ? ( ams ? {lfo_mod, 2'b0} : {2'b0, lfo_mod} ) : 6'd0;
sum_eg_tl = { 2'b0, tl, 3'd0 } +
{ 1'b0, ksl_dB, 1'd0 } +
{ 1'b0, eg_pure_in}; // leading zeros needed to compute correctly
sum_eg_tl_am = sum_eg_tl + { 5'd0, am_final };
end
always @(*) begin
eg_limited = sum_eg_tl_am[11:10]==2'd0 ? sum_eg_tl_am[9:0] : 10'h3ff;
end
initial begin
ksl_lut[ 0] = 7'd00; ksl_lut[ 1] = 7'd32; ksl_lut[ 2] = 7'd40; ksl_lut[ 3] = 7'd45;
ksl_lut[ 4] = 7'd48; ksl_lut[ 5] = 7'd51; ksl_lut[ 6] = 7'd53; ksl_lut[ 7] = 7'd55;
ksl_lut[ 8] = 7'd56; ksl_lut[ 9] = 7'd58; ksl_lut[10] = 7'd59; ksl_lut[11] = 7'd60;
ksl_lut[12] = 7'd61; ksl_lut[13] = 7'd62; ksl_lut[14] = 7'd63; ksl_lut[15] = 7'd64;
end
endmodule

View File

@ -0,0 +1,81 @@
/* This file is part of JTOPL.
JTOPL is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JTOPL 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with JTOPL. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 17-6-2020
*/
module jtopl_eg_pure(
input wire attack,
input wire step,
input wire [ 5:1] rate,
input wire [ 9:0] eg_in,
input wire sum_up,
output reg [9:0] eg_pure
);
reg [ 3:0] dr_sum;
reg [ 9:0] dr_adj;
reg [10:0] dr_result;
always @(*) begin : dr_calculation
case( rate[5:2] )
4'b1100: dr_sum = { 2'b0, step, ~step }; // 12
4'b1101: dr_sum = { 1'b0, step, ~step, 1'b0 }; // 13
4'b1110: dr_sum = { step, ~step, 2'b0 }; // 14
4'b1111: dr_sum = 4'd8;// 15
default: dr_sum = { 2'b0, step, 1'b0 };
endcase
// Decay rate attenuation is multiplied by 4 for SSG operation
dr_adj = {6'd0, dr_sum};
dr_result = dr_adj + eg_in;
end
reg [ 7:0] ar_sum0;
reg [ 8:0] ar_sum1;
reg [10:0] ar_result;
reg [ 9:0] ar_sum;
always @(*) begin : ar_calculation
casez( rate[5:2] )
default: ar_sum0 = {2'd0, eg_in[9:4]};
4'b1101: ar_sum0 = {1'd0, eg_in[9:3]};
4'b111?: ar_sum0 = eg_in[9:2];
endcase
ar_sum1 = ar_sum0+9'd1;
if( rate[5:4] == 2'b11 )
ar_sum = step ? { ar_sum1, 1'b0 } : { 1'b0, ar_sum1 };
else
ar_sum = step ? { 1'b0, ar_sum1 } : 10'd0;
ar_result = eg_in-ar_sum;
end
///////////////////////////////////////////////////////////
// rate not used below this point
reg [9:0] eg_pre_fastar; // pre fast attack rate
always @(*) begin
if(sum_up) begin
if( attack )
eg_pre_fastar = ar_result[10] ? 10'd0: ar_result[9:0];
else
eg_pre_fastar = dr_result[10] ? 10'h3FF : dr_result[9:0];
end
else eg_pre_fastar = eg_in;
eg_pure = (attack&rate[5:1]==5'h1F) ? 10'd0 : eg_pre_fastar;
end
endmodule

View File

@ -0,0 +1,108 @@
/* This file is part of JTOPL.
JTOPL is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JTOPL 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with JTOPL. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 17-6-2020
*/
module jtopl_eg_step(
input wire attack,
input wire [ 4:0] base_rate,
input wire [ 3:0] keycode,
input wire [14:0] eg_cnt,
input wire cnt_in,
input wire ksr,
output wire cnt_lsb,
output reg step,
output reg [ 5:0] rate,
output reg sum_up
);
reg [6:0] pre_rate;
always @(*) begin : pre_rate_calc
if( base_rate == 5'd0 )
pre_rate = 7'd0;
else
pre_rate = { 1'b0, base_rate, 1'b0 } + (ksr ?
{ 3'b0, keycode }:
{ 5'b0, keycode[3:2] });
end
always @(*)
rate = pre_rate>=7'b1111_00 ? 6'b1111_11 : pre_rate[5:0];
reg [2:0] cnt;
reg [4:0] mux_sel;
always @(*) begin
mux_sel = attack ? (rate[5:2]+4'd1): {1'b0,rate[5:2]};
end
always @(*)
case( mux_sel )
5'h0: cnt = eg_cnt[14:12];
5'h1: cnt = eg_cnt[13:11];
5'h2: cnt = eg_cnt[12:10];
5'h3: cnt = eg_cnt[11: 9];
5'h4: cnt = eg_cnt[10: 8];
5'h5: cnt = eg_cnt[ 9: 7];
5'h6: cnt = eg_cnt[ 8: 6];
5'h7: cnt = eg_cnt[ 7: 5];
5'h8: cnt = eg_cnt[ 6: 4];
5'h9: cnt = eg_cnt[ 5: 3];
5'ha: cnt = eg_cnt[ 4: 2];
5'hb: cnt = eg_cnt[ 3: 1];
default: cnt = eg_cnt[ 2: 0];
endcase
////////////////////////////////
reg [7:0] step_idx;
always @(*) begin : rate_step
if( rate[5:4]==2'b11 ) begin // 0 means 1x, 1 means 2x
if( rate[5:2]==4'hf && attack)
step_idx = 8'b11111111; // Maximum attack speed, rates 60&61
else
case( rate[1:0] )
2'd0: step_idx = 8'b00000000;
2'd1: step_idx = 8'b10001000; // 2
2'd2: step_idx = 8'b10101010; // 4
2'd3: step_idx = 8'b11101110; // 6
endcase
end
else begin
if( rate[5:2]==4'd0 && !attack)
step_idx = 8'b11111110; // limit slowest decay rate
else
case( rate[1:0] )
2'd0: step_idx = 8'b10101010; // 4
2'd1: step_idx = 8'b11101010; // 5
2'd2: step_idx = 8'b11101110; // 6
2'd3: step_idx = 8'b11111110; // 7
endcase
end
// a rate of zero keeps the level still
step = rate[5:1]==5'd0 ? 1'b0 : step_idx[ cnt ];
end
assign cnt_lsb = cnt[0];
always @(*) begin
sum_up = cnt[0] != cnt_in;
end
endmodule // eg_step

View File

@ -0,0 +1,305 @@
/* This file is part of JTOPL.
JTOPL program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JTOPL program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with JTOPL. If not, see <http://www.gnu.org/licenses/>.
Based on Sauraen VHDL version of OPN/OPN2, which is based on die shots.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 20-6-2020
*/
// Yamaha used the same table for OPN, OPM and OPL
// Originally written in more compact way that required some logic to decompress
// Not really worth compressing when the target is an FPGA as one BRAM will be
// used in either case. So it's better to leave it uncompress and save the
// decoding logic
// altera message_off 10030
module jtopl_exprom
(
input wire [7:0] addr,
input wire clk,
input wire cen,
output reg [9:0] exp
);
reg [9:0] explut_jt51[255:0];
initial
begin
explut_jt51[8'd000] = 10'd1018;
explut_jt51[8'd001] = 10'd1013;
explut_jt51[8'd002] = 10'd1007;
explut_jt51[8'd003] = 10'd1002;
explut_jt51[8'd004] = 10'd0996;
explut_jt51[8'd005] = 10'd0991;
explut_jt51[8'd006] = 10'd0986;
explut_jt51[8'd007] = 10'd0980;
explut_jt51[8'd008] = 10'd0975;
explut_jt51[8'd009] = 10'd0969;
explut_jt51[8'd010] = 10'd0964;
explut_jt51[8'd011] = 10'd0959;
explut_jt51[8'd012] = 10'd0953;
explut_jt51[8'd013] = 10'd0948;
explut_jt51[8'd014] = 10'd0942;
explut_jt51[8'd015] = 10'd0937;
explut_jt51[8'd016] = 10'd0932;
explut_jt51[8'd017] = 10'd0927;
explut_jt51[8'd018] = 10'd0921;
explut_jt51[8'd019] = 10'd0916;
explut_jt51[8'd020] = 10'd0911;
explut_jt51[8'd021] = 10'd0906;
explut_jt51[8'd022] = 10'd0900;
explut_jt51[8'd023] = 10'd0895;
explut_jt51[8'd024] = 10'd0890;
explut_jt51[8'd025] = 10'd0885;
explut_jt51[8'd026] = 10'd0880;
explut_jt51[8'd027] = 10'd0874;
explut_jt51[8'd028] = 10'd0869;
explut_jt51[8'd029] = 10'd0864;
explut_jt51[8'd030] = 10'd0859;
explut_jt51[8'd031] = 10'd0854;
explut_jt51[8'd032] = 10'd0849;
explut_jt51[8'd033] = 10'd0844;
explut_jt51[8'd034] = 10'd0839;
explut_jt51[8'd035] = 10'd0834;
explut_jt51[8'd036] = 10'd0829;
explut_jt51[8'd037] = 10'd0824;
explut_jt51[8'd038] = 10'd0819;
explut_jt51[8'd039] = 10'd0814;
explut_jt51[8'd040] = 10'd0809;
explut_jt51[8'd041] = 10'd0804;
explut_jt51[8'd042] = 10'd0799;
explut_jt51[8'd043] = 10'd0794;
explut_jt51[8'd044] = 10'd0789;
explut_jt51[8'd045] = 10'd0784;
explut_jt51[8'd046] = 10'd0779;
explut_jt51[8'd047] = 10'd0774;
explut_jt51[8'd048] = 10'd0770;
explut_jt51[8'd049] = 10'd0765;
explut_jt51[8'd050] = 10'd0760;
explut_jt51[8'd051] = 10'd0755;
explut_jt51[8'd052] = 10'd0750;
explut_jt51[8'd053] = 10'd0745;
explut_jt51[8'd054] = 10'd0741;
explut_jt51[8'd055] = 10'd0736;
explut_jt51[8'd056] = 10'd0731;
explut_jt51[8'd057] = 10'd0726;
explut_jt51[8'd058] = 10'd0722;
explut_jt51[8'd059] = 10'd0717;
explut_jt51[8'd060] = 10'd0712;
explut_jt51[8'd061] = 10'd0708;
explut_jt51[8'd062] = 10'd0703;
explut_jt51[8'd063] = 10'd0698;
explut_jt51[8'd064] = 10'd0693;
explut_jt51[8'd065] = 10'd0689;
explut_jt51[8'd066] = 10'd0684;
explut_jt51[8'd067] = 10'd0680;
explut_jt51[8'd068] = 10'd0675;
explut_jt51[8'd069] = 10'd0670;
explut_jt51[8'd070] = 10'd0666;
explut_jt51[8'd071] = 10'd0661;
explut_jt51[8'd072] = 10'd0657;
explut_jt51[8'd073] = 10'd0652;
explut_jt51[8'd074] = 10'd0648;
explut_jt51[8'd075] = 10'd0643;
explut_jt51[8'd076] = 10'd0639;
explut_jt51[8'd077] = 10'd0634;
explut_jt51[8'd078] = 10'd0630;
explut_jt51[8'd079] = 10'd0625;
explut_jt51[8'd080] = 10'd0621;
explut_jt51[8'd081] = 10'd0616;
explut_jt51[8'd082] = 10'd0612;
explut_jt51[8'd083] = 10'd0607;
explut_jt51[8'd084] = 10'd0603;
explut_jt51[8'd085] = 10'd0599;
explut_jt51[8'd086] = 10'd0594;
explut_jt51[8'd087] = 10'd0590;
explut_jt51[8'd088] = 10'd0585;
explut_jt51[8'd089] = 10'd0581;
explut_jt51[8'd090] = 10'd0577;
explut_jt51[8'd091] = 10'd0572;
explut_jt51[8'd092] = 10'd0568;
explut_jt51[8'd093] = 10'd0564;
explut_jt51[8'd094] = 10'd0560;
explut_jt51[8'd095] = 10'd0555;
explut_jt51[8'd096] = 10'd0551;
explut_jt51[8'd097] = 10'd0547;
explut_jt51[8'd098] = 10'd0542;
explut_jt51[8'd099] = 10'd0538;
explut_jt51[8'd100] = 10'd0534;
explut_jt51[8'd101] = 10'd0530;
explut_jt51[8'd102] = 10'd0526;
explut_jt51[8'd103] = 10'd0521;
explut_jt51[8'd104] = 10'd0517;
explut_jt51[8'd105] = 10'd0513;
explut_jt51[8'd106] = 10'd0509;
explut_jt51[8'd107] = 10'd0505;
explut_jt51[8'd108] = 10'd0501;
explut_jt51[8'd109] = 10'd0496;
explut_jt51[8'd110] = 10'd0492;
explut_jt51[8'd111] = 10'd0488;
explut_jt51[8'd112] = 10'd0484;
explut_jt51[8'd113] = 10'd0480;
explut_jt51[8'd114] = 10'd0476;
explut_jt51[8'd115] = 10'd0472;
explut_jt51[8'd116] = 10'd0468;
explut_jt51[8'd117] = 10'd0464;
explut_jt51[8'd118] = 10'd0460;
explut_jt51[8'd119] = 10'd0456;
explut_jt51[8'd120] = 10'd0452;
explut_jt51[8'd121] = 10'd0448;
explut_jt51[8'd122] = 10'd0444;
explut_jt51[8'd123] = 10'd0440;
explut_jt51[8'd124] = 10'd0436;
explut_jt51[8'd125] = 10'd0432;
explut_jt51[8'd126] = 10'd0428;
explut_jt51[8'd127] = 10'd0424;
explut_jt51[8'd128] = 10'd0420;
explut_jt51[8'd129] = 10'd0416;
explut_jt51[8'd130] = 10'd0412;
explut_jt51[8'd131] = 10'd0409;
explut_jt51[8'd132] = 10'd0405;
explut_jt51[8'd133] = 10'd0401;
explut_jt51[8'd134] = 10'd0397;
explut_jt51[8'd135] = 10'd0393;
explut_jt51[8'd136] = 10'd0389;
explut_jt51[8'd137] = 10'd0385;
explut_jt51[8'd138] = 10'd0382;
explut_jt51[8'd139] = 10'd0378;
explut_jt51[8'd140] = 10'd0374;
explut_jt51[8'd141] = 10'd0370;
explut_jt51[8'd142] = 10'd0367;
explut_jt51[8'd143] = 10'd0363;
explut_jt51[8'd144] = 10'd0359;
explut_jt51[8'd145] = 10'd0355;
explut_jt51[8'd146] = 10'd0352;
explut_jt51[8'd147] = 10'd0348;
explut_jt51[8'd148] = 10'd0344;
explut_jt51[8'd149] = 10'd0340;
explut_jt51[8'd150] = 10'd0337;
explut_jt51[8'd151] = 10'd0333;
explut_jt51[8'd152] = 10'd0329;
explut_jt51[8'd153] = 10'd0326;
explut_jt51[8'd154] = 10'd0322;
explut_jt51[8'd155] = 10'd0318;
explut_jt51[8'd156] = 10'd0315;
explut_jt51[8'd157] = 10'd0311;
explut_jt51[8'd158] = 10'd0308;
explut_jt51[8'd159] = 10'd0304;
explut_jt51[8'd160] = 10'd0300;
explut_jt51[8'd161] = 10'd0297;
explut_jt51[8'd162] = 10'd0293;
explut_jt51[8'd163] = 10'd0290;
explut_jt51[8'd164] = 10'd0286;
explut_jt51[8'd165] = 10'd0283;
explut_jt51[8'd166] = 10'd0279;
explut_jt51[8'd167] = 10'd0276;
explut_jt51[8'd168] = 10'd0272;
explut_jt51[8'd169] = 10'd0268;
explut_jt51[8'd170] = 10'd0265;
explut_jt51[8'd171] = 10'd0262;
explut_jt51[8'd172] = 10'd0258;
explut_jt51[8'd173] = 10'd0255;
explut_jt51[8'd174] = 10'd0251;
explut_jt51[8'd175] = 10'd0248;
explut_jt51[8'd176] = 10'd0244;
explut_jt51[8'd177] = 10'd0241;
explut_jt51[8'd178] = 10'd0237;
explut_jt51[8'd179] = 10'd0234;
explut_jt51[8'd180] = 10'd0231;
explut_jt51[8'd181] = 10'd0227;
explut_jt51[8'd182] = 10'd0224;
explut_jt51[8'd183] = 10'd0220;
explut_jt51[8'd184] = 10'd0217;
explut_jt51[8'd185] = 10'd0214;
explut_jt51[8'd186] = 10'd0210;
explut_jt51[8'd187] = 10'd0207;
explut_jt51[8'd188] = 10'd0204;
explut_jt51[8'd189] = 10'd0200;
explut_jt51[8'd190] = 10'd0197;
explut_jt51[8'd191] = 10'd0194;
explut_jt51[8'd192] = 10'd0190;
explut_jt51[8'd193] = 10'd0187;
explut_jt51[8'd194] = 10'd0184;
explut_jt51[8'd195] = 10'd0181;
explut_jt51[8'd196] = 10'd0177;
explut_jt51[8'd197] = 10'd0174;
explut_jt51[8'd198] = 10'd0171;
explut_jt51[8'd199] = 10'd0168;
explut_jt51[8'd200] = 10'd0164;
explut_jt51[8'd201] = 10'd0161;
explut_jt51[8'd202] = 10'd0158;
explut_jt51[8'd203] = 10'd0155;
explut_jt51[8'd204] = 10'd0152;
explut_jt51[8'd205] = 10'd0148;
explut_jt51[8'd206] = 10'd0145;
explut_jt51[8'd207] = 10'd0142;
explut_jt51[8'd208] = 10'd0139;
explut_jt51[8'd209] = 10'd0136;
explut_jt51[8'd210] = 10'd0133;
explut_jt51[8'd211] = 10'd0130;
explut_jt51[8'd212] = 10'd0126;
explut_jt51[8'd213] = 10'd0123;
explut_jt51[8'd214] = 10'd0120;
explut_jt51[8'd215] = 10'd0117;
explut_jt51[8'd216] = 10'd0114;
explut_jt51[8'd217] = 10'd0111;
explut_jt51[8'd218] = 10'd0108;
explut_jt51[8'd219] = 10'd0105;
explut_jt51[8'd220] = 10'd0102;
explut_jt51[8'd221] = 10'd0099;
explut_jt51[8'd222] = 10'd0096;
explut_jt51[8'd223] = 10'd0093;
explut_jt51[8'd224] = 10'd0090;
explut_jt51[8'd225] = 10'd0087;
explut_jt51[8'd226] = 10'd0084;
explut_jt51[8'd227] = 10'd0081;
explut_jt51[8'd228] = 10'd0078;
explut_jt51[8'd229] = 10'd0075;
explut_jt51[8'd230] = 10'd0072;
explut_jt51[8'd231] = 10'd0069;
explut_jt51[8'd232] = 10'd0066;
explut_jt51[8'd233] = 10'd0063;
explut_jt51[8'd234] = 10'd0060;
explut_jt51[8'd235] = 10'd0057;
explut_jt51[8'd236] = 10'd0054;
explut_jt51[8'd237] = 10'd0051;
explut_jt51[8'd238] = 10'd0048;
explut_jt51[8'd239] = 10'd0045;
explut_jt51[8'd240] = 10'd0042;
explut_jt51[8'd241] = 10'd0040;
explut_jt51[8'd242] = 10'd0037;
explut_jt51[8'd243] = 10'd0034;
explut_jt51[8'd244] = 10'd0031;
explut_jt51[8'd245] = 10'd0028;
explut_jt51[8'd246] = 10'd0025;
explut_jt51[8'd247] = 10'd0022;
explut_jt51[8'd248] = 10'd0020;
explut_jt51[8'd249] = 10'd0017;
explut_jt51[8'd250] = 10'd0014;
explut_jt51[8'd251] = 10'd0011;
explut_jt51[8'd252] = 10'd0008;
explut_jt51[8'd253] = 10'd0006;
explut_jt51[8'd254] = 10'd0003;
explut_jt51[8'd255] = 10'd0000;
end
always @ (posedge clk) if(cen)
exp <= explut_jt51[addr];
endmodule

View File

@ -0,0 +1,80 @@
/* This file is part of JTOPL.
JTOPL is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JTOPL 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with JTOPL. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 21-6-2020
*/
// Follows OPLL Reverse Engineering from Nuked
// https://github.com/nukeykt/Nuked-OPLL
// The AM logic renders a triangular waveform. The logic for it is rather
// obscure, but apparently that's how the original was done
module jtopl_lfo(
input wire rst,
input wire clk,
input wire cenop,
input wire [17:0] slot,
output wire [ 2:0] vib_cnt,
output reg [ 3:0] trem
);
parameter [6:0] LIM=7'd60;
reg [12:0] cnt;
reg am_inc, am_incen, am_dir, am_step;
reg [ 1:0] am_bit;
reg am_carry;
reg [ 8:0] am_cnt;
wire [12:0] next = cnt+1'b1;
assign vib_cnt = cnt[12:10];
always @(*) begin
am_inc = (slot[0] | am_dir ) & am_step & am_incen;
am_bit = {1'b0, am_cnt[0]} + {1'b0, am_inc} + {1'b0, am_carry & am_incen};
end
always @(posedge clk) begin
if( rst ) begin
cnt <= 13'd0;
am_incen <= 1;
am_dir <= 0;
am_carry <= 0;
am_cnt <= 9'd0;
am_step <= 0;
end else if( cenop ) begin
if( slot[17] ) begin
cnt <= next;
am_step <= &next[5:0];
am_incen <= 1;
end
else if(slot[8]) am_incen <= 0;
am_cnt <= { am_bit[0], am_cnt[8:1] };
am_carry <= am_bit[1];
if( slot[0] ) begin
if( am_dir && am_cnt[6:0]==7'd0 ) am_dir <= 0;
else
if( !am_dir && ( (am_cnt[6:0]&7'h69) == 7'h69) ) am_dir <= 1;
end
// output
if( slot[0] ) trem <= am_cnt[6:3];
end
end
endmodule

View File

@ -0,0 +1,297 @@
/* This file is part of JTOPL.
JTOPL program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JTOPL program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with JTOPL. If not, see <http://www.gnu.org/licenses/>.
Based on Sauraen VHDL version of OPN/OPN2, which is based on die shots.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 13-6-2020
*/
//altera message_off 10030
module jtopl_logsin(
input wire clk,
input wire cen,
input wire [ 7:0] addr,
output reg [11:0] logsin
);
reg [11:0] sinelut[255:0];
initial begin
sinelut[8'd000] = 12'h000;
sinelut[8'd001] = 12'h000;
sinelut[8'd002] = 12'h000;
sinelut[8'd003] = 12'h000;
sinelut[8'd004] = 12'h000;
sinelut[8'd005] = 12'h000;
sinelut[8'd006] = 12'h000;
sinelut[8'd007] = 12'h000;
sinelut[8'd008] = 12'h001;
sinelut[8'd009] = 12'h001;
sinelut[8'd010] = 12'h001;
sinelut[8'd011] = 12'h001;
sinelut[8'd012] = 12'h001;
sinelut[8'd013] = 12'h001;
sinelut[8'd014] = 12'h001;
sinelut[8'd015] = 12'h002;
sinelut[8'd016] = 12'h002;
sinelut[8'd017] = 12'h002;
sinelut[8'd018] = 12'h002;
sinelut[8'd019] = 12'h003;
sinelut[8'd020] = 12'h003;
sinelut[8'd021] = 12'h003;
sinelut[8'd022] = 12'h004;
sinelut[8'd023] = 12'h004;
sinelut[8'd024] = 12'h004;
sinelut[8'd025] = 12'h005;
sinelut[8'd026] = 12'h005;
sinelut[8'd027] = 12'h005;
sinelut[8'd028] = 12'h006;
sinelut[8'd029] = 12'h006;
sinelut[8'd030] = 12'h007;
sinelut[8'd031] = 12'h007;
sinelut[8'd032] = 12'h007;
sinelut[8'd033] = 12'h008;
sinelut[8'd034] = 12'h008;
sinelut[8'd035] = 12'h009;
sinelut[8'd036] = 12'h009;
sinelut[8'd037] = 12'h00a;
sinelut[8'd038] = 12'h00a;
sinelut[8'd039] = 12'h00b;
sinelut[8'd040] = 12'h00c;
sinelut[8'd041] = 12'h00c;
sinelut[8'd042] = 12'h00d;
sinelut[8'd043] = 12'h00d;
sinelut[8'd044] = 12'h00e;
sinelut[8'd045] = 12'h00f;
sinelut[8'd046] = 12'h00f;
sinelut[8'd047] = 12'h010;
sinelut[8'd048] = 12'h011;
sinelut[8'd049] = 12'h011;
sinelut[8'd050] = 12'h012;
sinelut[8'd051] = 12'h013;
sinelut[8'd052] = 12'h014;
sinelut[8'd053] = 12'h014;
sinelut[8'd054] = 12'h015;
sinelut[8'd055] = 12'h016;
sinelut[8'd056] = 12'h017;
sinelut[8'd057] = 12'h017;
sinelut[8'd058] = 12'h018;
sinelut[8'd059] = 12'h019;
sinelut[8'd060] = 12'h01a;
sinelut[8'd061] = 12'h01b;
sinelut[8'd062] = 12'h01c;
sinelut[8'd063] = 12'h01d;
sinelut[8'd064] = 12'h01e;
sinelut[8'd065] = 12'h01f;
sinelut[8'd066] = 12'h020;
sinelut[8'd067] = 12'h021;
sinelut[8'd068] = 12'h022;
sinelut[8'd069] = 12'h023;
sinelut[8'd070] = 12'h024;
sinelut[8'd071] = 12'h025;
sinelut[8'd072] = 12'h026;
sinelut[8'd073] = 12'h027;
sinelut[8'd074] = 12'h028;
sinelut[8'd075] = 12'h029;
sinelut[8'd076] = 12'h02a;
sinelut[8'd077] = 12'h02b;
sinelut[8'd078] = 12'h02d;
sinelut[8'd079] = 12'h02e;
sinelut[8'd080] = 12'h02f;
sinelut[8'd081] = 12'h030;
sinelut[8'd082] = 12'h031;
sinelut[8'd083] = 12'h033;
sinelut[8'd084] = 12'h034;
sinelut[8'd085] = 12'h035;
sinelut[8'd086] = 12'h037;
sinelut[8'd087] = 12'h038;
sinelut[8'd088] = 12'h039;
sinelut[8'd089] = 12'h03b;
sinelut[8'd090] = 12'h03c;
sinelut[8'd091] = 12'h03e;
sinelut[8'd092] = 12'h03f;
sinelut[8'd093] = 12'h040;
sinelut[8'd094] = 12'h042;
sinelut[8'd095] = 12'h043;
sinelut[8'd096] = 12'h045;
sinelut[8'd097] = 12'h046;
sinelut[8'd098] = 12'h048;
sinelut[8'd099] = 12'h04a;
sinelut[8'd100] = 12'h04b;
sinelut[8'd101] = 12'h04d;
sinelut[8'd102] = 12'h04e;
sinelut[8'd103] = 12'h050;
sinelut[8'd104] = 12'h052;
sinelut[8'd105] = 12'h053;
sinelut[8'd106] = 12'h055;
sinelut[8'd107] = 12'h057;
sinelut[8'd108] = 12'h059;
sinelut[8'd109] = 12'h05b;
sinelut[8'd110] = 12'h05c;
sinelut[8'd111] = 12'h05e;
sinelut[8'd112] = 12'h060;
sinelut[8'd113] = 12'h062;
sinelut[8'd114] = 12'h064;
sinelut[8'd115] = 12'h066;
sinelut[8'd116] = 12'h068;
sinelut[8'd117] = 12'h06a;
sinelut[8'd118] = 12'h06c;
sinelut[8'd119] = 12'h06e;
sinelut[8'd120] = 12'h070;
sinelut[8'd121] = 12'h072;
sinelut[8'd122] = 12'h074;
sinelut[8'd123] = 12'h076;
sinelut[8'd124] = 12'h078;
sinelut[8'd125] = 12'h07a;
sinelut[8'd126] = 12'h07d;
sinelut[8'd127] = 12'h07f;
sinelut[8'd128] = 12'h081;
sinelut[8'd129] = 12'h083;
sinelut[8'd130] = 12'h086;
sinelut[8'd131] = 12'h088;
sinelut[8'd132] = 12'h08a;
sinelut[8'd133] = 12'h08d;
sinelut[8'd134] = 12'h08f;
sinelut[8'd135] = 12'h092;
sinelut[8'd136] = 12'h094;
sinelut[8'd137] = 12'h097;
sinelut[8'd138] = 12'h099;
sinelut[8'd139] = 12'h09c;
sinelut[8'd140] = 12'h09f;
sinelut[8'd141] = 12'h0a1;
sinelut[8'd142] = 12'h0a4;
sinelut[8'd143] = 12'h0a7;
sinelut[8'd144] = 12'h0a9;
sinelut[8'd145] = 12'h0ac;
sinelut[8'd146] = 12'h0af;
sinelut[8'd147] = 12'h0b2;
sinelut[8'd148] = 12'h0b5;
sinelut[8'd149] = 12'h0b8;
sinelut[8'd150] = 12'h0bb;
sinelut[8'd151] = 12'h0be;
sinelut[8'd152] = 12'h0c1;
sinelut[8'd153] = 12'h0c4;
sinelut[8'd154] = 12'h0c7;
sinelut[8'd155] = 12'h0ca;
sinelut[8'd156] = 12'h0cd;
sinelut[8'd157] = 12'h0d1;
sinelut[8'd158] = 12'h0d4;
sinelut[8'd159] = 12'h0d7;
sinelut[8'd160] = 12'h0db;
sinelut[8'd161] = 12'h0de;
sinelut[8'd162] = 12'h0e2;
sinelut[8'd163] = 12'h0e5;
sinelut[8'd164] = 12'h0e9;
sinelut[8'd165] = 12'h0ec;
sinelut[8'd166] = 12'h0f0;
sinelut[8'd167] = 12'h0f4;
sinelut[8'd168] = 12'h0f8;
sinelut[8'd169] = 12'h0fb;
sinelut[8'd170] = 12'h0ff;
sinelut[8'd171] = 12'h103;
sinelut[8'd172] = 12'h107;
sinelut[8'd173] = 12'h10b;
sinelut[8'd174] = 12'h10f;
sinelut[8'd175] = 12'h114;
sinelut[8'd176] = 12'h118;
sinelut[8'd177] = 12'h11c;
sinelut[8'd178] = 12'h121;
sinelut[8'd179] = 12'h125;
sinelut[8'd180] = 12'h129;
sinelut[8'd181] = 12'h12e;
sinelut[8'd182] = 12'h133;
sinelut[8'd183] = 12'h137;
sinelut[8'd184] = 12'h13c;
sinelut[8'd185] = 12'h141;
sinelut[8'd186] = 12'h146;
sinelut[8'd187] = 12'h14b;
sinelut[8'd188] = 12'h150;
sinelut[8'd189] = 12'h155;
sinelut[8'd190] = 12'h15b;
sinelut[8'd191] = 12'h160;
sinelut[8'd192] = 12'h166;
sinelut[8'd193] = 12'h16b;
sinelut[8'd194] = 12'h171;
sinelut[8'd195] = 12'h177;
sinelut[8'd196] = 12'h17c;
sinelut[8'd197] = 12'h182;
sinelut[8'd198] = 12'h188;
sinelut[8'd199] = 12'h18f;
sinelut[8'd200] = 12'h195;
sinelut[8'd201] = 12'h19b;
sinelut[8'd202] = 12'h1a2;
sinelut[8'd203] = 12'h1a9;
sinelut[8'd204] = 12'h1b0;
sinelut[8'd205] = 12'h1b7;
sinelut[8'd206] = 12'h1be;
sinelut[8'd207] = 12'h1c5;
sinelut[8'd208] = 12'h1cd;
sinelut[8'd209] = 12'h1d4;
sinelut[8'd210] = 12'h1dc;
sinelut[8'd211] = 12'h1e4;
sinelut[8'd212] = 12'h1ec;
sinelut[8'd213] = 12'h1f5;
sinelut[8'd214] = 12'h1fd;
sinelut[8'd215] = 12'h206;
sinelut[8'd216] = 12'h20f;
sinelut[8'd217] = 12'h218;
sinelut[8'd218] = 12'h222;
sinelut[8'd219] = 12'h22c;
sinelut[8'd220] = 12'h236;
sinelut[8'd221] = 12'h240;
sinelut[8'd222] = 12'h24b;
sinelut[8'd223] = 12'h256;
sinelut[8'd224] = 12'h261;
sinelut[8'd225] = 12'h26d;
sinelut[8'd226] = 12'h279;
sinelut[8'd227] = 12'h286;
sinelut[8'd228] = 12'h293;
sinelut[8'd229] = 12'h2a0;
sinelut[8'd230] = 12'h2af;
sinelut[8'd231] = 12'h2bd;
sinelut[8'd232] = 12'h2cd;
sinelut[8'd233] = 12'h2dc;
sinelut[8'd234] = 12'h2ed;
sinelut[8'd235] = 12'h2ff;
sinelut[8'd236] = 12'h311;
sinelut[8'd237] = 12'h324;
sinelut[8'd238] = 12'h339;
sinelut[8'd239] = 12'h34e;
sinelut[8'd240] = 12'h365;
sinelut[8'd241] = 12'h37e;
sinelut[8'd242] = 12'h398;
sinelut[8'd243] = 12'h3b5;
sinelut[8'd244] = 12'h3d3;
sinelut[8'd245] = 12'h3f5;
sinelut[8'd246] = 12'h41a;
sinelut[8'd247] = 12'h443;
sinelut[8'd248] = 12'h471;
sinelut[8'd249] = 12'h4a6;
sinelut[8'd250] = 12'h4e4;
sinelut[8'd251] = 12'h52e;
sinelut[8'd252] = 12'h58b;
sinelut[8'd253] = 12'h607;
sinelut[8'd254] = 12'h6c3;
sinelut[8'd255] = 12'h859;
end
always @ (posedge clk) if(cen) begin
logsin <= sinelut[addr];
end
endmodule

View File

@ -0,0 +1,277 @@
/* This file is part of JTOPL.
JTOPL is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JTOPL 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with JTOPL. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 10-6-2020
*/
module jtopl_mmr #(parameter OPL_TYPE=1)
(
input wire rst,
input wire clk,
input wire cen,
output wire cenop,
input wire [ 7:0] din,
input wire write,
input wire addr,
// location
output wire zero,
output wire [ 1:0] group,
output wire op,
output wire [17:0] slot,
output reg rhy_en,
// Timers
output reg [ 7:0] value_A,
output reg [ 7:0] value_B,
output reg load_A,
output reg load_B,
output reg flagen_A,
output reg flagen_B,
output reg clr_flag_A,
output reg clr_flag_B,
input wire flag_A,
input wire overflow_A,
// Phase Generator
output wire [ 9:0] fnum_I,
output wire [ 2:0] block_I,
output wire [ 3:0] mul_II,
output wire viben_I,
// Operator
output wire [ 1:0] wavsel_I,
// Envelope Generator
output wire keyon_I,
output wire en_sus_I, // enable sustain
output wire [ 3:0] arate_I, // attack rate
output wire [ 3:0] drate_I, // decay rate
output wire [ 3:0] rrate_I, // release rate
output wire [ 3:0] sl_I, // sustain level
output wire ks_II, // key scale
output wire [ 5:0] tl_IV,
output wire amen_IV,
// global values
output reg am_dep,
output reg vib_dep,
output wire [ 1:0] ksl_IV,
// Operator configuration
output wire [ 2:0] fb_I,
output wire con_I
);
//parameter OPL_TYPE=1;
jtopl_div #(OPL_TYPE) u_div (
.rst ( rst ),
.clk ( clk ),
.cen ( cen ),
.cenop ( cenop )
);
localparam [7:0] REG_TESTYM = 8'h01,
REG_CLKA = 8'h02,
REG_CLKB = 8'h03,
REG_TIMER = 8'h04,
REG_CSM = 8'h08,
REG_RYTHM = 8'hBD;
reg [ 7:0] selreg; // selected register
reg [ 7:0] din_copy;
reg csm, effect;
reg [ 1:0] sel_group; // group to update
reg [ 2:0] sel_sub; // subslot to update
reg up_fnumlo, up_fnumhi, up_fbcon,
up_mult, up_ksl_tl, up_ar_dr, up_sl_rr,
up_wav;
reg wave_mode, // 1 if waveform selection is enabled (OPL2)
csm_en,
note_sel; // keyboard split, not implemented
reg [ 4:0] rhy_kon;
// this runs at clk speed, no clock gating here
// if I try to make this an async rst it fails to map it
// as flip flops but uses latches instead. So I keep it as sync. reset
always @(posedge clk) begin
if( rst ) begin
selreg <= 8'h0;
sel_group <= 2'd0;
sel_sub <= 3'd0;
// Updaters
up_fbcon <= 0;
up_fnumlo <= 0;
up_fnumhi <= 0;
up_mult <= 0;
up_ksl_tl <= 0;
up_ar_dr <= 0;
up_sl_rr <= 0;
up_wav <= 0;
// Rhythms
rhy_en <= 0;
rhy_kon <= 5'd0;
// sensitivity to LFO
am_dep <= 0;
vib_dep <= 0;
csm_en <= 0;
note_sel <= 0;
// OPL2 waveforms
wave_mode <= 0;
// timers
{ value_A, value_B } <= 16'd0;
{ clr_flag_B, clr_flag_A, load_B, load_A } <= 4'd0;
flagen_A <= 1;
flagen_B <= 1;
din_copy <= 8'd0;
end else begin
// WRITE IN REGISTERS
if( write ) begin
if( !addr ) begin
$display ("[[[ YM3526 ]]] READ_VALUE:%02h t=%0t", din , $realtime);
selreg <= din;
end else begin
// Global registers
din_copy <= din;
up_fnumhi <= 0;
up_fnumlo <= 0;
up_fbcon <= 0;
up_mult <= 0;
up_ksl_tl <= 0;
up_ar_dr <= 0;
up_sl_rr <= 0;
up_wav <= 0;
// General control (<0x20 registers)
casez( selreg )
REG_TESTYM: if(OPL_TYPE>1) wave_mode <= din[5];
REG_CLKA: begin value_A <= din; $display ("[[[ YM3526 ]]] REG_CLKA t=%0t" , $realtime); end
REG_CLKB: begin value_B <= din; $display ("[[[ YM3526 ]]] REG_CLKB t=%0t" , $realtime); end
REG_TIMER: begin
$display ("[[[ YM3526 ]]] REG_TIMER t=%0t" , $realtime);
clr_flag_A <= din[7];
clr_flag_B <= din[7];
if (~din[7]) begin
flagen_A <= ~din[6];
flagen_B <= ~din[5];
{ load_B, load_A } <= din[1:0];
end
end
REG_CSM: begin {csm_en, note_sel} <= din[7:6]; $display ("[[[ YM3526 ]]] REG_CSM t=%0t" , $realtime); end
default:;
endcase
// Operator registers
if( selreg >= 8'h20 &&
(selreg < 8'hA0 || (selreg>=8'hE0 && OPL_TYPE>1) ) &&
selreg[2:0]<=3'd5 && selreg[4:3]!=2'b11) begin
sel_group <= selreg[4:3];
sel_sub <= selreg[2:0];
$display ("[[[ YM3526 ]]] OPERATOR REGISTERS t=%0t" , $realtime);
case( selreg[7:5] )
3'b001: up_mult <= 1;
3'b010: up_ksl_tl <= 1;
3'b011: up_ar_dr <= 1;
3'b100: up_sl_rr <= 1;
3'b111: up_wav <= OPL_TYPE!=1;
default:;
endcase
end
// Channel registers
if( selreg[3:0]<=4'd8) begin
$display ("[[[ YM3526 ]]] CHANNEL REGISTERS t=%0t", $realtime);
case( selreg[7:4] )
4'hA: up_fnumlo <= 1;
4'hB: up_fnumhi <= 1;
4'hC: up_fbcon <= 1;
default:;
endcase
end
if( selreg[7:4]>=4'hA && selreg[7:4]<4'hd
&& selreg[3:0]<=8 ) begin
$display ("[[[ YM3526 ]]] SEL_GROUP,SUB REGISTERS t=%0t", $realtime);
sel_group <= selreg[3:0] < 4'd3 ? 2'd0 :
( selreg[3:0] < 4'd6 ? 2'd1 :
( selreg[3:0] < 4'd9 ? 2'd2 : 2'd3) );
sel_sub <= selreg[3:0] < 4'd6 ? selreg[2:0] :
{ 1'b0, ~&selreg[2:1], selreg[0] };
end
// Global register
if( selreg==REG_RYTHM ) begin
$display ("[[[ YM3526 ]]] REG_RYTHM t=%0t" , $realtime);
am_dep <= din[7];
vib_dep <= din[6];
rhy_en <= din[5];
rhy_kon <= din[4:0];
end
end
end
else if(cenop) begin /* clear once-only bits */
{ clr_flag_B, clr_flag_A } <= 2'd0;
end
end
end
jtopl_reg #(.OPL_TYPE(OPL_TYPE)) u_reg(
.rst ( rst ),
.clk ( clk ),
.cen ( cenop ),
.din ( din_copy ),
.write ( write ),
// Pipeline order
.zero ( zero ),
.group ( group ),
.op ( op ),
.slot ( slot ),
.sel_group ( sel_group ), // group to update
.sel_sub ( sel_sub ), // subslot to update
.rhy_en ( rhy_en ),
.rhy_kon ( rhy_kon ),
//input csm,
//input flag_A,
//input overflow_A,
.up_fbcon ( up_fbcon ),
.up_fnumlo ( up_fnumlo ),
.up_fnumhi ( up_fnumhi ),
.up_mult ( up_mult ),
.up_ksl_tl ( up_ksl_tl ),
.up_ar_dr ( up_ar_dr ),
.up_sl_rr ( up_sl_rr ),
.up_wav ( up_wav ),
// PG
.fnum_I ( fnum_I ),
.block_I ( block_I ),
.mul_II ( mul_II ),
.viben_I ( viben_I ),
// OP
.wavsel_I ( wavsel_I ),
.wave_mode ( wave_mode ),
// EG
.keyon_I ( keyon_I ),
.en_sus_I ( en_sus_I ),
.arate_I ( arate_I ),
.drate_I ( drate_I ),
.rrate_I ( rrate_I ),
.sl_I ( sl_I ),
.ks_II ( ks_II ),
.ksl_IV ( ksl_IV ),
.amen_IV ( amen_IV ),
.tl_IV ( tl_IV ),
// Timbre - Neiro
.fb_I ( fb_I ),
.con_I ( con_I )
);
endmodule

View File

@ -0,0 +1,47 @@
/* This file is part of JTOPL.
JTOPL is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JTOPL 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with JTOPL. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 24-6-2020
*/
module jtopl_noise(
input wire rst, // rst should be at least 6 clk&cen cycles long
input wire clk, // CPU clock
input wire cen, // optional clock enable, it not needed leave as 1'b1
output wire noise
);
reg [22:0] no;
reg nbit;
assign noise = no[0];
always @(*) begin
nbit = no[0] ^ no[14];
nbit = nbit | (no==23'd0);
end
always @(posedge clk, posedge rst) begin
if( rst )
no <= 23'd1<<22;
else if(cen) begin
no <= { nbit, no[22:1] };
end
end
endmodule

View File

@ -0,0 +1,263 @@
/* This file is part of JTOPL.
JTOPL program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JTOPL program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with JTOPL. If not, see <http://www.gnu.org/licenses/>.
Based on Sauraen VHDL version of OPN/OPN2, which is based on die shots.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 19-6-2020
*/
module jtopl_op #(parameter OPL_TYPE=1)
(
input wire rst,
input wire clk,
input wire cenop,
// these signals need be delayed
input wire [1:0] group,
input wire op, // 0 for modulator operators
input wire con_I,
input wire [2:0] fb_I, // voice feedback
input wire zero,
input wire [9:0] pg_phase_I,
input wire [1:0] wavsel_I,
input wire [9:0] eg_atten_II, // output from envelope generator
output reg signed [12:0] op_result,
output wire op_out,
output wire con_out
);
//parameter OPL_TYPE=1;
localparam OPW=13, // Operator Width
PW=OPW*2; // Previous data Width
reg [11:0] level_II;
reg signbit_II, signbit_III;
reg nullify_II;
wire [ 8:0] ctrl_in, ctrl_dly;
wire [ 1:0] group_d;
wire op_d, con_I_d;
wire [ 1:0] wavsel_d;
wire [ 2:0] fb_I_d;
reg [PW-1:0] prev, prev0_din, prev1_din, prev2_din;
wire [PW-1:0] prev0, prev1, prev2;
assign ctrl_in = { wavsel_I, group, op, con_I, fb_I };
assign { wavsel_d, group_d, op_d, con_I_d, fb_I_d } = ctrl_dly;
jtopl_sh #( .width(9), .stages(3)) u_delay(
.clk ( clk ),
.cen ( cenop ),
.din ( ctrl_in ),
.drop ( ctrl_dly )
);
jtopl_sh #( .width(2), .stages(3)) u_condly(
.clk ( clk ),
.cen ( cenop ),
.din ( {op_d, con_I_d} ),
.drop ( {op_out, con_out} )
);
always @(*) begin
prev0_din = op_d && group_d==2'd0 ? { prev0[OPW-1:0], op_result } : prev0;
prev1_din = op_d && group_d==2'd1 ? { prev1[OPW-1:0], op_result } : prev1;
prev2_din = op_d && group_d==2'd2 ? { prev2[OPW-1:0], op_result } : prev2;
case( group_d )
default: prev = prev0;
2'd1: prev = prev1;
2'd2: prev = prev2;
endcase
end
jtopl_sh #( .width(PW), .stages(3)) u_csr0(
.clk ( clk ),
.cen ( cenop ),
.din ( prev0_din ),
.drop ( prev0 )
);
jtopl_sh #( .width(PW), .stages(3)) u_csr1(
.clk ( clk ),
.cen ( cenop ),
.din ( prev1_din ),
.drop ( prev1 )
);
jtopl_sh #( .width(PW), .stages(3)) u_csr2(
.clk ( clk ),
.cen ( cenop ),
.din ( prev2_din ),
.drop ( prev2 )
);
reg [ 10:0] subtresult;
reg [OPW-1:0] shifter;
wire signed [OPW-1:0] fb1 = prev[PW-1:OPW];
wire signed [OPW-1:0] fb0 = prev[OPW-1:0];
// REGISTER/CYCLE 1
// Creation of phase modulation (FM) feedback signal, before shifting
reg signed [OPW-1:0] modmux_I;
reg signed [OPW-1:0] fbmod_I;
always @(*) begin
modmux_I = op_d ? op_result : fb1+fb0;
// OPL-L shifts by 8-FB
// OPL3 shifts by 9-FB
// OPLL seems to use lower resolution for OPW so it makes
// sense that it shifts by one fewer
fbmod_I = modmux_I>>>(4'd9-{1'b0,fb_I_d});
end
reg signed [9:0] phasemod_I;
always @(*) begin
// Shift FM feedback signal
if (op_d)
phasemod_I = con_I_d ? 10'd0 : modmux_I[9:0];
else
phasemod_I = fb_I_d==3'd0 ? 10'd0 : fbmod_I[9:0];
end
reg [ 9:0] phase;
reg [ 7:0] aux_I;
always @(*) begin
phase = phasemod_I + pg_phase_I;
aux_I = phase[7:0] ^ {8{~phase[8]}};
end
// REGISTER/CYCLE 1
always @(posedge clk) if( cenop ) begin
if( OPL_TYPE==1 ) begin
signbit_II <= phase[9];
nullify_II <= 0;
end else begin
signbit_II <= wavsel_d==0 && phase[9];
nullify_II <= (wavsel_d==2'b01 && phase[9]) || (wavsel_d==2'b11 && phase[8]);
end
end
wire [11:0] logsin_II;
jtopl_logsin u_logsin (
.clk ( clk ),
.cen ( cenop ),
.addr ( aux_I[7:0] ),
.logsin ( logsin_II )
);
// REGISTER/CYCLE 2
// Sine table
// Main sine table body
always @(*) begin
subtresult = eg_atten_II + logsin_II[11:2];
level_II = { subtresult[9:0], logsin_II[1:0] } | {12{subtresult[10]}};
if( nullify_II ) begin
level_II = ~12'h0;
end
end
wire [9:0] mantissa_III;
reg [3:0] exponent_III;
jtopl_exprom u_exprom(
.clk ( clk ),
.cen ( cenop ),
.addr ( level_II[7:0] ),
.exp ( mantissa_III )
);
always @(posedge clk) if( cenop ) begin
exponent_III <= level_II[11:8];
signbit_III <= signbit_II;
end
// REGISTER/CYCLE 3
// 2's complement & Carry-out discarded
always @(*) begin
// Floating-point to integer, and incorporating sign bit
shifter = { 2'b01, mantissa_III,1'b0 } >> exponent_III;
end
// It looks like OPLL and OPL3 don't do full 2's complement but just bit inversion
always @(posedge clk) if( cenop ) begin
op_result <= ( shifter ^ {OPW{signbit_III}});// + {13'd0,signbit_III};
end
`ifdef SIMULATION
reg signed [OPW-1:0] op_sep0_0;
reg signed [OPW-1:0] op_sep1_0;
reg signed [OPW-1:0] op_sep2_0;
reg signed [OPW-1:0] op_sep0_1;
reg signed [OPW-1:0] op_sep1_1;
reg signed [OPW-1:0] op_sep2_1;
reg signed [OPW-1:0] op_sep4_0;
reg signed [OPW-1:0] op_sep5_0;
reg signed [OPW-1:0] op_sep6_0;
reg signed [OPW-1:0] op_sep4_1;
reg signed [OPW-1:0] op_sep5_1;
reg signed [OPW-1:0] op_sep6_1;
reg signed [OPW-1:0] op_sep7_0;
reg signed [OPW-1:0] op_sep8_0;
reg signed [OPW-1:0] op_sep9_0;
reg signed [OPW-1:0] op_sep7_1;
reg signed [OPW-1:0] op_sep8_1;
reg signed [OPW-1:0] op_sep9_1;
reg [ 4:0] sepcnt;
always @(posedge clk) if(cenop) begin
sepcnt <= zero ? 5'd0 : sepcnt+5'd1;
case( (sepcnt+3)%18 )
0: op_sep0_0 <= op_result;
1: op_sep1_0 <= op_result;
2: op_sep2_0 <= op_result;
3: op_sep0_1 <= op_result;
4: op_sep1_1 <= op_result;
5: op_sep2_1 <= op_result;
6: op_sep4_0 <= op_result;
7: op_sep5_0 <= op_result;
8: op_sep6_0 <= op_result;
9: op_sep4_1 <= op_result;
10: op_sep5_1 <= op_result;
11: op_sep6_1 <= op_result;
12: op_sep7_0 <= op_result;
13: op_sep8_0 <= op_result;
14: op_sep9_0 <= op_result;
15: op_sep7_1 <= op_result;
16: op_sep8_1 <= op_result;
17: op_sep9_1 <= op_result;
endcase
end
`endif
endmodule

View File

@ -0,0 +1,129 @@
/* This file is part of JTOPL.
JTOPL is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JTOPL 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with JTOPL. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 13-6-2020
*/
module jtopl_pg(
input wire rst,
input wire clk,
input wire cenop,
input wire [17:0] slot,
input wire rhy_en,
// Channel frequency
input wire [ 9:0] fnum_I,
input wire [ 2:0] block_I,
// Operator multiplying
input wire [ 3:0] mul_II,
// phase modulation from LFO (vibrato at 6.4Hz)
input wire [ 2:0] vib_cnt,
input wire vib_dep,
input wire viben_I,
// phase operation
input wire pg_rst_II,
output reg [ 3:0] keycode_II,
output wire [ 9:0] phase_IV
);
parameter CH=9;
wire [ 3:0] keycode_I;
wire [16:0] phinc_I;
reg [16:0] phinc_II;
wire [18:0] phase_drop, phase_in;
wire [ 9:0] phase_II;
wire noise;
reg [ 9:0] hh, tc;
reg rm_xor;
wire hh_en, sd_en, tc_en;
always @(posedge clk) if(cenop) begin
keycode_II <= keycode_I;
phinc_II <= phinc_I;
end
// Rhythm phase
always @(posedge clk, posedge rst) begin
if( rst ) begin
hh <= 10'd0;
tc <= 10'd0;
end else begin
if( slot[13] ) hh <= phase_drop[18:9];
if( slot[17] ) tc <= phase_drop[18:9];
rm_xor <= (hh[2]^hh[7]) | (hh[3]^tc[5]) | (tc[3]^tc[5]);
end
end
assign hh_en = rhy_en & slot[14]; // 13+1
assign sd_en = rhy_en & slot[17]; // 16+1
assign tc_en = rhy_en & slot[ 0]; // (17+1)%18
jtopl_noise u_noise(
.clk ( clk ),
.cen ( cenop ),
.rst ( rst ),
.noise ( noise )
);
jtopl_pg_comb u_comb(
.block ( block_I ),
.fnum ( fnum_I ),
// Phase Modulation
.vib_cnt ( vib_cnt ),
.vib_dep ( vib_dep ),
.viben ( viben_I ),
.keycode ( keycode_I ),
// Phase increment
.phinc_out ( phinc_I ),
// Phase add
.mul ( mul_II ),
.phase_in ( phase_drop ),
.pg_rst ( pg_rst_II ),
.phinc_in ( phinc_II ),
// Rhythm
.hh_en ( hh_en ),
.sd_en ( sd_en ),
.tc_en ( tc_en ),
.rm_xor ( rm_xor ),
.noise ( noise ),
.hh ( hh ),
.phase_out ( phase_in ),
.phase_op ( phase_II )
);
jtopl_sh_rst #( .width(19), .stages(2*CH) ) u_phsh(
.clk ( clk ),
.cen ( cenop ),
.rst ( rst ),
.din ( phase_in ),
.drop ( phase_drop)
);
jtopl_sh_rst #( .width(10), .stages(2) ) u_pad(
.clk ( clk ),
.cen ( cenop ),
.rst ( rst ),
.din ( phase_II ),
.drop ( phase_IV )
);
endmodule

View File

@ -0,0 +1,95 @@
/* This file is part of JTOPL.
JTOPL is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JTOPL 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with JTOPL. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 13-6-2020
*/
module jtopl_pg_comb (
input wire [ 2:0] block,
input wire [ 9:0] fnum,
// Phase Modulation
input wire [ 2:0] vib_cnt,
input wire vib_dep,
input wire viben,
output wire [ 3:0] keycode,
// Phase increment
output wire [16:0] phinc_out,
// Phase add
input wire [ 3:0] mul,
input wire [18:0] phase_in,
input wire pg_rst,
// input signed [7:0] pm_in,
input wire [16:0] phinc_in,
// Rhythm
input wire noise,
input wire [ 9:0] hh,
input wire hh_en,
input wire tc_en,
input wire sd_en,
input wire rm_xor,
output wire [18:0] phase_out,
output wire [ 9:0] phase_op
);
wire signed [3:0] pm_offset;
wire [9:0] phase_pre;
assign keycode = { block, fnum[9] };
/* pm and pg_inc operate in parallel */
jtopl_pm u_pm(
.vib_cnt ( vib_cnt ),
.fnum ( fnum ),
.vib_dep ( vib_dep ),
.viben ( viben ),
.pm_offset ( pm_offset )
);
jtopl_pg_inc u_inc(
.block ( block ),
.fnum ( fnum ),
.pm_offset ( pm_offset ),
.phinc_pure ( phinc_out )
);
// pg_sum uses the output from the previous blocks
jtopl_pg_sum u_sum(
.mul ( mul ),
.phase_in ( phase_in ),
.pg_rst ( pg_rst ),
.phinc_pure ( phinc_in ),
.phase_out ( phase_out ),
.phase_op ( phase_pre )
);
jtopl_pg_rhy u_rhy(
.phase_pre ( phase_pre ),
// Rhythm
.noise ( noise ),
.hh ( hh ),
.hh_en ( hh_en ),
.tc_en ( tc_en ),
.sd_en ( sd_en ),
.rm_xor ( rm_xor ),
.phase_op ( phase_op )
);
endmodule // jtopl_pg_comb

View File

@ -0,0 +1,38 @@
/* This file is part of JTOPL.
JTOPL is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JTOPL 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with JTOPL. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 13-6-2020
*/
module jtopl_pg_inc (
input wire [ 2:0] block,
input wire [ 9:0] fnum,
input wire signed [ 3:0] pm_offset,
output reg [16:0] phinc_pure
);
reg [16:0] freq;
always @(*) begin
freq = { 7'd0, fnum } + { {13{pm_offset[3]}}, pm_offset };
// Add PM here
freq = freq << block;
phinc_pure = freq >> 1;
end
endmodule // jtopl_pg_inc

View File

@ -0,0 +1,49 @@
/* This file is part of JTOPL.
JTOPL is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JTOPL 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with JTOPL. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 25-6-2020
*/
module jtopl_pg_rhy (
input wire [ 9:0] phase_pre,
// Rhythm
input wire noise,
input wire [ 9:0] hh,
input wire hh_en,
input wire tc_en,
input wire sd_en,
input wire rm_xor,
output reg [ 9:0] phase_op
);
always @(*) begin
if( hh_en ) begin
phase_op = {rm_xor, 9'd0 };
if( rm_xor ^ noise )
phase_op = phase_op | 10'hd0;
else
phase_op = phase_op | 10'h34;
end else if( sd_en ) begin
phase_op = { hh[8], hh[8]^noise, 8'd0 };
end else if( tc_en ) begin
phase_op = { rm_xor, 9'h80 };
end else
phase_op = phase_pre;
end
endmodule // jtopl_pg_sum

View File

@ -0,0 +1,52 @@
/* This file is part of JTOPL.
JTOPL is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JTOPL 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with JTOPL. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 13-6-2020
*/
// Original hardware uses an adder to do the multiplication
// but I think it will take less resources of the FPGA to
// use a real multiplier instead
module jtopl_pg_sum (
input wire [ 3:0] mul,
input wire [18:0] phase_in,
input wire pg_rst,
input wire [16:0] phinc_pure,
output reg [18:0] phase_out,
output reg [ 9:0] phase_op
);
reg [21:0] phinc_mul;
reg [ 4:0] factor[0:15];
always @(*) begin
phinc_mul = { 5'b0, phinc_pure} * factor[mul];
phase_out = pg_rst ? 'd0 : (phase_in + phinc_mul[19:1]);
phase_op = phase_out[18:9];
end
initial begin
factor[ 0] = 5'd01; factor[ 1] = 5'd02; factor[ 2] = 5'd04; factor[ 3] = 5'd06;
factor[ 4] = 5'd08; factor[ 5] = 5'd10; factor[ 6] = 5'd12; factor[ 7] = 5'd14;
factor[ 8] = 5'd16; factor[ 9] = 5'd18; factor[10] = 5'd20; factor[11] = 5'd20;
factor[12] = 5'd24; factor[13] = 5'd24; factor[14] = 5'd30; factor[15] = 5'd30;
end
endmodule // jtopl_pg_sum

View File

@ -0,0 +1,47 @@
/* This file is part of JTOPL.
JTOPL is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JTOPL 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with JTOPL. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 21-6-2020
*/
// Based on Nuked's work on OPLL and OPL3
module jtopl_pm (
input wire [ 2:0] vib_cnt,
input wire [ 9:0] fnum,
input wire vib_dep,
input wire viben,
output reg [ 3:0] pm_offset
);
reg [2:0] range;
always @(*) begin
if( vib_cnt[1:0]==2'b00 )
range = 3'd0;
else begin
range = fnum[9:7]>>vib_cnt[0];
if(!vib_dep) range = range>>1;
end
if( vib_cnt[2] )
pm_offset = ~{1'b0, range } + 4'd1;
else
pm_offset = {1'b0, range };
if(!viben) pm_offset = 4'd0;
end
endmodule

View File

@ -0,0 +1,270 @@
/* This file is part of JTOPL
JTOPL program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JTOPL program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with JTOPL. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 13-6-2020
*/
module jtopl_reg #(parameter OPL_TYPE=1)
(
input wire rst,
input wire clk,
input wire cen,
input wire [7:0] din,
input wire write,
// Pipeline order
output wire zero,
output reg [1:0] group,
output reg op, // 0 for modulator operators
output reg [17:0] slot, // hot one encoding of active slot
input wire [1:0] sel_group, // group to update
input wire [2:0] sel_sub, // subslot to update
input wire rhy_en, // rhythm enable
input wire [4:0] rhy_kon, // key-on for each rhythm instrument
//input csm,
//input flag_A,
//input overflow_A,
input wire up_fbcon,
input wire up_fnumlo,
input wire up_fnumhi,
input wire up_mult,
input wire up_ksl_tl,
input wire up_ar_dr,
input wire up_sl_rr,
input wire up_wav,
// PG
output wire [9:0] fnum_I,
output wire [2:0] block_I,
// channel configuration
output wire [2:0] fb_I,
output wire [3:0] mul_II, // frequency multiplier
output wire [1:0] ksl_IV, // key shift level
output wire amen_IV,
output wire viben_I,
// OP
output wire [1:0] wavsel_I,
input wire wave_mode,
// EG
output wire keyon_I,
output wire [5:0] tl_IV,
output wire en_sus_I, // enable sustain
output wire [3:0] arate_I, // attack rate
output wire [3:0] drate_I, // decay rate
output wire [3:0] rrate_I, // release rate
output wire [3:0] sl_I, // sustain level
output wire ks_II, // key scale
output wire con_I
);
//parameter OPL_TYPE=1;
localparam CH=9;
// Each group contains three channels
// and each subslot contains six operators
reg [2:0] subslot;
reg [5:0] rhy_csr;
reg rhy_oen;
`ifdef SIMULATION
// These signals need to operate during rst
// initial state is not relevant (or critical) in real life
// but we need a clear value during simulation
initial begin
group = 2'd0;
subslot = 3'd0;
slot = 18'd1;
end
`endif
wire match = { group, subslot } == { sel_group, sel_sub};
wire [2:0] next_sub = subslot==3'd5 ? 3'd0 : (subslot+3'd1);
wire [1:0] next_group = subslot==3'd5 ? (group==2'b10 ? 2'b00 : group+2'b1) : group;
// channel data
wire [2:0] fb_in = din[3:1];
wire con_in = din[0];
wire up_fnumlo_ch = up_fnumlo & match,
up_fnumhi_ch = up_fnumhi & match,
up_fbcon_ch = up_fbcon & match,
update_op_I = !write && sel_group == group && sel_sub == subslot;
reg update_op_II, update_op_III, update_op_IV;
assign zero = slot[0];
always @(posedge clk) begin : up_counter
if( cen ) begin
{ group, subslot } <= { next_group, next_sub };
if( { next_group, next_sub }==5'd0 ) begin
slot <= 18'd1;
end else begin
slot <= { slot[16:0], 1'b0 };
end
op <= next_sub >= 3'd3;
end
end
always @(posedge clk) begin
if(write) begin
update_op_II <= 0;
update_op_III <= 0;
update_op_IV <= 0;
end else if( cen ) begin
update_op_II <= update_op_I;
update_op_III <= update_op_II;
update_op_IV <= update_op_III;
end
end
localparam OPCFGW = 4*8 + (OPL_TYPE!=1 ? 2 : 0);
wire [OPCFGW-1:0] shift_out;
wire en_sus;
// Sustained is disabled in rhythm mode for channels in group 2 (i.e. 6,7,8)
assign en_sus_I = rhy_oen ? 1'b0 : en_sus;
jtopl_csr #(.LEN(CH*2),.W(OPCFGW)) u_csr(
.rst ( rst ),
.clk ( clk ),
.cen ( cen ),
.din ( din ),
.shift_out ( shift_out ),
.up_mult ( up_mult ),
.up_ksl_tl ( up_ksl_tl ),
.up_ar_dr ( up_ar_dr ),
.up_sl_rr ( up_sl_rr ),
.up_wav ( up_wav ),
.update_op_I ( update_op_I ),
.update_op_II ( update_op_II ),
.update_op_IV ( update_op_IV )
);
assign { amen_IV, viben_I, en_sus, ks_II, mul_II,
ksl_IV, tl_IV,
arate_I, drate_I,
sl_I, rrate_I } = shift_out[4*8-1:0];
generate
if( OPL_TYPE==1 )
assign wavsel_I = 0;
else
assign wavsel_I = shift_out[OPCFGW-1:OPCFGW-2] & {2{wave_mode}};
endgenerate
// Memory for CH registers
localparam KONW = 1,
FNUMW = 10,
BLOCKW = 3,
FBW = 3,
CONW = 1;
localparam CHCSRW = KONW+FNUMW+BLOCKW+FBW+CONW;
wire [CHCSRW-1:0] chcfg0_out, chcfg1_out, chcfg2_out;
reg [CHCSRW-1:0] chcfg, chcfg0_in, chcfg1_in, chcfg2_in;
wire [CHCSRW-1:0] chcfg_inmux;
wire keyon_csr, con_csr;
wire disable_con;
assign chcfg_inmux = {
up_fnumhi_ch ? din[5:0] : { keyon_csr, block_I, fnum_I[9:8] },
up_fnumlo_ch ? din : fnum_I[7:0],
up_fbcon_ch ? { fb_in, con_in } : { fb_I, con_csr }
};
assign disable_con = rhy_oen && !slot[12] && !slot[13];
assign con_I = !rhy_en || !disable_con ? con_csr : 1'b1;
always @(*) begin
case( group )
default: chcfg = chcfg0_out;
2'd1: chcfg = chcfg1_out;
2'd2: chcfg = chcfg2_out;
endcase
chcfg0_in = group==2'b00 ? chcfg_inmux : chcfg0_out;
chcfg1_in = group==2'b01 ? chcfg_inmux : chcfg1_out;
chcfg2_in = group==2'b10 ? chcfg_inmux : chcfg2_out;
end
`ifdef SIMULATION
reg [CHCSRW-1:0] chsnap0, chsnap1,chsnap2;
always @(posedge clk) if(zero) begin
chsnap0 <= chcfg0_out;
chsnap1 <= chcfg1_out;
chsnap2 <= chcfg2_out;
end
`endif
assign { keyon_csr, block_I, fnum_I, fb_I, con_csr } = chcfg;
// Rhythm key-on CSR
localparam BD=4, SD=3, TOM=2, TC=1, HH=0;
always @(posedge clk, posedge rst) begin
if( rst ) begin
rhy_csr <= 6'd0;
rhy_oen <= 0;
end else if(cen) begin
if(slot[11]) rhy_oen <= rhy_en;
if(slot[17]) begin
rhy_csr <= { rhy_kon[BD], rhy_kon[HH], rhy_kon[TOM],
rhy_kon[BD], rhy_kon[SD], rhy_kon[TC] };
rhy_oen <= 0;
end else
rhy_csr <= { rhy_csr[4:0], rhy_csr[5] };
end
end
assign keyon_I = rhy_oen ? rhy_csr[5] : keyon_csr;
jtopl_sh_rst #(.width(CHCSRW),.stages(3)) u_group0(
.clk ( clk ),
.cen ( cen ),
.rst ( rst ),
.din ( chcfg0_in ),
.drop ( chcfg0_out )
);
jtopl_sh_rst #(.width(CHCSRW),.stages(3)) u_group1(
.clk ( clk ),
.cen ( cen ),
.rst ( rst ),
.din ( chcfg1_in ),
.drop ( chcfg1_out )
);
jtopl_sh_rst #(.width(CHCSRW),.stages(3)) u_group2(
.clk ( clk ),
.cen ( cen ),
.rst ( rst ),
.din ( chcfg2_in ),
.drop ( chcfg2_out )
);
endmodule

View File

@ -0,0 +1,42 @@
/* This file is part of JTOPL.
JTOPL is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JTOPL 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with JTOPL. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 19-6-2020
*/
// stages must be greater than 2
module jtopl_sh #(parameter width=5, stages=24 )
(
input wire clk,
input wire cen,
input wire [width-1:0] din,
output wire [width-1:0] drop
);
reg [stages-1:0] bits[width-1:0];
genvar i;
generate
for (i=0; i < width; i=i+1) begin: bit_shifter
always @(posedge clk) if(cen) begin
bits[i] <= {bits[i][stages-2:0], din[i]};
end
assign drop[i] = bits[i][stages-1];
end
endgenerate
endmodule

View File

@ -0,0 +1,54 @@
/* This file is part of JTOPL.
JTOPL is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JTOPL 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with JTOPL. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 13-6-2020
*/
// stages must be greater than 2
module jtopl_sh_rst #(parameter width=5, stages=18, rstval=1'b0 )
(
input wire rst,
input wire clk,
input wire cen,
input wire [width-1:0] din,
output wire [width-1:0] drop
);
reg [stages-1:0] bits[width-1:0];
genvar i;
integer k;
generate
initial
for (k=0; k < width; k=k+1) begin
bits[k] = { stages{rstval}};
end
endgenerate
generate
for (i=0; i < width; i=i+1) begin: bit_shifter
always @(posedge clk, posedge rst)
if( rst ) begin
bits[i] <= {stages{rstval}};
end else if(cen) begin
bits[i] <= {bits[i][stages-2:0], din[i]};
end
assign drop[i] = bits[i][stages-1];
end
endgenerate
endmodule

View File

@ -0,0 +1,61 @@
/* This file is part of JTOPL.
JTOPL program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JTOPL program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with JTOPL. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 20-6-2020
*/
// Accumulates an arbitrary number of inputs with saturation
// restart the sum when input "zero" is high
module jtopl_single_acc #(parameter
INW=13, // input data width
OUTW=16 // output data width
)(
input wire clk,
input wire cenop,
input wire [INW-1:0] op_result,
input wire sum_en,
input wire zero,
output reg [OUTW-1:0] snd
);
// for full resolution use INW=14, OUTW=16
// for cut down resolution use INW=9, OUTW=12
// OUTW-INW should be > 0
reg signed [OUTW-1:0] next, acc, current;
reg overflow;
wire [OUTW-1:0] plus_inf = { 1'b0, {(OUTW-1){1'b1}} }; // maximum positive value
wire [OUTW-1:0] minus_inf = { 1'b1, {(OUTW-1){1'b0}} }; // minimum negative value
always @(*) begin
current = sum_en ? { {(OUTW-INW){op_result[INW-1]}}, op_result } : {OUTW{1'b0}};
next = zero ? current : current + acc;
overflow = !zero &&
(current[OUTW-1] == acc[OUTW-1]) &&
(acc[OUTW-1]!=next[OUTW-1]);
end
always @(posedge clk) if( cenop ) begin
acc <= overflow ? (acc[OUTW-1] ? minus_inf : plus_inf) : next;
if(zero) snd <= acc;
end
endmodule

View File

@ -0,0 +1,125 @@
/* This file is part of JTOPL.
JTOPL is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JTOPL 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with JTOPL. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 10-6-2020
*/
module jtopl_timers(
input wire clk,
input wire rst,
input wire cenop,
input wire zero,
input wire [7:0] value_A,
input wire [7:0] value_B,
input wire load_A,
input wire load_B,
input wire clr_flag_A,
input wire clr_flag_B,
output wire flag_A,
output wire flag_B,
input wire flagen_A,
input wire flagen_B,
output wire overflow_A,
output wire irq_n
);
wire pre_A, pre_B;
assign flag_A = pre_A & flagen_A;
assign flag_B = pre_B & flagen_B;
assign irq_n = ~( flag_A | flag_B );
// 1 count per 288 master clock ticks
jtopl_timer #(.MW(2)) timer_A (
.clk ( clk ),
.rst ( rst ),
.cenop ( cenop ),
.zero ( zero ),
.start_value( value_A ),
.load ( load_A ),
.clr_flag ( clr_flag_A),
.flag ( pre_A ),
.overflow ( overflow_A)
);
// 1 count per 288*4 master clock ticks
jtopl_timer #(.MW(4)) timer_B(
.clk ( clk ),
.rst ( rst ),
.cenop ( cenop ),
.zero ( zero ),
.start_value( value_B ),
.load ( load_B ),
.clr_flag ( clr_flag_B),
.flag ( pre_B ),
.overflow ( )
);
endmodule
module jtopl_timer #(parameter MW=2) (
input wire clk,
input wire rst,
input wire cenop,
input wire zero,
input wire [7:0] start_value,
input wire load,
input wire clr_flag,
output reg flag,
output reg overflow
);
reg [7:0] cnt, next, init;
reg [MW-1:0] free_cnt, free_next;
reg load_l, free_ov;
always@(posedge clk)
if( clr_flag || rst)
flag <= 1'b0;
else if(cenop && zero && load && overflow) flag<=1'b1;
always @(*) begin
{free_ov, free_next} = { 1'b0, free_cnt} + 1'b1;
/* verilator lint_off WIDTH */
{overflow, next } = {1'b0, cnt}+free_ov;
/* verilator lint_on WIDTH */
init = start_value;
end
always @(posedge clk) begin
load_l <= load;
if( (!load_l && load) || rst) begin
cnt <= start_value;
end else if( cenop && zero && load ) begin
cnt <= overflow ? init : next;
end
end
// Free running counter, resetting
// the value of this part with the load
// event can slow down music, vg Bad Dudes
always @(posedge clk) begin
if( rst ) begin
free_cnt <= 0;
end else if( cenop && zero ) begin
free_cnt <= free_next;
end
end
endmodule

Binary file not shown.