Update turbosound.

This commit is contained in:
sorgelig
2020-05-11 23:43:24 +08:00
parent 5a66d5ec1c
commit c08d8479be
51 changed files with 4523 additions and 3446 deletions

View File

@ -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 ]

73
rtl/sound/jt12/jt03.v Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
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

66
rtl/sound/jt12/jt03_acc.v Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
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

View File

@ -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 <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with JT12. If not, see <http://www.gnu.org/licenses/>.
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

43
rtl/sound/jt12/jt12.vhd Normal file
View File

@ -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;

View File

@ -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 <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with JT12. If not, see <http://www.gnu.org/licenses/>.
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

View File

@ -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 <http://www.gnu.org/licenses/>.
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

82
rtl/sound/jt12/jt12_csr.v Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
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

82
rtl/sound/jt12/jt12_div.v Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
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

View File

@ -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 <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with JT12. If not, see <http://www.gnu.org/licenses/>.
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<eg_VI ? eg_VI-ar_sum : 10'd0;
end
always @(posedge clk) begin
if( rst ) begin
eg_VII <= 10'h3ff;
state_VII <= RELEASE;
end
else begin
if( ar_off_VI ) begin
// eg_VII <= ssg_en_II ? 10'h200 : 10'd0;
eg_VII <= 10'd0;
end
else
if( state_VI == ATTACK ) begin
if( sum_up && eg_VI != 10'd0 )
if( rate_VI[5:1]==4'hf )
eg_VII <= 10'd0;
else
eg_VII <= ar_result;
else
eg_VII <= eg_VI;
end
else begin : DECAY_SUM
if( sum_up ) begin
if ( egatt_VI<= 10'd1023 )
eg_VII <= egatt_VI[9:0];
else eg_VII <= 10'h3FF;
end
else eg_VII <= eg_VI;
end
state_VII <= state_VI;
end
end
//////////////////////////////////////////////////////////////
// Register cycle VII
reg [9:0] eg_internal_VIII;
reg [8:0] am_final;
reg [11:0] sum_eg_tl;
always @(*) begin : sum_eg_and_tl
casex( {amsen_VII, ams_VII } )
3'b0xx,3'b100: am_final <= 9'd0;
3'b101: am_final <= { 2'b00, am };
3'b110: am_final <= { 1'b0, am, 1'b0};
3'b111: am_final <= { am, 2'b0 };
endcase
`ifdef TEST_SUPPORT
if( test_eg && tl_VII!=7'd0 )
sum_eg_tl <= 11'd0;
else
`endif
sum_eg_tl <= { tl_VII, 3'd0 }
+ eg_VII
+ { am_final, 1'b0 };
end
always @(posedge clk) begin
if( rst ) begin
eg_internal_VIII <= 10'h3ff;
state_VIII <= RELEASE;
end
else begin
eg_internal_VIII <= sum_eg_tl[11:10] > 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

View File

@ -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 <http://www.gnu.org/licenses/>.
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

View File

@ -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 <http://www.gnu.org/licenses/>.
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

View File

@ -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 <http://www.gnu.org/licenses/>.
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

View File

@ -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 <http://www.gnu.org/licenses/>.
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

View File

@ -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 <http://www.gnu.org/licenses/>.
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

View File

@ -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 <http://www.gnu.org/licenses/>.
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

View File

@ -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 <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with JT12. If not, see <http://www.gnu.org/licenses/>.
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

View File

@ -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 <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with JT12. If not, see <http://www.gnu.org/licenses/>.
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

View File

@ -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

View File

@ -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

View File

@ -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 <http://www.gnu.org/licenses/>.
Based on Sauraen VHDL version of OPN/OPN2, which is based on die shots.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 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

View File

@ -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 <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with JT12. If not, see <http://www.gnu.org/licenses/>.
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

View File

@ -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

View File

@ -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 <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with JT12. If not, see <http://www.gnu.org/licenses/>.
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

View File

@ -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 <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with JT12. If not, see <http://www.gnu.org/licenses/>.
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

View File

@ -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 <http://www.gnu.org/licenses/>.
Based on Sauraen VHDL version of OPN/OPN2, which is based on die shots.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 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

109
rtl/sound/jt12/jt12_pcm.v Normal file
View File

@ -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

View File

@ -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 <http://www.gnu.org/licenses/>.
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 <http://www.gnu.org/licenses/>.
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

View File

@ -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 <http://www.gnu.org/licenses/>.
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

View File

@ -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 <http://www.gnu.org/licenses/>.
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

View File

@ -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 <http://www.gnu.org/licenses/>.
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

View File

@ -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 <http://www.gnu.org/licenses/>.
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

View File

@ -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 <http://www.gnu.org/licenses/>.
Based on Sauraen VHDL version of OPN/OPN2, which is based on die shots.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 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

62
rtl/sound/jt12/jt12_pm.v Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
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

View File

@ -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 <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with JT12. If not, see <http://www.gnu.org/licenses/>.
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

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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 <http://www.gnu.org/licenses/>.
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

View File

@ -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

View File

@ -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

View File

@ -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<mult_max )
{overflow, next } <= { {1'b0, cnt}, mult+1'b1 } ;
else
{overflow, next } <= { {1'b0, cnt}+1'b1, {mult_width{1'b0}} };
init <= { start_value, {mult_width{1'b0}} };
if( mult<mult_max ) begin
// mult not meant to overflow in this line
{overflow, next } = { {1'b0, cnt}, mult+1'b1 } ;
end else begin
{overflow, next } = { {1'b0, cnt}+1'b1, {mult_width{1'b0}} };
end
init = { start_value, {mult_width{1'b0}} };
end
always @(posedge clk)
if( load || rst) begin
always @(posedge clk)
if( ~load || rst) begin
mult <= { (mult_width){1'b0} };
cnt <= start_value;
end

476
rtl/sound/jt12/jt12_top.v Normal file
View File

@ -0,0 +1,476 @@
/* 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 <http://www.gnu.org/licenses/>.
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

View File

@ -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

View File

@ -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

View File

@ -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 <http://www.gnu.org/licenses/>.
Based on Sauraen VHDL version of OPN/OPN2, which is based on die shots.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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),