diff --git a/files.qip b/files.qip index 060f82a..37d11e9 100644 --- a/files.qip +++ b/files.qip @@ -12,9 +12,8 @@ set_global_assignment -name VERILOG_FILE rtl/common/zint.v set_global_assignment -name VERILOG_FILE rtl/common/zclock.v set_global_assignment -name VERILOG_FILE rtl/rtc/mc146818a.v set_global_assignment -name VHDL_FILE rtl/sound/soundrive.vhd -set_global_assignment -name QIP_FILE rtl/sound/jt12/jt12.qip +set_global_assignment -name QIP_FILE rtl/sound/jt12/jt03.qip set_global_assignment -name SYSTEMVERILOG_FILE rtl/sound/ym2149.sv -set_global_assignment -name SYSTEMVERILOG_FILE rtl/sound/ym2203.sv set_global_assignment -name SYSTEMVERILOG_FILE rtl/sound/turbosound.sv set_global_assignment -name VERILOG_FILE rtl/sound/gs.v set_global_assignment -name SYSTEMVERILOG_FILE rtl/sound/saa1099.sv diff --git a/rtl/sound/jt12/jt12.qip b/rtl/sound/jt12/jt03.qip similarity index 56% rename from rtl/sound/jt12/jt12.qip rename to rtl/sound/jt12/jt03.qip index 0b87eb7..c8a0497 100644 --- a/rtl/sound/jt12/jt12.qip +++ b/rtl/sound/jt12/jt03.qip @@ -1,21 +1,34 @@ -set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12.v ] -set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_acc.v ] -set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_clksync.v ] +set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt03.v ] +set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) jt12.vhd ] +set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_top.v ] +set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt03_acc.v ] +set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_single_acc.v ] set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_eg.v ] +set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_eg_cnt.v ] +set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_eg_comb.v ] +set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_eg_step.v ] +set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_eg_pure.v ] +set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_eg_final.v ] +set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_eg_ctrl.v ] set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_exprom.v ] set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_kon.v ] set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_lfo.v ] set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_limitamp.v ] set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_mmr.v ] +set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_div.v ] set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_mod.v ] set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_op.v ] -set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_opram.v ] +set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_csr.v ] set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_pg.v ] -set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_phrom.v ] +set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_pg_inc.v ] +set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_pg_dt.v ] +set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_pg_sum.v ] +set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_pg_comb.v ] +set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_pm.v ] +set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_logsin.v ] set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_reg.v ] set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_sh.v ] set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_sh_rst.v ] set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_sh24.v ] set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_sumch.v ] -set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_syn.v ] set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_timers.v ] diff --git a/rtl/sound/jt12/jt03.v b/rtl/sound/jt12/jt03.v new file mode 100644 index 0000000..9b3212a --- /dev/null +++ b/rtl/sound/jt12/jt03.v @@ -0,0 +1,73 @@ +/* This file is part of JT12. + + + JT12 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. + + JT12 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 JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 27-12-2018 +*/ + +// Wrapper to output only combined channels. Defaults to YM2203 mode. + + + +module jt03( + input rst, // rst should be at least 6 clk&cen cycles long + input clk, // CPU clock + input cen, // optional clock enable, it not needed leave as 1'b1 + input [7:0] din, + input addr, + input cs_n, + input wr_n, + + output [7:0] dout, + output irq_n, + // Separated output + output [ 7:0] psg_A, + output [ 7:0] psg_B, + output [ 7:0] psg_C, + output signed [15:0] fm_snd, + // combined output + output [ 9:0] psg_snd, + output signed [15:0] snd, + output snd_sample +); + +jt12_top #(.use_lfo(0),.use_ssg(1), .num_ch(3), .use_pcm(0), .use_lr(0)) +u_jt12( + .rst ( rst ), // rst should be at least 6 clk&cen cycles long + .clk ( clk ), // CPU clock + .cen ( cen ), // optional clock enable, it not needed leave as 1'b1 + .din ( din ), + .addr ( {1'b0, addr} ), + .cs_n ( cs_n ), + .wr_n ( wr_n ), + + .dout ( dout ), + .irq_n ( irq_n ), + // Separated output + .psg_A ( psg_A ), + .psg_B ( psg_B ), + .psg_C ( psg_C ), + .psg_snd ( psg_snd ), + .fm_snd_left ( fm_snd ), + .fm_snd_right (), + + .snd_right ( snd ), + .snd_left (), + .snd_sample ( snd_sample ) +); + +endmodule // jt03 \ No newline at end of file diff --git a/rtl/sound/jt12/jt03_acc.v b/rtl/sound/jt12/jt03_acc.v new file mode 100644 index 0000000..8d9805d --- /dev/null +++ b/rtl/sound/jt12/jt03_acc.v @@ -0,0 +1,66 @@ +/* This file is part of JT12. + + + JT12 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. + + JT12 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 JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 15-11-2018 + +*/ + +`timescale 1ns / 1ps + +/* Use for YM2203 + no left/right channels + full operator resolution + clamped to maximum output of signed 16 bits */ + +module jt03_acc +( + input rst, + input clk, + input clk_en, + input signed [13:0] op_result, + input s1_enters, + input s2_enters, + input s3_enters, + input s4_enters, + input zero, + input [2:0] alg, + // combined output + output signed [15:0] snd +); + +reg sum_en; + +always @(*) begin + case ( alg ) + default: sum_en = s4_enters; + 3'd4: sum_en = s2_enters | s4_enters; + 3'd5,3'd6: sum_en = ~s1_enters; + 3'd7: sum_en = 1'b1; + endcase +end + +jt12_single_acc #(.win(14),.wout(16)) u_mono( + .clk ( clk ), + .clk_en ( clk_en ), + .op_result ( op_result ), + .sum_en ( sum_en ), + .zero ( zero ), + .snd ( snd ) +); + +endmodule diff --git a/rtl/sound/jt12/jt12.v b/rtl/sound/jt12/jt12.v index caa242b..b3b553e 100644 --- a/rtl/sound/jt12/jt12.v +++ b/rtl/sound/jt12/jt12.v @@ -1,116 +1,65 @@ -`timescale 1ns / 1ps - - /* This file is part of JT12. - JT12 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. + JT12 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. - JT12 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. + JT12 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 JT12. If not, see . + You should have received a copy of the GNU General Public License + along with JT12. If not, see . - Based on information provided by - Sauraen VHDL version of OPN/OPN2, which is based on die shots. - Nemesis reports, based on measurements - Comparisons with real hardware lent by Mikes (Va de retro) - - Author: Jose Tejada Gomez. Twitter: @topapate - Version: 1.0 - Date: 1-4-2017 - - Use tab = 4 spaces + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 27-12-2018 */ -// syn_clk "1.285714" +// Wrapper to output only combined channels. Defaults to YM2612 mode. -module jt12( - input rst, - // CPU interface - input cpu_clk, - input [7:0] cpu_din, - input [1:0] cpu_addr, - input cpu_cs_n, - input cpu_wr_n, - input cpu_limiter_en, - - output [7:0] cpu_dout, - output cpu_irq_n, - // Synthesizer clock domain - input syn_clk, - // combined output - output signed [11:0] syn_snd_right, - output signed [11:0] syn_snd_left, - output syn_snd_sample, - // multiplexed output - output signed [8:0] syn_mux_right, - output signed [8:0] syn_mux_left, - output syn_mux_sample +module jt12 ( + input rst, // rst should be at least 6 clk&cen cycles long + input clk, // CPU clock + input cen, // optional clock enable, it not needed leave as 1'b1 + input [7:0] din, + input [1:0] addr, + input cs_n, + input wr_n, + + output [7:0] dout, + output irq_n, + // combined output + output signed [15:0] snd_right, + output signed [15:0] snd_left, + output snd_sample ); -// Timers -wire syn_flag_A, syn_flag_B; - - -wire [7:0] syn_din; -wire [1:0] syn_addr; -wire syn_write, syn_limiter_en, syn_busy; -wire syn_rst, syn_irq_n; - -jt12_clksync u_clksync( - .rst ( rst ), - .cpu_clk ( cpu_clk ), - .syn_clk ( syn_clk ), - - // CPU interface - .cpu_din ( cpu_din ), - .cpu_addr ( cpu_addr ), - .cpu_dout ( cpu_dout ), - .cpu_cs_n ( cpu_cs_n ), - .cpu_wr_n ( cpu_wr_n ), - .cpu_irq_n ( cpu_irq_n ), - .cpu_limiter_en( cpu_limiter_en ), - - // Synthesizer interface - .syn_rst ( syn_rst ), - .syn_write ( syn_write ), - .syn_din ( syn_din ), - .syn_addr ( syn_addr ), - .syn_limiter_en( syn_limiter_en ), - - .syn_busy ( syn_busy ), - .syn_flag_A ( syn_flag_A), - .syn_flag_B ( syn_flag_B), - .syn_irq_n ( syn_irq_n ) +jt12_top u_jt12( + .rst ( rst ), // rst should be at least 6 clk&cen cycles long + .clk ( clk ), // CPU clock + .cen ( cen ), // optional clock enable, it not needed leave as 1'b1 + .din ( din ), + .addr ( addr ), + .cs_n ( cs_n ), + .wr_n ( wr_n ), + + .dout ( dout ), + .irq_n ( irq_n ), + // Separated output + .psg_A (), + .psg_B (), + .psg_C (), + .fm_snd_left (), + .fm_snd_right (), + // combined output + .psg_snd (), + .snd_right ( snd_right ), // FM+PSG + .snd_left ( snd_left ), // FM+PSG + .snd_sample ( snd_sample ) ); - -jt12_syn u_syn( - .rst ( syn_rst ), - .clk ( syn_clk ), - .din ( syn_din ), - .addr ( syn_addr ), - .busy ( syn_busy ), - .flag_A ( syn_flag_A), - .flag_B ( syn_flag_B), - .write ( syn_write ), - .limiter_en ( syn_limiter_en), - .irq_n ( syn_irq_n ), - // Mixed sound - .snd_right ( syn_snd_right ), - .snd_left ( syn_snd_left ), - .snd_sample ( syn_snd_sample), - // Multiplexed sound - .mux_right ( syn_mux_right ), - .mux_left ( syn_mux_left ), - .mux_sample ( syn_mux_sample) -); - -endmodule +endmodule // jt03 \ No newline at end of file diff --git a/rtl/sound/jt12/jt12.vhd b/rtl/sound/jt12/jt12.vhd new file mode 100644 index 0000000..58fa856 --- /dev/null +++ b/rtl/sound/jt12/jt12.vhd @@ -0,0 +1,43 @@ +library IEEE; +use IEEE.std_logic_1164.all; + +package jt12 is + +component jt12 +port +( + rst : in std_logic; + clk : in std_logic; -- CPU clock + cen : in std_logic := '1'; -- optional clock enable, if not needed leave as '1' + din : in std_logic_vector(7 downto 0); + addr : in std_logic_vector(1 downto 0); + cs_n : in std_logic; + wr_n : in std_logic; + + dout : out std_logic_vector(7 downto 0); + irq_n : out std_logic; + + -- combined output + snd_right : out std_logic_vector(15 downto 0); -- signed + snd_left : out std_logic_vector(15 downto 0); -- signed + snd_sample : out std_logic +); +end component; + +component jt12_genmix +port +( + rst : in std_logic; + clk : in std_logic; -- expects 54 MHz clock + fm_left : in std_logic_vector(15 downto 0); -- FM at 55kHz + fm_right: in std_logic_vector(15 downto 0); -- FM at 55kHz + psg_snd : in std_logic_vector(10 downto 0); -- PSG at 220kHz + fm_en : in std_logic; + psg_en : in std_logic; + -- Mixed sound at 54 MHz + snd_left : out std_logic_vector(15 downto 0); + snd_right : out std_logic_vector(15 downto 0) +); +end component; + +end; diff --git a/rtl/sound/jt12/jt12_acc.v b/rtl/sound/jt12/jt12_acc.v index e2e7047..d0fc9fe 100644 --- a/rtl/sound/jt12/jt12_acc.v +++ b/rtl/sound/jt12/jt12_acc.v @@ -1,178 +1,109 @@ -`timescale 1ns / 1ps - - /* This file is part of JT12. - JT12 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. + JT12 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. - JT12 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. + JT12 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 JT12. If not, see . + You should have received a copy of the GNU General Public License + along with JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 27-1-2017 + + Each channel can use the full range of the DAC as they do not + get summed in the real chip. + + Operator data is summed up without adding extra bits. This is + the case of real YM3438, which was used on Megadrive 2 models. - Author: Jose Tejada Gomez. Twitter: @topapate - Version: 1.0 - Date: 27-1-2017 - - Each channel can use the full range of the DAC as they do not - get summed in the real chip. */ +/* + YM2612 had a limiter to prevent overflow + YM3438 did not + JT12 always has a limiter enabled + */ - -`timescale 1ns / 1ps - -module jt12_acc -( - input rst, - input clk, - input signed [8:0] op_result, - input [ 1:0] rl, - input limiter_en, // enables the limiter on - // the accumulator to prevent overfow. - // I reckon that: - // YM2612 had a limiter - // YM3438 did not - // note that the order changes to deal - // with the operator pipeline delay - input s1_enters, - input s2_enters, - input s3_enters, - input s4_enters, - input ch6op, - input [2:0] alg, - input pcm_en, // only enabled for channel 6 - input [8:0] pcm, - // combined output - output reg signed [11:0] left, - output reg signed [11:0] right, - output sample, - // multiplexed output - output reg signed [8:0] mux_left, - output reg signed [8:0] mux_right, - output reg mux_sample +module jt12_acc( + input rst, + input clk, + input clk_en, + input signed [8:0] op_result, + input [ 1:0] rl, + input zero, + input s1_enters, + input s2_enters, + input s3_enters, + input s4_enters, + input ch6op, + input [2:0] alg, + input pcm_en, // only enabled for channel 6 + input signed [8:0] pcm, + // combined output + output reg signed [11:0] left, + output reg signed [11:0] right ); -reg signed [11:0] pre_left, pre_right; -wire signed [8:0] total; +parameter num_ch=6; + reg sum_en; always @(*) begin - case ( alg ) - default: sum_en <= s4_enters; - 3'd4: sum_en <= s2_enters | s4_enters; - 3'd5,3'd6: sum_en <= ~s1_enters; - 3'd7: sum_en <= 1'b1; + case ( alg ) + default: sum_en = s4_enters; + 3'd4: sum_en = s2_enters | s4_enters; + 3'd5,3'd6: sum_en = ~s1_enters; + 3'd7: sum_en = 1'b1; endcase end - -reg sum_all; -assign sample = ~sum_all; -wire [8:0] buffer; -reg [8:0] buffer2; -reg [8:0] buf_mux; -reg [1:0] rl2,rl3; -reg last_s1; -reg [1:0] mux_cnt; +reg pcm_sum; -wire signed [11:0] total_signext = { {3{total[8]}}, total }; +always @(posedge clk) if(clk_en) + if( zero ) pcm_sum <= 1'b1; + else if( ch6op ) pcm_sum <= 1'b0; -always @(posedge clk) begin : mux_dac_input - buffer2 <= buffer; - rl2 <= rl; - last_s1 <= s1_enters; - mux_cnt <= last_s1 && s3_enters ? 2'd01 : mux_cnt + 1'b1; - if( mux_cnt==2'b11 ) begin - if( s1_enters || s3_enters ) begin - buf_mux <= buffer2; - rl3 <= rl2; - end - else begin - buf_mux <= buffer; - rl3 <= rl; - end - end - if( mux_cnt==2'd0 ) begin - mux_left <= rl3[1] ? buf_mux : 9'd0; - mux_right<= rl3[0] ? buf_mux : 9'd0; - mux_sample <= 1'b1; - end - else - mux_sample <= 1'b0; -end +wire use_pcm = ch6op && pcm_en; +wire sum_or_pcm = sum_en | use_pcm; +wire left_en = rl[1]; +wire right_en= rl[0]; +wire signed [8:0] pcm_data = pcm_sum ? pcm : 9'd0; +wire [8:0] acc_input = use_pcm ? pcm_data : op_result; -always @(posedge clk) begin - if( rst ) begin - sum_all <= 1'b0; - end - else begin - if( s3_enters ) begin - sum_all <= 1'b1; - if( !sum_all ) begin - pre_right <= rl[0] ? total_signext : 12'd0; - pre_left <= rl[1] ? total_signext : 12'd0; - end - else begin - pre_right <= pre_right + (rl[0] ? total_signext : 12'd0); - pre_left <= pre_left + (rl[1] ? total_signext : 12'd0); - end - end - if( s2_enters ) begin - sum_all <= 1'b0; - left <= pre_left; - right <= pre_right; - `ifdef DUMPSOUND - $strobe("%d\t%d", left, right); - `endif - end - end -end - -reg signed [8:0] next, opsum, prev; -wire signed [9:0] opsum10 = next+total; - -always @(*) begin - next <= sum_en ? op_result : 9'd0; - if( s3_enters ) - opsum <= (ch6op && pcm_en) ? { ~pcm[8], pcm[7:0] } : next; - else begin - if( sum_en && !(ch6op && pcm_en) ) - if( limiter_en ) begin - if( opsum10[9]==opsum10[8] ) - opsum <= opsum10[8:0]; - else begin - opsum <= opsum10[9] ? 9'h100 : 9'h0ff; - end - end - else begin - // MSB is discarded according to - // YM3438 application notes - opsum <= opsum10[8:0]; - end - else - opsum <= total; - end -end - -jt12_sh #(.width(9),.stages(6)) u_acc( - .clk ( clk ), - .din ( opsum ), - .drop ( total ) +// Continuous output +wire signed [11:0] pre_left, pre_right; +jt12_single_acc #(.win(9),.wout(12)) u_left( + .clk ( clk ), + .clk_en ( clk_en ), + .op_result ( acc_input ), + .sum_en ( sum_or_pcm & left_en ), + .zero ( zero ), + .snd ( pre_left ) ); -jt12_sh #(.width(9),.stages(6)) u_buffer( - .clk ( clk ), - .din ( s3_enters ? total : buffer ), - .drop ( buffer ) +jt12_single_acc #(.win(9),.wout(12)) u_right( + .clk ( clk ), + .clk_en ( clk_en ), + .op_result ( acc_input ), + .sum_en ( sum_or_pcm & right_en ), + .zero ( zero ), + .snd ( pre_right ) ); +// Output can be amplied by 8/6=1.33 to use full range +// an easy alternative is to add 1/4th and get 1.25 amplification +always @(posedge clk) if(clk_en) begin + left <= pre_left + { {2{left [11]}}, left [11:2] }; + right <= pre_right + { {2{right[11]}}, right[11:2] }; +end + endmodule diff --git a/rtl/sound/jt12/jt12_clksync.v b/rtl/sound/jt12/jt12_clksync.v deleted file mode 100644 index 3ad3a7c..0000000 --- a/rtl/sound/jt12/jt12_clksync.v +++ /dev/null @@ -1,106 +0,0 @@ -`timescale 1ns / 1ps - - -/* This file is part of JT12. - - - JT12 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. - - JT12 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 JT12. If not, see . - - Author: Jose Tejada Gomez. Twitter: @topapate - Version: 1.0 - Date: 14-2-2017 - -*/ - -module jt12_clksync( - input rst, - input cpu_clk, - input syn_clk, - - // CPU interface - input [7:0] cpu_din, - input [1:0] cpu_addr, - output[7:0] cpu_dout, - input cpu_cs_n, - input cpu_wr_n, - output cpu_irq_n, - input cpu_limiter_en, - - // Synthesizer interface - output reg [7:0] syn_din, - output reg [1:0] syn_addr, - output reg syn_rst, - output reg syn_write, - output syn_limiter_en, - - input syn_busy, - input syn_flag_A, - input syn_flag_B, - input syn_irq_n -); - -// reset generation -reg rst_aux; - -assign syn_limiter_en = cpu_limiter_en; - -always @(negedge syn_clk or posedge rst) - if( rst ) begin - syn_rst <= 1'b1; - rst_aux <= 1'b1; - end - else begin - syn_rst <= rst_aux; - rst_aux <= 1'b0; - end - -reg cpu_busy; -wire cpu_flag_B, cpu_flag_A; - -assign cpu_dout = cpu_cs_n ? 8'hFF : { cpu_busy, 5'h0, cpu_flag_B, cpu_flag_A }; - -wire write_raw = !cpu_cs_n && !cpu_wr_n; - -reg [1:0]busy_sh; -always @(posedge cpu_clk) begin - busy_sh <= { busy_sh[0], syn_busy }; -end - -jt12_sh #(.width(3),.stages(2) ) u_syn2cpu( - .clk ( cpu_clk ), - .din ( { syn_flag_B, syn_flag_A, syn_irq_n } ), - .drop ( { cpu_flag_B, cpu_flag_A, cpu_irq_n } ) -); - -always @(posedge cpu_clk) begin - reg old_write; - - old_write <= write_raw; - - if( rst ) begin - cpu_busy <= 1'b0; - end - else begin - if( ~old_write & write_raw ) begin - cpu_busy <= 1; - syn_write <= ~syn_write; - syn_addr <= cpu_addr; - syn_din <= cpu_din; - end - - if(cpu_busy && busy_sh==2'b10) cpu_busy <= 0; - end -end - -endmodule diff --git a/rtl/sound/jt12/jt12_csr.v b/rtl/sound/jt12/jt12_csr.v new file mode 100644 index 0000000..b258a55 --- /dev/null +++ b/rtl/sound/jt12/jt12_csr.v @@ -0,0 +1,82 @@ +/* This file is part of JT12. + + + JT12 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. + + JT12 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 JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 14-2-2017 + +*/ + +module jt12_csr( // Circular Shift Register + input mux + input rst, + input clk, + input clk_en, + input [ 7:0] din, + input [43:0] shift_in, + output [43:0] shift_out, + + input up_tl, + input up_dt1, + input up_ks_ar, + input up_amen_dr, + input up_sr, + input up_sl_rr, + input up_ssgeg, + input update_op_I, + input update_op_II, + input update_op_IV +); + +localparam regop_width=44; + +reg [regop_width-1:0] regop_in; + +jt12_sh_rst #(.width(regop_width),.stages(12)) u_regch( + .clk ( clk ), + .clk_en ( clk_en ), + .rst ( rst ), + .din ( regop_in ), + .drop ( shift_out ) +); + +wire up_tl_op = up_tl & update_op_IV; +wire up_dt1_op = up_dt1 & update_op_I; +wire up_mul_op = up_dt1 & update_op_II; +wire up_ks_op = up_ks_ar & update_op_II; +wire up_ar_op = up_ks_ar & update_op_I; +wire up_amen_op = up_amen_dr& update_op_IV; +wire up_dr_op = up_amen_dr& update_op_I; +wire up_sr_op = up_sr & update_op_I; +wire up_sl_op = up_sl_rr & update_op_I; +wire up_rr_op = up_sl_rr & update_op_I; +wire up_ssg_op = up_ssgeg & update_op_I; + +always @(*) + regop_in = { + up_tl_op ? din[6:0] : shift_in[43:37], // 7 + up_dt1_op ? din[6:4] : shift_in[36:34], // 3 + up_mul_op ? din[3:0] : shift_in[33:30], // 4 + up_ks_op ? din[7:6] : shift_in[29:28], // 2 + up_ar_op ? din[4:0] : shift_in[27:23], // 5 + up_amen_op ? din[7] : shift_in[ 22], // 1 + up_dr_op ? din[4:0] : shift_in[21:17], // 5 + up_sr_op ? din[4:0] : shift_in[16:12], // 5 + up_sl_op ? din[7:4] : shift_in[11: 8], // 4 + up_rr_op ? din[3:0] : shift_in[ 7: 4], // 4 + up_ssg_op ? din[3:0] : shift_in[ 3: 0] // 4 + }; + +endmodule // jt12_reg \ No newline at end of file diff --git a/rtl/sound/jt12/jt12_div.v b/rtl/sound/jt12/jt12_div.v new file mode 100644 index 0000000..e06bfda --- /dev/null +++ b/rtl/sound/jt12/jt12_div.v @@ -0,0 +1,82 @@ +/* This file is part of JT12. + + JT12 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. + + JT12 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 JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 14-2-2017 + */ + +`timescale 1ns / 1ps + +module jt12_div( + input rst, + input clk, + input cen, + input [1:0] div_setting, + output reg clk_en, + output reg clk_en_ssg +); + +parameter use_ssg=0, num_ch; + +reg [3:0] opn_pres, opn_cnt; +reg [2:0] ssg_pres, ssg_cnt; +reg cen_int, cen_ssg_int; + +always @(*) + if( num_ch==6 ) begin + opn_pres = 4'd5; + ssg_pres = 3'd3; // unused, really + end + else + casez( div_setting ) + 2'b0?: { opn_pres, ssg_pres } = { 4'd2-4'd1, 3'd0 }; // 2 + 2'b10: { opn_pres, ssg_pres } = { 4'd6-4'd1, 3'd3 }; // 6 - Default for YM2608 + 2'b11: { opn_pres, ssg_pres } = { 4'd3-4'd1, 3'd1 }; // 3 - Default for YM2203 + endcase // div_setting + + +always @(negedge clk) begin + cen_int <= opn_cnt == 4'd0; + cen_ssg_int <= ssg_cnt == 3'd0; + `ifdef FASTDIV + // always enabled for fast sims (use with GYM output, timer will not work well) + clk_en <= 1'b1; + clk_en_ssg <= 1'b1; + `else + clk_en <= cen & cen_int; + clk_en_ssg <= use_ssg ? (cen & cen_ssg_int) : 1'b0; + `endif +end + +// OPN +always @(posedge clk) + if( cen ) begin + if( opn_cnt == opn_pres ) begin + opn_cnt <= 4'd0; + end + else opn_cnt <= opn_cnt + 4'd1; + end + +// SSG +always @(posedge clk) + if( cen ) begin + if( ssg_cnt == ssg_pres ) begin + ssg_cnt <= 3'd0; + end + else ssg_cnt <= ssg_cnt + 3'd1; + end + +endmodule // jt12_div diff --git a/rtl/sound/jt12/jt12_eg.v b/rtl/sound/jt12/jt12_eg.v index bccf571..4a5dbc9 100644 --- a/rtl/sound/jt12/jt12_eg.v +++ b/rtl/sound/jt12/jt12_eg.v @@ -1,621 +1,203 @@ /* This file is part of JT12. - JT12 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. + JT12 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. - JT12 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. + JT12 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 JT12. If not, see . + You should have received a copy of the GNU General Public License + along with JT12. If not, see . - Author: Jose Tejada Gomez. Twitter: @topapate - Version: 1.0 - Date: 14-2-2017 + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 29-10-2018 - The non SSG-EG section is basically that of JT51's jt51_envelope.v - adapted to 6 channels, instead of the eight. - - The SSG-EG is based on the works of Nemesis, published on - http://gendev.spritesmind.net/forum/search.php?st=0&sk=t&sd=d&sr=posts&keywords=SSG-EG&t=386&sf=msgonly&ch=-1&start=15 - - This module tries to replicate exactly the original YM2612 waveforms. - Nonetheless, the verilog code is not a replica of the original circuit - as there is no reverse engineering description of it. - - Questions: - -I latch the SSG enable bit on keyon. I have to do this in order to ignore the inversion bit before the keyon - -If SSG enable is set to 0 by software before issueing a keyoff it will be ignored - -However, the other SSG bits will have an effect if changed in the meantime between keyon and keyoff - -Was YM2612 like that? - - */ - -`timescale 1ns / 1ps - -/* - - tab size 4 - -*/ + */ module jt12_eg ( - `ifdef TEST_SUPPORT - input test_eg, - `endif - input rst, - input clk, - input zero, - input eg_stop, - // envelope configuration - input [4:0] keycode_III, - input [4:0] arate_II, // attack rate - input [4:0] rate1_II, // decay rate - input [4:0] rate2_II, // sustain rate - input [3:0] rrate_II, // release rate - input [3:0] d1l, // sustain level - input [1:0] ks_III, // key scale - // SSG operation - input ssg_en_II, - input [2:0] ssg_eg_II, - // envelope operation - input keyon_II, - // envelope number - input [6:0] am, - input [6:0] tl_VII, - input [1:0] ams_VII, - input amsen_VII, + input rst, + input clk, + input clk_en, + input zero, + input eg_stop, + // envelope configuration + input [4:0] keycode_II, + input [4:0] arate_I, // attack rate + input [4:0] rate1_I, // decay rate + input [4:0] rate2_I, // sustain rate + input [3:0] rrate_I, // release rate + input [3:0] sl_I, // sustain level + input [1:0] ks_II, // key scale + // SSG operation + input ssg_en_I, + input [2:0] ssg_eg_I, + // envelope operation + input keyon_I, + // envelope number + input [6:0] lfo_mod, + input amsen_IV, + input [1:0] ams_IV, + input [6:0] tl_IV, - output reg [9:0] eg_IX, - output reg pg_rst_III + output reg [9:0] eg_V, + output reg pg_rst_II ); - // eg[9:6] -> direct attenuation (divide by 2) - // eg[5:0] -> mantisa attenuation (uses LUT) - // 1 LSB of eg is -0.09257 dB +parameter num_ch=6; -wire ssg_inv_II = ssg_eg_II[2] & ssg_en_II; -wire ssg_alt_II = ssg_eg_II[1] & ssg_en_II; -wire ssg_hold_II = ssg_eg_II[0] & ssg_en_II; +wire [14:0] eg_cnt; -parameter ATTACK=3'd0, DECAY1=3'd1, DECAY2=3'd2, RELEASE=3'd7, HOLD=3'd3; - -reg [4:0] d1level_II; -reg [9:0] eg_III, eg_IV, eg_V; -wire [9:0] eg_II; - -reg step_V; -reg sum_up; -reg [5:0] rate_V; - -// remember: { log_msb, pow_addr } <= log_val[11:0] + { tl, 5'd0 } + { eg, 2'd0 }; - -reg [1:0] eg_cnt_base; -reg [14:0] eg_cnt; - -always @(posedge clk) begin : envelope_counter - if( rst ) begin - eg_cnt_base <= 2'd0; - eg_cnt <=15'd0; - end - else begin - if( zero ) begin - // envelope counter increases every 3 output samples, - // there is one sample every 32 clock ticks - if( eg_cnt_base == 2'd2 ) begin - eg_cnt <= eg_cnt + 1'b1; - eg_cnt_base <= 2'd0; - end - else eg_cnt_base <= eg_cnt_base + 1'b1; - end - end -end - -wire cnt_out; // = all_cnt_last[3*31-1:3*30]; - - -reg [7:0] step_idx; -reg [2:0] state_III, state_IV, state_V, state_VI, state_VII, state_VIII; -wire [2:0] state_II; - - -wire ar_off_VI; -reg ar_off_III; - -// Register Cycle I - -always @(posedge clk) begin - if( d1l == 4'd15 ) - d1level_II <= 5'h1f; // 93dB - else - d1level_II <= d1l; -end - -// Register Cycle II -wire ssg_invertion_II, ssg_invertion_VIII; -reg ssg_invertion_III; -reg [4:0] cfg_III; -wire ssg_pg_rst = eg_II>=10'h200 && ssg_en_II && - !( ssg_alt_II || ssg_hold_II ); -wire ssg_en_out; -wire keyon_last_II; -reg ssg_en_in_II; - -always @(*) begin - if( state_II==RELEASE ) - ssg_en_in_II <= 1'b0; - else - ssg_en_in_II <= keyon_II ? ssg_en_II : ssg_en_out; -end - -wire ar_off_II = arate_II == 5'h1f; - -wire keyon_now_II = !keyon_last_II && keyon_II; -wire keyoff_now_II = keyon_last_II && !keyon_II; - -always @(posedge clk) begin - // ar_off_III <= arate_II == 5'h1f; - // trigger release - if( keyoff_now_II ) begin - cfg_III <= { rrate_II, 1'b1 }; - state_III <= RELEASE; - pg_rst_III <= 1'b0; - ar_off_III <= 1'b0; - end - else begin - // trigger 1st decay - if( keyon_now_II ) begin - cfg_III <= arate_II; - state_III <= ATTACK; - pg_rst_III <= 1'b1; - ar_off_III <= ar_off_II; - end - else begin : sel_rate - pg_rst_III <= (eg_II==10'h3FF) ||ssg_pg_rst; - if( (state_II==DECAY1 ||state_II==DECAY2) && ssg_en_II && eg_II >= 10'h200 ) begin - ssg_invertion_III <= ssg_alt_II ^ ssg_invertion_II; - if( ssg_hold_II ) begin - cfg_III <= 5'd0; - state_III <= HOLD; // repeats! - ar_off_III <= 1'b0; - end - else begin - cfg_III <= rate2_II; - state_III <= ATTACK; // repeats! - ar_off_III <= 1'b1; - end - end - else begin - ssg_invertion_III <= state_II==RELEASE ? 1'b0 : ssg_invertion_II; - case ( state_II ) - ATTACK: begin - if( eg_II==10'd0 ) begin - state_III <= DECAY1; - cfg_III <= rate1_II; - end - else begin - state_III <= state_II; // attack - cfg_III <= arate_II; - end - ar_off_III <= 1'b0; - end - DECAY1: begin - if( eg_II[9:5] >= d1level_II ) begin - cfg_III <= rate2_II; - state_III <= DECAY2; - end - else begin - cfg_III <= rate1_II; - state_III <= state_II; // decay1 - end - ar_off_III <= 1'b0; - end - DECAY2: - begin - cfg_III <= rate2_II; - state_III <= state_II; // decay2 - ar_off_III <= 1'b0; - end - RELEASE: begin - cfg_III <= { rrate_II, 1'b1 }; - state_III <= state_II; // release - ar_off_III <= 1'b0; - end - HOLD: begin - cfg_III <= 5'd0; - state_III <= HOLD; // repeats! - ar_off_III <= 1'b0; - end - endcase - end - end - end - - eg_III <= eg_II; -end - -/////////////////////////////////////////////////////////////////// -// Register Cycle III -reg [6:0] pre_rate_III; -reg [5:0] rate_IV; - -always @(*) begin : pre_rate_calc - if( cfg_III == 5'd0 ) - pre_rate_III <= 6'd0; - else - case( ks_III ) - 2'd3: pre_rate_III <= { cfg_III, 1'b0 } + keycode_III; - 2'd2: pre_rate_III <= { cfg_III, 1'b0 } + { 1'b0, keycode_III[4:1] }; - 2'd1: pre_rate_III <= { cfg_III, 1'b0 } + { 2'b0, keycode_III[4:2] }; - 2'd0: pre_rate_III <= { cfg_III, 1'b0 } + { 3'b0, keycode_III[4:3] }; - endcase -end - -always @(posedge clk) begin - if( rst ) begin - state_IV <= RELEASE; - eg_IV <= 10'h3ff; - rate_IV <= 5'h1F; - end - else begin - state_IV <= state_III; - eg_IV <= eg_III; - rate_IV <= pre_rate_III[6] ? 6'd63 : pre_rate_III[5:0]; - end -end -/////////////////////////////////////////////////////////////////// -// Register Cycle IV -reg [2:0] cnt_V; - -always @(posedge clk) begin - if( rst ) begin - state_V <= RELEASE; - rate_V <= 5'h1f; - eg_V <= 10'h3ff; - //cnt_V<= 3'd0; - end - else begin - state_V <= state_IV; - rate_V <= rate_IV; - eg_V <= eg_IV; - if( state_IV == ATTACK ) - case( rate_IV[5:2] ) - 4'h0: cnt_V <= eg_cnt[13:11]; - 4'h1: cnt_V <= eg_cnt[12:10]; - 4'h2: cnt_V <= eg_cnt[11: 9]; - 4'h3: cnt_V <= eg_cnt[10: 8]; - 4'h4: cnt_V <= eg_cnt[ 9: 7]; - 4'h5: cnt_V <= eg_cnt[ 8: 6]; - 4'h6: cnt_V <= eg_cnt[ 7: 5]; - 4'h7: cnt_V <= eg_cnt[ 6: 4]; - 4'h8: cnt_V <= eg_cnt[ 5: 3]; - 4'h9: cnt_V <= eg_cnt[ 4: 2]; - 4'ha: cnt_V <= eg_cnt[ 3: 1]; - default: cnt_V <= eg_cnt[ 2: 0]; - endcase - else - case( rate_IV[5:2] ) - 4'h0: cnt_V <= eg_cnt[14:12]; - 4'h1: cnt_V <= eg_cnt[13:11]; - 4'h2: cnt_V <= eg_cnt[12:10]; - 4'h3: cnt_V <= eg_cnt[11: 9]; - 4'h4: cnt_V <= eg_cnt[10: 8]; - 4'h5: cnt_V <= eg_cnt[ 9: 7]; - 4'h6: cnt_V <= eg_cnt[ 8: 6]; - 4'h7: cnt_V <= eg_cnt[ 7: 5]; - 4'h8: cnt_V <= eg_cnt[ 6: 4]; - 4'h9: cnt_V <= eg_cnt[ 5: 3]; - 4'ha: cnt_V <= eg_cnt[ 4: 2]; - 4'hb: cnt_V <= eg_cnt[ 3: 1]; - default: cnt_V <= eg_cnt[ 2: 0]; - endcase - end -end -////////////////////////////////////////////////////////////// -// Register Cycle V -always @(*) begin : rate_step - if( rate_V[5:4]==2'b11 ) begin // 0 means 1x, 1 means 2x - if( rate_V[5:2]==4'hf && state_V == ATTACK) - step_idx <= 8'b11111111; // Maximum attack speed, rates 60&61 - else - case( rate_V[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_V[5:2]==4'd0 && state_V != ATTACK) - step_idx <= 8'b11111110; // limit slowest decay rate_IV - else - case( rate_V[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_IV of zero keeps the level still - step_V <= rate_V[5:1]==5'd0 ? 1'b0 : step_idx[ cnt_V ]; -end - -reg [5:1] rate_VI; -reg [9:0] eg_VI; -reg step_VI; - -always @(posedge clk) begin - if( rst ) begin - state_VI <= RELEASE; - rate_VI <= 5'd1; - eg_VI <= 10'h3ff; - sum_up <= 1'b0; - step_VI <= 1'b0; - end - else begin - state_VI <= state_V; - rate_VI <= rate_V[5:1]; - eg_VI <= eg_V; - sum_up <= cnt_V[0] != cnt_out; - step_VI <= step_V; - end -end -////////////////////////////////////////////////////////////// -// Register cycle VI -reg [3:0] preatt_VI; -reg [5:0] att_VI; -wire ssg_en_VI; -reg [9:0] eg_VII, eg_stopped_VII; -reg [10:0] egatt_VI; - -always @(*) begin - case( rate_VI[5:2] ) - 4'b1100: preatt_VI <= { step_VI, ~step_VI }; // 12 - 4'b1101: preatt_VI <= { step_VI, ~step_VI, 1'b0 }; // 13 - 4'b1110: preatt_VI <= { step_VI, ~step_VI, 2'b0 }; // 14 - 4'b1111: preatt_VI <= 4'd8;// 15 - default: preatt_VI <= { step_VI, 1'b0 }; - endcase - att_VI <= ssg_en_VI ? { preatt_VI, 2'd0 } : { 2'd0, preatt_VI }; - egatt_VI <= att_VI + eg_VI; - eg_stopped_VII <= eg_VI; -end - -reg [8:0] ar_sum0; -reg [9:0] ar_result, ar_sum; - -always @(*) begin : ar_calculation - casex( rate_VI[5:2] ) - default: ar_sum0 <= eg_VI[9:4] + 1'd1; - 4'b1100: ar_sum0 <= eg_VI[9:4] + 1'd1; - 4'b1101: ar_sum0 <= eg_VI[9:3] + 1'd1; - 4'b111x: ar_sum0 <= eg_VI[9:2] + 1'd1; - endcase - if( rate_VI[5:4] == 2'b11 ) - ar_sum <= step_VI ? { ar_sum0, 1'b0 } : { 1'b0, ar_sum0 }; - else - ar_sum <= step_VI ? { 1'b0, ar_sum0 } : 10'd0; - ar_result <= ar_sum 2'b0 ? {10{1'b1}} : sum_eg_tl[9:0]; - state_VIII <= state_VII; - end -end - -////////////////////////////////////////////////////////////// -// Register cycle VIII -wire ssg_inv_VIII, ssg_en_VIII; -//reg [9:0] eg_IX; -always @(posedge clk) begin - if( rst ) - eg_IX <= 10'h3ff; - else begin - if( ssg_en_VIII && (ssg_invertion_VIII ^^ ssg_inv_VIII) ) - eg_IX <= eg_internal_VIII>=10'h200 ? 10'h0 : (10'h200 - eg_internal_VIII); - else - eg_IX <= eg_internal_VIII; - end -end - -////////////////////////////////////////////////////////////// -// Register cycle IX-XII -/* -jt12_sh #(.width(10), .stages(12-8)) u_padding( - .clk ( clk ), - .din ( eg_IX ), - .drop ( eg_XII ) -); -*/ -////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////// -// Shift registers - -jt12_sh24 #( .width(1) ) u_ssgen( - .clk ( clk ), - .din ( ssg_en_in_II ), - .st4 ( ssg_en_VI ), - .st6 ( ssg_en_VIII ), // note that din is *_II - .st24 ( ssg_en_out ) +jt12_eg_cnt u_egcnt( + .rst ( rst ), + .clk ( clk ), + .clk_en ( clk_en & ~eg_stop ), + .zero ( zero ), + .eg_cnt ( eg_cnt) ); -jt12_sh #( .width(1), .stages(6) ) u_ssgattsh( - .clk ( clk ), - .din ( ssg_inv_II ), - .drop ( ssg_inv_VIII ) +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 ssg_inv_in_I, ssg_inv_out_I; +reg ssg_inv_II, ssg_inv_III, ssg_inv_IV; +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, ssg_en_II, ssg_en_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; + + + +jt12_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 + .arate ( arate_I ), // attack rate + .rate1 ( rate1_I ), // decay rate + .rate2 ( rate2_I ), // sustain rate + .rrate ( rrate_I ), + .sl ( sl_I ), // sustain level + // SSG operation + .ssg_en ( ssg_en_I ), + .ssg_eg ( ssg_eg_I ), + // SSG output inversion + .ssg_inv_in ( ssg_inv_in_I ), + .ssg_inv_out ( ssg_inv_out_I ), + + .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 ), + .ks ( ks_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_ssg_en ( ssg_en_III ), + .pure_eg_in ( eg_in_III ), + .pure_eg_out ( pure_eg_out_III ), + .sum_up_in ( sum_in_III ), + /////////////////////////////////// + // IV + .lfo_mod ( lfo_mod ), + .amsen ( amsen_IV ), + .ams ( ams_IV ), + .tl ( tl_IV ), + .final_ssg_inv ( ssg_inv_IV ), + .final_eg_in ( eg_in_IV ), + .final_eg_out ( eg_out_IV ) ); -jt12_sh #( .width(1), .stages(3) ) u_aroffsh( - .clk ( clk ), - .din ( ar_off_III), - .drop ( ar_off_VI ) +always @(posedge clk) if(clk_en) begin + eg_in_II <= eg_in_I; + attack_II <= state_next_I[0]; + base_rate_II<= base_rate_I; + ssg_en_II <= ssg_en_I; + ssg_inv_II <= ssg_inv_out_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]; + ssg_en_III <= ssg_en_II; + ssg_inv_III <= ssg_inv_II; + step_III <= step_II; + sum_in_III <= sum_out_II; + + ssg_inv_IV <= ssg_inv_III; + eg_in_IV <= pure_eg_out_III; + eg_V <= eg_out_IV; +end + +jt12_sh #( .width(1), .stages(4*num_ch) ) u_cntsh( + .clk ( clk ), + .clk_en ( clk_en ), + .din ( cnt_lsb_II), + .drop ( cnt_in_II ) ); -jt12_sh #( .width(1), .stages(5) ) u_ssg1sh( - .clk ( clk ), - .din ( ssg_invertion_III ), - .drop ( ssg_invertion_VIII ) +jt12_sh_rst #( .width(10), .stages(4*num_ch-3), .rstval(1'b1) ) u_egsh( + .clk ( clk ), + .clk_en ( clk_en ), + .rst ( rst ), + .din ( eg_in_IV ), + .drop ( eg_in_I ) +); + +jt12_sh_rst #( .width(3), .stages(4*num_ch), .rstval(1'b1) ) u_egstate( + .clk ( clk ), + .clk_en ( clk_en ), + .rst ( rst ), + .din ( state_next_I ), + .drop ( state_in_I ) +); + +jt12_sh_rst #( .width(1), .stages(4*num_ch-3), .rstval(1'b0) ) u_ssg_inv( + .clk ( clk ), + .clk_en ( clk_en ), + .rst ( rst ), + .din ( ssg_inv_IV ), + .drop ( ssg_inv_in_I ) +); + +jt12_sh_rst #( .width(1), .stages(4*num_ch), .rstval(1'b0) ) u_konsh( + .clk ( clk ), + .clk_en ( clk_en ), + .rst ( rst ), + .din ( keyon_I ), + .drop ( keyon_last_I ) ); -jt12_sh #( .width(1), .stages(18) ) u_ssg2sh( - .clk ( clk ), - .din ( ssg_invertion_VIII ), - .drop ( ssg_invertion_II ) -); - - -/* Had 27 stages in JT51, for 32 operators - Has 19 stages here, for 24 operators - plus 1 extra stage. 20 stages does not work well. - Maybe JT51 should be 26!! */ -jt12_sh/*_rst*/ #( .width(10), .stages(19)/*, .rstval(1'b1)*/ ) u_egsh( - .clk ( clk ), -// .rst ( rst ), - .din ( eg_stop ? eg_stopped_VII : eg_VII ), - .drop ( eg_II ) -); - -/* Had 32 stages in JT51, for 32 operators - Has 24 stages here, for 24 operators */ -jt12_sh/*_rst*/ #( .width(1), .stages(24) ) u_cntsh( - .clk ( clk ), -// .rst ( rst ), - .din ( cnt_V[0] ), - .drop ( cnt_out ) -); - -jt12_sh_rst #( .width(1), .stages(24) ) u_konsh( - .clk ( clk ), -// .rst ( rst ), - .din ( keyon_II ), - .drop ( keyon_last_II ) -); - -/* Had 31 stages in JT51, for 32 operators - Has 23 stages here, for 24 operators */ -jt12_sh/*_rst*/ #( .width(3), .stages(18)/*, .rstval(1'b1)*/ ) u_statesh( - .clk ( clk ), -// .rst ( rst ), - .din ( state_VIII), - .drop ( state_II ) -); - -`ifdef SIMULATION -reg [4:0] sep24_cnt; - -wire [2:0] state_ch0s1, state_ch1s1, state_ch2s1, state_ch3s1, - state_ch4s1, state_ch5s1, state_ch0s2, state_ch1s2, - state_ch2s2, state_ch3s2, state_ch4s2, state_ch5s2, - state_ch0s3, state_ch1s3, state_ch2s3, state_ch3s3, - state_ch4s3, state_ch5s3, state_ch0s4, state_ch1s4, - state_ch2s4, state_ch3s4, state_ch4s4, state_ch5s4; - - -always @(posedge clk) - sep24_cnt <= !zero ? sep24_cnt+1'b1 : 5'd0; - -sep24 #( .width(3), .pos0(0) ) stsep -( - .clk ( clk ), - .mixed ( state_II ), - .mask ( 0 ), - .cnt ( sep24_cnt ), - - .ch0s1 (state_ch0s1), - .ch1s1 (state_ch1s1), - .ch2s1 (state_ch2s1), - .ch3s1 (state_ch3s1), - .ch4s1 (state_ch4s1), - .ch5s1 (state_ch5s1), - - .ch0s2 (state_ch0s2), - .ch1s2 (state_ch1s2), - .ch2s2 (state_ch2s2), - .ch3s2 (state_ch3s2), - .ch4s2 (state_ch4s2), - .ch5s2 (state_ch5s2), - - .ch0s3 (state_ch0s3), - .ch1s3 (state_ch1s3), - .ch2s3 (state_ch2s3), - .ch3s3 (state_ch3s3), - .ch4s3 (state_ch4s3), - .ch5s3 (state_ch5s3), - - .ch0s4 (state_ch0s4), - .ch1s4 (state_ch1s4), - .ch2s4 (state_ch2s4), - .ch3s4 (state_ch3s4), - .ch4s4 (state_ch4s4), - .ch5s4 (state_ch5s4) -); - -`endif - -endmodule - +endmodule // jt12_eg \ No newline at end of file diff --git a/rtl/sound/jt12/jt12_eg_cnt.v b/rtl/sound/jt12/jt12_eg_cnt.v new file mode 100644 index 0000000..b83292e --- /dev/null +++ b/rtl/sound/jt12/jt12_eg_cnt.v @@ -0,0 +1,50 @@ +/* This file is part of JT12. + + JT12 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. + + JT12 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 JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 29-10-2018 + + */ + +module jt12_eg_cnt( + input rst, + input clk, + input clk_en, + input zero, + output reg [14:0] eg_cnt +); + +reg [1:0] eg_cnt_base; + +always @(posedge clk) begin : envelope_counter + if( rst ) begin + eg_cnt_base <= 2'd0; + eg_cnt <=15'd0; + end + else begin + if( zero && clk_en ) begin + // envelope counter increases every 3 output samples, + // there is one sample every 24 clock ticks + if( eg_cnt_base == 2'd2 ) begin + eg_cnt <= eg_cnt + 1'b1; + eg_cnt_base <= 2'd0; + end + else eg_cnt_base <= eg_cnt_base + 1'b1; + end + end +end + +endmodule // jt12_eg_cnt \ No newline at end of file diff --git a/rtl/sound/jt12/jt12_eg_comb.v b/rtl/sound/jt12/jt12_eg_comb.v new file mode 100644 index 0000000..ddf0c53 --- /dev/null +++ b/rtl/sound/jt12/jt12_eg_comb.v @@ -0,0 +1,139 @@ +/* This file is part of JT12. + + JT12 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. + + JT12 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 JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 30-10-2018 + + */ + +module jt12_eg_comb( + input keyon_now, + input keyoff_now, + input [2:0] state_in, + input [9:0] eg_in, + // envelope configuration + input [4:0] arate, // attack rate + input [4:0] rate1, // decay rate + input [4:0] rate2, // sustain rate + input [3:0] rrate, + input [3:0] sl, // sustain level + // SSG operation + input ssg_en, + input [2:0] ssg_eg, + // SSG output inversion + input ssg_inv_in, + output ssg_inv_out, + + output [4:0] base_rate, + output [2:0] state_next, + output pg_rst, + /////////////////////////////////// + // II + input step_attack, + input [ 4:0] step_rate_in, + input [ 4:0] keycode, + input [14:0] eg_cnt, + input cnt_in, + input [ 1:0] ks, + output cnt_lsb, + output step, + output [5:0] step_rate_out, + output sum_up_out, + /////////////////////////////////// + // III + input pure_attack, + input pure_step, + input [ 5:1] pure_rate, + input pure_ssg_en, + input [ 9:0] pure_eg_in, + output [9:0] pure_eg_out, + input sum_up_in, + /////////////////////////////////// + // IV + input [ 6:0] lfo_mod, + input amsen, + input [ 1:0] ams, + input [ 6:0] tl, + input [ 9:0] final_eg_in, + input final_ssg_inv, + output [9:0] final_eg_out +); + +// I +jt12_eg_ctrl u_ctrl( + .keyon_now ( keyon_now ), + .keyoff_now ( keyoff_now ), + .state_in ( state_in ), + .eg ( eg_in ), + // envelope configuration + .arate ( arate ), // attack rate + .rate1 ( rate1 ), // decay rate + .rate2 ( rate2 ), // sustain rate + .rrate ( rrate ), + .sl ( sl ), // sustain level + // SSG operation + .ssg_en ( ssg_en ), + .ssg_eg ( ssg_eg ), + // SSG output inversion + .ssg_inv_in ( ssg_inv_in ), + .ssg_inv_out ( ssg_inv_out ), + + .base_rate ( base_rate ), + .state_next ( state_next ), + .pg_rst ( pg_rst ) +); + +// II + +jt12_eg_step u_step( + .attack ( step_attack ), + .base_rate ( step_rate_in ), + .keycode ( keycode ), + .eg_cnt ( eg_cnt ), + .cnt_in ( cnt_in ), + .ks ( ks ), + .cnt_lsb ( cnt_lsb ), + .step ( step ), + .rate ( step_rate_out ), + .sum_up ( sum_up_out ) +); + +// III + +wire [9:0] egin, egout; +jt12_eg_pure u_pure( + .attack ( pure_attack ), + .step ( pure_step ), + .rate ( pure_rate ), + .ssg_en ( pure_ssg_en ), + .eg_in ( pure_eg_in ), + .eg_pure( pure_eg_out ), + .sum_up ( sum_up_in ) +); + +// IV + +jt12_eg_final u_final( + .lfo_mod ( lfo_mod ), + .amsen ( amsen ), + .ams ( ams ), + .tl ( tl ), + .ssg_inv ( final_ssg_inv ), + .eg_pure_in ( final_eg_in ), + .eg_limited ( final_eg_out ) +); + +endmodule // jt12_eg_comb \ No newline at end of file diff --git a/rtl/sound/jt12/jt12_eg_ctrl.v b/rtl/sound/jt12/jt12_eg_ctrl.v new file mode 100644 index 0000000..3b4816b --- /dev/null +++ b/rtl/sound/jt12/jt12_eg_ctrl.v @@ -0,0 +1,122 @@ +/* This file is part of JT12. + + JT12 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. + + JT12 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 JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 29-10-2018 + + */ + +module jt12_eg_ctrl( + input keyon_now, + input keyoff_now, + input [2:0] state_in, + input [9:0] eg, + // envelope configuration + input [4:0] arate, // attack rate + input [4:0] rate1, // decay rate + input [4:0] rate2, // sustain rate + input [3:0] rrate, + input [3:0] sl, // sustain level + // SSG operation + input ssg_en, + input [2:0] ssg_eg, + // SSG output inversion + input ssg_inv_in, + output reg ssg_inv_out, + + 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]; + +reg [4:0] sustain; + +always @(*) + if( sl == 4'd15 ) + sustain = 5'h1f; // 93dB + else + sustain = {1'b0, sl}; + +wire ssg_en_out; +reg ssg_en_in, ssg_pg_rst; + +// aliases +wire ssg_att = ssg_eg[2]; +wire ssg_alt = ssg_eg[1]; +wire ssg_hold = ssg_eg[0] & ssg_en; + +reg ssg_over; + + +always @(*) begin + ssg_over = ssg_en && eg[9]; // eg >=10'h200 + ssg_pg_rst = ssg_over && !( ssg_alt || ssg_hold ); + pg_rst = keyon_now | ssg_pg_rst; +end + +always @(*) + casez ( { keyoff_now, keyon_now, state_in} ) + 5'b01_???: begin // key on + base_rate = arate; + state_next = ATTACK; + ssg_inv_out = ssg_att & ssg_en; + end + {2'b00, ATTACK}: + if( eg==10'd0 ) begin + base_rate = rate1; + state_next = DECAY; + ssg_inv_out = ssg_inv_in; + end + else begin + base_rate = arate; + state_next = ATTACK; + ssg_inv_out = ssg_inv_in; + end + {2'b00, DECAY}: begin + if( ssg_over ) begin + base_rate = ssg_hold ? 5'd0 : arate; + state_next = ssg_hold ? HOLD : ATTACK; + ssg_inv_out = ssg_en & (ssg_alt ^ ssg_inv_in); + end + else begin + base_rate = eg[9:5] >= sustain ? rate2 : rate1; + state_next = DECAY; + ssg_inv_out = ssg_inv_in; + end + end + {2'b00, HOLD}: begin + base_rate = 5'd0; + state_next = HOLD; + ssg_inv_out = ssg_inv_in; + end + default: begin // RELEASE, note that keyoff_now==1 will enter this state too + base_rate = { rrate, 1'b1 }; + state_next = RELEASE; // release + ssg_inv_out = 1'b0; // this can produce a glitch in the output + // But to release from SSG cannot be done nicely while + // inverting the ouput + end + endcase + + +endmodule // jt12_eg_ctrl \ No newline at end of file diff --git a/rtl/sound/jt12/jt12_eg_final.v b/rtl/sound/jt12/jt12_eg_final.v new file mode 100644 index 0000000..5919fc0 --- /dev/null +++ b/rtl/sound/jt12/jt12_eg_final.v @@ -0,0 +1,57 @@ +/* This file is part of JT12. + + JT12 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. + + JT12 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 JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 29-10-2018 + + */ + +module jt12_eg_final( + input [ 6:0] lfo_mod, + input amsen, + input [ 1:0] ams, + input [ 6:0] tl, + input [ 9:0] eg_pure_in, + input ssg_inv, + output reg [9:0] eg_limited +); + +reg [ 8:0] am_final; +reg [11:0] sum_eg_tl; +reg [11:0] sum_eg_tl_am; +reg [ 5:0] am_inverted; +reg [ 9:0] eg_pream; + +always @(*) begin + am_inverted = lfo_mod[6] ? ~lfo_mod[5:0] : lfo_mod[5:0]; +end + +always @(*) begin + casez( {amsen, ams } ) + default: am_final = 9'd0; + 3'b1_01: am_final = { 5'd0, am_inverted[5:2] }; + 3'b1_10: am_final = { 3'd0, am_inverted }; + 3'b1_11: am_final = { 2'd0, am_inverted, 1'b0 }; + endcase + eg_pream = ssg_inv ? (10'h200-eg_pure_in) : eg_pure_in; + sum_eg_tl = { 1'b0, tl, 3'd0 } + {1'b0, eg_pream}; // leading zeros needed to compute correctly + sum_eg_tl_am = sum_eg_tl + { 3'd0, am_final }; +end + +always @(*) + eg_limited = sum_eg_tl_am[11:10]==2'd0 ? sum_eg_tl_am[9:0] : 10'h3ff; + +endmodule // jt12_eg_final \ No newline at end of file diff --git a/rtl/sound/jt12/jt12_eg_pure.v b/rtl/sound/jt12/jt12_eg_pure.v new file mode 100644 index 0000000..02a3678 --- /dev/null +++ b/rtl/sound/jt12/jt12_eg_pure.v @@ -0,0 +1,81 @@ +/* This file is part of JT12. + + JT12 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. + + JT12 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 JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 29-10-2018 + + */ + +module jt12_eg_pure( + input attack, + input step, + input [ 5:1] rate, + input [ 9:0] eg_in, + input ssg_en, + input 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 = ssg_en ? {4'd0, dr_sum, 2'd0} : {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 // jt12_eg_pure \ No newline at end of file diff --git a/rtl/sound/jt12/jt12_eg_step.v b/rtl/sound/jt12/jt12_eg_step.v new file mode 100644 index 0000000..4225e4e --- /dev/null +++ b/rtl/sound/jt12/jt12_eg_step.v @@ -0,0 +1,111 @@ +/* This file is part of JT12. + + JT12 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. + + JT12 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 JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 29-10-2018 + + */ + +module jt12_eg_step( + input attack, + input [ 4:0] base_rate, + input [ 4:0] keycode, + input [14:0] eg_cnt, + input cnt_in, + input [ 1:0] ks, + output 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 + case( ks ) + 2'd3: pre_rate = { base_rate, 1'b0 } + { 1'b0, keycode }; + 2'd2: pre_rate = { base_rate, 1'b0 } + { 2'b0, keycode[4:1] }; + 2'd1: pre_rate = { base_rate, 1'b0 } + { 3'b0, keycode[4:2] }; + 2'd0: pre_rate = { base_rate, 1'b0 } + { 4'b0, keycode[4:3] }; + endcase +end + +always @(*) + rate = pre_rate[6] ? 6'd63 : 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 @(*) + +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 \ No newline at end of file diff --git a/rtl/sound/jt12/jt12_exprom.v b/rtl/sound/jt12/jt12_exprom.v index a564725..1bb1891 100644 --- a/rtl/sound/jt12/jt12_exprom.v +++ b/rtl/sound/jt12/jt12_exprom.v @@ -4,73 +4,299 @@ /* This file is part of JT12. - JT12 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. + JT12 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. - JT12 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. + JT12 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 JT12. If not, see . + You should have received a copy of the GNU General Public License + along with JT12. If not, see . - Based on Sauraen VHDL version of OPN/OPN2, which is based on die shots. + Based on Sauraen VHDL version of OPN/OPN2, which is based on die shots. - Author: Jose Tejada Gomez. Twitter: @topapate - Version: 1.0 - Date: 27-1-2017 + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 27-1-2017 */ -// altera message_off 10030 + +// altera message_off 10030 module jt12_exprom ( - input [4:0] addr, - input clk, - output reg [44:0] exp + input [7:0] addr, + input clk, + input clk_en, + output reg [9:0] exp ); - reg [44:0] explut_jt51[31:0]; - initial - begin - explut_jt51[0] <= 45'b111110101011010110001011010000010010111011011; - explut_jt51[1] <= 45'b111101010011010101000011001100101110110101011; - explut_jt51[2] <= 45'b111011111011010011110111001000110010101110011; - explut_jt51[3] <= 45'b111010100101010010101111000100110010101000011; - explut_jt51[4] <= 45'b111001001101010001100111000000110010100001011; - explut_jt51[5] <= 45'b110111111011010000011110111101010010011011011; - explut_jt51[6] <= 45'b110110100011001111010110111001010010010100100; - explut_jt51[7] <= 45'b110101001011001110001110110101110010001110011; - explut_jt51[8] <= 45'b110011111011001101000110110001110010001000011; - explut_jt51[9] <= 45'b110010100011001011111110101110010010000010011; - explut_jt51[10] <= 45'b110001010011001010111010101010010001111011011; - explut_jt51[11] <= 45'b101111111011001001110010100110110001110101011; - explut_jt51[12] <= 45'b101110101011001000101010100011001101101111011; - explut_jt51[13] <= 45'b101101010101000111100110011111010001101001011; - explut_jt51[14] <= 45'b101100000011000110100010011011110001100011011; - explut_jt51[15] <= 45'b101010110011000101011110011000010001011101011; - explut_jt51[16] <= 45'b101001100011000100011010010100101101010111011; - explut_jt51[17] <= 45'b101000010011000011010010010001001101010001011; - explut_jt51[18] <= 45'b100111000011000010010010001101101101001011011; - explut_jt51[19] <= 45'b100101110011000001001110001010001101000101011; - explut_jt51[20] <= 45'b100100100011000000001010000110010000111111011; - explut_jt51[21] <= 45'b100011010010111111001010000011001100111001011; - explut_jt51[22] <= 45'b100010000010111110000101111111101100110011011; - explut_jt51[23] <= 45'b100000110010111101000001111100001100101101011; - explut_jt51[24] <= 45'b011111101010111100000001111000101100101000010; - explut_jt51[25] <= 45'b011110011010111011000001110101001100100010011; - explut_jt51[26] <= 45'b011101001010111010000001110001110000011100011; - explut_jt51[27] <= 45'b011100000010111001000001101110010000010110011; - explut_jt51[28] <= 45'b011010110010111000000001101011001100010001011; - explut_jt51[29] <= 45'b011001101010110111000001100111101100001011011; - explut_jt51[30] <= 45'b011000100000110110000001100100010000000110010; - explut_jt51[31] <= 45'b010111010010110101000001100001001100000000011; - end + 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) - exp <= explut_jt51[addr]; + always @ (posedge clk) if(clk_en) + exp <= explut_jt51[addr]; endmodule diff --git a/rtl/sound/jt12/jt12_kon.v b/rtl/sound/jt12/jt12_kon.v index 78d41d2..42cfd00 100644 --- a/rtl/sound/jt12/jt12_kon.v +++ b/rtl/sound/jt12/jt12_kon.v @@ -4,65 +4,120 @@ /* This file is part of JT12. - JT12 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. + JT12 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. - JT12 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. + JT12 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 JT12. If not, see . + You should have received a copy of the GNU General Public License + along with JT12. If not, see . - Author: Jose Tejada Gomez. Twitter: @topapate - Version: 1.0 - Date: 27-1-2017 + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 27-1-2017 */ module jt12_kon( - input rst, - input clk, - input [3:0] keyon_op, - input [2:0] keyon_ch, - input [1:0] cur_op, - input [2:0] cur_ch, - input up_keyon, - input csm, - input flag_A, - input overflow_A, + input rst, + input clk, + input clk_en, + input [3:0] keyon_op, + input [2:0] keyon_ch, + input [1:0] next_op, + input [2:0] next_ch, + input up_keyon, + input csm, + // input flag_A, + input overflow_A, - output reg keyon_II + output reg keyon_I ); -//reg csm_copy; +parameter num_ch=6; reg din; -wire drop; +wire csr_out; -reg [3:0] cur_op_hot; +reg [3:0] next_op_hot; +reg [3:0] next_op6_hot; -always @(posedge clk) - keyon_II <= (csm&&cur_ch==2'd2&&overflow_A) || drop; always @(*) begin - case( cur_op ) - 2'd0: cur_op_hot <= 4'b0001; // S1 - 2'd1: cur_op_hot <= 4'b0100; // S3 - 2'd2: cur_op_hot <= 4'b0010; // S2 - 2'd3: cur_op_hot <= 4'b1000; // S4 - endcase - din <= keyon_ch==cur_ch && up_keyon ? |(keyon_op&cur_op_hot) : drop; + case( next_op ) + 2'd0: next_op_hot = 4'b0001; // S1 + 2'd1: next_op_hot = 4'b0100; // S3 + 2'd2: next_op_hot = 4'b0010; // S2 + 2'd3: next_op_hot = 4'b1000; // S4 + endcase + din = keyon_ch==next_ch && up_keyon ? |(keyon_op&next_op_hot) : csr_out; end -jt12_sh_rst #(.width(1),.stages(24)) u_konch( - .clk ( clk ), -// .rst ( rst ), - .din ( din ), - .drop ( drop ) -); +generate +if(num_ch==6) begin + // capture overflow signal so it lasts long enough + reg overflow2; + reg [4:0] overflow_cycle; + + always @(posedge clk) if( clk_en ) begin + if(overflow_A) begin + overflow2 <= 1'b1; + overflow_cycle <= { next_op, next_ch }; + end else begin + if(overflow_cycle == {next_op, next_ch}) overflow2<=1'b0; + end + end + + wire middle; + reg mid_din; + + always @(posedge clk) if( clk_en ) + keyon_I <= (csm&&next_ch==3'd2&&overflow2) || csr_out; + + always @(*) begin + case( {~next_op[1], next_op[0]} ) + 2'd0: next_op6_hot = 4'b0001; // S1 + 2'd1: next_op6_hot = 4'b0100; // S3 + 2'd2: next_op6_hot = 4'b0010; // S2 + 2'd3: next_op6_hot = 4'b1000; // S4 + endcase + mid_din = keyon_ch==next_ch && up_keyon ? |(keyon_op&next_op6_hot) : middle; + end + + jt12_sh_rst #(.width(1),.stages(12),.rstval(1'b0)) u_konch0( + .clk ( clk ), + .clk_en ( clk_en ), + .rst ( rst ), + .din ( din ), + .drop ( middle ) + ); + + jt12_sh_rst #(.width(1),.stages(12),.rstval(1'b0)) u_konch1( + .clk ( clk ), + .clk_en ( clk_en ), + .rst ( rst ), + .din ( mid_din ), + .drop ( csr_out ) + ); +end +else begin // 3 channels + always @(posedge clk) if( clk_en ) + keyon_I <= csr_out; // No CSM for YM2203 + + jt12_sh_rst #(.width(1),.stages(12),.rstval(1'b0)) u_konch1( + .clk ( clk ), + .clk_en ( clk_en ), + .rst ( rst ), + .din ( din ), + .drop ( csr_out ) + ); +end +endgenerate + endmodule diff --git a/rtl/sound/jt12/jt12_lfo.v b/rtl/sound/jt12/jt12_lfo.v index 26c3e24..3f3fa90 100644 --- a/rtl/sound/jt12/jt12_lfo.v +++ b/rtl/sound/jt12/jt12_lfo.v @@ -22,47 +22,82 @@ /* - tab size 4 + Does the LFO frequency depend on the pre-scaler for YM2608 ? + + From spritesmind.net: + "That would be 7-bit LFO step counter (which is incremented on each LFO clock and reset when LFO enable bit is cleared). + LFO AM value indeed corresponds to LFO step counter bits 0:5 shifted left by one + and XORed with inversion of bit 6 (to generate an inverted triangle waveform) + + LFO AM sensitivity (2 bits) indicates to EG how much LFO AM value is shifted before adding to EG output + [...] + LFO PM step (0-31), which takes bits 2:6 of LFO step counter (0-127) and goes to LFO PM calcuation unit + " + + From Sauraen: + +The LFO seems to have 3 sections: + + [*] 7-bit linear prescaler. The test bit 0x21:1 goes into what looks like the carry-in or something similar; + it could go into the reset, I can't quite tell with more detailed analysis. The 7-bit output (plus maybe carry-out) + gets logiced together into 8 lines (evidently perform "== N" with N hardcoded for each line), and these go into a + little selector unit which is also fed by the LFO Speed and LFO Enable bits. I can't quite see the output of this, + but I do see there's some sort of feedback to the prescaler's reset. So this clearly seems like a divide-by-N prescaler. + I can try to read the eight N's for you if you want, but you should be able to reverse engineer them from knowing what the LFO speeds are. + + [*] 7-bit linear counter, with an 8-bit unit after the output (possibly inverts the output after each cycle to make a triangle wave?). + Bits 1:6 of the output of this go to the EG, and stick into its pipeline at the same place where the LFO->Amplitude two bits go. + (Elsewhere the operator LFO enable flag simply forces these two bits to zero for operators not affected by the LFO.) + Some modified version of the 8-bit signal between the counter and the inverter unit thing goes to the third unit of the LFO. + + [*] Highly complex unit which modifies the frequency data as it goes from the channel registers to the PG. The block bits bypass this, + but all the frequency bits get modified by it. There's a bitslice portion corresponding to bits 0:6, and then what appears to be + the same logic folded over to process bits 7:A. But the interesting part is that bits 4:A of the frequency data go into the + bitslices 0:6. That is, the bitslice unit for bit 0 has bit 0 enter at the middle and leave (to the PG) at the bottom. But it also has bit 4 enter at the top. + And so on through bit 6 having bit A enter at the top. It looks like the top portion is some sort of shifter for bits 4:A--the wires go diagonally + so that bit 4 only gets used once, bit 5 gets used in bitslice 1 and 0, bit 6 gets used in bitslices 2:0, and so on so that bit A gets used in all of them. + I'm guessing this whole unit is basically a multiplier, multiplying bits 4:A of the frequency value by bits 0:7 of the LFO state, and then adding the result + to bits 0:6 of the frequency value (with carry up to the higher bits). It looks like, between the multiplied output and the adder, there's another shifter + whose value is based on the the LFO->Frequency bits. But it looks like it's a bit more complex than I'm describing. */ module jt12_lfo( input rst, input clk, + input clk_en, input zero, input lfo_rst, input lfo_en, input [2:0] lfo_freq, - output reg [6:0] lfo_mod + output reg [6:0] lfo_mod // 7-bit width according to spritesmind.net ); reg [6:0] cnt, limit; always @(*) - case( lfo_freq ) - 3'd0: limit <= 7'd108; - 3'd1: limit <= 7'd78; - 3'd2: limit <= 7'd71; - 3'd3: limit <= 7'd67; - 3'd4: limit <= 7'd62; - 3'd5: limit <= 7'd44; - 3'd6: limit <= 7'd8; - 3'd7: limit <= 7'd5; + case( lfo_freq ) // same values as in MAME + 3'd0: limit = 7'd108; + 3'd1: limit = 7'd77; + 3'd2: limit = 7'd71; + 3'd3: limit = 7'd67; + 3'd4: limit = 7'd62; + 3'd5: limit = 7'd44; + 3'd6: limit = 7'd8; + 3'd7: limit = 7'd5; endcase -always @(posedge clk) begin +always @(posedge clk) if( rst || !lfo_en ) { lfo_mod, cnt } <= 14'd0; - else begin - if(zero) begin - if( cnt == limit ) begin - cnt <= 7'd0; - lfo_mod <= lfo_mod + 1'b1; - end - else - cnt <= cnt + 1'b1; + else if( clk_en && zero) begin + if( cnt == limit ) begin + cnt <= 7'd0; + lfo_mod <= lfo_mod + 1'b1; + end + else begin + cnt <= cnt + 1'b1; end end -end endmodule diff --git a/rtl/sound/jt12/jt12_limitamp.v b/rtl/sound/jt12/jt12_limitamp.v index d6ff147..b990fd0 100644 --- a/rtl/sound/jt12/jt12_limitamp.v +++ b/rtl/sound/jt12/jt12_limitamp.v @@ -30,11 +30,11 @@ module jt12_limitamp #( parameter width=20, shift=5 ) ( ); always @(*) begin - left_out <= ^left_in[width-1:width-1-shift] ? + left_out = ^left_in[width-1:width-1-shift] ? { left_in[width-1], {(width-1){~left_in[width-1]}}} : left_in <<< shift; - right_out <= ^right_in[width-1:width-1-shift] ? + right_out = ^right_in[width-1:width-1-shift] ? { right_in[width-1], {(width-1){~right_in[width-1]}}} : right_in <<< shift; end diff --git a/rtl/sound/jt12/jt12_logsin.v b/rtl/sound/jt12/jt12_logsin.v new file mode 100644 index 0000000..8974375 --- /dev/null +++ b/rtl/sound/jt12/jt12_logsin.v @@ -0,0 +1,298 @@ +/* This file is part of JT12. + + + JT12 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. + + JT12 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 JT12. If not, see . + + Based on Sauraen VHDL version of OPN/OPN2, which is based on die shots. + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 27-1-2017 + +*/ + +//altera message_off 10030 + +module jt12_logsin +( + input [7:0] addr, + input clk, + input clk_en, + 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(clk_en) + logsin <= sinelut[addr]; + +endmodule diff --git a/rtl/sound/jt12/jt12_mmr.v b/rtl/sound/jt12/jt12_mmr.v index aea9c4a..8839001 100644 --- a/rtl/sound/jt12/jt12_mmr.v +++ b/rtl/sound/jt12/jt12_mmr.v @@ -1,370 +1,392 @@ /* This file is part of JT12. - JT12 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. + JT12 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. - JT12 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. + JT12 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 JT12. If not, see . + You should have received a copy of the GNU General Public License + along with JT12. If not, see . - Author: Jose Tejada Gomez. Twitter: @topapate - Version: 1.0 - Date: 14-2-2017 - */ + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 14-2-2017 + */ `timescale 1ns / 1ps module jt12_mmr( - input rst, - input clk, - input [7:0] din, - input write, - input [1:0] addr, - output reg busy, - output ch6op, - // LFO - output reg [2:0] lfo_freq, - output reg lfo_en, - // Timers - output reg [9:0] value_A, - output reg [7:0] value_B, - output reg load_A, - output reg load_B, - output reg enable_irq_A, - output reg enable_irq_B, - output reg clr_flag_A, - output reg clr_flag_B, - output reg fast_timers, - input flag_A, - input overflow_A, - // PCM - output reg [8:0] pcm, - output reg pcm_en, + input rst, + input clk, + input cen, + output clk_en, + output clk_en_ssg, + input [7:0] din, + input write, + input [1:0] addr, + output reg busy, + output ch6op, + // LFO + output reg [2:0] lfo_freq, + output reg lfo_en, + // Timers + output reg [9:0] value_A, + output reg [7:0] value_B, + output reg load_A, + output reg load_B, + output reg enable_irq_A, + output reg enable_irq_B, + output reg clr_flag_A, + output reg clr_flag_B, + output reg fast_timers, + input flag_A, + input overflow_A, + // PCM + output reg [8:0] pcm, + output reg pcm_en, + output reg pcm_wr, // high for one clock cycle when PCM is written + // Operator + output xuse_prevprev1, + output xuse_internal, + output yuse_internal, + output xuse_prev2, + output yuse_prev1, + output yuse_prev2, + // PG + output [10:0] fnum_I, + output [ 2:0] block_I, + output reg pg_stop, + // REG + output [ 1:0] rl, + output [ 2:0] fb_II, + output [ 2:0] alg_I, + output [ 2:0] pms_I, + output [ 1:0] ams_IV, + output amsen_IV, + output [ 2:0] dt1_I, + output [ 3:0] mul_II, + output [ 6:0] tl_IV, + output reg eg_stop, - `ifdef TEST_SUPPORT - // Test - output reg test_eg, - output reg test_op0, - `endif - // Operator - output use_prevprev1, - output use_internal_x, - output use_internal_y, - output use_prev2, - output use_prev1, - // PG - output [10:0] fnum_I, - output [ 2:0] block_I, - output reg pg_stop, - // REG - output [ 1:0] rl, - output [ 2:0] fb_II, - output [ 2:0] alg, - output [ 2:0] pms, - output [ 1:0] ams_VII, - output amsen_VII, - output [ 2:0] dt1_II, - output [ 3:0] mul_V, - output [ 6:0] tl_VII, - output reg eg_stop, + output [ 4:0] ar_I, + output [ 4:0] d1r_I, + output [ 4:0] d2r_I, + output [ 3:0] rr_I, + output [ 3:0] sl_I, + output [ 1:0] ks_II, + // SSG operation + output ssg_en_I, + output [2:0] ssg_eg_I, - output [ 4:0] ar_II, - output [ 4:0] d1r_II, - output [ 4:0] d2r_II, - output [ 3:0] rr_II, - output [ 3:0] d1l, - output [ 1:0] ks_III, - // SSG operation - output ssg_en_II, - output [2:0] ssg_eg_II, + output keyon_I, - output keyon_II, +// output [ 1:0] cur_op, + // Operator + output zero, + output s1_enters, + output s2_enters, + output s3_enters, + output s4_enters, -// output [ 1:0] cur_op, - // Operator - output zero, - output s1_enters, - output s2_enters, - output s3_enters, - output s4_enters + // PSG interace + output [3:0] psg_addr, + output [7:0] psg_data, + output reg psg_wr_n ); -reg [7:0] selected_register; +parameter use_ssg=0, num_ch=6, use_pcm=1; -//reg sch; // 0 => CH1~CH3 only available. 1=>CH4~CH6 +`ifdef SIMULATION + initial begin + cen_cnt = 3'd0; + end + `include "jt12_mmr_sim.vh" +`endif + +reg [1:0] div_setting; + + +jt12_div #(.use_ssg(use_ssg),.num_ch(num_ch)) u_div ( + .rst ( rst ), + .clk ( clk ), + .cen ( cen ), + .div_setting ( div_setting ), + .clk_en ( clk_en ), + .clk_en_ssg ( clk_en_ssg ) +); + +reg [7:0] selected_register; + +//reg sch; // 0 => CH1~CH3 only available. 1=>CH4~CH6 /* -reg irq_zero_en, irq_brdy_en, irq_eos_en, - irq_tb_en, irq_ta_en; - */ -reg up_clr; -reg up_alg; +reg irq_zero_en, irq_brdy_en, irq_eos_en, + irq_tb_en, irq_ta_en; + */ +reg [6:0] up_opreg; // hot-one encoding. tells which operator register gets updated next +reg [2:0] up_chreg; // hot-one encoding. tells which channel register gets updated next +reg up_keyon; -reg up_block; -reg up_fnumlo; -reg up_pms; -reg up_dt1; -reg up_tl; -reg up_ks_ar; -reg up_amen_d1r; -reg up_d2r; -reg up_d1l; -reg up_ssgeg; -reg up_keyon; +wire busy_reg; -wire busy_reg; - -parameter REG_TEST = 8'h01, - REG_TEST2 = 8'h02, - REG_TESTYM = 8'h21, - REG_LFO = 8'h22, - REG_CLKA1 = 8'h24, - REG_CLKA2 = 8'h25, - REG_CLKB = 8'h26, - REG_TIMER = 8'h27, - REG_KON = 8'h28, - REG_IRQMASK = 8'h29, - REG_PCM = 8'h2A, - REG_PCM_EN = 8'h2B, - REG_DACTEST = 8'h2C, - REG_CLK_N6 = 8'h2D, - REG_CLK_N3 = 8'h2E, - REG_CLK_N2 = 8'h2F; +parameter REG_TESTYM = 8'h21, + REG_LFO = 8'h22, + REG_CLKA1 = 8'h24, + REG_CLKA2 = 8'h25, + REG_CLKB = 8'h26, + REG_TIMER = 8'h27, + REG_KON = 8'h28, + REG_IRQMASK = 8'h29, + REG_PCM = 8'h2A, + REG_PCM_EN = 8'h2B, + REG_DACTEST = 8'h2C, + REG_CLK_N6 = 8'h2D, + REG_CLK_N3 = 8'h2E, + REG_CLK_N2 = 8'h2F; -reg csm, effect; +reg csm, effect; reg [ 2:0] block_ch3op2, block_ch3op3, block_ch3op1; reg [10:0] fnum_ch3op2, fnum_ch3op3, fnum_ch3op1; -reg [ 5:0] latch_ch3op2, latch_ch3op3, latch_ch3op1; +reg [ 5:0] latch_fnum; reg [2:0] up_ch; reg [1:0] up_op; -`include "jt12_mmr_sim.vh" +reg old_write; +reg [7:0] din_copy; +always @(posedge clk) + old_write <= write; + +generate + if( use_ssg ) begin + assign psg_addr = selected_register[3:0]; + assign psg_data = din_copy; + end else begin + assign psg_addr = 4'd0; + assign psg_data = 8'd0; + end +endgenerate + +reg part; + +// this runs at clk speed, no clock gating here always @(posedge clk) begin : memory_mapped_registers - reg old_write; - old_write <= write; - - if( rst ) begin - selected_register <= 8'h0; - busy <= 1'b0; - up_ch <= 3'd0; - up_op <= 2'd0; - { up_keyon, up_alg, up_block, up_fnumlo, - up_pms, up_dt1, up_tl, up_ks_ar, - up_amen_d1r,up_d2r, up_d1l, up_ssgeg } <= 12'd0; - `ifdef TEST_SUPPORT - { test_eg, test_op0 } <= 2'd0; - `endif - // IRQ Mask - /*{ irq_zero_en, irq_brdy_en, irq_eos_en, - irq_tb_en, irq_ta_en } = 5'h1f; */ - // timers - { value_A, value_B } <= 18'd0; - { clr_flag_B, clr_flag_A, - enable_irq_B, enable_irq_A, load_B, load_A } <= 6'd0; - up_clr <= 1'b0; - fast_timers <= 1'b0; - // LFO - lfo_freq <= 3'd0; - lfo_en <= 1'b0; - csm <= 1'b0; - effect <= 1'b0; - // PCM - pcm <= 9'h0; - pcm_en <= 1'b0; - // sch <= 1'b0; - // Original test features - eg_stop <= 1'b0; - pg_stop <= 1'b0; - `ifdef SIMULATION - mmr_dump <= 1'b0; - `endif - end else begin - // WRITE IN REGISTERS - if( old_write ^ write ) begin - busy <= 1'b1; - if( !addr[0] ) begin - selected_register <= din; - up_ch <= {addr[1], din[1:0]}; - up_op <= din[3:2]; // 0=S1,1=S3,2=S2,3=S4 - end else begin - // Global registers - if( selected_register < 8'h30 ) begin - case( selected_register) - // registros especiales - //REG_TEST: lfo_rst <= 1'b1; // regardless of din - `ifdef TEST_SUPPORT - REG_TEST2: { mmr_dump, test_op0, test_eg } <= din[2:0]; - `endif - REG_TESTYM: begin - eg_stop <= din[5]; - pg_stop <= din[3]; - fast_timers <= din[2]; - end - REG_KON: up_keyon <= 1'b1; - REG_CLKA1: value_A[9:2]<= din; - REG_CLKA2: value_A[1:0]<= din[1:0]; - REG_CLKB: value_B <= din; - REG_TIMER: begin - effect <= |din[7:6]; - csm <= din[7:6] == 2'b10; - { clr_flag_B, clr_flag_A, - enable_irq_B, enable_irq_A, - load_B, load_A } <= din[5:0]; - end - REG_LFO: { lfo_en, lfo_freq } <= din[3:0]; - REG_DACTEST:pcm[0] <= din[3]; - REG_PCM: pcm[8:1]<= din; - REG_PCM_EN: pcm_en <= din[7]; - endcase - end - else if( selected_register[1:0]!=2'b11 ) begin - // channel registers - if( selected_register >= 8'hA0 ) begin - case( selected_register ) - 8'hA0, 8'hA1, 8'hA2: up_fnumlo <= 1'b1; - 8'hA4, 8'hA5, 8'hA6: up_block <= 1'b1; - // CH3 special registers - 8'hA9: { block_ch3op1, fnum_ch3op1 } <= { latch_ch3op1, din }; - 8'hA8: { block_ch3op3, fnum_ch3op3 } <= { latch_ch3op3, din }; - 8'hAA: { block_ch3op2, fnum_ch3op2 } <= { latch_ch3op2, din }; - 8'hAD: latch_ch3op1 <= din[5:0]; - 8'hAC: latch_ch3op3 <= din[5:0]; - 8'hAE: latch_ch3op2 <= din[5:0]; - // FB + Algorithm - 8'hB0, 8'hB1, 8'hB2: up_alg <= 1'b1; - 8'hB4, 8'hB5, 8'hB6: up_pms <= 1'b1; - endcase - end - else - // operator registers - begin - case( selected_register[7:4] ) - 4'h3: up_dt1 <= 1'b1; - 4'h4: up_tl <= 1'b1; - 4'h5: up_ks_ar <= 1'b1; - 4'h6: up_amen_d1r <= 1'b1; - 4'h7: up_d2r <= 1'b1; - 4'h8: up_d1l <= 1'b1; - 4'h9: up_ssgeg <= 1'b1; - endcase - end + if( rst ) begin + selected_register <= 8'h0; + div_setting <= 2'b11; + up_ch <= 3'd0; + up_op <= 2'd0; + up_keyon <= 1'd0; + up_opreg <= 7'd0; + up_chreg <= 3'd0; + // IRQ Mask + /*{ irq_zero_en, irq_brdy_en, irq_eos_en, + irq_tb_en, irq_ta_en } = 5'h1f; */ + // timers + { value_A, value_B } <= 18'd0; + { clr_flag_B, clr_flag_A, + enable_irq_B, enable_irq_A, load_B, load_A } <= 6'd0; + fast_timers <= 1'b0; + // LFO + lfo_freq <= 3'd0; + lfo_en <= 1'b0; + csm <= 1'b0; + effect <= 1'b0; + // PCM + pcm <= 9'h0; + pcm_en <= 1'b0; + pcm_wr <= 1'b0; + // sch <= 1'b0; + // Original test features + eg_stop <= 1'b0; + pg_stop <= 1'b0; + psg_wr_n <= 1'b1; + end else begin + // WRITE IN REGISTERS + if( write ) begin + if( !addr[0] ) begin + selected_register <= din; + part <= addr[1]; + end else begin + // Global registers + din_copy <= din; + up_keyon <= selected_register == REG_KON; + up_ch <= {part, selected_register[1:0]}; + up_op <= selected_register[3:2]; // 0=S1,1=S3,2=S2,3=S4 + casez( selected_register) + //REG_TEST: lfo_rst <= 1'b1; // regardless of din + 8'h0?: psg_wr_n <= 1'b0; + REG_TESTYM: begin + eg_stop <= din[5]; + pg_stop <= din[3]; + fast_timers <= din[2]; + end + REG_CLKA1: value_A[9:2]<= din; + REG_CLKA2: value_A[1:0]<= din[1:0]; + REG_CLKB: value_B <= din; + REG_TIMER: begin + effect <= |din[7:6]; + csm <= din[7:6] == 2'b10; + { clr_flag_B, clr_flag_A, + enable_irq_B, enable_irq_A, + load_B, load_A } <= din[5:0]; + end + `ifndef NOLFO + REG_LFO: { lfo_en, lfo_freq } <= din[3:0]; + `endif + // clock divider + REG_CLK_N6: div_setting[1] <= 1'b1; + REG_CLK_N3: div_setting[0] <= 1'b1; + REG_CLK_N2: div_setting <= 2'b0; + // CH3 special registers + 8'hA9: { block_ch3op1, fnum_ch3op1 } <= { latch_fnum, din }; + 8'hA8: { block_ch3op3, fnum_ch3op3 } <= { latch_fnum, din }; + 8'hAA: { block_ch3op2, fnum_ch3op2 } <= { latch_fnum, din }; + // According to http://www.mjsstuf.x10host.com/pages/vgmPlay/vgmPlay.htm + // There is a single fnum latch for all channels + 8'hA4, 8'hA5, 8'hA6, 8'hAD, 8'hAC, 8'hAE: latch_fnum <= din[5:0]; + default:; // avoid incomplete-case warning + endcase + if( use_pcm==1 ) begin // for YM2612 only + casez( selected_register) + REG_DACTEST: pcm[0] <= din[3]; + REG_PCM: + pcm <= { ~din[7], din[6:0], 1'b1 }; + REG_PCM_EN: pcm_en <= din[7]; + default:; + endcase + pcm_wr <= selected_register==REG_PCM; end - end - end - else begin /* clear once-only bits */ - // csm <= 1'b0; - // lfo_rst <= 1'b0; - { clr_flag_B, clr_flag_A, load_B, load_A } <= 4'd0; - `ifdef SIMULATION - mmr_dump <= 1'b0; - `endif - up_keyon <= 1'b0; - if( |{ up_keyon, up_alg, up_block, up_fnumlo, - up_pms, up_dt1, up_tl, up_ks_ar, - up_amen_d1r,up_d2r, up_d1l, up_ssgeg } == 1'b0 ) - busy <= 0; - else - busy <= 1'b1; - - if( busy_reg ) begin - up_clr <= 1'b1; - end - else begin - up_clr <= 1'b0; - if( up_clr ) - { up_alg, up_block, up_fnumlo, - up_pms, up_dt1, up_tl, up_ks_ar, - up_amen_d1r,up_d2r, up_d1l, up_ssgeg } <= 11'd0; - end - end - end + if( selected_register[1:0]==2'b11 ) + { up_chreg, up_opreg } <= { 3'h0, 7'h0 }; + else + casez( selected_register ) + // channel registers + 8'hA0, 8'hA1, 8'hA2: { up_chreg, up_opreg } <= { 3'h1, 7'd0 }; // up_fnumlo + // FB + Algorithm + 8'hB0, 8'hB1, 8'hB2: { up_chreg, up_opreg } <= { 3'h2, 7'd0 }; // up_alg + 8'hB4, 8'hB5, 8'hB6: { up_chreg, up_opreg } <= { 3'h4, 7'd0 }; // up_pms + // operator registers + 8'h3?: { up_chreg, up_opreg } <= { 3'h0, 7'h01 }; // up_dt1 + 8'h4?: { up_chreg, up_opreg } <= { 3'h0, 7'h02 }; // up_tl + 8'h5?: { up_chreg, up_opreg } <= { 3'h0, 7'h04 }; // up_ks_ar + 8'h6?: { up_chreg, up_opreg } <= { 3'h0, 7'h08 }; // up_amen_dr + 8'h7?: { up_chreg, up_opreg } <= { 3'h0, 7'h10 }; // up_sr + 8'h8?: { up_chreg, up_opreg } <= { 3'h0, 7'h20 }; // up_sl + 8'h9?: { up_chreg, up_opreg } <= { 3'h0, 7'h40 }; // up_ssgeg + default: { up_chreg, up_opreg } <= { 3'h0, 7'h0 }; + endcase // selected_register + end + end + else if(clk_en) begin /* clear once-only bits */ + // lfo_rst <= 1'b0; + { clr_flag_B, clr_flag_A } <= 2'd0; + psg_wr_n <= 1'b1; + pcm_wr <= 1'b0; + end + end end -jt12_reg u_reg( - .rst ( rst ), - .clk ( clk ), // P1 - .din ( din ), +reg [4:0] busy_cnt; // busy lasts for 32 synth clock cycles, like in real chip - .up_keyon ( up_keyon ), - .up_alg ( up_alg ), - .up_block ( up_block ), - .up_fnumlo ( up_fnumlo ), - .up_pms ( up_pms ), - .up_dt1 ( up_dt1 ), - .up_tl ( up_tl ), - .up_ks_ar ( up_ks_ar ), - .up_amen_d1r(up_amen_d1r), - .up_d2r ( up_d2r ), +always @(posedge clk) + if( rst ) begin + busy <= 1'b0; + busy_cnt <= 5'd0; + end + else begin + if (!old_write && write && addr[0] ) begin // only set for data writes + busy <= 1'b1; + busy_cnt <= 5'd0; + end + else if(clk_en) begin + if( busy_cnt == 5'd31 ) busy <= 1'b0; + busy_cnt <= busy_cnt+5'd1; + end + end - .up_d1l ( up_d1l ), - .up_ssgeg ( up_ssgeg ), +jt12_reg #(.num_ch(num_ch)) u_reg( + .rst ( rst ), + .clk ( clk ), // P1 + .clk_en ( clk_en ), + .din ( din_copy ), - .op ( up_op ), // operator to update - .ch ( up_ch ), // channel to update + .up_keyon ( up_keyon ), + .up_fnumlo ( up_chreg[0] ), + .up_alg ( up_chreg[1] ), + .up_pms ( up_chreg[2] ), + .up_dt1 ( up_opreg[0] ), + .up_tl ( up_opreg[1] ), + .up_ks_ar ( up_opreg[2] ), + .up_amen_dr ( up_opreg[3] ), + .up_sr ( up_opreg[4] ), + .up_sl_rr ( up_opreg[5] ), + .up_ssgeg ( up_opreg[6] ), - .csm ( csm ), - .flag_A ( flag_A ), - .overflow_A ( overflow_A), + .op ( up_op ), // operator to update + .ch ( up_ch ), // channel to update - .busy ( busy_reg ), - .ch6op ( ch6op ), - // CH3 Effect-mode operation - .effect ( effect ), // allows independent freq. for CH 3 - .fnum_ch3op2( fnum_ch3op2 ), - .fnum_ch3op3( fnum_ch3op3 ), - .fnum_ch3op1( fnum_ch3op1 ), - .block_ch3op2( block_ch3op2 ), - .block_ch3op3( block_ch3op3 ), - .block_ch3op1( block_ch3op1 ), - // Operator - .use_prevprev1(use_prevprev1), - .use_internal_x(use_internal_x), - .use_internal_y(use_internal_y), - .use_prev2 ( use_prev2 ), - .use_prev1 ( use_prev1 ), - // PG - .fnum_I ( fnum_I ), - .block_I ( block_I ), - .mul_V ( mul_V ), - .dt1_II ( dt1_II ), + .csm ( csm ), + .flag_A ( flag_A ), + .overflow_A ( overflow_A), - // EG - .ar_II (ar_II ), // attack rate - .d1r_II (d1r_II ), // decay rate - .d2r_II (d2r_II ), // sustain rate - .rr_II (rr_II ), // release rate - .d1l (d1l ), // sustain level - .ks_III (ks_III ), // key scale - // SSG operation - .ssg_en_II ( ssg_en_II ), - .ssg_eg_II ( ssg_eg_II ), - // envelope number - .tl_VII (tl_VII ), - .pms (pms ), - .ams_VII (ams_VII ), - .amsen_VII (amsen_VII ), - // channel configuration - .rl ( rl ), - .fb_II ( fb_II ), - .alg ( alg ), - .keyon_II ( keyon_II ), + .ch6op ( ch6op ), + // CH3 Effect-mode operation + .effect ( effect ), // allows independent freq. for CH 3 + .fnum_ch3op2( fnum_ch3op2 ), + .fnum_ch3op3( fnum_ch3op3 ), + .fnum_ch3op1( fnum_ch3op1 ), + .block_ch3op2( block_ch3op2 ), + .block_ch3op3( block_ch3op3 ), + .block_ch3op1( block_ch3op1 ), + .latch_fnum ( latch_fnum ), + // Operator + .xuse_prevprev1 ( xuse_prevprev1 ), + .xuse_internal ( xuse_internal ), + .yuse_internal ( yuse_internal ), + .xuse_prev2 ( xuse_prev2 ), + .yuse_prev1 ( yuse_prev1 ), + .yuse_prev2 ( yuse_prev2 ), + // PG + .fnum_I ( fnum_I ), + .block_I ( block_I ), + .mul_II ( mul_II ), + .dt1_I ( dt1_I ), - //.cur_op ( cur_op ), - .zero ( zero ), - .s1_enters ( s1_enters ), - .s2_enters ( s2_enters ), - .s3_enters ( s3_enters ), - .s4_enters ( s4_enters ) + // EG + .ar_I (ar_I ), // attack rate + .d1r_I (d1r_I ), // decay rate + .d2r_I (d2r_I ), // sustain rate + .rr_I (rr_I ), // release rate + .sl_I (sl_I ), // sustain level + .ks_II (ks_II ), // key scale + // SSG operation + .ssg_en_I ( ssg_en_I ), + .ssg_eg_I ( ssg_eg_I ), + // envelope number + .tl_IV (tl_IV ), + .pms_I (pms_I ), + .ams_IV (ams_IV ), + .amsen_IV (amsen_IV ), + // channel configuration + .rl ( rl ), + .fb_II ( fb_II ), + .alg_I ( alg_I ), + .keyon_I ( keyon_I ), + + .zero ( zero ), + .s1_enters ( s1_enters ), + .s2_enters ( s2_enters ), + .s3_enters ( s3_enters ), + .s4_enters ( s4_enters ) ); endmodule diff --git a/rtl/sound/jt12/jt12_mmr_sim.vh b/rtl/sound/jt12/jt12_mmr_sim.vh index 5bddb08..96d60d8 100644 --- a/rtl/sound/jt12/jt12_mmr_sim.vh +++ b/rtl/sound/jt12/jt12_mmr_sim.vh @@ -1,9 +1,10 @@ `ifdef SIMULATION +/* verilator lint_off PINMISSING */ reg [4:0] sep24_cnt; reg mmr_dump; -always @(posedge clk ) +always @(posedge clk ) if(clk_en) sep24_cnt <= !zero ? sep24_cnt+1'b1 : 5'd0; wire [10:0] fnum_ch0s1, fnum_ch1s1, fnum_ch2s1, fnum_ch3s1, @@ -16,8 +17,9 @@ wire [10:0] fnum_ch0s1, fnum_ch1s1, fnum_ch2s1, fnum_ch3s1, sep24 #( .width(11), .pos0(1) ) fnum_sep ( .clk ( clk ), + .clk_en ( clk_en ), .mixed ( fnum_I ), - .mask ( 11'd0 ), + .mask ( 24'd0 ), .cnt ( sep24_cnt ), .ch0s1 (fnum_ch0s1), @@ -59,8 +61,9 @@ wire [2:0] block_ch0s1, block_ch1s1, block_ch2s1, block_ch3s1, sep24 #( .width(3), .pos0(1) ) block_sep ( .clk ( clk ), + .clk_en ( clk_en ), .mixed ( block_I ), - .mask ( 3'd0 ), + .mask ( 24'd0 ), .cnt ( sep24_cnt ), .ch0s1 (block_ch0s1), @@ -102,8 +105,9 @@ wire [1:0] rl_ch0s1, rl_ch1s1, rl_ch2s1, rl_ch3s1, sep24 #( .width(2), .pos0(1) ) rl_sep ( .clk ( clk ), + .clk_en ( clk_en ), .mixed ( rl ), - .mask ( 2'd0 ), + .mask ( 24'd0 ), .cnt ( sep24_cnt ), .ch0s1 (rl_ch0s1), @@ -145,8 +149,9 @@ wire [2:0] fb_ch0s1, fb_ch1s1, fb_ch2s1, fb_ch3s1, sep24 #( .width(3), .pos0(0) ) fb_sep ( .clk ( clk ), + .clk_en ( clk_en ), .mixed ( fb_II ), - .mask ( 3'd0 ), + .mask ( 24'd0 ), .cnt ( sep24_cnt ), .ch0s1 (fb_ch0s1), @@ -188,8 +193,9 @@ wire [2:0] alg_ch0s1, alg_ch1s1, alg_ch2s1, alg_ch3s1, sep24 #( .width(3), .pos0(1) ) alg_sep ( .clk ( clk ), + .clk_en ( clk_en ), .mixed ( alg ), - .mask ( 3'd0 ), + .mask ( 24'd0 ), .cnt ( sep24_cnt ), .ch0s1 (alg_ch0s1), @@ -231,8 +237,9 @@ wire [2:0] dt1_ch0s1, dt1_ch1s1, dt1_ch2s1, dt1_ch3s1, sep24 #( .width(3), .pos0(0) ) dt1_sep ( .clk ( clk ), + .clk_en ( clk_en ), .mixed ( dt1_II ), - .mask ( 3'd0 ), + .mask ( 24'd0 ), .cnt ( sep24_cnt ), .ch0s1 (dt1_ch0s1), @@ -274,8 +281,9 @@ wire [3:0] mul_ch0s1, mul_ch1s1, mul_ch2s1, mul_ch3s1, sep24 #( .width(4), .pos0(21) ) mul_sep ( .clk ( clk ), + .clk_en ( clk_en ), .mixed ( mul_V ), - .mask ( 4'd0 ), + .mask ( 24'd0 ), .cnt ( sep24_cnt ), .ch0s1 (mul_ch0s1), @@ -314,11 +322,12 @@ wire [6:0] tl_ch0s1, tl_ch1s1, tl_ch2s1, tl_ch3s1, tl_ch4s3, tl_ch5s3, tl_ch0s4, tl_ch1s4, tl_ch2s4, tl_ch3s4, tl_ch4s4, tl_ch5s4; -sep24 #( .width(7), .pos0(19) ) tl_step +sep24 #( .width(7), .pos0(22) ) tl_step ( .clk ( clk ), - .mixed ( tl_VII ), - .mask ( 7'd0 ), + .clk_en ( clk_en ), + .mixed ( tl_IV ), + .mask ( 24'd0 ), .cnt ( sep24_cnt ), .ch0s1 (tl_ch0s1), @@ -357,11 +366,12 @@ wire [4:0] ar_ch0s1, ar_ch1s1, ar_ch2s1, ar_ch3s1, ar_ch4s3, ar_ch5s3, ar_ch0s4, ar_ch1s4, ar_ch2s4, ar_ch3s4, ar_ch4s4, ar_ch5s4; -sep24 #( .width(5), .pos0(0) ) ar_step +sep24 #( .width(5), .pos0(1) ) ar_step ( .clk ( clk ), - .mixed ( ar_II ), - .mask ( 5'd0 ), + .clk_en ( clk_en ), + .mixed ( ar_I ), + .mask ( 24'd0 ), .cnt ( sep24_cnt ), .ch0s1 (ar_ch0s1), @@ -400,11 +410,12 @@ wire [4:0] d1r_ch0s1, d1r_ch1s1, d1r_ch2s1, d1r_ch3s1, d1r_ch4s3, d1r_ch5s3, d1r_ch0s4, d1r_ch1s4, d1r_ch2s4, d1r_ch3s4, d1r_ch4s4, d1r_ch5s4; -sep24 #( .width(5), .pos0(0) ) d1r_step +sep24 #( .width(5), .pos0(1) ) d1r_step ( .clk ( clk ), - .mixed ( d1r_II ), - .mask ( 0 ), + .clk_en ( clk_en ), + .mixed ( d1r_I ), + .mask ( 24'd0 ), .cnt ( sep24_cnt ), .ch0s1 (d1r_ch0s1), @@ -443,11 +454,12 @@ wire [4:0] d2r_ch0s1, d2r_ch1s1, d2r_ch2s1, d2r_ch3s1, d2r_ch4s3, d2r_ch5s3, d2r_ch0s4, d2r_ch1s4, d2r_ch2s4, d2r_ch3s4, d2r_ch4s4, d2r_ch5s4; -sep24 #( .width(5), .pos0(0) ) d2r_step +sep24 #( .width(5), .pos0(1) ) d2r_step ( .clk ( clk ), - .mixed ( d2r_II ), - .mask ( 5'd0 ), + .clk_en ( clk_en ), + .mixed ( d2r_I ), + .mask ( 24'd0 ), .cnt ( sep24_cnt ), .ch0s1 (d2r_ch0s1), @@ -486,11 +498,12 @@ wire [3:0] rr_ch0s1, rr_ch1s1, rr_ch2s1, rr_ch3s1, rr_ch4s3, rr_ch5s3, rr_ch0s4, rr_ch1s4, rr_ch2s4, rr_ch3s4, rr_ch4s4, rr_ch5s4; -sep24 #( .width(4), .pos0(0) ) rr_step +sep24 #( .width(4), .pos0(1) ) rr_step ( .clk ( clk ), - .mixed ( rr_II ), - .mask ( 0 ), + .clk_en ( clk_en ), + .mixed ( rr_I ), + .mask ( 24'd0 ), .cnt ( sep24_cnt ), .ch0s1 (rr_ch0s1), @@ -532,8 +545,9 @@ wire [3:0] d1l_ch0s1, d1l_ch1s1, d1l_ch2s1, d1l_ch3s1, sep24 #( .width(4), .pos0(1) ) d1l_step ( .clk ( clk ), - .mixed ( d1l ), - .mask ( 4'd0 ), + .clk_en ( clk_en ), + .mixed ( sl_I ), + .mask ( 24'd0 ), .cnt ( sep24_cnt ), .ch0s1 (d1l_ch0s1), @@ -572,11 +586,12 @@ wire [1:0] ks_ch0s1, ks_ch1s1, ks_ch2s1, ks_ch3s1, ks_ch4s3, ks_ch5s3, ks_ch0s4, ks_ch1s4, ks_ch2s4, ks_ch3s4, ks_ch4s4, ks_ch5s4; -sep24 #( .width(2), .pos0(23) ) ks_step +sep24 #( .width(2), .pos0(0) ) ks_step ( .clk ( clk ), - .mixed ( ks_III ), - .mask ( 0 ), + .clk_en ( clk_en ), + .mixed ( ks_II ), + .mask ( 24'd0 ), .cnt ( sep24_cnt ), .ch0s1 (ks_ch0s1), @@ -608,7 +623,7 @@ sep24 #( .width(2), .pos0(23) ) ks_step .ch5s4 (ks_ch5s4) ); -wire [3:0] ssg_II = {ssg_en_II, ssg_eg_II}; +wire [3:0] ssg_I = {ssg_en_I, ssg_eg_I}; wire [3:0] ssg_ch0s1, ssg_ch1s1, ssg_ch2s1, ssg_ch3s1, ssg_ch4s1, ssg_ch5s1, ssg_ch0s2, ssg_ch1s2, @@ -617,11 +632,12 @@ wire [3:0] ssg_ch0s1, ssg_ch1s1, ssg_ch2s1, ssg_ch3s1, ssg_ch4s3, ssg_ch5s3, ssg_ch0s4, ssg_ch1s4, ssg_ch2s4, ssg_ch3s4, ssg_ch4s4, ssg_ch5s4; -sep24 #( .width(4), .pos0(0) ) ssg_step +sep24 #( .width(4), .pos0(1) ) ssg_step ( .clk ( clk ), - .mixed ( ssg_II ), - .mask ( 4'd0 ), + .clk_en ( clk_en ), + .mixed ( ssg_I ), + .mask ( 24'd0 ), .cnt ( sep24_cnt ), .ch0s1 (ssg_ch0s1), @@ -660,11 +676,12 @@ wire kon_ch0s1, kon_ch1s1, kon_ch2s1, kon_ch3s1, kon_ch4s3, kon_ch5s3, kon_ch0s4, kon_ch1s4, kon_ch2s4, kon_ch3s4, kon_ch4s4, kon_ch5s4; -sep24 #( .width(1), .pos0(0) ) konstep +sep24 #( .width(1), .pos0(1) ) konstep ( .clk ( clk ), - .mixed ( keyon_II ), - .mask ( 1'd0 ), + .clk_en ( clk_en ), + .mixed ( keyon_I ), + .mask ( 24'd0 ), .cnt ( sep24_cnt ), .ch0s1 (kon_ch0s1), @@ -699,7 +716,7 @@ sep24 #( .width(1), .pos0(0) ) konstep /* Dump all registers on request */ integer fmmr; initial begin - fmmr=$fopen("mmr_dump.log"); + fmmr=$fopen("mmr_dump.log","w"); end always @(posedge clk ) @@ -832,5 +849,6 @@ if (mmr_dump ) begin d2r_ch5s4, rr_ch5s4, d1l_ch5s4, ks_ch5s4, ssg_ch5s4, kon_ch5s4 ); end +/* verilator lint_on PINMISSING */ `endif diff --git a/rtl/sound/jt12/jt12_mod.v b/rtl/sound/jt12/jt12_mod.v index 9e41603..a057f8f 100644 --- a/rtl/sound/jt12/jt12_mod.v +++ b/rtl/sound/jt12/jt12_mod.v @@ -4,119 +4,152 @@ /* This file is part of JT12. - JT12 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. + JT12 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. - JT12 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. + JT12 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 JT12. If not, see . + You should have received a copy of the GNU General Public License + along with JT12. If not, see . - Author: Jose Tejada Gomez. Twitter: @topapate - Version: 1.0 - Date: 27-1-2017 + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 27-1-2017 */ module jt12_mod( - input s1_enters, - input s2_enters, - input s3_enters, - input s4_enters, + input s1_enters, + input s2_enters, + input s3_enters, + input s4_enters, input [2:0] alg_I, - output reg use_prevprev1, - output reg use_internal_x, - output reg use_internal_y, - output reg use_prev2, - output reg use_prev1 + output reg xuse_prevprev1, + output reg xuse_internal, + output reg yuse_internal, + output reg xuse_prev2, + output reg yuse_prev1, + output reg yuse_prev2 ); +parameter num_ch=6; + reg [7:0] alg_hot; always @(*) begin - case( alg_I ) - 3'd0: alg_hot <= 8'h1; // D0 - 3'd1: alg_hot <= 8'h2; // D1 - 3'd2: alg_hot <= 8'h4; // D2 - 3'd3: alg_hot <= 8'h8; // D3 - 3'd4: alg_hot <= 8'h10; // D4 - 3'd5: alg_hot <= 8'h20; // D5 - 3'd6: alg_hot <= 8'h40; // D6 - 3'd7: alg_hot <= 8'h80; // D7 - endcase + case( alg_I ) + 3'd0: alg_hot = 8'h1; // D0 + 3'd1: alg_hot = 8'h2; // D1 + 3'd2: alg_hot = 8'h4; // D2 + 3'd3: alg_hot = 8'h8; // D3 + 3'd4: alg_hot = 8'h10; // D4 + 3'd5: alg_hot = 8'h20; // D5 + 3'd6: alg_hot = 8'h40; // D6 + 3'd7: alg_hot = 8'h80; // D7 + endcase end -always @(*) begin - use_prevprev1 <= s1_enters | (s3_enters&alg_hot[5]); - use_prev2 <= (s3_enters&(|alg_hot[2:0])) | (s4_enters&alg_hot[3]); - use_internal_x <= s4_enters & alg_hot[2]; - use_internal_y <= s4_enters & (|{alg_hot[4:3],alg_hot[1:0]}); - use_prev1 <= s1_enters | (s3_enters&alg_hot[1]) | - (s2_enters&(|{alg_hot[6:3],alg_hot[0]}) )| - (s4_enters&(|{alg_hot[5],alg_hot[2]})); -end +// prev2 cannot modulate with prevprev1 at the same time +// x = prev2, prevprev1, internal_x +// y = prev1, internal_y -/* -always @(*) begin - use_prevprev1 <= s1_enters || (s3_enters&&(alg_I==3'd5)); - use_prev2 <= (s3_enters&&(alg_I<=3'd2)) || (s4_enters&&(alg_I==3'd3)); - use_internal_x <= s4_enters && (alg_I==3'd2); - use_internal_y <= s4_enters && (alg_I<=3'd4 && alg_I!=3'd2); - use_prev1 <= s1_enters || (s3_enters&&(alg_I==3'd1)) || - (s2_enters&&(alg_I==3'd0 || - alg_I==3'd3 || alg_I==3'd4 || - alg_I==3'd5 || alg_I==3'd6)) || - (s4_enters&&(alg_I==3'd2 || alg_I==3'd5)); -end +generate + if( num_ch==6 ) begin + always @(*) begin + xuse_prevprev1 = s1_enters | (s3_enters&alg_hot[5]); + xuse_prev2 = (s3_enters&(|alg_hot[2:0])) | (s4_enters&alg_hot[3]); + xuse_internal = s4_enters & alg_hot[2]; + yuse_internal = s4_enters & (|{alg_hot[4:3],alg_hot[1:0]}); + yuse_prev1 = s1_enters | (s3_enters&alg_hot[1]) | + (s2_enters&(|{alg_hot[6:3],alg_hot[0]}) )| + (s4_enters&(|{alg_hot[5],alg_hot[2]})); + yuse_prev2 = 1'b0; // unused for 6 channels + end + end else begin + reg [2:0] xuse_s4, xuse_s3, xuse_s2, xuse_s1; + reg [2:0] yuse_s4, yuse_s3, yuse_s2, yuse_s1; + always @(*) begin // 3 ch + // S1 + { xuse_s1, yuse_s1 } = { 3'b001, 3'b100 }; + // S2 + casez( 1'b1 ) + // S2 modulated by S1 + alg_hot[6], alg_hot[5], alg_hot[4], alg_hot[3], alg_hot[0]: + { xuse_s2, yuse_s2 } = { 3'b000, 3'b100 }; // prev1 + default: { xuse_s2, yuse_s2 } = 6'd0; + endcase + // S3 + casez( 1'b1 ) + // S3 modulated by S1 + alg_hot[5]: + { xuse_s3, yuse_s3 } = { 3'b000, 3'b100 }; // prev1 + // S3 modulated by S2 + alg_hot[2], alg_hot[0]: + { xuse_s3, yuse_s3 } = { 3'b000, 3'b010 }; // prev2 + // S3 modulated by S2+S1 + alg_hot[1]: + { xuse_s3, yuse_s3 } = { 3'b010, 3'b100 }; // prev2 + prev1 + default: { xuse_s3, yuse_s3 } = 6'd0; + endcase + // S4 + casez( 1'b1 ) + // S4 modulated by S1 + alg_hot[5]: + { xuse_s4, yuse_s4 } = { 3'b000, 3'b100 }; // prev1 + // S4 modulated by S3 + alg_hot[4], alg_hot[1], alg_hot[0]: + { xuse_s4, yuse_s4 } = { 3'b100, 3'b000 }; // prevprev1 + // S4 modulated by S3+S2 + alg_hot[3]: + { xuse_s4, yuse_s4 } = { 3'b100, 3'b010 }; // prevprev1+prev2 + // S4 modulated by S3+S1 + alg_hot[2]: + { xuse_s4, yuse_s4 } = { 3'b100, 3'b100 }; // prevprev1+prev1 + default: { xuse_s4, yuse_s4 } = 6'd0; + endcase + case( {s4_enters, s3_enters, s2_enters, s1_enters}) + 4'b1000: begin + {xuse_prevprev1, xuse_prev2, xuse_internal} = xuse_s4; + {yuse_prev1, yuse_prev2, yuse_internal } = yuse_s4; + end + 4'b0100: begin + {xuse_prevprev1, xuse_prev2, xuse_internal} = xuse_s3; + {yuse_prev1, yuse_prev2, yuse_internal } = yuse_s3; + end + 4'b0010: begin + {xuse_prevprev1, xuse_prev2, xuse_internal} = xuse_s2; + {yuse_prev1, yuse_prev2, yuse_internal } = yuse_s2; + end + 4'b0001: begin + {xuse_prevprev1, xuse_prev2, xuse_internal} = xuse_s1; + {yuse_prev1, yuse_prev2, yuse_internal } = yuse_s1; + end + default: begin + {xuse_prevprev1, xuse_prev2, xuse_internal} = 3'b0; + {yuse_prev1, yuse_prev2, yuse_internal } = 3'b0; + end + endcase + end + end +endgenerate -always @(*) begin -case( {s1_enters, s3_enters, s2_enters, s4_enters} ) // synthesis parallel_case - 4'b1000: begin // S1 - use_prevprev1 <= 1'b1; - use_prev2 <= 1'b0; - use_internal_x<= 1'b0; - use_internal_y<= 1'b0; - use_prev1 <= 1'b1; - end - 4'b0100: begin // S3 - use_prevprev1 <= alg_I==3'd5; - use_prev2 <= (alg_I<=3'd2); - use_internal_x<= 1'b0; - use_internal_y<= 1'b0; - use_prev1 <= alg_I==3'd1; - end - 4'b0010: begin // S2 - use_prevprev1 <= 1'b0; - use_prev2 <= 1'b0; - use_internal_x<= 1'b0; - use_prev1 <= (alg_I==3'd0 || - alg_I==3'd3 || alg_I==3'd4 || - alg_I==3'd5 || alg_I==3'd6 ); - use_internal_y<= 1'b0; - end - 4'b0001: begin // S4 - use_prevprev1 <= 1'b0; - use_prev2 <= ( alg_I==3'd3 ); - use_internal_x <= alg_I==3'd2; - use_prev1 <= (alg_I==3'd2 || alg_I==3'd5); - use_internal_y <= ( alg_I<=3'd4 && alg_I!=3'd2); - end - default:begin - use_prevprev1 <= 1'bx; - use_prev2 <= 1'bx; - use_internal_x<= 1'bx; - use_prev1 <= 1'bx; - use_internal_y<= 1'bx; - end - endcase -end -*/ +`ifdef SIMULATION +// Control signals for simulation: should be 2'b0 or 2'b1 +wire [1:0] xusage = xuse_prevprev1+xuse_prev2+xuse_internal; +wire [1:0] yusage = yuse_prev1+yuse_internal; + +always @(xusage,yusage) + if( xusage>2'b1 || yusage>2'b1 ) begin + $display("ERROR: x/y over use in jt12_mod"); + $finish; + end +`endif endmodule diff --git a/rtl/sound/jt12/jt12_op.v b/rtl/sound/jt12/jt12_op.v index 9dfd931..c9a406e 100644 --- a/rtl/sound/jt12/jt12_op.v +++ b/rtl/sound/jt12/jt12_op.v @@ -4,121 +4,140 @@ /* This file is part of JT12. - JT12 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. + JT12 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. - JT12 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. + JT12 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 JT12. If not, see . + You should have received a copy of the GNU General Public License + along with JT12. If not, see . - Based on Sauraen VHDL version of OPN/OPN2, which is based on die shots. + Based on Sauraen VHDL version of OPN/OPN2, which is based on die shots. - Author: Jose Tejada Gomez. Twitter: @topapate - Version: 1.0 - Date: 27-1-2017 + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 27-1-2017 */ module jt12_op( - input rst, - input clk, - input [9:0] pg_phase_VIII, - input [9:0] eg_atten_IX, // output from envelope generator - input [2:0] fb_II, // voice feedback - input use_prevprev1, - input use_internal_x, - input use_internal_y, - input use_prev2, - input use_prev1, - input test_214, - - input s1_enters, - input s2_enters, - input s3_enters, - input s4_enters, - input zero, + input rst, + input clk, + input clk_en, + input [9:0] pg_phase_VIII, + input [9:0] eg_atten_IX, // output from envelope generator + input [2:0] fb_II, // voice feedback + input xuse_prevprev1, + input xuse_prev2, + input xuse_internal, + input yuse_prev1, + input yuse_prev2, + input yuse_internal, + input test_214, - output signed [8:0] op_result + input s1_enters, + input s2_enters, + input s3_enters, + input s4_enters, + input zero, + + output signed [ 8:0] op_result, + output signed [13:0] full_result ); -/* enters exits - S1 S2 - S3 S4 - S2 S1 - S4 S3 +/* enters exits + S1 S2 + S3 S4 + S2 S1 + S4 S3 */ -reg [13:0] op_result_internal, op_XII; -reg [11:0] atten_internal_IX; +reg [13:0] op_result_internal, op_XII; +reg [11:0] atten_internal_IX; -assign op_result = op_result_internal[13:5]; +assign op_result = op_result_internal[13:5]; +assign full_result = op_result_internal; -parameter NUM_VOICES = 6; +parameter num_ch = 6; -reg signbit_IX, signbit_X, signbit_XI; -reg [11:0] totalatten_X; +reg signbit_IX, signbit_X, signbit_XI; +reg [11:0] totalatten_X; -wire [13:0] prev1, prevprev1, prev2; +wire [13:0] prev1, prevprev1, prev2; -jt12_sh/*_rst*/ #( .width(14), .stages(NUM_VOICES)) prev1_buffer( -// .rst ( rst ), - .clk ( clk ), - .din ( s2_enters ? op_result_internal : prev1 ), - .drop ( prev1 ) +reg [13:0] prev1_din, prevprev1_din, prev2_din; + +always @(*) + if( num_ch==3 ) begin + prev1_din = s1_enters ? op_result_internal : prev1; + prevprev1_din = s3_enters ? op_result_internal : prevprev1; + prev2_din = s2_enters ? op_result_internal : prev2; + end else begin // 6 channels + prev1_din = s2_enters ? op_result_internal : prev1; + prevprev1_din = s2_enters ? prev1 : prevprev1; + prev2_din = s1_enters ? op_result_internal : prev2; + end + +jt12_sh #( .width(14), .stages(num_ch)) prev1_buffer( +// .rst ( rst ), + .clk ( clk ), + .clk_en ( clk_en ), + .din ( prev1_din ), + .drop ( prev1 ) ); -jt12_sh/*_rst*/ #( .width(14), .stages(NUM_VOICES)) prevprev1_buffer( -// .rst ( rst ), - .clk ( clk ), - .din ( s2_enters ? prev1 : prevprev1 ), - .drop ( prevprev1 ) +jt12_sh #( .width(14), .stages(num_ch)) prevprev1_buffer( +// .rst ( rst ), + .clk ( clk ), + .clk_en ( clk_en ), + .din ( prevprev1_din ), + .drop ( prevprev1 ) ); -jt12_sh/*_rst*/ #( .width(14), .stages(NUM_VOICES)) prev2_buffer( -// .rst ( rst ), - .clk ( clk ), - .din ( s1_enters ? op_result_internal : prev2 ), - .drop ( prev2 ) +jt12_sh #( .width(14), .stages(num_ch)) prev2_buffer( +// .rst ( rst ), + .clk ( clk ), + .clk_en ( clk_en ), + .din ( prev2_din ), + .drop ( prev2 ) ); -reg [18:0] stb; -reg [10:0] stf, stg; -reg [11:0] logsin; -reg [10:0] subtresult; +reg [10:0] subtresult; -reg [12:0] etb; -reg [ 9:0] etf, etg, mantissa_XI; -reg [ 3:0] exponent_XI; - -reg [12:0] shifter, shifter_2, shifter_3; +reg [12:0] shifter, shifter_2, shifter_3; // REGISTER/CYCLE 1 // Creation of phase modulation (FM) feedback signal, before shifting reg [13:0] x, y; -reg [14:0] xs, ys, pm_preshift_II; -reg s1_II; +reg [14:0] xs, ys, pm_preshift_II; +reg s1_II; always @(*) begin - - x <= ( {14{use_prevprev1}} & prevprev1 ) | - ( {14{use_internal_x}} & op_result_internal ) | - ( {14{use_prev2}} & prev2 ); - y <= ( {14{use_prev1}} & prev1 ) | - ( {14{use_internal_y}} & op_result_internal ); - xs <= { x[13], x }; // sign-extend - ys <= { y[13], y }; // sign-extend + casez( {xuse_prevprev1, xuse_prev2, xuse_internal }) + 3'b1??: x = prevprev1; + 3'b01?: x = prev2; + 3'b001: x = op_result_internal; + default: x = 14'd0; + endcase + casez( {yuse_prev1, yuse_prev2, yuse_internal }) + 3'b1??: y = prev1; + 3'b01?: y = prev2; + 3'b001: y = op_result_internal; + default: y = 14'd0; + endcase + xs = { x[13], x }; // sign-extend + ys = { y[13], y }; // sign-extend end -always @(posedge clk) begin - pm_preshift_II <= xs + ys; // carry is discarded +always @(posedge clk) if( clk_en ) begin + pm_preshift_II <= xs + ys; // carry is discarded s1_II <= s1_enters; end @@ -129,407 +148,357 @@ end are 6 cycles worth of registers between the generated (non-registered) phasemod_II signal and the input to add_pg_phase. */ -reg [9:0] phasemod_II; -wire [9:0] phasemod_VIII; +reg [9:0] phasemod_II; +wire [9:0] phasemod_VIII; always @(*) begin - // Shift FM feedback signal - if (!s1_II ) // Not S1 - phasemod_II <= pm_preshift_II[10:1]; // Bit 0 of pm_preshift_II is never used - else // S1 - case( fb_II ) - 3'd0: phasemod_II <= 10'd0; - 3'd1: phasemod_II <= { {4{pm_preshift_II[14]}}, pm_preshift_II[14:9] }; - 3'd2: phasemod_II <= { {3{pm_preshift_II[14]}}, pm_preshift_II[14:8] }; - 3'd3: phasemod_II <= { {2{pm_preshift_II[14]}}, pm_preshift_II[14:7] }; - 3'd4: phasemod_II <= { pm_preshift_II[14], pm_preshift_II[14:6] }; - 3'd5: phasemod_II <= pm_preshift_II[14:5]; - 3'd6: phasemod_II <= pm_preshift_II[13:4]; - 3'd7: phasemod_II <= pm_preshift_II[12:3]; - endcase + // Shift FM feedback signal + if (!s1_II ) // Not S1 + phasemod_II = pm_preshift_II[10:1]; // Bit 0 of pm_preshift_II is never used + else // S1 + case( fb_II ) + 3'd0: phasemod_II = 10'd0; + 3'd1: phasemod_II = { {4{pm_preshift_II[14]}}, pm_preshift_II[14:9] }; + 3'd2: phasemod_II = { {3{pm_preshift_II[14]}}, pm_preshift_II[14:8] }; + 3'd3: phasemod_II = { {2{pm_preshift_II[14]}}, pm_preshift_II[14:7] }; + 3'd4: phasemod_II = { pm_preshift_II[14], pm_preshift_II[14:6] }; + 3'd5: phasemod_II = pm_preshift_II[14:5]; + 3'd6: phasemod_II = pm_preshift_II[13:4]; + 3'd7: phasemod_II = pm_preshift_II[12:3]; + endcase end // REGISTER/CYCLE 2-7 -jt12_sh #( .width(10), .stages(NUM_VOICES)) phasemod_sh( - .clk ( clk ), - .din ( phasemod_II ), - .drop ( phasemod_VIII ) -); +//generate +// if( num_ch==6 ) + jt12_sh #( .width(10), .stages(6)) phasemod_sh( + .clk ( clk ), + .clk_en ( clk_en), + .din ( phasemod_II ), + .drop ( phasemod_VIII ) + ); +// else begin +// assign phasemod_VIII = phasemod_II; +// end +// endgenerate // REGISTER/CYCLE 8 -reg [ 9:0] phase; +reg [ 9:0] phase; // Sets the maximum number of fanouts for a register or combinational // cell. The Quartus II software will replicate the cell and split // the fanouts among the duplicates until the fanout of each cell // is below the maximum. -reg [ 7:0] phaselo_IX, aux_VIII; +reg [ 7:0] aux_VIII; always @(*) begin - phase <= phasemod_VIII + pg_phase_VIII; - aux_VIII<= phase[7:0] ^ {8{~phase[8]}}; + phase = phasemod_VIII + pg_phase_VIII; + aux_VIII= phase[7:0] ^ {8{~phase[8]}}; end -always @(posedge clk) begin - phaselo_IX <= aux_VIII; - signbit_IX <= phase[9]; - +always @(posedge clk) if( clk_en ) begin + signbit_IX <= phase[9]; end -wire [45:0] sta_IX; +wire [11:0] logsin_IX; + +jt12_logsin u_logsin ( + .clk ( clk ), + .clk_en ( clk_en ), + .addr ( aux_VIII[7:0] ), + .logsin ( logsin_IX ) +); -jt12_phrom u_phrom( - .clk ( clk ), - .addr ( aux_VIII[5:1] ), - .ph ( sta_IX ) -); // REGISTER/CYCLE 9 // Sine table // Main sine table body - always @(*) begin - //sta_IX <= sinetable[ phaselo_IX[5:1] ]; - // 2-bit row chooser - case( phaselo_IX[7:6] ) - 2'b00: stb <= { 10'b0, sta_IX[29], sta_IX[25], 2'b0, sta_IX[18], - sta_IX[14], 1'b0, sta_IX[7] , sta_IX[3] }; - 2'b01: stb <= { 6'b0 , sta_IX[37], sta_IX[34], 2'b0, sta_IX[28], - sta_IX[24], 2'b0, sta_IX[17], sta_IX[13], sta_IX[10], sta_IX[6], sta_IX[2] }; - 2'b10: stb <= { 2'b0, sta_IX[43], sta_IX[41], 2'b0, sta_IX[36], - sta_IX[33], 2'b0, sta_IX[27], sta_IX[23], 1'b0, sta_IX[20], - sta_IX[16], sta_IX[12], sta_IX[9], sta_IX[5], sta_IX[1] }; - default: stb <= { - sta_IX[45], sta_IX[44], sta_IX[42], sta_IX[40] - , sta_IX[39], sta_IX[38], sta_IX[35], sta_IX[32] - , sta_IX[31], sta_IX[30], sta_IX[26], sta_IX[22] - , sta_IX[21], sta_IX[19], sta_IX[15], sta_IX[11] - , sta_IX[8], sta_IX[4], sta_IX[0] }; - endcase - // Fixed value to sum - stf <= { stb[18:15], stb[12:11], stb[8:7], stb[4:3], stb[0] }; - // Gated value to sum; bit 14 is indeed used twice - if( phaselo_IX[0] ) - stg <= { 2'b0, stb[14], stb[14:13], stb[10:9], stb[6:5], stb[2:1] }; - else - stg <= 11'd0; - // Sum to produce final logsin value - logsin <= stf + stg; // Carry-out of 11-bit addition becomes 12th bit - // Invert-subtract logsin value from EG attenuation value, with inverted carry - // In the actual chip, the output of the above logsin sum is already inverted. - // The two LSBs go through inverters (so they're non-inverted); the eg_atten_IX signal goes through inverters. - // The adder is normal except the carry-in is 1. It's a 10-bit adder. - // The outputs are inverted outputs, including the carry bit. - //subtresult <= not (('0' & not eg_atten_IX) - ('1' & logsin([11:2]))); - // After a little pencil-and-paper, turns out this is equivalent to a regular adder! - subtresult <= eg_atten_IX + logsin[11:2]; - // Place all but carry bit into result; also two LSBs of logsin - // If addition overflowed, make it the largest value (saturate) - atten_internal_IX <= { subtresult[9:0], logsin[1:0] } | {12{subtresult[10]}}; + subtresult = eg_atten_IX + logsin_IX[11:2]; + atten_internal_IX = { subtresult[9:0], logsin_IX[1:0] } | {12{subtresult[10]}}; end -wire [44:0] exp_X; +wire [9:0] mantissa_X; +reg [9:0] mantissa_XI; +reg [3:0] exponent_X, exponent_XI; jt12_exprom u_exprom( - .clk ( clk ), - .addr ( atten_internal_IX[5:1] ), - .exp ( exp_X ) + .clk ( clk ), + .clk_en ( clk_en ), + .addr ( atten_internal_IX[7:0] ), + .exp ( mantissa_X ) ); -always @(posedge clk) begin - totalatten_X <= atten_internal_IX; - signbit_X <= signbit_IX; +always @(posedge clk) if( clk_en ) begin + exponent_X <= atten_internal_IX[11:8]; + signbit_X <= signbit_IX; end -//wire [1:0] et_sel = totalatten_X[7:6]; -//wire [4:0] et_fine = totalatten_X[5:1]; - -// REGISTER/CYCLE 10 -// Exponential table -// Main sine table body -always @(*) begin - //eta <= explut_jt51[ totalatten_X[5:1] ]; - // 2-bit row chooser - case( totalatten_X[7:6] ) - 2'b00: begin - etf <= { 1'b1, exp_X[44:36] }; - etg <= { 1'b1, exp_X[35:34] }; - end - 2'b01: begin - etf <= exp_X[33:24]; - etg <= { 2'b10, exp_X[23] }; - end - 2'b10: begin - etf <= { 1'b0, exp_X[22:14] }; - etg <= exp_X[13:11]; - end - 2'b11: begin - etf <= { 2'b00, exp_X[10:3] }; - etg <= exp_X[2:0]; - end - - endcase -end - -always @(posedge clk) begin - //RESULT - mantissa_XI <= etf + ( totalatten_X[0] ? 3'd0 : etg ); //carry-out discarded - exponent_XI <= totalatten_X[11:8]; - signbit_XI <= signbit_X; +always @(posedge clk) if( clk_en ) begin + mantissa_XI <= mantissa_X; + exponent_XI <= exponent_X; + signbit_XI <= signbit_X; end // REGISTER/CYCLE 11 // Introduce test bit as MSB, 2's complement & Carry-out discarded always @(*) begin - // Floating-point to integer, and incorporating sign bit - // Two-stage shifting of mantissa_XI by exponent_XI - shifter <= { 3'b001, mantissa_XI }; - case( ~exponent_XI[1:0] ) - 2'b00: shifter_2 <= { 1'b0, shifter[12:1] }; // LSB discarded - 2'b01: shifter_2 <= shifter; - 2'b10: shifter_2 <= { shifter[11:0], 1'b0 }; - 2'b11: shifter_2 <= { shifter[10:0], 2'b0 }; - endcase - case( ~exponent_XI[3:2] ) - 2'b00: shifter_3 <= {12'b0, shifter_2[12] }; - 2'b01: shifter_3 <= { 8'b0, shifter_2[12:8] }; - 2'b10: shifter_3 <= { 4'b0, shifter_2[12:4] }; - 2'b11: shifter_3 <= shifter_2; - endcase + // Floating-point to integer, and incorporating sign bit + // Two-stage shifting of mantissa_XI by exponent_XI + shifter = { 3'b001, mantissa_XI }; + case( ~exponent_XI[1:0] ) + 2'b00: shifter_2 = { 1'b0, shifter[12:1] }; // LSB discarded + 2'b01: shifter_2 = shifter; + 2'b10: shifter_2 = { shifter[11:0], 1'b0 }; + 2'b11: shifter_2 = { shifter[10:0], 2'b0 }; + endcase + case( ~exponent_XI[3:2] ) + 2'b00: shifter_3 = {12'b0, shifter_2[12] }; + 2'b01: shifter_3 = { 8'b0, shifter_2[12:8] }; + 2'b10: shifter_3 = { 4'b0, shifter_2[12:4] }; + 2'b11: shifter_3 = shifter_2; + endcase end -always @(posedge clk) begin - // REGISTER CYCLE 11 - op_XII <= ({ test_214, shifter_3 } ^ {14{signbit_XI}}) + signbit_XI; - // REGISTER CYCLE 12 - // Extra register, take output after here +always @(posedge clk) if( clk_en ) begin + // REGISTER CYCLE 11 + op_XII <= ({ test_214, shifter_3 } ^ {14{signbit_XI}}) + {13'd0,signbit_XI}; + // REGISTER CYCLE 12 + // Extra register, take output after here op_result_internal <= op_XII; end `ifdef SIMULATION +/* verilator lint_off PINMISSING */ reg [4:0] sep24_cnt; wire signed [13:0] op_ch0s1, op_ch1s1, op_ch2s1, op_ch3s1, - op_ch4s1, op_ch5s1, op_ch0s2, op_ch1s2, - op_ch2s2, op_ch3s2, op_ch4s2, op_ch5s2, - op_ch0s3, op_ch1s3, op_ch2s3, op_ch3s3, - op_ch4s3, op_ch5s3, op_ch0s4, op_ch1s4, - op_ch2s4, op_ch3s4, op_ch4s4, op_ch5s4; + op_ch4s1, op_ch5s1, op_ch0s2, op_ch1s2, + op_ch2s2, op_ch3s2, op_ch4s2, op_ch5s2, + op_ch0s3, op_ch1s3, op_ch2s3, op_ch3s3, + op_ch4s3, op_ch5s3, op_ch0s4, op_ch1s4, + op_ch2s4, op_ch3s4, op_ch4s4, op_ch5s4; -always @(posedge clk ) - sep24_cnt <= !zero ? sep24_cnt+1'b1 : 5'd0; +always @(posedge clk ) if( clk_en ) begin + sep24_cnt <= !zero ? sep24_cnt+1'b1 : 5'd0; +end sep24 #( .width(14), .pos0(13)) opsep ( - .clk ( clk ), - .mixed ( op_result_internal ), - .mask ( 0 ), - .cnt ( sep24_cnt ), - - .ch0s1 (op_ch0s1), - .ch1s1 (op_ch1s1), - .ch2s1 (op_ch2s1), - .ch3s1 (op_ch3s1), - .ch4s1 (op_ch4s1), - .ch5s1 (op_ch5s1), + .clk ( clk ), + .clk_en ( clk_en ), + .mixed ( op_result_internal ), + .mask ( 24'd0 ), + .cnt ( sep24_cnt ), + + .ch0s1 (op_ch0s1), + .ch1s1 (op_ch1s1), + .ch2s1 (op_ch2s1), + .ch3s1 (op_ch3s1), + .ch4s1 (op_ch4s1), + .ch5s1 (op_ch5s1), - .ch0s2 (op_ch0s2), - .ch1s2 (op_ch1s2), - .ch2s2 (op_ch2s2), - .ch3s2 (op_ch3s2), - .ch4s2 (op_ch4s2), - .ch5s2 (op_ch5s2), + .ch0s2 (op_ch0s2), + .ch1s2 (op_ch1s2), + .ch2s2 (op_ch2s2), + .ch3s2 (op_ch3s2), + .ch4s2 (op_ch4s2), + .ch5s2 (op_ch5s2), - .ch0s3 (op_ch0s3), - .ch1s3 (op_ch1s3), - .ch2s3 (op_ch2s3), - .ch3s3 (op_ch3s3), - .ch4s3 (op_ch4s3), - .ch5s3 (op_ch5s3), + .ch0s3 (op_ch0s3), + .ch1s3 (op_ch1s3), + .ch2s3 (op_ch2s3), + .ch3s3 (op_ch3s3), + .ch4s3 (op_ch4s3), + .ch5s3 (op_ch5s3), - .ch0s4 (op_ch0s4), - .ch1s4 (op_ch1s4), - .ch2s4 (op_ch2s4), - .ch3s4 (op_ch3s4), - .ch4s4 (op_ch4s4), - .ch5s4 (op_ch5s4) + .ch0s4 (op_ch0s4), + .ch1s4 (op_ch1s4), + .ch2s4 (op_ch2s4), + .ch3s4 (op_ch3s4), + .ch4s4 (op_ch4s4), + .ch5s4 (op_ch5s4) ); wire signed [8:0] acc_ch0s1, acc_ch1s1, acc_ch2s1, acc_ch3s1, - acc_ch4s1, acc_ch5s1, acc_ch0s2, acc_ch1s2, - acc_ch2s2, acc_ch3s2, acc_ch4s2, acc_ch5s2, - acc_ch0s3, acc_ch1s3, acc_ch2s3, acc_ch3s3, - acc_ch4s3, acc_ch5s3, acc_ch0s4, acc_ch1s4, - acc_ch2s4, acc_ch3s4, acc_ch4s4, acc_ch5s4; + acc_ch4s1, acc_ch5s1, acc_ch0s2, acc_ch1s2, + acc_ch2s2, acc_ch3s2, acc_ch4s2, acc_ch5s2, + acc_ch0s3, acc_ch1s3, acc_ch2s3, acc_ch3s3, + acc_ch4s3, acc_ch5s3, acc_ch0s4, acc_ch1s4, + acc_ch2s4, acc_ch3s4, acc_ch4s4, acc_ch5s4; sep24 #( .width(9), .pos0(13)) accsep ( - .clk ( clk ), - .mixed ( op_result_internal[13:5] ), - .mask ( 0 ), - .cnt ( sep24_cnt ), - - .ch0s1 (acc_ch0s1), - .ch1s1 (acc_ch1s1), - .ch2s1 (acc_ch2s1), - .ch3s1 (acc_ch3s1), - .ch4s1 (acc_ch4s1), - .ch5s1 (acc_ch5s1), + .clk ( clk ), + .clk_en ( clk_en ), + .mixed ( op_result_internal[13:5] ), + .mask ( 24'd0 ), + .cnt ( sep24_cnt ), + + .ch0s1 (acc_ch0s1), + .ch1s1 (acc_ch1s1), + .ch2s1 (acc_ch2s1), + .ch3s1 (acc_ch3s1), + .ch4s1 (acc_ch4s1), + .ch5s1 (acc_ch5s1), - .ch0s2 (acc_ch0s2), - .ch1s2 (acc_ch1s2), - .ch2s2 (acc_ch2s2), - .ch3s2 (acc_ch3s2), - .ch4s2 (acc_ch4s2), - .ch5s2 (acc_ch5s2), + .ch0s2 (acc_ch0s2), + .ch1s2 (acc_ch1s2), + .ch2s2 (acc_ch2s2), + .ch3s2 (acc_ch3s2), + .ch4s2 (acc_ch4s2), + .ch5s2 (acc_ch5s2), - .ch0s3 (acc_ch0s3), - .ch1s3 (acc_ch1s3), - .ch2s3 (acc_ch2s3), - .ch3s3 (acc_ch3s3), - .ch4s3 (acc_ch4s3), - .ch5s3 (acc_ch5s3), + .ch0s3 (acc_ch0s3), + .ch1s3 (acc_ch1s3), + .ch2s3 (acc_ch2s3), + .ch3s3 (acc_ch3s3), + .ch4s3 (acc_ch4s3), + .ch5s3 (acc_ch5s3), - .ch0s4 (acc_ch0s4), - .ch1s4 (acc_ch1s4), - .ch2s4 (acc_ch2s4), - .ch3s4 (acc_ch3s4), - .ch4s4 (acc_ch4s4), - .ch5s4 (acc_ch5s4) + .ch0s4 (acc_ch0s4), + .ch1s4 (acc_ch1s4), + .ch2s4 (acc_ch2s4), + .ch3s4 (acc_ch3s4), + .ch4s4 (acc_ch4s4), + .ch5s4 (acc_ch5s4) ); wire signed [9:0] pm_ch0s1, pm_ch1s1, pm_ch2s1, pm_ch3s1, - pm_ch4s1, pm_ch5s1, pm_ch0s2, pm_ch1s2, - pm_ch2s2, pm_ch3s2, pm_ch4s2, pm_ch5s2, - pm_ch0s3, pm_ch1s3, pm_ch2s3, pm_ch3s3, - pm_ch4s3, pm_ch5s3, pm_ch0s4, pm_ch1s4, - pm_ch2s4, pm_ch3s4, pm_ch4s4, pm_ch5s4; + pm_ch4s1, pm_ch5s1, pm_ch0s2, pm_ch1s2, + pm_ch2s2, pm_ch3s2, pm_ch4s2, pm_ch5s2, + pm_ch0s3, pm_ch1s3, pm_ch2s3, pm_ch3s3, + pm_ch4s3, pm_ch5s3, pm_ch0s4, pm_ch1s4, + pm_ch2s4, pm_ch3s4, pm_ch4s4, pm_ch5s4; sep24 #( .width(10), .pos0( 18 ) ) pmsep ( - .clk ( clk ), - .mixed ( phasemod_VIII ), - .mask ( 0 ), - .cnt ( sep24_cnt ), - - .ch0s1 (pm_ch0s1), - .ch1s1 (pm_ch1s1), - .ch2s1 (pm_ch2s1), - .ch3s1 (pm_ch3s1), - .ch4s1 (pm_ch4s1), - .ch5s1 (pm_ch5s1), + .clk ( clk ), + .clk_en ( clk_en ), + .mixed ( phasemod_VIII ), + .mask ( 24'd0 ), + .cnt ( sep24_cnt ), + + .ch0s1 (pm_ch0s1), + .ch1s1 (pm_ch1s1), + .ch2s1 (pm_ch2s1), + .ch3s1 (pm_ch3s1), + .ch4s1 (pm_ch4s1), + .ch5s1 (pm_ch5s1), - .ch0s2 (pm_ch0s2), - .ch1s2 (pm_ch1s2), - .ch2s2 (pm_ch2s2), - .ch3s2 (pm_ch3s2), - .ch4s2 (pm_ch4s2), - .ch5s2 (pm_ch5s2), + .ch0s2 (pm_ch0s2), + .ch1s2 (pm_ch1s2), + .ch2s2 (pm_ch2s2), + .ch3s2 (pm_ch3s2), + .ch4s2 (pm_ch4s2), + .ch5s2 (pm_ch5s2), - .ch0s3 (pm_ch0s3), - .ch1s3 (pm_ch1s3), - .ch2s3 (pm_ch2s3), - .ch3s3 (pm_ch3s3), - .ch4s3 (pm_ch4s3), - .ch5s3 (pm_ch5s3), + .ch0s3 (pm_ch0s3), + .ch1s3 (pm_ch1s3), + .ch2s3 (pm_ch2s3), + .ch3s3 (pm_ch3s3), + .ch4s3 (pm_ch4s3), + .ch5s3 (pm_ch5s3), - .ch0s4 (pm_ch0s4), - .ch1s4 (pm_ch1s4), - .ch2s4 (pm_ch2s4), - .ch3s4 (pm_ch3s4), - .ch4s4 (pm_ch4s4), - .ch5s4 (pm_ch5s4) + .ch0s4 (pm_ch0s4), + .ch1s4 (pm_ch1s4), + .ch2s4 (pm_ch2s4), + .ch3s4 (pm_ch3s4), + .ch4s4 (pm_ch4s4), + .ch5s4 (pm_ch5s4) ); wire [9:0] phase_ch0s1, phase_ch1s1, phase_ch2s1, phase_ch3s1, - phase_ch4s1, phase_ch5s1, phase_ch0s2, phase_ch1s2, - phase_ch2s2, phase_ch3s2, phase_ch4s2, phase_ch5s2, - phase_ch0s3, phase_ch1s3, phase_ch2s3, phase_ch3s3, - phase_ch4s3, phase_ch5s3, phase_ch0s4, phase_ch1s4, - phase_ch2s4, phase_ch3s4, phase_ch4s4, phase_ch5s4; + phase_ch4s1, phase_ch5s1, phase_ch0s2, phase_ch1s2, + phase_ch2s2, phase_ch3s2, phase_ch4s2, phase_ch5s2, + phase_ch0s3, phase_ch1s3, phase_ch2s3, phase_ch3s3, + phase_ch4s3, phase_ch5s3, phase_ch0s4, phase_ch1s4, + phase_ch2s4, phase_ch3s4, phase_ch4s4, phase_ch5s4; sep24 #( .width(10), .pos0( 18 ) ) phsep ( - .clk ( clk ), - .mixed ( phase ), - .mask ( 0 ), - .cnt ( sep24_cnt ), - - .ch0s1 (phase_ch0s1), - .ch1s1 (phase_ch1s1), - .ch2s1 (phase_ch2s1), - .ch3s1 (phase_ch3s1), - .ch4s1 (phase_ch4s1), - .ch5s1 (phase_ch5s1), + .clk ( clk ), + .clk_en ( clk_en ), + .mixed ( phase ), + .mask ( 24'd0 ), + .cnt ( sep24_cnt ), + + .ch0s1 (phase_ch0s1), + .ch1s1 (phase_ch1s1), + .ch2s1 (phase_ch2s1), + .ch3s1 (phase_ch3s1), + .ch4s1 (phase_ch4s1), + .ch5s1 (phase_ch5s1), - .ch0s2 (phase_ch0s2), - .ch1s2 (phase_ch1s2), - .ch2s2 (phase_ch2s2), - .ch3s2 (phase_ch3s2), - .ch4s2 (phase_ch4s2), - .ch5s2 (phase_ch5s2), + .ch0s2 (phase_ch0s2), + .ch1s2 (phase_ch1s2), + .ch2s2 (phase_ch2s2), + .ch3s2 (phase_ch3s2), + .ch4s2 (phase_ch4s2), + .ch5s2 (phase_ch5s2), - .ch0s3 (phase_ch0s3), - .ch1s3 (phase_ch1s3), - .ch2s3 (phase_ch2s3), - .ch3s3 (phase_ch3s3), - .ch4s3 (phase_ch4s3), - .ch5s3 (phase_ch5s3), + .ch0s3 (phase_ch0s3), + .ch1s3 (phase_ch1s3), + .ch2s3 (phase_ch2s3), + .ch3s3 (phase_ch3s3), + .ch4s3 (phase_ch4s3), + .ch5s3 (phase_ch5s3), - .ch0s4 (phase_ch0s4), - .ch1s4 (phase_ch1s4), - .ch2s4 (phase_ch2s4), - .ch3s4 (phase_ch3s4), - .ch4s4 (phase_ch4s4), - .ch5s4 (phase_ch5s4) + .ch0s4 (phase_ch0s4), + .ch1s4 (phase_ch1s4), + .ch2s4 (phase_ch2s4), + .ch3s4 (phase_ch3s4), + .ch4s4 (phase_ch4s4), + .ch5s4 (phase_ch5s4) ); wire [9:0] eg_ch0s1, eg_ch1s1, eg_ch2s1, eg_ch3s1, eg_ch4s1, eg_ch5s1, - eg_ch0s2, eg_ch1s2, eg_ch2s2, eg_ch3s2, eg_ch4s2, eg_ch5s2, - eg_ch0s3, eg_ch1s3, eg_ch2s3, eg_ch3s3, eg_ch4s3, eg_ch5s3, - eg_ch0s4, eg_ch1s4, eg_ch2s4, eg_ch3s4, eg_ch4s4, eg_ch5s4; + eg_ch0s2, eg_ch1s2, eg_ch2s2, eg_ch3s2, eg_ch4s2, eg_ch5s2, + eg_ch0s3, eg_ch1s3, eg_ch2s3, eg_ch3s3, eg_ch4s3, eg_ch5s3, + eg_ch0s4, eg_ch1s4, eg_ch2s4, eg_ch3s4, eg_ch4s4, eg_ch5s4; sep24 #( .width(10), .pos0(17) ) egsep ( - .clk ( clk ), - .mixed ( eg_atten_IX ), - .mask ( 0 ), - .cnt ( sep24_cnt ), - - .ch0s1 (eg_ch0s1), - .ch1s1 (eg_ch1s1), - .ch2s1 (eg_ch2s1), - .ch3s1 (eg_ch3s1), - .ch4s1 (eg_ch4s1), - .ch5s1 (eg_ch5s1), + .clk ( clk ), + .clk_en ( clk_en ), + .mixed ( eg_atten_IX ), + .mask ( 24'd0 ), + .cnt ( sep24_cnt ), + + .ch0s1 (eg_ch0s1), + .ch1s1 (eg_ch1s1), + .ch2s1 (eg_ch2s1), + .ch3s1 (eg_ch3s1), + .ch4s1 (eg_ch4s1), + .ch5s1 (eg_ch5s1), - .ch0s2 (eg_ch0s2), - .ch1s2 (eg_ch1s2), - .ch2s2 (eg_ch2s2), - .ch3s2 (eg_ch3s2), - .ch4s2 (eg_ch4s2), - .ch5s2 (eg_ch5s2), + .ch0s2 (eg_ch0s2), + .ch1s2 (eg_ch1s2), + .ch2s2 (eg_ch2s2), + .ch3s2 (eg_ch3s2), + .ch4s2 (eg_ch4s2), + .ch5s2 (eg_ch5s2), - .ch0s3 (eg_ch0s3), - .ch1s3 (eg_ch1s3), - .ch2s3 (eg_ch2s3), - .ch3s3 (eg_ch3s3), - .ch4s3 (eg_ch4s3), - .ch5s3 (eg_ch5s3), + .ch0s3 (eg_ch0s3), + .ch1s3 (eg_ch1s3), + .ch2s3 (eg_ch2s3), + .ch3s3 (eg_ch3s3), + .ch4s3 (eg_ch4s3), + .ch5s3 (eg_ch5s3), - .ch0s4 (eg_ch0s4), - .ch1s4 (eg_ch1s4), - .ch2s4 (eg_ch2s4), - .ch3s4 (eg_ch3s4), - .ch4s4 (eg_ch4s4), - .ch5s4 (eg_ch5s4) + .ch0s4 (eg_ch0s4), + .ch1s4 (eg_ch1s4), + .ch2s4 (eg_ch2s4), + .ch3s4 (eg_ch3s4), + .ch4s4 (eg_ch4s4), + .ch5s4 (eg_ch5s4) ); - +/* verilator lint_on PINMISSING */ `endif diff --git a/rtl/sound/jt12/jt12_opram.v b/rtl/sound/jt12/jt12_opram.v deleted file mode 100644 index e2e3c63..0000000 --- a/rtl/sound/jt12/jt12_opram.v +++ /dev/null @@ -1,79 +0,0 @@ -`timescale 1ns / 1ps - - -/* This file is part of JT12. - - - JT12 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. - - JT12 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 JT12. If not, see . - - Based on Sauraen VHDL version of OPN/OPN2, which is based on die shots. - - Author: Jose Tejada Gomez. Twitter: @topapate - Version: 1.0 - Date: 27-1-2017 - -*/ - -module jt12_opram -( - input [4:0] wr_addr, - input [4:0] rd_addr, - input clk, - input [43:0] data, - output reg [43:0] q -); - - reg [43:0] ram[31:0]; - initial - begin - ram[0] = { ~7'd0, 37'd0 }; - ram[1] = { ~7'd0, 37'd0 }; - ram[2] = { ~7'd0, 37'd0 }; - ram[3] = { ~7'd0, 37'd0 }; - ram[4] = { ~7'd0, 37'd0 }; - ram[5] = { ~7'd0, 37'd0 }; - ram[6] = { ~7'd0, 37'd0 }; - ram[7] = { ~7'd0, 37'd0 }; - ram[8] = { ~7'd0, 37'd0 }; - ram[9] = { ~7'd0, 37'd0 }; - ram[10] = { ~7'd0, 37'd0 }; - ram[11] = { ~7'd0, 37'd0 }; - ram[12] = { ~7'd0, 37'd0 }; - ram[13] = { ~7'd0, 37'd0 }; - ram[14] = { ~7'd0, 37'd0 }; - ram[15] = { ~7'd0, 37'd0 }; - ram[16] = { ~7'd0, 37'd0 }; - ram[17] = { ~7'd0, 37'd0 }; - ram[18] = { ~7'd0, 37'd0 }; - ram[19] = { ~7'd0, 37'd0 }; - ram[20] = { ~7'd0, 37'd0 }; - ram[21] = { ~7'd0, 37'd0 }; - ram[22] = { ~7'd0, 37'd0 }; - ram[23] = { ~7'd0, 37'd0 }; - ram[24] = { ~7'd0, 37'd0 }; - ram[25] = { ~7'd0, 37'd0 }; - ram[26] = { ~7'd0, 37'd0 }; - ram[27] = { ~7'd0, 37'd0 }; - ram[28] = { ~7'd0, 37'd0 }; - ram[29] = { ~7'd0, 37'd0 }; - ram[30] = { ~7'd0, 37'd0 }; - ram[31] = { ~7'd0, 37'd0 }; - end - - always @ (posedge clk) begin - q <= ram[rd_addr]; - ram[wr_addr] <= data; - end - -endmodule diff --git a/rtl/sound/jt12/jt12_pcm.v b/rtl/sound/jt12/jt12_pcm.v new file mode 100644 index 0000000..88724f8 --- /dev/null +++ b/rtl/sound/jt12/jt12_pcm.v @@ -0,0 +1,109 @@ +module jt12_pcm( + input rst, + input clk, +(* direct_enable *) input clk_en, + input zero, + input signed [8:0] pcm, + input pcm_wr, + output reg signed [8:0] pcm_resampled +); + +// reg [2:0] ratesel; +// reg [3:0] cnt8; +// reg wrcnt, wrclr; +reg last_zero; +wire zero_edge = !last_zero && zero; +/* +always @(posedge clk) + if(rst) begin + cnt8 <= 4'd0; + wrclr <= 1'd0; + ratesel <= 3'd1; + wrcnt <= 1'b0; + end else if(clk_en) begin + if( pcm_wr ) begin + if( wrcnt ) begin + // case( cnt8[3:2] ) + // 2'd3: ratesel <= 3'b111; // x8 + // 2'd2: ratesel <= 3'b011; // x4 + // 2'd1: ratesel <= 3'b001; // x2 + // 2'd0: ratesel <= 3'b000; // x1 + // endcase + cnt8 <= 4'd0; + wrcnt <= 1'b0; + end + else wrcnt <= 1'b1; + end else + if( cnt8!=4'hf && zero ) cnt8 <= cnt8 + 4'd1; + end +*/ +// up-rate PCM samples +reg rate1, rate2; //, rate4, rate8; +reg cen1, cen2; //, cen4, cen8; + +always @(posedge clk) + if(rst) + rate2 <= 1'b0; + else begin + last_zero <= zero; + rate1 <= zero_edge; + if(zero_edge) begin + rate2 <= ~rate2; +// if(rate2) begin +// rate4 <= ~rate4; +// if(rate4) rate8<=~rate8; +// end + end + end + +always @(negedge clk) begin + cen1 <= rate1; + cen2 <= rate1 && rate2; +// cen4 <= rate1 && rate2 && rate4; +// cen8 <= rate1 && rate2 && rate4 && rate8; +end + +wire signed [8:0] pcm3; //,pcm2, pcm1; + +//always @(posedge clk) if( clk_en ) +// pcm_resampled <= ratesel[0] ? pcm3 : pcm; +always @(*) + pcm_resampled = pcm3; + +// rate x2 +//wire signed [8:0] pcm_in2 = ratesel[1] ? pcm2 : pcm; +jt12_interpol #(.calcw(10),.inw(9),.rate(2),.m(1),.n(2)) +u_uprate_3( + .clk ( clk ), + .rst ( rst ), + .cen_in ( cen2 ), + .cen_out( cen1 ), + // .snd_in ( pcm_in2 ), + .snd_in ( pcm ), + .snd_out( pcm3 ) +); +/* +// rate x2 +wire signed [8:0] pcm_in1 = ratesel[2] ? pcm1 : pcm; +jt12_interpol #(.calcw(10),.inw(9),.rate(2),.m(1),.n(2)) +u_uprate_2( + .clk ( clk ), + .rst ( rst ), + .cen_in ( cen4 ), + .cen_out( cen2 ), + .snd_in ( pcm_in1 ), + .snd_out( pcm2 ) +); + +// rate x2 +jt12_interpol #(.calcw(10),.inw(9),.rate(2),.m(1),.n(2)) +u_uprate_1( + .clk ( clk ), + .rst ( rst ), + .cen_in ( cen8 ), + .cen_out( cen4 ), + .snd_in ( pcm ), + .snd_out( pcm1 ) +); +*/ +endmodule // jt12_pcm \ No newline at end of file diff --git a/rtl/sound/jt12/jt12_pg.v b/rtl/sound/jt12/jt12_pg.v index cb73d0c..cf6b004 100644 --- a/rtl/sound/jt12/jt12_pg.v +++ b/rtl/sound/jt12/jt12_pg.v @@ -1,412 +1,114 @@ /* This file is part of JT12. - JT12 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. + JT12 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. - JT12 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. + JT12 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 JT12. If not, see . - - Author: Jose Tejada Gomez. Twitter: @topapate - Version: 1.0 - Date: 14-2-2016 - - Based on information posted by Nemesis on: + You should have received a copy of the GNU General Public License + along with JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 14-2-2016 + + Based on information posted by Nemesis on: http://gendev.spritesmind.net/forum/viewtopic.php?t=386&postdays=0&postorder=asc&start=167 - Based on jt51_phasegen.v, from JT51 - - */ + Based on jt51_phasegen.v, from JT51 + + */ `timescale 1ns / 1ps /* - tab size 4 + tab size 4 */ module jt12_pg( - input clk, - input rst, - // Channel frequency - input [10:0] fnum_I, - input [ 2:0] block_I, - // Operator multiplying - input [ 3:0] mul_V, - // Operator detuning - input [ 2:0] dt1_II, // same as JT51's DT1 - // phase modulation from LFO - //input [ 7:0] pm, - //input [ 2:0] pms, - // phase operation - input pg_rst_III, - input zero, - input pg_stop, - - output reg [ 4:0] keycode_III, - output reg [ 9:0] phase_VIII + input clk, + input clk_en, + input rst, + // Channel frequency + input [10:0] fnum_I, + input [ 2:0] block_I, + // Operator multiplying + input [ 3:0] mul_II, + // Operator detuning + input [ 2:0] dt1_I, // same as JT51's DT1 + // phase modulation from LFO + input [ 6:0] lfo_mod, + input [ 2:0] pms_I, + // phase operation + input pg_rst_II, + input pg_stop, // not implemented + + output reg [ 4:0] keycode_II, + output [ 9:0] phase_VIII ); -/* -reg signed [8:0] mod; +parameter num_ch=6; -always @(*) begin - case( pms ) // comprobar en silicio - 3'd0: mod <= 9'd0; - 3'd1: mod <= { 7'd0, pm[6:5] }; - 3'd2: mod <= { 6'd0, pm[6:4] }; - 3'd3: mod <= { 5'd0, pm[6:3] }; - 3'd4: mod <= { 4'd0, pm[6:2] }; - 3'd5: mod <= { 3'd0, pm[6:1] }; - 3'd6: mod <= { 1'd0, pm[6:0], 1'b0 }; - 3'd7: mod <= { pm[6:0], 2'b0 }; - endcase +wire [4:0] keycode_I; +wire signed [5:0] detune_mod_I; +reg signed [5:0] detune_mod_II; +wire [16:0] phinc_I; +reg [16:0] phinc_II; +wire [19:0] phase_drop, phase_in; +wire [ 9:0] phase_II; + +always @(posedge clk) if(clk_en) begin + keycode_II <= keycode_I; + detune_mod_II <= detune_mod_I; + phinc_II <= phinc_I; end -jt12_pm u_pm( - // Channel frequency - .kc(kc), - .kf(kf), - .add(~pm[7]), - .mod(mod), - .kcex(keycode_I) -); -*/ +jt12_pg_comb u_comb( + .block ( block_I ), + .fnum ( fnum_I ), + // Phase Modulation + .lfo_mod ( lfo_mod[6:2] ), + .pms ( pms_I ), -wire pg_rst_VI; + // Detune + .detune ( dt1_I ), + .keycode ( keycode_I ), + .detune_out ( detune_mod_I ), + // Phase increment + .phinc_out ( phinc_I ), + // Phase add + .mul ( mul_II ), + .phase_in ( phase_drop ), + .pg_rst ( pg_rst_II ), + .detune_in ( detune_mod_II ), + .phinc_in ( phinc_II ), -////////////////////////////////////////////////// -// I -reg [4:0] keycode_II; -reg [16:0] phinc_II; - -always @(posedge clk) begin : phase_calculation_I - case ( block_I ) - 3'd0: phinc_II <= { 7'd0, fnum_I[10:1] }; - 3'd1: phinc_II <= { 6'd0, fnum_I }; - 3'd2: phinc_II <= { 5'd0, fnum_I, 1'd0 }; - 3'd3: phinc_II <= { 4'd0, fnum_I, 2'd0 }; - 3'd4: phinc_II <= { 3'd0, fnum_I, 3'd0 }; - 3'd5: phinc_II <= { 2'd0, fnum_I, 4'd0 }; - 3'd6: phinc_II <= { 1'd0, fnum_I, 5'd0 }; - 3'd7: phinc_II <= { fnum_I, 6'd0 }; - endcase - keycode_II <= { block_I, fnum_I[10], fnum_I[10] ? (|fnum_I[9:7]) : (&fnum_I[9:7])}; -end - -////////////////////////////////////////////////// -// II -reg [ 5:0] dt1_kf_III; -reg [16:0] phinc_III; -reg [ 2:0] dt1_III; - -always @(posedge clk) begin : phase_calculation_II - case( dt1_II[1:0] ) - 2'd1: dt1_kf_III <= { 1'b0, keycode_II } - 6'd4; - 2'd2: dt1_kf_III <= { 1'b0, keycode_II } + 6'd4; - 2'd3: dt1_kf_III <= { 1'b0, keycode_II } + 6'd8; - default:dt1_kf_III <= { 1'b0, keycode_II }; - endcase - dt1_III <= dt1_II; - phinc_III <= phinc_II; - keycode_III <= keycode_II; -end - -////////////////////////////////////////////////// -// III -reg [16:0] phinc_IV; -reg [ 4:0] pow2; -reg [ 2:0] dt1_IV; - -always @(*) begin : calcpow2 - case( dt1_kf_III[2:0] ) - 3'd0: pow2 <= 5'd16; - 3'd1: pow2 <= 5'd17; - 3'd2: pow2 <= 5'd19; - 3'd3: pow2 <= 5'd20; - 3'd4: pow2 <= 5'd22; - 3'd5: pow2 <= 5'd24; - 3'd6: pow2 <= 5'd26; - 3'd7: pow2 <= 5'd29; - endcase -end - -reg [5:0] dt1_unlimited; -reg [4:0] dt1_limit, dt1_offset_IV; - -always @(*) begin : dt1_limit_mux - case( dt1_III[1:0] ) - default: dt1_limit <= 5'd8; - 2'd1: dt1_limit <= 5'd8; - 2'd2: dt1_limit <= 5'd16; - 2'd3: dt1_limit <= 5'd22; - endcase - case( dt1_kf_III[5:3] ) - 3'd0: dt1_unlimited <= { 5'd0, pow2[4] }; // <2 - 3'd1: dt1_unlimited <= { 4'd0, pow2[4:3] }; // <4 - 3'd2: dt1_unlimited <= { 3'd0, pow2[4:2] }; // <8 - 3'd3: dt1_unlimited <= { 2'd0, pow2[4:1] }; - 3'd4: dt1_unlimited <= { 1'd0, pow2[4:0] }; - 3'd5: dt1_unlimited <= { pow2[4:0], 1'd0 }; - default:dt1_unlimited <= 6'd0; - endcase -end - -always @(posedge clk) begin : phase_calculation_III - dt1_offset_IV <= dt1_unlimited > dt1_limit ? - dt1_limit : dt1_unlimited[4:0]; - dt1_IV <= dt1_III; - phinc_IV <= phinc_III; -end - -////////////////////////////////////////////////// -// IV -reg [16:0] phinc_V; - -always @(posedge clk) begin : phase_calculation_IV - if( dt1_IV[1:0]==2'd0 ) - phinc_V <= phinc_IV; - else begin - if( !dt1_IV[2] ) - phinc_V <= phinc_IV + dt1_offset_IV; - else - phinc_V <= phinc_IV - dt1_offset_IV; - end -end - -////////////////////////////////////////////////// -// V APPLY_MUL -reg [16:0] phinc_VI; -always @(posedge clk) begin : phase_calculation_V - if( mul_V==4'd0 ) - phinc_VI <= { 1'b0, phinc_V[16:1] }; - else - phinc_VI <= phinc_V * mul_V; -end - -////////////////////////////////////////////////// -// VI add phinc to the phase -wire keyon_VI; -wire [19:0] phase_drop; -reg [19:0] phase_in; -reg [ 9:0] phase_VII; - -always @(*) - phase_in <= pg_rst_VI ? 20'd0 : - ( pg_stop ? phase_drop : phase_drop + phinc_VI); - -always @(posedge clk) begin : phase_calculation_VI - phase_VII <= phase_in[19:10]; -end - -////////////////////////////////////////////////// -// VIII padding - -always @(posedge clk) - phase_VIII <= phase_VII; - -jt12_sh #( .width(20), .stages(24) ) u_phsh( - .clk ( clk ), -// .rst ( rst ), - .din ( phase_in ), - .drop ( phase_drop) + .phase_out ( phase_in ), + .phase_op ( phase_II ) ); -jt12_sh #( .width(1), .stages(3) ) u_rstsh( - .clk ( clk ), - .din ( pg_rst_III), - .drop ( pg_rst_VI ) +jt12_sh_rst #( .width(20), .stages(4*num_ch) ) u_phsh( + .clk ( clk ), + .clk_en ( clk_en ), + .rst ( rst ), + .din ( phase_in ), + .drop ( phase_drop) ); - - -`ifdef SIMULATION -reg [4:0] sep24_cnt; - -wire [9:0] pg_ch0s1, pg_ch1s1, pg_ch2s1, pg_ch3s1, - pg_ch4s1, pg_ch5s1, pg_ch0s2, pg_ch1s2, - pg_ch2s2, pg_ch3s2, pg_ch4s2, pg_ch5s2, - pg_ch0s3, pg_ch1s3, pg_ch2s3, pg_ch3s3, - pg_ch4s3, pg_ch5s3, pg_ch0s4, pg_ch1s4, - pg_ch2s4, pg_ch3s4, pg_ch4s4, pg_ch5s4; - -always @(posedge clk) - sep24_cnt <= !zero ? sep24_cnt+1'b1 : 5'd0; - -sep24 #( .width(10), .pos0(18)) stsep -( - .clk ( clk ), - .mixed ( phase_VIII), - .mask ( 0 ), - .cnt ( sep24_cnt ), - - .ch0s1 (pg_ch0s1), - .ch1s1 (pg_ch1s1), - .ch2s1 (pg_ch2s1), - .ch3s1 (pg_ch3s1), - .ch4s1 (pg_ch4s1), - .ch5s1 (pg_ch5s1), - - .ch0s2 (pg_ch0s2), - .ch1s2 (pg_ch1s2), - .ch2s2 (pg_ch2s2), - .ch3s2 (pg_ch3s2), - .ch4s2 (pg_ch4s2), - .ch5s2 (pg_ch5s2), - - .ch0s3 (pg_ch0s3), - .ch1s3 (pg_ch1s3), - .ch2s3 (pg_ch2s3), - .ch3s3 (pg_ch3s3), - .ch4s3 (pg_ch4s3), - .ch5s3 (pg_ch5s3), - - .ch0s4 (pg_ch0s4), - .ch1s4 (pg_ch1s4), - .ch2s4 (pg_ch2s4), - .ch3s4 (pg_ch3s4), - .ch4s4 (pg_ch4s4), - .ch5s4 (pg_ch5s4) +jt12_sh_rst #( .width(10), .stages(6) ) u_pad( + .clk ( clk ), + .clk_en ( clk_en ), + .rst ( rst ), + .din ( phase_II ), + .drop ( phase_VIII) ); -wire [16:0] phinc_ch0s1, phinc_ch1s1, phinc_ch2s1, phinc_ch3s1, - phinc_ch4s1, phinc_ch5s1, phinc_ch0s2, phinc_ch1s2, - phinc_ch2s2, phinc_ch3s2, phinc_ch4s2, phinc_ch5s2, - phinc_ch0s3, phinc_ch1s3, phinc_ch2s3, phinc_ch3s3, - phinc_ch4s3, phinc_ch5s3, phinc_ch0s4, phinc_ch1s4, - phinc_ch2s4, phinc_ch3s4, phinc_ch4s4, phinc_ch5s4; - -sep24 #( .width(17), .pos0(3+6)) pisep -( - .clk ( clk ), - .mixed ( phinc_VI), - .mask ( 0 ), - .cnt ( sep24_cnt ), - - .ch0s1 (phinc_ch0s1), - .ch1s1 (phinc_ch1s1), - .ch2s1 (phinc_ch2s1), - .ch3s1 (phinc_ch3s1), - .ch4s1 (phinc_ch4s1), - .ch5s1 (phinc_ch5s1), - - .ch0s2 (phinc_ch0s2), - .ch1s2 (phinc_ch1s2), - .ch2s2 (phinc_ch2s2), - .ch3s2 (phinc_ch3s2), - .ch4s2 (phinc_ch4s2), - .ch5s2 (phinc_ch5s2), - - .ch0s3 (phinc_ch0s3), - .ch1s3 (phinc_ch1s3), - .ch2s3 (phinc_ch2s3), - .ch3s3 (phinc_ch3s3), - .ch4s3 (phinc_ch4s3), - .ch5s3 (phinc_ch5s3), - - .ch0s4 (phinc_ch0s4), - .ch1s4 (phinc_ch1s4), - .ch2s4 (phinc_ch2s4), - .ch3s4 (phinc_ch3s4), - .ch4s4 (phinc_ch4s4), - .ch5s4 (phinc_ch5s4) -); - -wire [10:0] fnum_ch0s1, fnum_ch1s1, fnum_ch2s1, fnum_ch3s1, - fnum_ch4s1, fnum_ch5s1, fnum_ch0s2, fnum_ch1s2, - fnum_ch2s2, fnum_ch3s2, fnum_ch4s2, fnum_ch5s2, - fnum_ch0s3, fnum_ch1s3, fnum_ch2s3, fnum_ch3s3, - fnum_ch4s3, fnum_ch5s3, fnum_ch0s4, fnum_ch1s4, - fnum_ch2s4, fnum_ch3s4, fnum_ch4s4, fnum_ch5s4; - -sep24 #( .width(11), .pos0(3+1)) fnsep -( - .clk ( clk ), - .mixed ( fnum_I), - .mask ( 0 ), - .cnt ( sep24_cnt ), - - .ch0s1 (fnum_ch0s1), - .ch1s1 (fnum_ch1s1), - .ch2s1 (fnum_ch2s1), - .ch3s1 (fnum_ch3s1), - .ch4s1 (fnum_ch4s1), - .ch5s1 (fnum_ch5s1), - - .ch0s2 (fnum_ch0s2), - .ch1s2 (fnum_ch1s2), - .ch2s2 (fnum_ch2s2), - .ch3s2 (fnum_ch3s2), - .ch4s2 (fnum_ch4s2), - .ch5s2 (fnum_ch5s2), - - .ch0s3 (fnum_ch0s3), - .ch1s3 (fnum_ch1s3), - .ch2s3 (fnum_ch2s3), - .ch3s3 (fnum_ch3s3), - .ch4s3 (fnum_ch4s3), - .ch5s3 (fnum_ch5s3), - - .ch0s4 (fnum_ch0s4), - .ch1s4 (fnum_ch1s4), - .ch2s4 (fnum_ch2s4), - .ch3s4 (fnum_ch3s4), - .ch4s4 (fnum_ch4s4), - .ch5s4 (fnum_ch5s4) -); - -wire pgrst_III_ch0s1, pgrst_III_ch1s1, pgrst_III_ch2s1, pgrst_III_ch3s1, - pgrst_III_ch4s1, pgrst_III_ch5s1, pgrst_III_ch0s2, pgrst_III_ch1s2, - pgrst_III_ch2s2, pgrst_III_ch3s2, pgrst_III_ch4s2, pgrst_III_ch5s2, - pgrst_III_ch0s3, pgrst_III_ch1s3, pgrst_III_ch2s3, pgrst_III_ch3s3, - pgrst_III_ch4s3, pgrst_III_ch5s3, pgrst_III_ch0s4, pgrst_III_ch1s4, - pgrst_III_ch2s4, pgrst_III_ch3s4, pgrst_III_ch4s4, pgrst_III_ch5s4; - -sep24 #( .width(1), .pos0(23)) pgrstsep -( - .clk ( clk ), - .mixed ( pg_rst_III), - .mask ( 0 ), - .cnt ( sep24_cnt ), - - .ch0s1 (pgrst_III_ch0s1), - .ch1s1 (pgrst_III_ch1s1), - .ch2s1 (pgrst_III_ch2s1), - .ch3s1 (pgrst_III_ch3s1), - .ch4s1 (pgrst_III_ch4s1), - .ch5s1 (pgrst_III_ch5s1), - - .ch0s2 (pgrst_III_ch0s2), - .ch1s2 (pgrst_III_ch1s2), - .ch2s2 (pgrst_III_ch2s2), - .ch3s2 (pgrst_III_ch3s2), - .ch4s2 (pgrst_III_ch4s2), - .ch5s2 (pgrst_III_ch5s2), - - .ch0s3 (pgrst_III_ch0s3), - .ch1s3 (pgrst_III_ch1s3), - .ch2s3 (pgrst_III_ch2s3), - .ch3s3 (pgrst_III_ch3s3), - .ch4s3 (pgrst_III_ch4s3), - .ch5s3 (pgrst_III_ch5s3), - - .ch0s4 (pgrst_III_ch0s4), - .ch1s4 (pgrst_III_ch1s4), - .ch2s4 (pgrst_III_ch2s4), - .ch3s4 (pgrst_III_ch3s4), - .ch4s4 (pgrst_III_ch4s4), - .ch5s4 (pgrst_III_ch5s4) -); - - -`endif - endmodule diff --git a/rtl/sound/jt12/jt12_pg_comb.v b/rtl/sound/jt12/jt12_pg_comb.v new file mode 100644 index 0000000..a8091d2 --- /dev/null +++ b/rtl/sound/jt12/jt12_pg_comb.v @@ -0,0 +1,90 @@ +/* This file is part of JT12. + + JT12 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. + + JT12 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 JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 2-11-2018 + + Based on information posted by Nemesis on: +http://gendev.spritesmind.net/forum/viewtopic.php?t=386&postdays=0&postorder=asc&start=167 + + 100% compared with Alexey Khokholov (Nuke.YKT) work with identical results. +*/ + +module jt12_pg_comb( + input [ 2:0] block, + input [10:0] fnum, + // Phase Modulation + input [ 4:0] lfo_mod, + input [ 2:0] pms, + // output [ 7:0] pm_out, + + // Detune + input [ 2:0] detune, + + output [ 4:0] keycode, + output signed [5:0] detune_out, + // Phase increment + output [16:0] phinc_out, + // Phase add + input [ 3:0] mul, + input [19:0] phase_in, + input pg_rst, + // input signed [7:0] pm_in, + input signed [5:0] detune_in, + input [16:0] phinc_in, + + output [19:0] phase_out, + output [ 9:0] phase_op +); + +wire signed [8:0] pm_offset; + +/* pm, pg_dt and pg_inc operate in parallel */ +jt12_pm u_pm( + .lfo_mod ( lfo_mod ), + .fnum ( fnum ), + .pms ( pms ), + .pm_offset ( pm_offset ) +); + +jt12_pg_dt u_dt( + .block ( block ), + .fnum ( fnum ), + .detune ( detune ), + .keycode ( keycode ), + .detune_signed( detune_out ) +); + +jt12_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 + +jt12_pg_sum u_sum( + .mul ( mul ), + .phase_in ( phase_in ), + .pg_rst ( pg_rst ), + .detune_signed ( detune_in ), + .phinc_pure ( phinc_in ), + .phase_out ( phase_out ), + .phase_op ( phase_op ) +); + +endmodule // jt12_pg_comb \ No newline at end of file diff --git a/rtl/sound/jt12/jt12_pg_dt.v b/rtl/sound/jt12/jt12_pg_dt.v new file mode 100644 index 0000000..9b9e0f3 --- /dev/null +++ b/rtl/sound/jt12/jt12_pg_dt.v @@ -0,0 +1,82 @@ +/* This file is part of JT12. + + JT12 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. + + JT12 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 JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 2-11-2018 + + Based on information posted by Nemesis on: +http://gendev.spritesmind.net/forum/viewtopic.php?t=386&postdays=0&postorder=asc&start=167 + + Note that detune produces an output even for fnum==0, is that correct? + + Based on jt51_phasegen.v, from JT51 + + */ + +module jt12_pg_dt( + input [ 2:0] block, + input [10:0] fnum, + input [ 2:0] detune, + + output reg [ 4:0] keycode, + output reg signed [5:0] detune_signed +); + +reg [5:0] detune_kf; +reg [4:0] pow2; +reg [5:0] detune_unlimited; +reg [4:0] detune_limit, detune_limited; + + +always @(*) begin + keycode = { block, fnum[10], fnum[10] ? (|fnum[9:7]) : (&fnum[9:7])}; + case( detune[1:0] ) + 2'd1: detune_kf = { 1'b0, keycode } - 6'd4; + 2'd2: detune_kf = { 1'b0, keycode } + 6'd4; + 2'd3: detune_kf = { 1'b0, keycode } + 6'd8; + default:detune_kf = { 1'b0, keycode }; + endcase + case( detune_kf[2:0] ) + 3'd0: pow2 = 5'd16; + 3'd1: pow2 = 5'd17; + 3'd2: pow2 = 5'd19; + 3'd3: pow2 = 5'd20; + 3'd4: pow2 = 5'd22; + 3'd5: pow2 = 5'd24; + 3'd6: pow2 = 5'd26; + 3'd7: pow2 = 5'd29; + endcase + case( detune[1:0] ) + 2'd0: detune_limit = 5'd0; + 2'd1: detune_limit = 5'd8; + 2'd2: detune_limit = 5'd16; + 2'd3: detune_limit = 5'd22; + endcase + case( detune_kf[5:3] ) + 3'd0: detune_unlimited = { 5'd0, pow2[4] }; // <2 + 3'd1: detune_unlimited = { 4'd0, pow2[4:3] }; // <4 + 3'd2: detune_unlimited = { 3'd0, pow2[4:2] }; // <8 + 3'd3: detune_unlimited = { 2'd0, pow2[4:1] }; + 3'd4: detune_unlimited = { 1'd0, pow2[4:0] }; + 3'd5: detune_unlimited = { pow2[4:0], 1'd0 }; + default:detune_unlimited = 6'd0; + endcase + detune_limited = detune_unlimited > {1'b0, detune_limit} ? + detune_limit : detune_unlimited[4:0]; + detune_signed = !detune[2] ? {1'b0,detune_limited} : (~{1'b0,detune_limited}+6'd1); +end + +endmodule diff --git a/rtl/sound/jt12/jt12_pg_inc.v b/rtl/sound/jt12/jt12_pg_inc.v new file mode 100644 index 0000000..bee1c8d --- /dev/null +++ b/rtl/sound/jt12/jt12_pg_inc.v @@ -0,0 +1,50 @@ +/* This file is part of JT12. + + JT12 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. + + JT12 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 JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 2-11-2018 + + Based on information posted by Nemesis on: +http://gendev.spritesmind.net/forum/viewtopic.php?t=386&postdays=0&postorder=asc&start=167 + + Based on jt51_phasegen.v, from JT51 + + */ + +module jt12_pg_inc ( + input [ 2:0] block, + input [10:0] fnum, + input signed [8:0] pm_offset, + output reg [16:0] phinc_pure +); + +reg [11:0] fnum_mod; + +always @(*) begin + fnum_mod = {fnum,1'b0} + {{3{pm_offset[8]}},pm_offset}; + case ( block ) + 3'd0: phinc_pure = { 7'd0, fnum_mod[11:2] }; + 3'd1: phinc_pure = { 6'd0, fnum_mod[11:1] }; + 3'd2: phinc_pure = { 5'd0, fnum_mod[11:0] }; + 3'd3: phinc_pure = { 4'd0, fnum_mod, 1'd0 }; + 3'd4: phinc_pure = { 3'd0, fnum_mod, 2'd0 }; + 3'd5: phinc_pure = { 2'd0, fnum_mod, 3'd0 }; + 3'd6: phinc_pure = { 1'd0, fnum_mod, 4'd0 }; + 3'd7: phinc_pure = { fnum_mod, 5'd0 }; + endcase +end + +endmodule // jt12_pg_inc \ No newline at end of file diff --git a/rtl/sound/jt12/jt12_pg_sum.v b/rtl/sound/jt12/jt12_pg_sum.v new file mode 100644 index 0000000..ca79c2e --- /dev/null +++ b/rtl/sound/jt12/jt12_pg_sum.v @@ -0,0 +1,49 @@ +/* This file is part of JT12. + + JT12 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. + + JT12 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 JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 2-11-2018 + + Based on information posted by Nemesis on: +http://gendev.spritesmind.net/forum/viewtopic.php?t=386&postdays=0&postorder=asc&start=167 + + Based on jt51_phasegen.v, from JT51 + + */ + +module jt12_pg_sum ( + input [ 3:0] mul, + input [19:0] phase_in, + input pg_rst, + input signed [5:0] detune_signed, + input [16:0] phinc_pure, + + output reg [19:0] phase_out, + output reg [ 9:0] phase_op +); + +reg [16:0] phinc_premul; +reg [19:0] phinc_mul; + +always @(*) begin + phinc_premul = phinc_pure + {{11{detune_signed[5]}},detune_signed}; + phinc_mul = ( mul==4'd0 ) ? {4'b0,phinc_premul[16:1]} : ({3'd0,phinc_premul} * mul); + + phase_out = pg_rst ? 20'd0 : (phase_in + { phinc_mul}); + phase_op = phase_out[19:10]; +end + +endmodule // jt12_pg_sum \ No newline at end of file diff --git a/rtl/sound/jt12/jt12_phrom.v b/rtl/sound/jt12/jt12_phrom.v deleted file mode 100644 index 2ca926c..0000000 --- a/rtl/sound/jt12/jt12_phrom.v +++ /dev/null @@ -1,77 +0,0 @@ -`timescale 1ns / 1ps - - -/* This file is part of JT12. - - - JT12 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. - - JT12 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 JT12. If not, see . - - Based on Sauraen VHDL version of OPN/OPN2, which is based on die shots. - - Author: Jose Tejada Gomez. Twitter: @topapate - Version: 1.0 - Date: 27-1-2017 - -*/ -// altera message_off 10030 - -module jt12_phrom -( - input [4:0] addr, - input clk, - output reg [45:0] ph -); - - reg [45:0] sinetable[31:0]; - initial - begin - sinetable[5'd0 ] <= 46'b0001100000100100010001000010101010101001010010; - sinetable[5'd1 ] <= 46'b0001100000110100000100000010010001001101000001; - sinetable[5'd2 ] <= 46'b0001100000110100000100110010001011001101100000; - sinetable[5'd3 ] <= 46'b0001110000010000000000110010110001001101110010; - sinetable[5'd4 ] <= 46'b0001110000010000001100000010111010001101101001; - sinetable[5'd5 ] <= 46'b0001110000010100001001100010000000101101111010; - sinetable[5'd6 ] <= 46'b0001110000010100001101100010010011001101011010; - sinetable[5'd7 ] <= 46'b0001110000011100000101010010111000101111111100; - sinetable[5'd8 ] <= 46'b0001110000111000000001110010101110001101110111; - sinetable[5'd9 ] <= 46'b0001110000111000010100111000011101011010100110; - sinetable[5'd10] <= 46'b0001110000111100011000011000111100001001111010; - sinetable[5'd11] <= 46'b0001110000111100011100111001101011001001110111; - sinetable[5'd12] <= 46'b0100100001010000010001011001001000111010110111; - sinetable[5'd13] <= 46'b0100100001010100010001001001110001111100101010; - sinetable[5'd14] <= 46'b0100100001010100010101101101111110100101000110; - sinetable[5'd15] <= 46'b0100100011100000001000011001010110101101111001; - sinetable[5'd16] <= 46'b0100100011100100001000101011100101001011101111; - sinetable[5'd17] <= 46'b0100100011101100000111011010000001011010110001; - sinetable[5'd18] <= 46'b0100110011001000000111101010000010111010111111; - sinetable[5'd19] <= 46'b0100110011001100001011011110101110110110000001; - sinetable[5'd20] <= 46'b0100110011101000011010111011001010001101110001; - sinetable[5'd21] <= 46'b0100110011101101011010110101111001010100001111; - sinetable[5'd22] <= 46'b0111000010000001010111000101010101010110010111; - sinetable[5'd23] <= 46'b0111000010000101010111110111110101010010111011; - sinetable[5'd24] <= 46'b0111000010110101101000101100001000010000011001; - sinetable[5'd25] <= 46'b0111010010011001100100011110100100010010010010; - sinetable[5'd26] <= 46'b0111010010111010100101100101000000110100100011; - sinetable[5'd27] <= 46'b1010000010011010101101011101100001110010011010; - sinetable[5'd28] <= 46'b1010000010111111111100100111010100010000111001; - sinetable[5'd29] <= 46'b1010010111110100110010001100111001010110100000; - sinetable[5'd30] <= 46'b1011010111010011111011011110000100110010100001; - sinetable[5'd31] <= 46'b1110011011110001111011100111100001110110100111; - - end - - always @ (posedge clk) - ph <= sinetable[addr]; - -endmodule diff --git a/rtl/sound/jt12/jt12_pm.v b/rtl/sound/jt12/jt12_pm.v new file mode 100644 index 0000000..e233f94 --- /dev/null +++ b/rtl/sound/jt12/jt12_pm.v @@ -0,0 +1,62 @@ +/* This file is part of jt12. + + jt12 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. + + jt12 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 jt12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 14-10-2018 + */ + +// altera message_off 10030 + +`timescale 1ns / 1ps + +// This implementation follows that of Alexey Khokholov (Nuke.YKT) in C language. + +module jt12_pm ( + input [4:0] lfo_mod, + input [10:0] fnum, + input [2:0] pms, + output reg signed [8:0] pm_offset +); + + +reg [7:0] pm_unsigned; +reg [7:0] pm_base; +reg [9:0] pm_shifted; + +wire [2:0] index = lfo_mod[3] ? (~lfo_mod[2:0]) : lfo_mod[2:0]; + +reg [3:0] lfo_sh1_lut [0:63]; +reg [3:0] lfo_sh2_lut [0:63]; +reg [2:0] lfo_sh1, lfo_sh2; + +initial begin + $readmemh("lfo_sh1_lut.hex",lfo_sh1_lut); + $readmemh("lfo_sh2_lut.hex",lfo_sh2_lut); +end + +always @(*) begin + lfo_sh1 = lfo_sh1_lut[{pms,index}][2:0]; + lfo_sh2 = lfo_sh2_lut[{pms,index}][2:0]; + pm_base = ({1'b0,fnum[10:4]}>>lfo_sh1) + ({1'b0,fnum[10:4]}>>lfo_sh2); + case( pms ) + default: pm_shifted = { 2'b0, pm_base }; + 3'd6: pm_shifted = { 1'b0, pm_base, 1'b0 }; + 3'd7: pm_shifted = { pm_base, 2'b0 }; + endcase // pms + pm_offset = lfo_mod[4] ? (-{1'b0,pm_shifted[9:2]}) : {1'b0,pm_shifted[9:2]}; +end // always @(*) + +endmodule diff --git a/rtl/sound/jt12/jt12_reg.v b/rtl/sound/jt12/jt12_reg.v index 7295871..08cee76 100644 --- a/rtl/sound/jt12/jt12_reg.v +++ b/rtl/sound/jt12/jt12_reg.v @@ -1,114 +1,126 @@ -`timescale 1ns / 1ps - - /* This file is part of JT12. - JT12 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. + JT12 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. - JT12 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. + JT12 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 JT12. If not, see . + You should have received a copy of the GNU General Public License + along with JT12. If not, see . - Author: Jose Tejada Gomez. Twitter: @topapate - Version: 1.0 - Date: 14-2-2017 + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 14-2-2017 */ - module jt12_reg( - input rst, - input clk, - input [7:0] din, - - input [2:0] ch, - input [1:0] op, - - input csm, - input flag_A, - input overflow_A, + input rst, + input clk, + input clk_en, + input [7:0] din, + + input [2:0] ch, + input [1:0] op, + + input csm, + input flag_A, + input overflow_A, - input up_keyon, - input up_alg, - input up_block, - input up_fnumlo, - input up_pms, - input up_dt1, - input up_tl, - input up_ks_ar, - input up_amen_d1r, - input up_d2r, - - input up_d1l, - input up_ssgeg, + input up_keyon, + input up_alg, + input up_fnumlo, + input up_pms, + input up_dt1, + input up_tl, + input up_ks_ar, + input up_amen_dr, + input up_sr, + + input up_sl_rr, + input up_ssgeg, - output busy, - output reg ch6op, // 1 when the operator belongs to CH6 - - // CH3 Effect-mode operation - input effect, - input [10:0] fnum_ch3op2, - input [10:0] fnum_ch3op3, - input [10:0] fnum_ch3op1, - input [ 2:0] block_ch3op2, - input [ 2:0] block_ch3op3, - input [ 2:0] block_ch3op1, - // Pipeline order - output reg zero, - output s1_enters, - output s2_enters, - output s3_enters, - output s4_enters, - - // Operator - output use_prevprev1, - output use_internal_x, - output use_internal_y, - output use_prev2, - output use_prev1, - - // PG - output [10:0] fnum_I, - output [ 2:0] block_I, - // channel configuration - output [1:0] rl, - output reg [2:0] fb_II, - output [2:0] alg, - // Operator multiplying - output [ 3:0] mul_V, - // Operator detuning - output [ 2:0] dt1_II, - - // EG - output [4:0] ar_II, // attack rate - output [4:0] d1r_II, // decay rate - output [4:0] d2r_II, // sustain rate - output [3:0] rr_II, // release rate - output [3:0] d1l, // sustain level - output [1:0] ks_III, // key scale - output ssg_en_II, - output [2:0] ssg_eg_II, - output [6:0] tl_VII, - output [2:0] pms, - output [1:0] ams_VII, - output amsen_VII, + output reg ch6op, // 1 when the operator belongs to CH6 + + // CH3 Effect-mode operation + input effect, + input [10:0] fnum_ch3op2, + input [10:0] fnum_ch3op3, + input [10:0] fnum_ch3op1, + input [ 2:0] block_ch3op2, + input [ 2:0] block_ch3op3, + input [ 2:0] block_ch3op1, + input [ 5:0] latch_fnum, + // Pipeline order + output reg zero, + output s1_enters, + output s2_enters, + output s3_enters, + output s4_enters, + + // Operator + output xuse_prevprev1, + output xuse_internal, + output yuse_internal, + output xuse_prev2, + output yuse_prev1, + output yuse_prev2, + + // PG + output [10:0] fnum_I, + output [ 2:0] block_I, + // channel configuration + output [1:0] rl, + output reg [2:0] fb_II, + output [2:0] alg_I, + // Operator multiplying + output [ 3:0] mul_II, + // Operator detuning + output [ 2:0] dt1_I, + + // EG + output [4:0] ar_I, // attack rate + output [4:0] d1r_I, // decay rate + output [4:0] d2r_I, // sustain rate + output [3:0] rr_I, // release rate + output [3:0] sl_I, // sustain level + output [1:0] ks_II, // key scale + output ssg_en_I, + output [2:0] ssg_eg_I, + output [6:0] tl_IV, + output [2:0] pms_I, + output [1:0] ams_IV, + output amsen_IV, - // envelope operation - output keyon_II + // envelope operation + output keyon_I ); +parameter num_ch=6; // Use only 3 (YM2203/YM2610) or 6 (YM2612/YM2608) + -reg [4:0] cnt; reg [1:0] next_op, cur_op; reg [2:0] next_ch, cur_ch; +reg last; + +`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 +// This does not work with NCVERILOG +initial begin + cur_op = 2'd0; + cur_ch = 3'd0; + last = 1'b0; + zero = 1'b1; +end +`endif assign s1_enters = cur_op == 2'b00; assign s3_enters = cur_op == 2'b01; @@ -120,244 +132,239 @@ wire [4:0] cur = { cur_op, cur_ch }; wire [2:0] fb_I; -always @(posedge clk) begin - fb_II <= fb_I; - ch6op <= next_ch==3'd6; -end +always @(posedge clk) if( clk_en ) begin + fb_II <= fb_I; + ch6op <= next_ch==3'd6; +end // FNUM and BLOCK -wire [10:0] fnum_I_raw; -wire [ 2:0] block_I_raw; +wire [10:0] fnum_I_raw; +wire [ 2:0] block_I_raw; wire effect_on = effect && (cur_ch==3'd2); wire effect_on_s1 = effect_on && (cur_op == 2'd0 ); wire effect_on_s3 = effect_on && (cur_op == 2'd1 ); wire effect_on_s2 = effect_on && (cur_op == 2'd2 ); -wire noeffect = ~|{effect_on_s1, effect_on_s3, effect_on_s2}; +wire noeffect = ~|{effect_on_s1, effect_on_s3, effect_on_s2}; assign fnum_I = ( {11{effect_on_s1}} & fnum_ch3op1 ) | - ( {11{effect_on_s2}} & fnum_ch3op2 ) | - ( {11{effect_on_s3}} & fnum_ch3op3 ) | - ( {11{noeffect}} & fnum_I_raw ); + ( {11{effect_on_s2}} & fnum_ch3op2 ) | + ( {11{effect_on_s3}} & fnum_ch3op3 ) | + ( {11{noeffect}} & fnum_I_raw ); assign block_I =( {3{effect_on_s1}} & block_ch3op1 ) | - ( {3{effect_on_s2}} & block_ch3op2 ) | - ( {3{effect_on_s3}} & block_ch3op3 ) | - ( {3{noeffect}} & block_I_raw ); - + ( {3{effect_on_s2}} & block_ch3op2 ) | + ( {3{effect_on_s3}} & block_ch3op3 ) | + ( {3{noeffect}} & block_I_raw ); + wire [2:0] ch_II, ch_III, ch_IV, ch_V, ch_VI; wire [4:0] req_opch_I = { op, ch }; -wire [4:0] req_opch_II, req_opch_III, - req_opch_IV, req_opch_V, req_opch_VI; - -jt12_sumch u_opch_II ( .chin(req_opch_I ), .chout(req_opch_II) ); -jt12_sumch u_opch_III( .chin(req_opch_II ), .chout(req_opch_III) ); -jt12_sumch u_opch_IV ( .chin(req_opch_III), .chout(req_opch_IV) ); -jt12_sumch u_opch_V ( .chin(req_opch_IV ), .chout(req_opch_V) ); -jt12_sumch u_opch_VI ( .chin(req_opch_V ), .chout(req_opch_VI) ); +wire [4:0] req_opch_II, req_opch_III, + req_opch_IV, req_opch_V, req_opch_VI; + +jt12_sumch #(.num_ch(num_ch)) u_opch_II ( .chin(req_opch_I ), .chout(req_opch_II ) ); +jt12_sumch #(.num_ch(num_ch)) u_opch_III( .chin(req_opch_II ), .chout(req_opch_III) ); +jt12_sumch #(.num_ch(num_ch)) u_opch_IV ( .chin(req_opch_III), .chout(req_opch_IV ) ); +jt12_sumch #(.num_ch(num_ch)) u_opch_V ( .chin(req_opch_IV ), .chout(req_opch_V ) ); +// jt12_sumch #(.num_ch(num_ch)) u_opch_VI ( .chin(req_opch_V ), .chout(req_opch_VI) ); wire update_op_I = cur == req_opch_I; wire update_op_II = cur == req_opch_II; -wire update_op_III= cur == req_opch_III; -// wire update_op_IV = cur == opch_IV; -wire update_op_V = cur == req_opch_V; +// wire update_op_III= cur == req_opch_III; +wire update_op_IV = cur == req_opch_IV; +// wire update_op_V = cur == req_opch_V; // wire update_op_VI = cur == opch_VI; -wire [2:0] op_plus1 = op+2'd1; -wire update_op_VII= cur == { op_plus1[1:0], ch }; +// wire [2:0] op_plus1 = op+2'd1; +// wire update_op_VII= cur == { op_plus1[1:0], ch }; // key on/off -wire [3:0] keyon_op = din[7:4]; -wire [2:0] keyon_ch = din[2:0]; +wire [3:0] keyon_op = din[7:4]; +wire [2:0] keyon_ch = din[2:0]; // channel data -wire [1:0] rl_in = din[7:6]; -wire [2:0] fb_in = din[5:3]; -wire [2:0] alg_in = din[2:0]; -wire [2:0] pms_in = din[2:0]; -wire [1:0] ams_in = din[5:4]; -wire [2:0] block_in= din[5:3]; -wire [2:0] fnhi_in = din[2:0]; -wire [7:0] fnlo_in = din; -// operator data -wire [2:0] dt1_in = din[6:4]; -wire [3:0] mul_in = din[3:0]; -wire [6:0] tl_in = din[6:0]; -wire [1:0] ks_in = din[7:6]; -wire [4:0] ar_in = din[4:0]; -wire amen_in = din[7]; -wire [4:0] d1r_in = din[4:0]; -wire [4:0] d2r_in = din[4:0]; -wire [3:0] d1l_in = din[7:4]; -wire [3:0] rr_in = din[3:0]; -wire [3:0] ssg_in = din[3:0]; +//wire [1:0] rl_in = din[7:6]; +wire [2:0] fb_in = din[5:3]; +wire [2:0] alg_in = din[2:0]; +wire [2:0] pms_in = din[2:0]; +wire [1:0] ams_in = din[5:4]; +wire [7:0] fnlo_in = din; -wire [3:0] ssg; -reg last; +wire update_ch_I = cur_ch == ch; +wire update_ch_IV = num_ch==6 ? + { ~cur_ch[2], cur_ch[1:0]} == ch : // 6 channels + cur[1:0] == ch[1:0]; // 3 channels -wire update_ch_I = cur_ch == ch; - -wire up_alg_ch = up_alg & update_ch_I; -wire up_block_ch= up_block & update_ch_I; +wire up_alg_ch = up_alg & update_ch_I; wire up_fnumlo_ch=up_fnumlo & update_ch_I; -wire up_pms_ch = up_pms & update_ch_I; - -// DT1 & MUL -wire up_dt1_op = up_dt1 & update_op_II; -wire up_mul_op = up_dt1 & update_op_V; -// TL -wire up_tl_op = up_tl & update_op_VII; -// KS & AR -wire up_ks_op = up_ks_ar & update_op_III; -wire up_ar_op = up_ks_ar & update_op_II; -// AM ON, D1R -wire up_amen_op = up_amen_d1r & update_op_VII; -wire up_d1r_op = up_amen_d1r & update_op_II; -// Sustain Rate (D2R) -wire up_d2r_op = up_d2r & update_op_II; -// D1L & RR -wire up_d1l_op = up_d1l & update_op_I; -wire up_rr_op = up_d1l & update_op_II; -// SSG -//wire up_ssgen_op = up_ssgeg & update_op_I; -wire up_ssg_op = up_ssgeg & update_op_II; - -wire up = up_alg | up_block | up_fnumlo | up_pms | - up_dt1 | up_tl | up_ks_ar | up_amen_d1r | - up_d2r | up_d1l | up_ssgeg | up_keyon; +wire up_pms_ch = up_pms & update_ch_I; +wire up_ams_ch = up_pms & update_ch_IV; always @(*) begin - // next <= cur==5'd23 ? 5'd0 : cur +1'b1; - next_op <= cur_ch==3'd6 ? cur_op+1'b1 : cur_op; - next_ch <= cur_ch[1:0]==2'b10 ? cur_ch+2'd2 : cur_ch+1'd1; + // next = cur==5'd23 ? 5'd0 : cur +1'b1; + if( num_ch==6 ) begin + next_op = cur_ch==3'd6 ? cur_op+1'b1 : cur_op; + next_ch = cur_ch[1:0]==2'b10 ? cur_ch+2'd2 : cur_ch+1'd1; + end else begin // 3 channels + next_op = cur_ch==3'd2 ? cur_op+1'b1 : cur_op; + next_ch = cur_ch[1:0]==2'b10 ? 3'd0 : cur_ch+1'd1; + end end -reg busy_op; -reg up_keyon_long; - -assign busy = busy_op; - - always @(posedge clk) begin : up_counter - if( rst ) begin - cnt <= 5'h0; - last <= 1'b0; - zero <= 1'b1; - busy_op <= 1'b0; - up_keyon_long <= 1'b0; - cur_op <= 2'd0; - cur_ch <= 3'd0; - end - else begin - { cur_op, cur_ch } <= { next_op, next_ch }; - zero <= next == 5'd0; - last <= up; - if( up && !last ) begin - cnt <= cur; - busy_op <= 1'b1; - up_keyon_long <= up_keyon; - end - else if( cnt == cur ) begin - busy_op <= 1'b0; - up_keyon_long <= 1'b0; - end - end + if( clk_en ) begin + { cur_op, cur_ch } <= { next_op, next_ch }; + zero <= next == 5'd0; + end end -jt12_kon u_kon( - .rst ( rst ), - .clk ( clk ), - .keyon_op ( keyon_op ), - .keyon_ch ( keyon_ch ), - .cur_op ( cur_op ), - .cur_ch ( cur_ch ), - .up_keyon ( up_keyon_long ), - .csm ( csm ), - .flag_A ( flag_A ), - .overflow_A ( overflow_A), - - .keyon_II ( keyon_II ) +jt12_kon #(.num_ch(num_ch)) u_kon( + .rst ( rst ), + .clk ( clk ), + .clk_en ( clk_en ), + .keyon_op ( keyon_op ), + .keyon_ch ( keyon_ch ), + .next_op ( next_op ), + .next_ch ( next_ch ), + .up_keyon ( up_keyon ), + .csm ( csm ), + // .flag_A ( flag_A ), + .overflow_A ( overflow_A), + + .keyon_I ( keyon_I ) ); -jt12_mod u_mod( - .alg_I ( alg ), - .s1_enters ( s1_enters ), - .s3_enters ( s3_enters ), - .s2_enters ( s2_enters ), - .s4_enters ( s4_enters ), - - .use_prevprev1 ( use_prevprev1 ), - .use_internal_x( use_internal_x ), - .use_internal_y( use_internal_y ), - .use_prev2 ( use_prev2 ), - .use_prev1 ( use_prev1 ) +jt12_mod #(.num_ch(num_ch)) u_mod( + .alg_I ( alg_I ), + .s1_enters ( s1_enters ), + .s3_enters ( s3_enters ), + .s2_enters ( s2_enters ), + .s4_enters ( s4_enters ), + + .xuse_prevprev1 ( xuse_prevprev1 ), + .xuse_internal ( xuse_internal ), + .yuse_internal ( yuse_internal ), + .xuse_prev2 ( xuse_prev2 ), + .yuse_prev1 ( yuse_prev1 ), + .yuse_prev2 ( yuse_prev2 ) ); -// memory for OP registers -parameter regop_width=44; +wire [43:0] shift_out; -wire [regop_width-1:0] regop_in, regop_out; +generate + if( num_ch==6 ) begin + // YM2612 / YM3438: Two CSR. + wire [43:0] shift_middle; -jt12_opram u_opram( - .clk ( clk ), - .wr_addr ( cur ), - .rd_addr ( next ), - .data ( regop_in ), - .q ( regop_out ) -); + jt12_csr u_csr0( + .rst ( rst ), + .clk ( clk ), + .clk_en ( clk_en ), + .din ( din ), + .shift_in ( shift_out ), + .shift_out ( shift_middle ), + .up_tl ( up_tl ), + .up_dt1 ( up_dt1 ), + .up_ks_ar ( up_ks_ar ), + .up_amen_dr ( up_amen_dr ), + .up_sr ( up_sr ), + .up_sl_rr ( up_sl_rr ), + .up_ssgeg ( up_ssgeg ), + .update_op_I ( update_op_I ), + .update_op_II ( update_op_II ), + .update_op_IV ( update_op_IV ) + ); -assign regop_in = { - up_tl_op ? tl_in : tl_VII, // 7 - up_dt1_op ? dt1_in : dt1_II, // 3 - up_mul_op ? mul_in : mul_V, // 4 - 7 - up_ks_op ? ks_in : ks_III, // 2 - 16 - up_ar_op ? ar_in : ar_II, // 5 - 21 - up_amen_op ? amen_in: amsen_VII,// 1 - 22 - up_d1r_op ? d1r_in : d1r_II, // 5 - 25 - up_d2r_op ? d2r_in : d2r_II, // 5 - 30 - up_d1l_op ? d1l_in : d1l, // 4 - 34 - up_rr_op ? rr_in : rr_II, // 4 - 38 - up_ssg_op ? ssg_in[3] : ssg_en_II, // 1 - 39 - up_ssg_op ? ssg_in[2:0] : ssg_eg_II // 3 - 42 -}; + wire up_midop_I = { ~cur[4], cur[3:0] } == req_opch_I; + wire up_midop_II = { ~cur[4], cur[3:0] } == req_opch_II; + wire up_midop_IV = { ~cur[4], cur[3:0] } == req_opch_IV; -assign { tl_VII, dt1_II, mul_V, ks_III, - ar_II, amsen_VII, d1r_II, d2r_II, d1l, rr_II, - ssg_en_II, ssg_eg_II } = regop_out; + jt12_csr u_csr1( + .rst ( rst ), + .clk ( clk ), + .clk_en ( clk_en ), + .din ( din ), + .shift_in ( shift_middle ), + .shift_out ( shift_out ), + .up_tl ( up_tl ), + .up_dt1 ( up_dt1 ), + .up_ks_ar ( up_ks_ar ), + .up_amen_dr ( up_amen_dr ), + .up_sr ( up_sr ), + .up_sl_rr ( up_sl_rr ), + .up_ssgeg ( up_ssgeg ), + // update in the middle: + .update_op_I ( up_midop_I ), + .update_op_II ( up_midop_II ), + .update_op_IV ( up_midop_IV ) + ); + end + else begin // YM2203 only has one CSR + jt12_csr u_csr0( + .rst ( rst ), + .clk ( clk ), + .clk_en ( clk_en ), + .din ( din ), + .shift_in ( shift_out ), + .shift_out ( shift_out ), + .up_tl ( up_tl ), + .up_dt1 ( up_dt1 ), + .up_ks_ar ( up_ks_ar ), + .up_amen_dr ( up_amen_dr ), + .up_sr ( up_sr ), + .up_sl_rr ( up_sl_rr ), + .up_ssgeg ( up_ssgeg ), + .update_op_I ( update_op_I ), + .update_op_II ( update_op_II ), + .update_op_IV ( update_op_IV ) + ); + end // else +endgenerate +assign { tl_IV, dt1_I, mul_II, ks_II, + ar_I, amsen_IV, d1r_I, d2r_I, + sl_I, rr_I, ssg_en_I, ssg_eg_I } = shift_out; -wire [2:0] block_latch, fnum_latch; // memory for CH registers // Block/fnum data is latched until fnum low byte is written to // Trying to synthesize this memory as M-9K RAM in Altera devices // turns out worse in terms of resource utilization. Probably because // this memory is already very small. It is better to leave it as it is. -parameter regch_width=31; +localparam regch_width=25; wire [regch_width-1:0] regch_out; wire [regch_width-1:0] regch_in = { - up_block_ch ? { block_in, fnhi_in } : { block_latch, fnum_latch }, // 3+3 - up_fnumlo_ch? { block_latch, fnum_latch, fnlo_in } : { block_I_raw, fnum_I_raw }, // 14 - up_alg_ch ? { fb_in, alg_in } : { fb_I, alg },//3+3 - up_pms_ch ? { ams_in, pms_in } : { ams_VII, pms }//2+2+3 + up_fnumlo_ch? { latch_fnum, fnlo_in } : { block_I_raw, fnum_I_raw }, // 14 + up_alg_ch ? { fb_in, alg_in } : { fb_I, alg_I },//3+3 + up_ams_ch ? ams_in : ams_IV, //2 + up_pms_ch ? pms_in : pms_I //3 }; -assign { block_latch, fnum_latch, - block_I_raw, fnum_I_raw, - fb_I, alg, ams_VII, pms } = regch_out; +assign { block_I_raw, fnum_I_raw, + fb_I, alg_I, ams_IV, pms_I } = regch_out; -jt12_sh #(.width(regch_width),.stages(6)) u_regch( - .clk ( clk ), - //.rst ( rst ), - .din ( regch_in ), - .drop ( regch_out ) +jt12_sh_rst #(.width(regch_width),.stages(num_ch)) u_regch( + .clk ( clk ), + .clk_en ( clk_en ), + .rst ( rst ), + .din ( regch_in ), + .drop ( regch_out ) ); -// RL is on a different register to -// have the reset to 1 -jt12_sh_rst #(.width(2),.stages(6),.rstval(1'b1)) u_regch_rl( - .clk ( clk ), -// .rst ( rst ), - .din ( up_pms_ch ? rl_in : rl ), - .drop ( rl ) -); +generate +if( num_ch==6 ) begin + // RL is on a different register to + // have the reset to 1 + wire [1:0] rl_in = din[7:6]; + jt12_sh_rst #(.width(2),.stages(num_ch),.rstval(1'b1)) u_regch_rl( + .clk ( clk ), + .clk_en ( clk_en ), + .rst ( rst ), + .din ( up_pms_ch ? rl_in : rl ), + .drop ( rl ) + ); +end else begin // YM2203 has no stereo output + assign rl=2'b11; +end + +endgenerate endmodule diff --git a/rtl/sound/jt12/jt12_sh.v b/rtl/sound/jt12/jt12_sh.v index ac2aeb9..a279489 100644 --- a/rtl/sound/jt12/jt12_sh.v +++ b/rtl/sound/jt12/jt12_sh.v @@ -20,11 +20,13 @@ `timescale 1ns / 1ps +// stages must be greater than 2 module jt12_sh #(parameter width=5, stages=24 ) ( - input clk, - input [width-1:0] din, - output [width-1:0] drop + input clk, + input clk_en, + input [width-1:0] din, + output [width-1:0] drop ); reg [stages-1:0] bits[width-1:0]; @@ -32,11 +34,8 @@ 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) begin - if( stages> 1 ) - bits[i] <= {bits[i][stages-2:0], din[i]}; - else - bits[i] <= din[i]; + always @(posedge clk) if(clk_en) begin + bits[i] <= {bits[i][stages-2:0], din[i]}; end assign drop[i] = bits[i][stages-1]; end diff --git a/rtl/sound/jt12/jt12_sh24.v b/rtl/sound/jt12/jt12_sh24.v index dfb1596..420762d 100644 --- a/rtl/sound/jt12/jt12_sh24.v +++ b/rtl/sound/jt12/jt12_sh24.v @@ -22,35 +22,36 @@ module jt12_sh24 #(parameter width=5 ) ( - input clk, - input [width-1:0] din, - output reg [width-1:0] st1, - output reg [width-1:0] st2, - output reg [width-1:0] st3, - output reg [width-1:0] st4, - output reg [width-1:0] st5, - output reg [width-1:0] st6, - output reg [width-1:0] st7, - output reg [width-1:0] st8, - output reg [width-1:0] st9, - output reg [width-1:0] st10, - output reg [width-1:0] st11, - output reg [width-1:0] st12, - output reg [width-1:0] st13, - output reg [width-1:0] st14, - output reg [width-1:0] st15, - output reg [width-1:0] st16, - output reg [width-1:0] st17, - output reg [width-1:0] st18, - output reg [width-1:0] st19, - output reg [width-1:0] st20, - output reg [width-1:0] st21, - output reg [width-1:0] st22, - output reg [width-1:0] st23, - output reg [width-1:0] st24 + input clk, + input clk_en, + input [width-1:0] din, + output reg [width-1:0] st1, + output reg [width-1:0] st2, + output reg [width-1:0] st3, + output reg [width-1:0] st4, + output reg [width-1:0] st5, + output reg [width-1:0] st6, + output reg [width-1:0] st7, + output reg [width-1:0] st8, + output reg [width-1:0] st9, + output reg [width-1:0] st10, + output reg [width-1:0] st11, + output reg [width-1:0] st12, + output reg [width-1:0] st13, + output reg [width-1:0] st14, + output reg [width-1:0] st15, + output reg [width-1:0] st16, + output reg [width-1:0] st17, + output reg [width-1:0] st18, + output reg [width-1:0] st19, + output reg [width-1:0] st20, + output reg [width-1:0] st21, + output reg [width-1:0] st22, + output reg [width-1:0] st23, + output reg [width-1:0] st24 ); -always @(posedge clk) begin +always @(posedge clk) if(clk_en) begin st24<= st23; st23<= st22; st22<= st21; diff --git a/rtl/sound/jt12/jt12_sh_rst.v b/rtl/sound/jt12/jt12_sh_rst.v index 3e2cc13..47e44c1 100644 --- a/rtl/sound/jt12/jt12_sh_rst.v +++ b/rtl/sound/jt12/jt12_sh_rst.v @@ -20,10 +20,12 @@ `timescale 1ns / 1ps +// stages must be greater than 2 module jt12_sh_rst #(parameter width=5, stages=32, rstval=1'b0 ) ( -// input rst, + input rst, input clk, + input clk_en, input [width-1:0] din, output [width-1:0] drop ); @@ -35,18 +37,18 @@ integer k; generate initial for (k=0; k < width; k=k+1) begin - bits[k] <= { stages{rstval}}; + bits[k] = { stages{rstval}}; end endgenerate generate for (i=0; i < width; i=i+1) begin: bit_shifter - always @(posedge clk) begin - if( stages> 1 ) + always @(posedge clk) + if( rst ) begin + bits[i] <= {stages{rstval}}; + end else if(clk_en) begin bits[i] <= {bits[i][stages-2:0], din[i]}; - else - bits[i] <= din[i]; - end + end assign drop[i] = bits[i][stages-1]; end endgenerate diff --git a/rtl/sound/jt12/jt12_single_acc.v b/rtl/sound/jt12/jt12_single_acc.v new file mode 100644 index 0000000..24996f8 --- /dev/null +++ b/rtl/sound/jt12/jt12_single_acc.v @@ -0,0 +1,59 @@ +/* This file is part of JT12. + + + JT12 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. + + JT12 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 JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 27-1-2017 + +*/ + +`timescale 1ns / 1ps + +module jt12_single_acc #(parameter win=14, // input data width + wout=16 // output data width +)( + input clk, + input clk_en, + input [win-1:0] op_result, + input sum_en, + input zero, + output reg [wout-1:0] snd +); + +// for full resolution use win=14, wout=16 +// for cut down resolution use win=9, wout=12 +// wout-win should be > 0 + +reg signed [wout-1:0] next, acc, current; +reg overflow; + +wire [wout-1:0] plus_inf = { 1'b0, {(wout-1){1'b1}} }; // maximum positive value +wire [wout-1:0] minus_inf = { 1'b1, {(wout-1){1'b0}} }; // minimum negative value + +always @(*) begin + current = sum_en ? { {(wout-win){op_result[win-1]}}, op_result } : {wout{1'b0}}; + next = zero ? current : current + acc; + overflow = !zero && + (current[wout-1] == acc[wout-1]) && + (acc[wout-1]!=next[wout-1]); +end + +always @(posedge clk) if( clk_en ) begin + acc <= overflow ? (acc[wout-1] ? minus_inf : plus_inf) : next; + if(zero) snd <= acc; +end + +endmodule // jt12_single_acc \ No newline at end of file diff --git a/rtl/sound/jt12/jt12_sumch.v b/rtl/sound/jt12/jt12_sumch.v index d3713ed..75b1d4f 100644 --- a/rtl/sound/jt12/jt12_sumch.v +++ b/rtl/sound/jt12/jt12_sumch.v @@ -20,18 +20,28 @@ `timescale 1ns / 1ps +/* The input is {op[1:0], ch[2:0]} + it adds 1 to the channel and overflow to the operator correctly */ + module jt12_sumch ( input [4:0] chin, output reg [4:0] chout ); +parameter num_ch=6; + reg [2:0] aux; always @(*) begin - aux <= chin[2:0] + 3'd1; - chout[2:0] <= aux[1:0]==2'b11 ? aux+3'd1 : aux; - chout[4:3] <= chin[2:0]==3'd6 ? chin[4:3]+2'd1 : chin[4:3]; + aux = chin[2:0] + 3'd1; + if( num_ch==6 ) begin + chout[2:0] = aux[1:0]==2'b11 ? aux+3'd1 : aux; + chout[4:3] = chin[2:0]==3'd6 ? chin[4:3]+2'd1 : chin[4:3]; // next operator + end else begin // 3 channels + chout[2:0] = aux[1:0]==2'b11 ? 3'd0 : aux; + chout[4:3] = chin[2:0]==3'd2 ? chin[4:3]+2'd1 : chin[4:3]; // next operator + end end endmodule diff --git a/rtl/sound/jt12/jt12_syn.v b/rtl/sound/jt12/jt12_syn.v deleted file mode 100644 index 5ee5a0c..0000000 --- a/rtl/sound/jt12/jt12_syn.v +++ /dev/null @@ -1,338 +0,0 @@ -module jt12_syn( - input rst, - input clk, // cpu_clk/6 ~ 1.3MHz - input [7:0] din, - input [1:0] addr, - input write, - input limiter_en, - - output busy, - output flag_A, - output flag_B, - output irq_n, - // combined output - output signed [11:0] snd_right, - output signed [11:0] snd_left, - output snd_sample, - // multiplexed output - output signed [8:0] mux_right, - output signed [8:0] mux_left, - output mux_sample -); -// Timers -wire [9:0] value_A; -wire [7:0] value_B; -wire load_A, load_B; -wire enable_irq_A, enable_irq_B; -wire clr_flag_A, clr_flag_B; -wire overflow_A; -wire fast_timers; - -wire zero; // Single-clock pulse at the begginig of s1_enters -// LFO -wire [2:0] lfo_freq; -wire lfo_en; -// Operators -wire amsen_VII; -wire [ 2:0] dt1_II; -wire [ 3:0] mul_V; -wire [ 6:0] tl_VII; - -wire [4:0] keycode_III; -wire [ 4:0] ar_II; -wire [ 4:0] d1r_II; -wire [ 4:0] d2r_II; -wire [ 3:0] rr_II; -wire [ 3:0] d1l; -wire [ 1:0] ks_III; -// SSG operation -wire ssg_en_II; -wire [2:0] ssg_eg_II; -// envelope operation -wire keyon_II; -wire [9:0] eg_IX; -wire pg_rst_III; -// Channel -wire [10:0] fnum_I; -wire [ 2:0] block_I; -wire [ 1:0] rl; -wire [ 2:0] fb_II; -wire [ 2:0] alg; -wire [ 2:0] pms; -wire [ 1:0] ams_VII; -// PCM -wire pcm_en; -wire [ 8:0] pcm; -// Test -wire pg_stop, eg_stop; - -wire ch6op; - -// Operator -wire use_internal_x, use_internal_y; -wire use_prevprev1, use_prev2, use_prev1; -wire [ 9:0] phase_VIII; -wire s1_enters, s2_enters, s3_enters, s4_enters; -wire rst_int; -// LFO -wire [6:0] lfo_mod; -wire lfo_rst; - -`ifdef TEST_SUPPORT -// Test bits -wire test_eg, test_op0; -`endif - -jt12_mmr u_mmr( - .rst ( rst ), - .clk ( clk ), - .din ( din ), - .write ( write ), - .addr ( addr ), - .busy ( busy ), - .ch6op ( ch6op ), - // LFO - .lfo_freq ( lfo_freq ), - .lfo_en ( lfo_en ), - // Timers - .value_A ( value_A ), - .value_B ( value_B ), - .load_A ( load_A ), - .load_B ( load_B ), - .enable_irq_A ( enable_irq_A ), - .enable_irq_B ( enable_irq_B ), - .clr_flag_A ( clr_flag_A ), - .clr_flag_B ( clr_flag_B ), - .flag_A ( flag_A ), - .overflow_A ( overflow_A ), - .fast_timers( fast_timers ), - // PCM - .pcm ( pcm ), - .pcm_en ( pcm_en ), - - `ifdef TEST_SUPPORT - // Test - .test_eg ( test_eg ), - .test_op0 ( test_op0 ), - `endif - // Operator - .use_prevprev1 ( use_prevprev1 ), - .use_internal_x ( use_internal_x ), - .use_internal_y ( use_internal_y ), - .use_prev2 ( use_prev2 ), - .use_prev1 ( use_prev1 ), - // PG - .fnum_I ( fnum_I ), - .block_I ( block_I ), - .pg_stop ( pg_stop ), - // EG - .rl ( rl ), - .fb_II ( fb_II ), - .alg ( alg ), - .pms ( pms ), - .ams_VII ( ams_VII ), - .amsen_VII ( amsen_VII ), - .dt1_II ( dt1_II ), - .mul_V ( mul_V ), - .tl_VII ( tl_VII ), - - .ar_II ( ar_II ), - .d1r_II ( d1r_II ), - .d2r_II ( d2r_II ), - .rr_II ( rr_II ), - .d1l ( d1l ), - .ks_III ( ks_III ), - - .eg_stop ( eg_stop ), - // SSG operation - .ssg_en_II ( ssg_en_II ), - .ssg_eg_II ( ssg_eg_II ), - - .keyon_II ( keyon_II ), - // Operator - .zero ( zero ), - .s1_enters ( s1_enters ), - .s2_enters ( s2_enters ), - .s3_enters ( s3_enters ), - .s4_enters ( s4_enters ) -); - -jt12_timers u_timers( - .clk ( clk ), - .rst ( rst ), - .clk_en ( zero ), - .fast_timers( fast_timers ), // fix this to work well with clock enable signals - .value_A ( value_A ), - .value_B ( value_B ), - .load_A ( load_A ), - .load_B ( load_B ), - .enable_irq_A( enable_irq_B ), - .enable_irq_B( enable_irq_A ), - .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 ) -); - -jt12_lfo u_lfo( - .rst ( rst ), - .clk ( clk ), - .zero ( zero ), - .lfo_rst ( 1'b0 ), - .lfo_en ( lfo_en ), - .lfo_freq ( lfo_freq ), - .lfo_mod ( lfo_mod ) -); - -`ifndef TIMERONLY - -jt12_pg u_pg( - .clk ( clk ), - .rst ( rst ), - // Channel frequency - .fnum_I ( fnum_I ), - .block_I ( block_I ), - // Operator multiplying - .mul_V ( mul_V ), - // Operator detuning - .dt1_II ( dt1_II ), // same as JT51's DT1 - // phase operation - .pg_rst_III ( pg_rst_III ), - .zero ( zero ), - .pg_stop ( pg_stop ), - .keycode_III( keycode_III ), - .phase_VIII ( phase_VIII ) -); - -jt12_eg u_eg( - `ifdef TEST_SUPPORT - .test_eg ( test_eg ), - `endif - .rst ( rst ), - .clk ( clk ), - .zero ( zero ), - .eg_stop ( eg_stop ), - // envelope configuration - .keycode_III ( keycode_III ), - .arate_II ( ar_II ), // attack rate - .rate1_II ( d1r_II ), // decay rate - .rate2_II ( d2r_II ), // sustain rate - .rrate_II ( rr_II ), // release rate - .d1l ( d1l ), // sustain level - .ks_III ( ks_III ), // key scale - // SSG operation - .ssg_en_II ( ssg_en_II ), - .ssg_eg_II ( ssg_eg_II ), - // envelope operation - .keyon_II ( keyon_II ), - // envelope number - .am ( lfo_mod ), - .tl_VII ( tl_VII ), - .ams_VII ( ams_VII ), - .amsen_VII ( amsen_VII ), - - .eg_IX ( eg_IX ), - .pg_rst_III ( pg_rst_III ) -); - -wire [8:0] op_result; - -jt12_op u_op( - .rst ( rst ), - .clk ( clk ), - .pg_phase_VIII ( phase_VIII ), - .eg_atten_IX ( eg_IX ), - .fb_II ( fb_II ), - - .test_214 ( 1'b0 ), - .s1_enters ( s1_enters ), - .s2_enters ( s2_enters ), - .s3_enters ( s3_enters ), - .s4_enters ( s4_enters ), - .use_prevprev1 ( use_prevprev1 ), - .use_internal_x ( use_internal_x), - .use_internal_y ( use_internal_y), - .use_prev2 ( use_prev2 ), - .use_prev1 ( use_prev1 ), - .zero ( zero ), - .op_result ( op_result ) -); - -jt12_acc u_acc( - .rst ( rst ), - .clk ( clk ), - .op_result ( op_result ), - .rl ( rl ), - .limiter_en ( limiter_en), - // note that the order changes to deal - // with the operator pipeline delay - .s1_enters ( s2_enters ), - .s2_enters ( s1_enters ), - .s3_enters ( s4_enters ), - .s4_enters ( s3_enters ), - .ch6op ( ch6op ), - .pcm_en ( pcm_en ), // only enabled for channel 6 - .pcm ( pcm ), - .alg ( alg ), - // combined output - .left ( snd_left ), - .right ( snd_right ), - .sample ( snd_sample), - // muxed output - .mux_left ( mux_left ), - .mux_right ( mux_right ), - .mux_sample ( mux_sample) -); - -`ifdef SIMULATION -reg [4:0] sep24_cnt; - -wire [9:0] eg_ch0s1, eg_ch1s1, eg_ch2s1, eg_ch3s1, eg_ch4s1, eg_ch5s1, - eg_ch0s2, eg_ch1s2, eg_ch2s2, eg_ch3s2, eg_ch4s2, eg_ch5s2, - eg_ch0s3, eg_ch1s3, eg_ch2s3, eg_ch3s3, eg_ch4s3, eg_ch5s3, - eg_ch0s4, eg_ch1s4, eg_ch2s4, eg_ch3s4, eg_ch4s4, eg_ch5s4; - -always @(posedge clk) - sep24_cnt <= !zero ? sep24_cnt+1'b1 : 5'd0; - -sep24 #( .width(10), .pos0(5'd0)) egsep -( - .clk ( clk ), - .mixed ( eg_IX ), - .mask ( 10'd0 ), - .cnt ( sep24_cnt ), - - .ch0s1 (eg_ch0s1), - .ch1s1 (eg_ch1s1), - .ch2s1 (eg_ch2s1), - .ch3s1 (eg_ch3s1), - .ch4s1 (eg_ch4s1), - .ch5s1 (eg_ch5s1), - - .ch0s2 (eg_ch0s2), - .ch1s2 (eg_ch1s2), - .ch2s2 (eg_ch2s2), - .ch3s2 (eg_ch3s2), - .ch4s2 (eg_ch4s2), - .ch5s2 (eg_ch5s2), - - .ch0s3 (eg_ch0s3), - .ch1s3 (eg_ch1s3), - .ch2s3 (eg_ch2s3), - .ch3s3 (eg_ch3s3), - .ch4s3 (eg_ch4s3), - .ch5s3 (eg_ch5s3), - - .ch0s4 (eg_ch0s4), - .ch1s4 (eg_ch1s4), - .ch2s4 (eg_ch2s4), - .ch3s4 (eg_ch3s4), - .ch4s4 (eg_ch4s4), - .ch5s4 (eg_ch5s4) -); -`endif - -`endif -endmodule diff --git a/rtl/sound/jt12/jt12_timers.v b/rtl/sound/jt12/jt12_timers.v index 4fb2bd8..4db0546 100644 --- a/rtl/sound/jt12/jt12_timers.v +++ b/rtl/sound/jt12/jt12_timers.v @@ -28,7 +28,6 @@ module jt12_timers( input clk, input rst, input clk_en, // clock enable - input fast_timers, input [9:0] value_A, input [7:0] value_B, input load_A, @@ -45,11 +44,11 @@ module jt12_timers( assign irq_n = ~( (flag_A&enable_irq_A) | (flag_B&enable_irq_B) ); -jt12_timer #(.mult_width(1), .mult_max(0), .counter_width(10)) +jt12_timer #(.mult_width(5), .mult_max(24), .counter_width(10)) timer_A( .clk ( clk ), .rst ( rst ), - .clk_en ( clk_en | fast_timers ), + .clk_en ( clk_en ), .start_value( value_A ), .load ( load_A ), .clr_flag ( clr_flag_A), @@ -57,11 +56,11 @@ timer_A( .overflow ( overflow_A) ); -jt12_timer #(.mult_width(4), .mult_max(15), .counter_width(8)) +jt12_timer #(.mult_width(9), .mult_max(384), .counter_width(8)) timer_B( .clk ( clk ), .rst ( rst ), - .clk_en ( clk_en | fast_timers ), + .clk_en ( clk_en ), .start_value( value_B ), .load ( load_B ), .clr_flag ( clr_flag_B), @@ -94,15 +93,17 @@ always@(posedge clk) reg [mult_width+counter_width-1:0] next, init; always @(*) begin - if( mult. + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 14-2-2016 + + Based on information posted by Nemesis on: +http://gendev.spritesmind.net/forum/viewtopic.php?t=386&postdays=0&postorder=asc&start=167 + + Based on jt51_phasegen.v, from JT51 + + */ + +module jt12_top ( + input rst, // rst should be at least 6 clk&cen cycles long + input clk, // CPU clock + input cen, // optional clock enable, it not needed leave as 1'b1 + input [7:0] din, + input [1:0] addr, + input cs_n, + input wr_n, + + output [7:0] dout, + output irq_n, + // Separated output + output [ 7:0] psg_A, + output [ 7:0] psg_B, + output [ 7:0] psg_C, + output signed [15:0] fm_snd_left, + output signed [15:0] fm_snd_right, + // combined output + output [ 9:0] psg_snd, + output signed [15:0] snd_right, // FM+PSG + output signed [15:0] snd_left, // FM+PSG + output snd_sample +); + +parameter use_lfo=1, use_ssg=0, num_ch=6, use_pcm=1, use_lr=1; // defaults to YM2612 + +wire flag_A, flag_B, busy; + +wire [7:0] fm_dout = { busy, 5'd0, flag_B, flag_A }; +wire write = !cs_n && !wr_n; +wire clk_en, clk_en_ssg; + +// Timers +wire [9:0] value_A; +wire [7:0] value_B; +wire load_A, load_B; +wire enable_irq_A, enable_irq_B; +wire clr_flag_A, clr_flag_B; +wire overflow_A; +wire fast_timers; + +wire zero; // Single-clock pulse at the begginig of s1_enters +// LFO +wire [2:0] lfo_freq; +wire lfo_en; +// Operators +wire amsen_IV; +wire [ 2:0] dt1_I; +wire [ 3:0] mul_II; +wire [ 6:0] tl_IV; + +wire [ 4:0] keycode_II; +wire [ 4:0] ar_I; +wire [ 4:0] d1r_I; +wire [ 4:0] d2r_I; +wire [ 3:0] rr_I; +wire [ 3:0] sl_I; +wire [ 1:0] ks_II; +// SSG operation +wire ssg_en_I; +wire [2:0] ssg_eg_I; +// envelope operation +wire keyon_I; +wire [9:0] eg_IX; +wire pg_rst_II; +// Channel +wire [10:0] fnum_I; +wire [ 2:0] block_I; +wire [ 1:0] rl; +wire [ 2:0] fb_II; +wire [ 2:0] alg_I; +wire [ 2:0] pms_I; +wire [ 1:0] ams_IV; +// PCM +wire pcm_en, pcm_wr; +wire [ 8:0] pcm; +// Test +wire pg_stop, eg_stop; + +wire ch6op; + +// Operator +wire xuse_internal, yuse_internal; +wire xuse_prevprev1, xuse_prev2, yuse_prev1, yuse_prev2; +wire [ 9:0] phase_VIII; +wire s1_enters, s2_enters, s3_enters, s4_enters; +wire rst_int; +// LFO +wire [6:0] lfo_mod; +wire lfo_rst; +// PSG +wire [3:0] psg_addr; +wire [7:0] psg_data, psg_dout; +wire psg_wr_n; + +jt12_mmr #(.use_ssg(use_ssg),.num_ch(num_ch),.use_pcm(use_pcm)) + u_mmr( + .rst ( rst ), + .clk ( clk ), + .cen ( cen ), // external clock enable + .clk_en ( clk_en ), // internal clock enable + .clk_en_ssg ( clk_en_ssg), // internal clock enable + .din ( din ), + .write ( write ), + .addr ( addr ), + .busy ( busy ), + .ch6op ( ch6op ), + // LFO + .lfo_freq ( lfo_freq ), + .lfo_en ( lfo_en ), + // Timers + .value_A ( value_A ), + .value_B ( value_B ), + .load_A ( load_A ), + .load_B ( load_B ), + .enable_irq_A ( enable_irq_A ), + .enable_irq_B ( enable_irq_B ), + .clr_flag_A ( clr_flag_A ), + .clr_flag_B ( clr_flag_B ), + .flag_A ( flag_A ), + .overflow_A ( overflow_A ), + .fast_timers( fast_timers ), + // PCM + .pcm ( pcm ), + .pcm_en ( pcm_en ), + .pcm_wr ( pcm_wr ), + + // Operator + .xuse_prevprev1 ( xuse_prevprev1 ), + .xuse_internal ( xuse_internal ), + .yuse_internal ( yuse_internal ), + .xuse_prev2 ( xuse_prev2 ), + .yuse_prev1 ( yuse_prev1 ), + .yuse_prev2 ( yuse_prev2 ), + // PG + .fnum_I ( fnum_I ), + .block_I ( block_I ), + .pg_stop ( pg_stop ), + // EG + .rl ( rl ), + .fb_II ( fb_II ), + .alg_I ( alg_I ), + .pms_I ( pms_I ), + .ams_IV ( ams_IV ), + .amsen_IV ( amsen_IV ), + .dt1_I ( dt1_I ), + .mul_II ( mul_II ), + .tl_IV ( tl_IV ), + + .ar_I ( ar_I ), + .d1r_I ( d1r_I ), + .d2r_I ( d2r_I ), + .rr_I ( rr_I ), + .sl_I ( sl_I ), + .ks_II ( ks_II ), + + .eg_stop ( eg_stop ), + // SSG operation + .ssg_en_I ( ssg_en_I ), + .ssg_eg_I ( ssg_eg_I ), + + .keyon_I ( keyon_I ), + // Operator + .zero ( zero ), + .s1_enters ( s1_enters ), + .s2_enters ( s2_enters ), + .s3_enters ( s3_enters ), + .s4_enters ( s4_enters ), + // PSG interace + .psg_addr ( psg_addr ), + .psg_data ( psg_data ), + .psg_wr_n ( psg_wr_n ) +); + +jt12_timers u_timers( + .clk ( clk ), + .clk_en ( clk_en | fast_timers ), + .rst ( rst ), + .value_A ( value_A ), + .value_B ( value_B ), + .load_A ( load_A ), + .load_B ( load_B ), + .enable_irq_A( enable_irq_B ), + .enable_irq_B( enable_irq_A ), + .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 ) +); + +// YM2203 does not have LFO +generate +if( use_lfo== 1) + jt12_lfo u_lfo( + .rst ( rst ), + .clk ( clk ), + .clk_en ( clk_en ), + .zero ( zero ), + `ifdef NOLFO + .lfo_rst ( 1'b1 ), + `else + .lfo_rst ( 1'b0 ), + `endif + .lfo_en ( lfo_en ), + .lfo_freq ( lfo_freq ), + .lfo_mod ( lfo_mod ) + ); +else + assign lfo_mod = 7'd0; +endgenerate + +// YM2203/YM2610 have a PSG + +generate + if( use_ssg==1 ) begin + ym2149 u_psg + ( + .CLK(clk), + .CE(clk_en_ssg), + .RESET(rst), + + .BDIR(write), + .BC(~addr[0] | ~write), + .DI(din), + .DO(psg_dout), + .CHANNEL_A(psg_A), + .CHANNEL_B(psg_B), + .CHANNEL_C(psg_C) + ); + assign psg_snd = {2'b00, psg_A} + {2'b00, psg_B} + {2'b00, psg_C}; + assign snd_left = fm_snd_left + { 2'b0, psg_snd[9:1],5'd0}; + assign snd_right = fm_snd_right + { 2'b0, psg_snd[9:1],5'd0}; + assign dout = addr[0] ? psg_dout : fm_dout; + end else begin + assign psg_snd = 10'd0; + assign snd_left = fm_snd_left; + assign snd_right= fm_snd_right; + assign psg_dout = 8'd0; + assign dout = fm_dout; + end +endgenerate + + +`ifndef TIMERONLY + +jt12_pg #(.num_ch(num_ch)) u_pg( + .rst ( rst ), + .clk ( clk ), + .clk_en ( clk_en ), + // Channel frequency + .fnum_I ( fnum_I ), + .block_I ( block_I ), + // Operator multiplying + .mul_II ( mul_II ), + // Operator detuning + .dt1_I ( dt1_I ), // same as JT51's DT1 + // Phase modulation by LFO + .lfo_mod ( lfo_mod ), + .pms_I ( pms_I ), + // phase operation + .pg_rst_II ( pg_rst_II ), + .pg_stop ( pg_stop ), + .keycode_II ( keycode_II ), + .phase_VIII ( phase_VIII ) +); + +wire [9:0] eg_V; + +jt12_eg #(.num_ch(num_ch)) u_eg( + .rst ( rst ), + .clk ( clk ), + .clk_en ( clk_en ), + .zero ( zero ), + .eg_stop ( eg_stop ), + // envelope configuration + .keycode_II ( keycode_II ), + .arate_I ( ar_I ), // attack rate + .rate1_I ( d1r_I ), // decay rate + .rate2_I ( d2r_I ), // sustain rate + .rrate_I ( rr_I ), // release rate + .sl_I ( sl_I ), // sustain level + .ks_II ( ks_II ), // key scale + // SSG operation + .ssg_en_I ( ssg_en_I ), + .ssg_eg_I ( ssg_eg_I ), + // envelope operation + .keyon_I ( keyon_I ), + // envelope number + .lfo_mod ( lfo_mod ), + .tl_IV ( tl_IV ), + .ams_IV ( ams_IV ), + .amsen_IV ( amsen_IV ), + + .eg_V ( eg_V ), + .pg_rst_II ( pg_rst_II ) +); + +jt12_sh #(.width(10),.stages(4)) u_egpad( + .clk ( clk ), + .clk_en ( clk_en ), + .din ( eg_V ), + .drop ( eg_IX ) +); + +wire [ 8:0] op_result; +wire [13:0] full_result; + +jt12_op #(.num_ch(num_ch)) u_op( + .rst ( rst ), + .clk ( clk ), + .clk_en ( clk_en ), + .pg_phase_VIII ( phase_VIII ), + .eg_atten_IX ( eg_IX ), + .fb_II ( fb_II ), + + .test_214 ( 1'b0 ), + .s1_enters ( s1_enters ), + .s2_enters ( s2_enters ), + .s3_enters ( s3_enters ), + .s4_enters ( s4_enters ), + .xuse_prevprev1 ( xuse_prevprev1), + .xuse_internal ( xuse_internal ), + .yuse_internal ( yuse_internal ), + .xuse_prev2 ( xuse_prev2 ), + .yuse_prev1 ( yuse_prev1 ), + .yuse_prev2 ( yuse_prev2 ), + .zero ( zero ), + .op_result ( op_result ), + .full_result ( full_result ) +); + +generate + if( use_lr==1 ) begin + assign fm_snd_right[3:0] = 4'd0; + assign fm_snd_left [3:0] = 4'd0; + assign snd_sample = zero; + wire signed [8:0] pcm2; + + // interpolate PCM samples with automatic sample rate detection + // this feature is not present in original YM2612 + // this improves PCM sample sound greatly + jt12_pcm u_pcm( + .rst ( rst ), + .clk ( clk ), + .clk_en ( clk_en ), + .zero ( zero ), + .pcm ( pcm ), + .pcm_wr ( pcm_wr ), + .pcm_resampled ( pcm2 ) + ); + + jt12_acc #(.num_ch(num_ch)) u_acc( + .rst ( rst ), + .clk ( clk ), + .clk_en ( clk_en ), + .op_result ( op_result ), + .rl ( rl ), + // note that the order changes to deal + // with the operator pipeline delay + .zero ( zero ), + .s1_enters ( s2_enters ), + .s2_enters ( s1_enters ), + .s3_enters ( s4_enters ), + .s4_enters ( s3_enters ), + .ch6op ( ch6op ), + .pcm_en ( pcm_en ), // only enabled for channel 6 + .pcm ( pcm2 ), + .alg ( alg_I ), + // combined output + .left ( fm_snd_left [15:4] ), + .right ( fm_snd_right[15:4] ) + ); + end else begin + wire signed [15:0] mono_snd; + assign fm_snd_left = mono_snd; + assign fm_snd_right = mono_snd; + assign snd_sample = zero; + jt03_acc u_acc( + .rst ( rst ), + .clk ( clk ), + .clk_en ( clk_en ), + .op_result ( full_result ), + // note that the order changes to deal + // with the operator pipeline delay + .s1_enters ( s1_enters ), + .s2_enters ( s2_enters ), + .s3_enters ( s3_enters ), + .s4_enters ( s4_enters ), + .alg ( alg_I ), + .zero ( zero ), + // combined output + .snd ( mono_snd ) + ); + end +endgenerate + +`ifdef SIMULATION +/* verilator lint_off PINMISSING */ +reg [4:0] sep24_cnt; + +wire [9:0] eg_ch0s1, eg_ch1s1, eg_ch2s1, eg_ch3s1, eg_ch4s1, eg_ch5s1, + eg_ch0s2, eg_ch1s2, eg_ch2s2, eg_ch3s2, eg_ch4s2, eg_ch5s2, + eg_ch0s3, eg_ch1s3, eg_ch2s3, eg_ch3s3, eg_ch4s3, eg_ch5s3, + eg_ch0s4, eg_ch1s4, eg_ch2s4, eg_ch3s4, eg_ch4s4, eg_ch5s4; + +always @(posedge clk) if( clk_en ) + sep24_cnt <= !zero ? sep24_cnt+1'b1 : 5'd0; + +sep24 #( .width(10), .pos0(5'd0)) egsep +( + .clk ( clk ), + .clk_en ( clk_en ), + .mixed ( eg_IX ), + .mask ( 24'd0 ), + .cnt ( sep24_cnt ), + + .ch0s1 (eg_ch0s1), + .ch1s1 (eg_ch1s1), + .ch2s1 (eg_ch2s1), + .ch3s1 (eg_ch3s1), + .ch4s1 (eg_ch4s1), + .ch5s1 (eg_ch5s1), + + .ch0s2 (eg_ch0s2), + .ch1s2 (eg_ch1s2), + .ch2s2 (eg_ch2s2), + .ch3s2 (eg_ch3s2), + .ch4s2 (eg_ch4s2), + .ch5s2 (eg_ch5s2), + + .ch0s3 (eg_ch0s3), + .ch1s3 (eg_ch1s3), + .ch2s3 (eg_ch2s3), + .ch3s3 (eg_ch3s3), + .ch4s3 (eg_ch4s3), + .ch5s3 (eg_ch5s3), + + .ch0s4 (eg_ch0s4), + .ch1s4 (eg_ch1s4), + .ch2s4 (eg_ch2s4), + .ch3s4 (eg_ch3s4), + .ch4s4 (eg_ch4s4), + .ch5s4 (eg_ch5s4) +); +`endif +/* verilator lint_on PINMISSING */ +`endif +endmodule diff --git a/rtl/sound/jt12/lfo_sh1_lut.hex b/rtl/sound/jt12/lfo_sh1_lut.hex new file mode 100644 index 0000000..16afdfb --- /dev/null +++ b/rtl/sound/jt12/lfo_sh1_lut.hex @@ -0,0 +1,64 @@ +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +1 +1 +7 +7 +7 +7 +1 +1 +1 +1 +7 +7 +7 +1 +1 +1 +1 +0 +7 +7 +1 +1 +0 +0 +0 +0 +7 +7 +1 +1 +0 +0 +0 +0 +7 +7 +1 +1 +0 +0 +0 +0 \ No newline at end of file diff --git a/rtl/sound/jt12/lfo_sh2_lut.hex b/rtl/sound/jt12/lfo_sh2_lut.hex new file mode 100644 index 0000000..57c3527 --- /dev/null +++ b/rtl/sound/jt12/lfo_sh2_lut.hex @@ -0,0 +1,64 @@ +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +2 +2 +2 +2 +7 +7 +7 +2 +2 +2 +7 +7 +7 +7 +2 +2 +7 +7 +2 +2 +7 +7 +2 +7 +7 +7 +2 +7 +7 +7 +7 +2 +7 +7 +2 +1 +7 +7 +7 +2 +7 +7 +2 +1 +7 +7 +7 +2 +7 +7 +2 +1 \ No newline at end of file diff --git a/rtl/sound/jt12/lut.vh b/rtl/sound/jt12/lut.vh deleted file mode 100644 index a520c53..0000000 --- a/rtl/sound/jt12/lut.vh +++ /dev/null @@ -1,92 +0,0 @@ -/* This file is part of JT12. - - - JT12 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. - - JT12 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 JT12. If not, see . - - Based on Sauraen VHDL version of OPN/OPN2, which is based on die shots. - - Author: Jose Tejada Gomez. Twitter: @topapate - Version: 1.0 - Date: 27-1-2017 - -*/ - - -initial begin - sinetable[5'd0 ] <= 46'b0001100000100100010001000010101010101001010010; - sinetable[5'd1 ] <= 46'b0001100000110100000100000010010001001101000001; - sinetable[5'd2 ] <= 46'b0001100000110100000100110010001011001101100000; - sinetable[5'd3 ] <= 46'b0001110000010000000000110010110001001101110010; - sinetable[5'd4 ] <= 46'b0001110000010000001100000010111010001101101001; - sinetable[5'd5 ] <= 46'b0001110000010100001001100010000000101101111010; - sinetable[5'd6 ] <= 46'b0001110000010100001101100010010011001101011010; - sinetable[5'd7 ] <= 46'b0001110000011100000101010010111000101111111100; - sinetable[5'd8 ] <= 46'b0001110000111000000001110010101110001101110111; - sinetable[5'd9 ] <= 46'b0001110000111000010100111000011101011010100110; - sinetable[5'd10] <= 46'b0001110000111100011000011000111100001001111010; - sinetable[5'd11] <= 46'b0001110000111100011100111001101011001001110111; - sinetable[5'd12] <= 46'b0100100001010000010001011001001000111010110111; - sinetable[5'd13] <= 46'b0100100001010100010001001001110001111100101010; - sinetable[5'd14] <= 46'b0100100001010100010101101101111110100101000110; - sinetable[5'd15] <= 46'b0100100011100000001000011001010110101101111001; - sinetable[5'd16] <= 46'b0100100011100100001000101011100101001011101111; - sinetable[5'd17] <= 46'b0100100011101100000111011010000001011010110001; - sinetable[5'd18] <= 46'b0100110011001000000111101010000010111010111111; - sinetable[5'd19] <= 46'b0100110011001100001011011110101110110110000001; - sinetable[5'd20] <= 46'b0100110011101000011010111011001010001101110001; - sinetable[5'd21] <= 46'b0100110011101101011010110101111001010100001111; - sinetable[5'd22] <= 46'b0111000010000001010111000101010101010110010111; - sinetable[5'd23] <= 46'b0111000010000101010111110111110101010010111011; - sinetable[5'd24] <= 46'b0111000010110101101000101100001000010000011001; - sinetable[5'd25] <= 46'b0111010010011001100100011110100100010010010010; - sinetable[5'd26] <= 46'b0111010010111010100101100101000000110100100011; - sinetable[5'd27] <= 46'b1010000010011010101101011101100001110010011010; - sinetable[5'd28] <= 46'b1010000010111111111100100111010100010000111001; - sinetable[5'd29] <= 46'b1010010111110100110010001100111001010110100000; - sinetable[5'd30] <= 46'b1011010111010011111011011110000100110010100001; - sinetable[5'd31] <= 46'b1110011011110001111011100111100001110110100111; - - explut_jt51[0] <= 45'b111110101011010110001011010000010010111011011; - explut_jt51[1] <= 45'b111101010011010101000011001100101110110101011; - explut_jt51[2] <= 45'b111011111011010011110111001000110010101110011; - explut_jt51[3] <= 45'b111010100101010010101111000100110010101000011; - explut_jt51[4] <= 45'b111001001101010001100111000000110010100001011; - explut_jt51[5] <= 45'b110111111011010000011110111101010010011011011; - explut_jt51[6] <= 45'b110110100011001111010110111001010010010100100; - explut_jt51[7] <= 45'b110101001011001110001110110101110010001110011; - explut_jt51[8] <= 45'b110011111011001101000110110001110010001000011; - explut_jt51[9] <= 45'b110010100011001011111110101110010010000010011; - explut_jt51[10] <= 45'b110001010011001010111010101010010001111011011; - explut_jt51[11] <= 45'b101111111011001001110010100110110001110101011; - explut_jt51[12] <= 45'b101110101011001000101010100011001101101111011; - explut_jt51[13] <= 45'b101101010101000111100110011111010001101001011; - explut_jt51[14] <= 45'b101100000011000110100010011011110001100011011; - explut_jt51[15] <= 45'b101010110011000101011110011000010001011101011; - explut_jt51[16] <= 45'b101001100011000100011010010100101101010111011; - explut_jt51[17] <= 45'b101000010011000011010010010001001101010001011; - explut_jt51[18] <= 45'b100111000011000010010010001101101101001011011; - explut_jt51[19] <= 45'b100101110011000001001110001010001101000101011; - explut_jt51[20] <= 45'b100100100011000000001010000110010000111111011; - explut_jt51[21] <= 45'b100011010010111111001010000011001100111001011; - explut_jt51[22] <= 45'b100010000010111110000101111111101100110011011; - explut_jt51[23] <= 45'b100000110010111101000001111100001100101101011; - explut_jt51[24] <= 45'b011111101010111100000001111000101100101000010; - explut_jt51[25] <= 45'b011110011010111011000001110101001100100010011; - explut_jt51[26] <= 45'b011101001010111010000001110001110000011100011; - explut_jt51[27] <= 45'b011100000010111001000001101110010000010110011; - explut_jt51[28] <= 45'b011010110010111000000001101011001100010001011; - explut_jt51[29] <= 45'b011001101010110111000001100111101100001011011; - explut_jt51[30] <= 45'b011000100000110110000001100100010000000110010; - explut_jt51[31] <= 45'b010111010010110101000001100001001100000000011; -end diff --git a/rtl/sound/turbosound.sv b/rtl/sound/turbosound.sv index 876eb99..7a8e59c 100644 --- a/rtl/sound/turbosound.sv +++ b/rtl/sound/turbosound.sv @@ -23,115 +23,157 @@ module turbosound ( input RESET, // Chip RESET (set all Registers to '0', active high) - input CLK, // Global clock - input CE_CPU, // CPU Clock enable - input CE_YM, // YM2203 Master Clock enable x2 (due to YM2612 model!) + input CE, // YM2203 Master Clock enable + input BDIR, // Bus Direction (0 - read , 1 - write) input BC, // Bus control input [7:0] DI, // Data In output [7:0] DO, // Data Out + output [11:0] CHANNEL_L, // Output channel L - output [11:0] CHANNEL_R, // Output channel R - output ACTIVE + output [11:0] CHANNEL_R // Output channel R ); + +reg RESET_s; +reg BDIR_s; +reg BC_s; +reg [7:0] DI_s; + +always_ff @(posedge CLK) begin + reg RESET_d; + reg BDIR_d; + reg BC_d; + reg [7:0] DI_d; + + RESET_d <= RESET; + BDIR_d <= BDIR; + BC_d <= BC; + DI_d <= DI; + + RESET_s <= RESET_d; + BDIR_s <= BDIR_d; + BC_s <= BC_d; + DI_s <= DI_d; +end + + // AY1 selected by default reg ay_select = 1; reg stat_sel = 1; reg fm_ena = 0; +reg ym_wr = 0; +reg [7:0] ym_di; -always_ff @(posedge CLK or posedge RESET) begin - if (RESET) begin +always_ff @(posedge CLK or posedge RESET_s) begin + reg old_BDIR = 0; + reg ym_acc = 0; + + if (RESET_s) begin ay_select <= 1; stat_sel <= 1; fm_ena <= 0; + ym_acc <= 0; + ym_wr <= 0; + old_BDIR <= 0; end - else if (BDIR & BC & &DI[7:3]) begin - ay_select <= DI[0]; - stat_sel <= DI[1]; - fm_ena <= ~DI[2]; + else begin + ym_wr <= 0; + old_BDIR <= BDIR_s; + if (~old_BDIR & BDIR_s) begin + if(BC_s & &DI_s[7:3]) begin + ay_select <= DI_s[0]; + stat_sel <= DI_s[1]; + fm_ena <= ~DI_s[2]; + ym_acc <= 0; + end + else if(BC_s) begin + ym_acc <= !DI_s[7:4] || fm_ena; + ym_wr <= !DI_s[7:4] || fm_ena; + end + else begin + ym_wr <= ym_acc; + end + ym_di <= DI_s; + end end end wire [7:0] psg_ch_a_0; wire [7:0] psg_ch_b_0; wire [7:0] psg_ch_c_0; -wire [10:0] opn_0; +wire [15:0] opn_0; wire [7:0] DO_0; -wire WE_0 = ~ay_select & BDIR; -wire ay0_playing; - -ym2203 ym2203_0 +jt03 ym2203_0 ( - .RESET(RESET), - .CLK(CLK), - .CE_CPU(CE_CPU), - .CE_YM(CE_YM), + .rst(RESET_s), + .clk(CLK), + .cen(CE), + .din(ym_di), + .addr((BDIR_s|ym_wr) ? ~BC_s : stat_sel), + .cs_n(ay_select), + .wr_n(~ym_wr), + .dout(DO_0), - .A0(WE_0 ? ~BC : stat_sel), - .WE(WE_0), - .DI(DI), - .DO(DO_0), + .psg_A(psg_ch_a_0), + .psg_B(psg_ch_b_0), + .psg_C(psg_ch_c_0), - .CHANNEL_A(psg_ch_a_0), - .CHANNEL_B(psg_ch_b_0), - .CHANNEL_C(psg_ch_c_0), - .CHANNEL_FM(opn_0), - - .PSG_ACTIVE(ay0_playing), - .FM_ENA(fm_ena) + .fm_snd(opn_0) ); wire [7:0] psg_ch_a_1; wire [7:0] psg_ch_b_1; wire [7:0] psg_ch_c_1; -wire [10:0] opn_1; +wire [15:0] opn_1; wire [7:0] DO_1; -wire WE_1 = ay_select & BDIR; -wire ay1_playing; - -ym2203 ym2203_1 +jt03 ym2203_1 ( - .RESET(RESET), - .CLK(CLK), - .CE_CPU(CE_CPU), - .CE_YM(CE_YM), + .rst(RESET_s), + .clk(CLK), + .cen(CE), + .din(ym_di), + .addr((BDIR_s|ym_wr) ? ~BC_s : stat_sel), + .cs_n(~ay_select), + .wr_n(~ym_wr), + .dout(DO_1), - .A0(WE_1 ? ~BC : stat_sel), - .WE(WE_1), - .DI(DI), - .DO(DO_1), + .psg_A(psg_ch_a_1), + .psg_B(psg_ch_b_1), + .psg_C(psg_ch_c_1), - .CHANNEL_A(psg_ch_a_1), - .CHANNEL_B(psg_ch_b_1), - .CHANNEL_C(psg_ch_c_1), - .CHANNEL_FM(opn_1), - - .PSG_ACTIVE(ay1_playing), - .FM_ENA(fm_ena) + .fm_snd(opn_1) ); assign DO = ay_select ? DO_1 : DO_0; -assign ACTIVE = ay0_playing | ay1_playing | fm_ena; -// Mix channel signals from both AY/YM chips (extending to 9 bits width to prevent clipping) -wire [8:0] sum_ch_a = { 1'b0, psg_ch_a_1 } + { 1'b0, psg_ch_a_0 }; -wire [8:0] sum_ch_b = { 1'b0, psg_ch_b_1 } + { 1'b0, psg_ch_b_0 }; -wire [8:0] sum_ch_c = { 1'b0, psg_ch_c_1 } + { 1'b0, psg_ch_c_0 }; +reg [8:0] sum_ch_a,sum_ch_b,sum_ch_c; +reg [7:0] psg_a,psg_b,psg_c; +reg [11:0] psg_l,psg_r,opn_s; +reg [11:0] ch_l, ch_r; -// Control output channels (Only AY_1 plays if not in TurboSound mode) -wire [7:0] psg_a = ~ay0_playing ? psg_ch_a_1 : sum_ch_a[8:1]; -wire [7:0] psg_b = ~ay0_playing ? psg_ch_b_1 : sum_ch_b[8:1]; -wire [7:0] psg_c = ~ay0_playing ? psg_ch_c_1 : sum_ch_c[8:1]; +always @(posedge CLK) begin -wire signed [11:0] psg_l = {3'b000, psg_a, 1'd0} + {4'b0000, psg_b}; -wire signed [11:0] psg_r = {3'b000, psg_c, 1'd0} + {4'b0000, psg_b}; -wire signed [11:0] opn_s = {{2{opn_0[10]}}, opn_0[10:1]} + {{2{opn_1[10]}}, opn_1[10:1]}; + sum_ch_a <= { 1'b0, psg_ch_a_1 } + { 1'b0, psg_ch_a_0 }; + sum_ch_b <= { 1'b0, psg_ch_b_1 } + { 1'b0, psg_ch_b_0 }; + sum_ch_c <= { 1'b0, psg_ch_c_1 } + { 1'b0, psg_ch_c_0 }; -assign CHANNEL_L = fm_ena ? opn_s + psg_l : psg_l; -assign CHANNEL_R = fm_ena ? opn_s + psg_r : psg_r; + psg_a <= sum_ch_a[8] ? 8'hFF : sum_ch_a[7:0]; + psg_b <= sum_ch_b[8] ? 8'hFF : sum_ch_b[7:0]; + psg_c <= sum_ch_c[8] ? 8'hFF : sum_ch_c[7:0]; + + psg_l <= {3'b000, psg_a, 1'd0} + {4'b0000, psg_b}; + psg_r <= {3'b000, psg_c, 1'd0} + {4'b0000, psg_b}; + opn_s <= {{2{opn_0[15]}}, opn_0[15:6]} + {{2{opn_1[15]}}, opn_1[15:6]}; + + ch_l <= fm_ena ? $signed(opn_s) + $signed(psg_l) : $signed(psg_l); + ch_r <= fm_ena ? $signed(opn_s) + $signed(psg_r) : $signed(psg_r); +end + +assign CHANNEL_L = ch_l; +assign CHANNEL_R = ch_r; endmodule diff --git a/rtl/sound/ym2149.sv b/rtl/sound/ym2149.sv index 1aa73ff..672cbda 100644 --- a/rtl/sound/ym2149.sv +++ b/rtl/sound/ym2149.sv @@ -1,6 +1,6 @@ // // Copyright (c) MikeJ - Jan 2005 -// Copyright (c) 2016-2018 Sorgelig +// Copyright (c) 2016-2019 Sorgelig // // All rights reserved // @@ -151,18 +151,13 @@ always @(posedge CLK) begin if(CE) begin if (ena_div_noise) begin - if(ymreg[6][4:0]) begin - if (noise_gen_cnt >= ymreg[6][4:0] - 1'd1) begin - noise_gen_cnt <= 0; - poly17 <= {(poly17[0] ^ poly17[2] ^ !poly17), poly17[16:1]}; - end else begin - noise_gen_cnt <= noise_gen_cnt + 1'd1; - end - noise_gen_op <= {3{poly17[0]}}; - end else begin - noise_gen_op <= ymreg[7][5:3]; + if (!ymreg[6][4:0] || noise_gen_cnt >= ymreg[6][4:0] - 1'd1) begin noise_gen_cnt <= 0; + poly17 <= {(poly17[0] ^ poly17[2] ^ !poly17), poly17[16:1]}; + end else begin + noise_gen_cnt <= noise_gen_cnt + 1'd1; end + noise_gen_op <= {3{poly17[0]}}; end end end @@ -192,7 +187,7 @@ always @(posedge CLK) begin tone_gen_cnt[i] <= tone_gen_cnt[i] + 1'd1; end end else begin - tone_gen_op[i] <= ymreg[7][i]; + tone_gen_op[i] <= ~ymreg[7][i]; tone_gen_cnt[i] <= 0; end end diff --git a/rtl/sound/ym2203.sv b/rtl/sound/ym2203.sv deleted file mode 100644 index 09c1bc4..0000000 --- a/rtl/sound/ym2203.sv +++ /dev/null @@ -1,130 +0,0 @@ -//============================================================================ -// YM2203 wrapper -// Copyright (C) 2018 Sorgelig -// -// This 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 2 of the License, or (at your option) -// any later version. -// -// This 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 this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -//============================================================================ - - -module ym2203 -( - input RESET, - input CLK, // Global clock - input CE_CPU, // CPU Clock enable - input CE_YM, // YM2203 Master Clock enable x2 (due to YM2612 model!) - - input A0, // 0 - register number/read FM, 1 - data/read PSG - input WE, // 0 - read , 1 - write - input [7:0] DI, // Data In - output [7:0] DO, // Data Out - - output [7:0] CHANNEL_A, // PSG Output channel A - output [7:0] CHANNEL_B, // PSG Output channel B - output [7:0] CHANNEL_C, // PSG Output channel C - output [10:0] CHANNEL_FM,// FM Output channel - - output PSG_ACTIVE, - input FM_ENA -); - -reg [7:0] ymreg; -reg [1:0] pres; - -always @(posedge CLK) begin - - if(RESET) pres <= 2; - else if(CE_CPU & WE) begin - if(FM_ENA) begin - if(~A0) ymreg <= DI; - else begin - case(ymreg) - 'h2d: pres[1] <= 1; - 'h2e: pres[0] <= 1; - 'h2f: pres <= 0; - endcase - end - end - end -end - -wire [2:0] opn_tbl[4] = '{1,1,5,2}; -wire [2:0] opn_pres = opn_tbl[pres]; - -wire [2:0] psg_tbl[4] = '{0,0,3,1}; -wire [2:0] psg_pres = psg_tbl[pres]; - -reg ce_psg_pre, ce_opn_pre; -always @(posedge CLK) begin - reg [2:0] div_psg, div_opn; - - {ce_opn_pre, ce_psg_pre} <= 0; - - if(RESET) {div_opn, div_psg} <= 0; - else if (CE_YM) begin - div_opn <= div_opn + 1'd1; - if(div_opn >= opn_pres) div_opn <= 0; - ce_opn_pre <= !div_opn; - - div_psg <= div_psg + 1'd1; - if(div_psg >= psg_pres) div_psg <= 0; - ce_psg_pre <= !div_psg; - end -end - -reg ce_opn, ce_psg; -always @(negedge CLK) {ce_opn, ce_psg} <= {ce_opn_pre, ce_psg_pre}; - -wire [5:0] psg_active; -wire [7:0] psg_dout; -ym2149 ym2149 -( - .CLK(CLK), - .CE(ce_psg), - .RESET(RESET), - .BDIR(WE), - .BC(~A0 | ~WE), - .DI(DI), - .DO(psg_dout), - .CHANNEL_A(CHANNEL_A), - .CHANNEL_B(CHANNEL_B), - .CHANNEL_C(CHANNEL_C), - .ACTIVE(psg_active), - .SEL(1'b0), - .MODE(1'b0) -); - -wire [7:0] opn_dout; -wire [11:0] opn_audio; -jt12 jt12 -( - .rst(RESET), - - .cpu_clk(CLK & CE_CPU), - .cpu_din(DI), - .cpu_dout(opn_dout), - .cpu_addr({1'b0,A0}), - .cpu_cs_n(~FM_ENA), - .cpu_wr_n(~WE), - - .syn_clk(CLK & ce_opn), - .cpu_limiter_en(1'b1), - .syn_snd_right(opn_audio) -); - -assign DO = A0 ? psg_dout : opn_dout; -assign PSG_ACTIVE = |psg_active; -assign CHANNEL_FM = opn_audio[10:0]; - -endmodule diff --git a/rtl/tsconf.v b/rtl/tsconf.v index 48d9407..70f20ce 100644 --- a/rtl/tsconf.v +++ b/rtl/tsconf.v @@ -794,7 +794,7 @@ soundrive SE10 // Turbosound FM reg ce_ym; always @(posedge clk_28mhz) begin - reg [1:0] div; + reg [2:0] div; div <= div + 1'd1; ce_ym <= !div; @@ -811,8 +811,7 @@ turbosound SE12 .RESET(reset), .CLK(clk_28mhz), - .CE_CPU(zpos), - .CE_YM(ce_ym), + .CE(ce_ym), .BDIR(ts_we), .BC(cpu_a_bus[14]), .DI(cpu_do_bus),