update JT12

This commit is contained in:
Eugene Lozovoy
2024-09-10 17:07:34 +03:00
parent b695f6d37c
commit ba7d903e12
46 changed files with 2259 additions and 2448 deletions

View File

@ -1,34 +1,36 @@
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_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_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_timers.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_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_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_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_reg_ch.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_timers.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_dout.v ]
set_global_assignment -name QIP_FILE [file join $::quartus(qip_path) ../jt49/jt49.qip ]

View File

@ -1,6 +1,6 @@
/* 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
@ -21,31 +21,43 @@
// 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 cen, // optional clock enable, if 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,
// I/O pins used by YM2203 embedded YM2149 chip
input [7:0] IOA_in,
input [7:0] IOB_in,
output [7:0] IOA_out,
output [7:0] IOB_out,
output IOA_oe,
output IOB_oe,
// 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 [ 9:0] psg_snd,
output signed [15:0] snd,
output snd_sample
output snd_sample,
// Debug
//input [ 7:0] debug_bus,
output [ 7:0] debug_view
);
jt12_top #(.use_lfo(0),.use_ssg(1), .num_ch(3), .use_pcm(0), .use_lr(0))
parameter YM2203_LUMPED=0; // set to 1 if all PSG outputs are shorted together without any resistor
jt12_top #(
.use_lfo(0),.use_ssg(1), .num_ch(3), .use_pcm(0), .use_adpcm(0), .mask_div(0),
.YM2203_LUMPED(YM2203_LUMPED) )
u_jt12(
.rst ( rst ), // rst should be at least 6 clk&cen cycles long
.clk ( clk ), // CPU clock
@ -54,20 +66,45 @@ u_jt12(
.addr ( {1'b0, addr} ),
.cs_n ( cs_n ),
.wr_n ( wr_n ),
.ch_enable ( 6'd0 ),
.dout ( dout ),
.irq_n ( irq_n ),
// YM2203 I/O pins
.IOA_in ( IOA_in ),
.IOB_in ( IOB_in ),
.IOA_out ( IOA_out ),
.IOB_out ( IOB_out ),
.IOA_oe ( IOA_oe ),
.IOB_oe ( IOB_oe ),
// Unused ADPCM pins
.en_hifi_pcm ( 1'b0 ), // used only on YM2612 mode
.adpcma_addr ( ), // real hardware has 10 pins multiplexed through RMPX pin
.adpcma_bank ( ),
.adpcma_roe_n ( ), // ADPCM-A ROM output enable
.adpcma_data ( 8'd0 ), // Data from RAM
.adpcmb_data ( 8'd0 ),
.adpcmb_addr ( ), // real hardware has 12 pins multiplexed through PMPX pin
.adpcmb_roe_n ( ), // ADPCM-B ROM output enable
// Separated output
.psg_A ( psg_A ),
.psg_B ( psg_B ),
.psg_C ( psg_C ),
.psg_snd ( psg_snd ),
.psg_snd ( psg_snd ),
.fm_snd_left ( fm_snd ),
.fm_snd_right (),
.adpcmA_l (),
.adpcmA_r (),
.adpcmB_l (),
.adpcmB_r (),
.snd_right ( snd ),
.snd_left (),
.snd_sample ( snd_sample )
.snd_sample ( snd_sample ),
//.debug_bus ( debug_bus ),
.debug_bus ( 8'd0 ),
.debug_view ( debug_view )
);
endmodule // jt03
endmodule // jt03

View File

@ -20,18 +20,20 @@
*/
`timescale 1ns / 1ps
/* Use for YM2203
no left/right channels
full operator resolution
clamped to maximum output of signed 16 bits */
// Use for YM2203
// no left/right channels
// full operator resolution
// clamped to maximum output of signed 16 bits
// This version does not clamp each channel individually
// That does not correspond to real hardware behaviour. I should
// change it.
module jt03_acc
(
input rst,
input clk,
input clk_en,
input clk_en /* synthesis direct_enable */,
input signed [13:0] op_result,
input s1_enters,
input s2_enters,
@ -54,6 +56,11 @@ always @(*) begin
endcase
end
// real YM2608 drops the op_result LSB, resulting in a 13-bit accumulator
// but in YM2203, a 13-bit acc for 3 channels only requires 15 bits
// and YM3014 has a 16-bit dynamic range.
// I am leaving the LSB and scaling the output voltage accordingly. This
// should result in less quantification noise.
jt12_single_acc #(.win(14),.wout(16)) u_mono(
.clk ( clk ),
.clk_en ( clk_en ),

View File

@ -1,65 +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/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 27-12-2018
*/
// Wrapper to output only combined channels. Defaults to YM2612 mode.
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
);
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 )
);
endmodule // jt03

View File

@ -16,6 +16,7 @@ port
dout : out std_logic_vector(7 downto 0);
irq_n : out std_logic;
en_hifi_pcm: in std_logic; -- set high to use interpolation on PCM samples
-- combined output
snd_right : out std_logic_vector(15 downto 0); -- signed

View File

@ -1,109 +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/>.
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.
*/
/*
YM2612 had a limiter to prevent overflow
YM3438 did not
JT12 always has a limiter enabled
*/
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
);
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;
endcase
end
reg pcm_sum;
always @(posedge clk) if(clk_en)
if( zero ) pcm_sum <= 1'b1;
else if( ch6op ) pcm_sum <= 1'b0;
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;
// 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_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

@ -23,7 +23,7 @@
module jt12_csr( // Circular Shift Register + input mux
input rst,
input clk,
input clk_en,
input clk_en /* synthesis direct_enable */,
input [ 7:0] din,
input [43:0] shift_in,
output [43:0] shift_out,

View File

@ -18,54 +18,102 @@
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
input cen /* synthesis direct_enable */,
input [1:0] div_setting,
output reg clk_en, // after prescaler
output reg clk_en_2, // cen divided by 2
output reg clk_en_ssg,
output reg clk_en_666, // 666 kHz
output reg clk_en_111, // 111 kHz
output reg clk_en_55 // 55 kHz
);
parameter use_ssg=0, num_ch;
parameter use_ssg=0;
reg [3:0] opn_pres, opn_cnt;
reg [2:0] ssg_pres, ssg_cnt;
reg cen_int, cen_ssg_int;
reg [3:0] opn_pres, opn_cnt=4'd0;
reg [2:0] ssg_pres, ssg_cnt=3'd0;
reg [4:0] adpcm_cnt666 = 5'd0;
reg [2:0] adpcm_cnt111 = 3'd0, adpcm_cnt55=3'd0;
reg cen_int, cen_ssg_int, cen_adpcm_int, cen_adpcm3_int;
always @(*)
if( num_ch==6 ) begin
opn_pres = 4'd5;
ssg_pres = 3'd3; // unused, really
end
else
// prescaler values for FM
// reset: 1/3
// sel1/sel2
// 0 0 1/3
// 0 1 1/2
// 1 0 1/6
// 1 1 1/2
//
// According to YM2608 document
// FM SSG div[1:0]
// reset value 1/6 1/4 10
// 2D 1/6 1/4 10 | 10
// 2D,2E 1/3 1/2 11 | 01
// 2F 1/2 1/1 00 & 00
//
always @(*) begin
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
2'b0?: begin // FM 1/2 - SSG 1/1
opn_pres = 4'd2-4'd1;
ssg_pres = 3'd0;
end
2'b10: begin // FM 1/6 - SSG 1/4 (reset value. Fixed for YM2610)
opn_pres = 4'd6-4'd1;
ssg_pres = 3'd3;
end
2'b11: begin // FM 1/3 - SSG 1/2
opn_pres = 4'd3-4'd1;
ssg_pres = 3'd1;
end
endcase // div_setting
end
`ifdef SIMULATION
initial clk_en_666 = 1'b0;
`endif
reg cen_55_int;
reg [1:0] div2=2'b0;
always @(negedge clk) begin
cen_int <= opn_cnt == 4'd0;
cen_ssg_int <= ssg_cnt == 3'd0;
cen_int <= opn_cnt == 4'd0;
cen_ssg_int <= ssg_cnt == 3'd0;
cen_adpcm_int <= adpcm_cnt666 == 5'd0;
cen_adpcm3_int <= adpcm_cnt111 == 3'd0;
cen_55_int <= adpcm_cnt55 == 3'd0;
`ifdef FASTDIV
// always enabled for fast sims (use with GYM output, timer will not work well)
clk_en <= 1'b1;
// always enabled for fast sims (use with GYM output, the timers will not work well)
clk_en <= 1'b1;
clk_en_2 <= 1'b1;
clk_en_ssg <= 1'b1;
clk_en_666 <= 1'b1;
clk_en_55 <= 1'b1;
`else
clk_en <= cen & cen_int;
clk_en_ssg <= use_ssg ? (cen & cen_ssg_int) : 1'b0;
clk_en <= cen & cen_int;
clk_en_2 <= cen && (div2==2'b00);
clk_en_ssg <= use_ssg ? (cen & cen_ssg_int) : 1'b0;
clk_en_666 <= cen & cen_adpcm_int;
clk_en_111 <= cen & cen_adpcm_int & cen_adpcm3_int;
clk_en_55 <= cen & cen_adpcm_int & cen_adpcm3_int & cen_55_int;
`endif
end
// Div/2
always @(posedge clk)
if( cen ) begin
div2 <= div2==2'b10 ? 2'b00 : (div2+2'b01);
end
// OPN
always @(posedge clk)
if( cen ) begin
if( opn_cnt == opn_pres ) begin
opn_cnt <= 4'd0;
opn_cnt <= 4'd0;
end
else opn_cnt <= opn_cnt + 4'd1;
end
@ -79,4 +127,15 @@ always @(posedge clk)
else ssg_cnt <= ssg_cnt + 3'd1;
end
// ADPCM-A
always @(posedge clk)
if( cen ) begin
adpcm_cnt666 <= adpcm_cnt666==5'd11 ? 5'd0 : adpcm_cnt666 + 5'd1;
if( adpcm_cnt666==5'd0 ) begin
adpcm_cnt111 <= adpcm_cnt111==3'd5 ? 3'd0 : adpcm_cnt111+3'd1;
if( adpcm_cnt111==3'd0)
adpcm_cnt55 <= adpcm_cnt55==3'd1 ? 3'd0: adpcm_cnt55+3'd1;
end
end
endmodule // jt12_div

View File

@ -0,0 +1,47 @@
/* 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: 21-03-2019
*/
module jt12_dout(
// input rst_n,
input clk, // CPU clock
input flag_A,
input flag_B,
input busy,
input [5:0] adpcma_flags,
input adpcmb_flag,
input [7:0] psg_dout,
input [1:0] addr,
output reg [7:0] dout
);
parameter use_ssg=0, use_adpcm=0;
always @(posedge clk) begin
casez( addr )
2'b00: dout <= {busy, 5'd0, flag_B, flag_A }; // YM2203
2'b01: dout <= (use_ssg ==1) ? psg_dout : {busy, 5'd0, flag_B, flag_A };
2'b1?: dout <= (use_adpcm==1) ?
{ adpcmb_flag, 1'b0, adpcma_flags } :
{ busy, 5'd0, flag_B, flag_A };
endcase
end
endmodule // jt12_dout

View File

@ -22,7 +22,7 @@
module jt12_eg (
input rst,
input clk,
input clk_en,
input clk_en /* synthesis direct_enable */,
input zero,
input eg_stop,
// envelope configuration

View File

@ -22,14 +22,14 @@
module jt12_eg_cnt(
input rst,
input clk,
input clk_en,
input clk_en /* synthesis direct_enable */,
input zero,
output reg [14:0] eg_cnt
);
reg [1:0] eg_cnt_base;
always @(posedge clk) begin : envelope_counter
always @(posedge clk, posedge rst) begin : envelope_counter
if( rst ) begin
eg_cnt_base <= 2'd0;
eg_cnt <=15'd0;

View File

@ -24,7 +24,7 @@ module jt12_eg_ctrl(
input keyoff_now,
input [2:0] state_in,
input [9:0] eg,
// envelope configuration
// envelope configuration
input [4:0] arate, // attack rate
input [4:0] rate1, // decay rate
input [4:0] rate2, // sustain rate
@ -42,16 +42,16 @@ module jt12_eg_ctrl(
output reg pg_rst
);
localparam ATTACK = 3'b001,
DECAY = 3'b010,
localparam ATTACK = 3'b001,
DECAY = 3'b010,
HOLD = 3'b100,
RELEASE= 3'b000; // default state is release
RELEASE= 3'b000; // default state is release
// wire is_decaying = state_in[1] | state_in[2];
reg [4:0] sustain;
always @(*)
always @(*)
if( sl == 4'd15 )
sustain = 5'h1f; // 93dB
else
@ -74,14 +74,14 @@ always @(*) begin
pg_rst = keyon_now | ssg_pg_rst;
end
always @(*)
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}:
{2'b00, ATTACK}:
if( eg==10'd0 ) begin
base_rate = rate1;
state_next = DECAY;
@ -99,7 +99,7 @@ always @(*)
ssg_inv_out = ssg_en & (ssg_alt ^ ssg_inv_in);
end
else begin
base_rate = eg[9:5] >= sustain ? rate2 : rate1;
base_rate = eg[9:5] >= sustain ? rate2 : rate1; // equal comparison according to Nuke
state_next = DECAY;
ssg_inv_out = ssg_inv_in;
end

View File

@ -1,4 +1,3 @@
`timescale 1ns / 1ps
/* This file is part of JT12.
@ -31,7 +30,7 @@ module jt12_exprom
(
input [7:0] addr,
input clk,
input clk_en,
input clk_en /* synthesis direct_enable */,
output reg [9:0] exp
);

View File

@ -1,4 +1,3 @@
`timescale 1ns / 1ps
/* This file is part of JT12.
@ -26,7 +25,7 @@
module jt12_kon(
input rst,
input clk,
input clk_en,
input clk_en /* synthesis direct_enable */,
input [3:0] keyon_op,
input [2:0] keyon_ch,
input [1:0] next_op,
@ -41,29 +40,14 @@ module jt12_kon(
parameter num_ch=6;
reg din;
wire csr_out;
reg [3:0] next_op_hot;
reg [3:0] next_op6_hot;
always @(*) begin
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
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;
@ -73,40 +57,83 @@ if(num_ch==6) begin
end
end
wire middle;
reg mid_din;
always @(posedge clk) if( clk_en )
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
reg up_keyon_reg;
reg [3:0] tkeyon_op;
reg [2:0] tkeyon_ch;
wire key_upnow;
jt12_sh_rst #(.width(1),.stages(12),.rstval(1'b0)) u_konch0(
assign key_upnow = up_keyon_reg && (tkeyon_ch==next_ch) && (next_op == 2'd3);
always @(posedge clk) if( clk_en ) begin
if (rst)
up_keyon_reg <= 1'b0;
if (up_keyon) begin
up_keyon_reg <= 1'b1;
tkeyon_op <= keyon_op;
tkeyon_ch <= keyon_ch; end
else if (key_upnow)
up_keyon_reg <= 1'b0;
end
wire middle1;
wire middle2;
wire middle3;
wire din = key_upnow ? tkeyon_op[3] : csr_out;
wire mid_din2 = key_upnow ? tkeyon_op[1] : middle1;
wire mid_din3 = key_upnow ? tkeyon_op[2] : middle2;
wire mid_din4 = key_upnow ? tkeyon_op[0] : middle3;
jt12_sh_rst #(.width(1),.stages(6),.rstval(1'b0)) u_konch0(
.clk ( clk ),
.clk_en ( clk_en ),
.rst ( rst ),
.din ( din ),
.drop ( middle )
.drop ( middle1 )
);
jt12_sh_rst #(.width(1),.stages(12),.rstval(1'b0)) u_konch1(
jt12_sh_rst #(.width(1),.stages(6),.rstval(1'b0)) u_konch1(
.clk ( clk ),
.clk_en ( clk_en ),
.rst ( rst ),
.din ( mid_din ),
.din ( mid_din2 ),
.drop ( middle2 )
);
jt12_sh_rst #(.width(1),.stages(6),.rstval(1'b0)) u_konch2(
.clk ( clk ),
.clk_en ( clk_en ),
.rst ( rst ),
.din ( mid_din3 ),
.drop ( middle3 )
);
jt12_sh_rst #(.width(1),.stages(6),.rstval(1'b0)) u_konch3(
.clk ( clk ),
.clk_en ( clk_en ),
.rst ( rst ),
.din ( mid_din4 ),
.drop ( csr_out )
);
end
else begin // 3 channels
always @(posedge clk) if( clk_en )
reg din;
reg [3:0] next_op_hot;
always @(*) begin
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[1:0]==next_ch[1:0] && up_keyon ? |(keyon_op&next_op_hot) : csr_out;
end
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(

View File

@ -18,7 +18,6 @@
Date: 25-2-2017
*/
`timescale 1ns / 1ps
/*

View File

@ -1,42 +0,0 @@
/* 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: March, 10th 2017
*/
/* Limiting amplifier by 3dB * shift */
`timescale 1ns / 1ps
module jt12_limitamp #( parameter width=20, shift=5 ) (
input signed [width-1:0] left_in,
input signed [width-1:0] right_in,
output reg signed [width-1:0] left_out,
output reg signed [width-1:0] right_out
);
always @(*) begin
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_in[width-1], {(width-1){~right_in[width-1]}}} :
right_in <<< shift;
end
endmodule

View File

@ -18,19 +18,24 @@
Date: 14-2-2017
*/
`timescale 1ns / 1ps
module jt12_mmr(
input rst,
input clk,
input cen,
input cen /* synthesis direct_enable */,
output clk_en,
output clk_en_2,
output clk_en_ssg,
output clk_en_666,
output clk_en_111,
output clk_en_55,
input [7:0] din,
input write,
input [1:0] addr,
output reg busy,
output ch6op,
output [2:0] cur_ch,
output [1:0] cur_op,
// LFO
output reg [2:0] lfo_freq,
output reg lfo_en,
@ -46,10 +51,33 @@ module jt12_mmr(
output reg fast_timers,
input flag_A,
input overflow_A,
output reg [1:0] div_setting,
// PCM
output reg [8:0] pcm,
output reg pcm_en,
output reg pcm_wr, // high for one clock cycle when PCM is written
// ADPCM-A
output reg [ 7:0] aon_a, // ON
output reg [ 5:0] atl_a, // TL
output reg [15:0] addr_a, // address latch
output reg [ 7:0] lracl, // L/R ADPCM Channel Level
output reg up_start, // write enable start address latch
output reg up_end, // write enable end address latch
output reg [ 2:0] up_addr, // write enable end address latch
output reg [ 2:0] up_lracl,
output reg up_aon, // There was a write AON register
// ADPCM-B
output reg acmd_on_b, // Control - Process start, Key On
output reg acmd_rep_b, // Control - Repeat
output reg acmd_rst_b, // Control - Reset
output reg acmd_up_b, // Control - New cmd received
output reg [ 1:0] alr_b, // Left / Right
output reg [15:0] astart_b, // Start address
output reg [15:0] aend_b, // End address
output reg [15:0] adeltan_b, // Delta-N
output reg [ 7:0] aeg_b, // Envelope Generator Control
output reg [ 6:0] flag_ctl,
output reg [ 6:0] flag_mask,
// Operator
output xuse_prevprev1,
output xuse_internal,
@ -85,7 +113,6 @@ module jt12_mmr(
output keyon_I,
// output [ 1:0] cur_op,
// Operator
output zero,
output s1_enters,
@ -96,33 +123,27 @@ module jt12_mmr(
// PSG interace
output [3:0] psg_addr,
output [7:0] psg_data,
output reg psg_wr_n
output reg psg_wr_n,
input [7:0] debug_bus
);
parameter use_ssg=0, num_ch=6, use_pcm=1;
parameter use_ssg=0, num_ch=6, use_pcm=1, use_adpcm=0, mask_div=1;
`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 )
jt12_div #(.use_ssg(use_ssg)) u_div (
.rst ( rst ),
.clk ( clk ),
.cen ( cen ),
.div_setting ( div_setting ),
.clk_en ( clk_en ),
.clk_en_2 ( clk_en_2 ),
.clk_en_ssg ( clk_en_ssg ),
.clk_en_666 ( clk_en_666 ),
.clk_en_111 ( clk_en_111 ),
.clk_en_55 ( clk_en_55 )
);
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;
@ -131,9 +152,7 @@ reg [6:0] up_opreg; // hot-one encoding. tells which operator register gets upda
reg [2:0] up_chreg; // hot-one encoding. tells which channel register gets updated next
reg up_keyon;
wire busy_reg;
parameter REG_TESTYM = 8'h21,
localparam REG_TESTYM = 8'h21,
REG_LFO = 8'h22,
REG_CLKA1 = 8'h24,
REG_CLKA2 = 8'h25,
@ -146,8 +165,11 @@ parameter REG_TESTYM = 8'h21,
REG_DACTEST = 8'h2C,
REG_CLK_N6 = 8'h2D,
REG_CLK_N3 = 8'h2E,
REG_CLK_N2 = 8'h2F;
REG_CLK_N2 = 8'h2F,
// ADPCM (YM2610)
REG_ADPCMA_ON = 8'h00,
REG_ADPCMA_TL = 8'h01,
REG_ADPCMA_TEST = 8'h02;
reg csm, effect;
@ -159,16 +181,12 @@ reg [ 5:0] latch_fnum;
reg [2:0] up_ch;
reg [1:0] up_op;
reg old_write;
reg [7:0] din_copy;
always @(posedge clk)
old_write <= write;
reg [7:0] op_din, ch_din;
generate
if( use_ssg ) begin
assign psg_addr = selected_register[3:0];
assign psg_data = din_copy;
assign psg_data = ch_din;
end else begin
assign psg_addr = 4'd0;
assign psg_data = 8'd0;
@ -177,76 +195,131 @@ endgenerate
reg part;
`ifdef SIMULATION
always @(posedge clk) if( write && rst ) begin
$display("WARNING [JT12]: detected write request while in reset.\nThis is likely a glue-logic error in the CPU-FM module.");
$finish;
end
`endif
wire [2:0] ch_sel = {part, selected_register[1:0]};
// this runs at clk speed, no clock gating here
// if I try to make this an async rst it fails to map it
// as flip flops but uses latches instead. So I keep it as sync. reset
always @(posedge clk) begin : memory_mapped_registers
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;
selected_register <= 0;
div_setting <= 2'b10; // FM=1/6, SSG=1/4
up_ch <= 0;
up_op <= 0;
up_keyon <= 0;
up_opreg <= 0;
up_chreg <= 0;
// 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;
{ value_A, value_B } <= 0;
{ clr_flag_B, clr_flag_A,
enable_irq_B, enable_irq_A, load_B, load_A } <= 6'd0;
fast_timers <= 1'b0;
enable_irq_B, enable_irq_A, load_B, load_A } <= 0;
fast_timers <= 0;
// LFO
lfo_freq <= 3'd0;
lfo_en <= 1'b0;
csm <= 1'b0;
effect <= 1'b0;
lfo_freq <= 0;
lfo_en <= 0;
csm <= 0;
effect <= 0;
// PCM
pcm <= 9'h0;
pcm_en <= 1'b0;
pcm_wr <= 1'b0;
// sch <= 1'b0;
pcm <= 0;
pcm_en <= 0;
pcm_wr <= 0;
// ADPCM-A
aon_a <= 0;
atl_a <= 0;
up_start <= 0;
up_end <= 0;
up_addr <= 7;
up_lracl <= 7;
up_aon <= 0;
lracl <= 0;
addr_a <= 0;
// ADPCM-B
acmd_on_b <= 0;
acmd_rep_b <= 0;
acmd_rst_b <= 0;
alr_b <= 0;
flag_ctl <= 0;
astart_b <= 0;
aend_b <= 0;
adeltan_b <= 0;
flag_mask <= 0;
aeg_b <= 8'hff;
// Original test features
eg_stop <= 1'b0;
pg_stop <= 1'b0;
psg_wr_n <= 1'b1;
eg_stop <= 0;
pg_stop <= 0;
psg_wr_n <= 1;
//
{ block_ch3op1, fnum_ch3op1 } <= {3'd0, 11'd0 };
{ block_ch3op3, fnum_ch3op3 } <= {3'd0, 11'd0 };
{ block_ch3op2, fnum_ch3op2 } <= {3'd0, 11'd0 };
latch_fnum <= 0;
op_din <= 0;
part <= 0;
end else begin
up_chreg <= 0;
// WRITE IN REGISTERS
if( write ) begin
if( !addr[0] ) begin
selected_register <= din;
part <= addr[1];
part <= addr[1];
if (!mask_div)
case(din)
// clock divider: should work only for ym2203
// and ym2608.
// clock divider works just by selecting the register
REG_CLK_N6: div_setting[1] <= 1'b1; // 2D
REG_CLK_N3: div_setting[0] <= 1'b1; // 2E
REG_CLK_N2: div_setting <= 2'b0; // 2F
default:;
endcase
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
ch_din <= din;
if( selected_register == REG_KON && !part ) begin
up_keyon <= 1;
op_din <= din;
end else begin
up_keyon <= 0;
end
// General control (<0x20 registers and A0==0)
if(!part) begin
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
default:;
endcase
end
// CH3 special registers
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 };
@ -255,7 +328,9 @@ always @(posedge clk) begin : memory_mapped_registers
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
// YM2612 PCM support
if( use_pcm==1 ) begin
casez( selected_register)
REG_DACTEST: pcm[0] <= din[3];
REG_PCM:
@ -265,9 +340,60 @@ always @(posedge clk) begin : memory_mapped_registers
endcase
pcm_wr <= selected_register==REG_PCM;
end
if( use_adpcm==1 ) begin
// YM2610 ADPCM-A support, A1=1, regs 0-2D
if(part && selected_register[7:6]==2'b0) begin
casez( selected_register[5:0] )
6'h0: begin
aon_a <= din;
up_aon <= 1'b1;
end
6'h1: atl_a <= din[5:0];
// LRACL
6'h8, 6'h9, 6'hA, 6'hB, 6'hC, 6'hD: begin
lracl <= din;
up_lracl <= selected_register[2:0];
end
6'b01_????, 6'b10_????: begin
if( !selected_register[3] ) addr_a[ 7:0] <= din;
if( selected_register[3] ) addr_a[15:8] <= din;
case( selected_register[5:4] )
2'b01, 2'b10: begin
{up_end, up_start } <= selected_register[5:4];
up_addr <= selected_register[2:0];
end
default: begin
up_start <= 1'b0;
up_end <= 1'b0;
end
endcase
end
default:;
endcase
end
if( !part && selected_register[7:4]==4'h1 ) begin
// YM2610 ADPCM-B support, A1=0, regs 1x
case(selected_register[3:0])
4'd0: {acmd_up_b, acmd_on_b, acmd_rep_b,acmd_rst_b} <= {1'd1,din[7],din[4],din[0]};
4'd1: alr_b <= din[7:6];
4'd2: astart_b [ 7:0] <= din;
4'd3: astart_b [15:8] <= din;
4'd4: aend_b [ 7:0] <= din;
4'd5: aend_b [15:8] <= din;
4'h9: adeltan_b[ 7:0] <= din;
4'ha: adeltan_b[15:8] <= din;
4'hb: aeg_b <= din;
4'hc: begin
flag_mask <= ~{din[7],din[5:0]};
flag_ctl <= {din[7],din[5:0]}; // this lasts a single clock cycle
end
default:;
endcase
end
end
if( selected_register[1:0]==2'b11 )
{ up_chreg, up_opreg } <= { 3'h0, 7'h0 };
else
else begin
casez( selected_register )
// channel registers
8'hA0, 8'hA1, 8'hA2: { up_chreg, up_opreg } <= { 3'h1, 7'd0 }; // up_fnumlo
@ -284,45 +410,59 @@ always @(posedge clk) begin : memory_mapped_registers
8'h9?: { up_chreg, up_opreg } <= { 3'h0, 7'h40 }; // up_ssgeg
default: { up_chreg, up_opreg } <= { 3'h0, 7'h0 };
endcase // selected_register
if( selected_register[7:4]>=3 && selected_register[7:4]<=9 ) begin
op_din <= din;
up_ch <= {part, selected_register[1:0]};
up_op <= selected_register[3:2]; // 0=S1,1=S3,2=S2,3=S4
end
end
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;
pcm_wr <= 1'b0;
flag_ctl <= 'd0;
up_aon <= 1'b0;
acmd_up_b <= 1'b0;
end
end
end
reg [4:0] busy_cnt; // busy lasts for 32 synth clock cycles, like in real chip
reg [4:0] busy_cnt; // busy lasts for 32 synthesizer clock cycles
wire [5:0] nx_busy = {1'd0,busy_cnt}+{5'd0,busy};
always @(posedge clk)
always @(posedge clk, posedge rst) begin
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;
busy <= 0;
busy_cnt <= 0;
end else begin
if( write&addr[0] ) begin
busy <= 1;
busy_cnt <= 0;
end else if(clk_en) begin
busy <= ~nx_busy[5] & busy;
busy_cnt <= nx_busy[4:0];
end
end
end
jt12_reg #(.num_ch(num_ch)) u_reg(
.rst ( rst ),
.clk ( clk ), // P1
.clk_en ( clk_en ),
.din ( din_copy ),
.up_keyon ( up_keyon ),
// channel udpates
.ch_sel ( ch_sel ),
.ch_din ( ch_din ),
.up_fnumlo ( up_chreg[0] ),
.up_alg ( up_chreg[1] ),
.up_pms ( up_chreg[2] ),
// operator updates
.din ( op_din ),
.up_keyon ( up_keyon ),
.up_dt1 ( up_opreg[0] ),
.up_tl ( up_opreg[1] ),
.up_ks_ar ( up_opreg[2] ),
@ -339,6 +479,8 @@ jt12_reg #(.num_ch(num_ch)) u_reg(
.overflow_A ( overflow_A),
.ch6op ( ch6op ),
.cur_ch ( cur_ch ),
.cur_op ( cur_op ),
// CH3 Effect-mode operation
.effect ( effect ), // allows independent freq. for CH 3
.fnum_ch3op2( fnum_ch3op2 ),

View File

@ -1,854 +0,0 @@
`ifdef SIMULATION
/* verilator lint_off PINMISSING */
reg [4:0] sep24_cnt;
reg mmr_dump;
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,
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(1) ) fnum_sep
(
.clk ( clk ),
.clk_en ( clk_en ),
.mixed ( fnum_I ),
.mask ( 24'd0 ),
.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 [2:0] block_ch0s1, block_ch1s1, block_ch2s1, block_ch3s1,
block_ch4s1, block_ch5s1, block_ch0s2, block_ch1s2,
block_ch2s2, block_ch3s2, block_ch4s2, block_ch5s2,
block_ch0s3, block_ch1s3, block_ch2s3, block_ch3s3,
block_ch4s3, block_ch5s3, block_ch0s4, block_ch1s4,
block_ch2s4, block_ch3s4, block_ch4s4, block_ch5s4;
sep24 #( .width(3), .pos0(1) ) block_sep
(
.clk ( clk ),
.clk_en ( clk_en ),
.mixed ( block_I ),
.mask ( 24'd0 ),
.cnt ( sep24_cnt ),
.ch0s1 (block_ch0s1),
.ch1s1 (block_ch1s1),
.ch2s1 (block_ch2s1),
.ch3s1 (block_ch3s1),
.ch4s1 (block_ch4s1),
.ch5s1 (block_ch5s1),
.ch0s2 (block_ch0s2),
.ch1s2 (block_ch1s2),
.ch2s2 (block_ch2s2),
.ch3s2 (block_ch3s2),
.ch4s2 (block_ch4s2),
.ch5s2 (block_ch5s2),
.ch0s3 (block_ch0s3),
.ch1s3 (block_ch1s3),
.ch2s3 (block_ch2s3),
.ch3s3 (block_ch3s3),
.ch4s3 (block_ch4s3),
.ch5s3 (block_ch5s3),
.ch0s4 (block_ch0s4),
.ch1s4 (block_ch1s4),
.ch2s4 (block_ch2s4),
.ch3s4 (block_ch3s4),
.ch4s4 (block_ch4s4),
.ch5s4 (block_ch5s4)
);
wire [1:0] rl_ch0s1, rl_ch1s1, rl_ch2s1, rl_ch3s1,
rl_ch4s1, rl_ch5s1, rl_ch0s2, rl_ch1s2,
rl_ch2s2, rl_ch3s2, rl_ch4s2, rl_ch5s2,
rl_ch0s3, rl_ch1s3, rl_ch2s3, rl_ch3s3,
rl_ch4s3, rl_ch5s3, rl_ch0s4, rl_ch1s4,
rl_ch2s4, rl_ch3s4, rl_ch4s4, rl_ch5s4;
sep24 #( .width(2), .pos0(1) ) rl_sep
(
.clk ( clk ),
.clk_en ( clk_en ),
.mixed ( rl ),
.mask ( 24'd0 ),
.cnt ( sep24_cnt ),
.ch0s1 (rl_ch0s1),
.ch1s1 (rl_ch1s1),
.ch2s1 (rl_ch2s1),
.ch3s1 (rl_ch3s1),
.ch4s1 (rl_ch4s1),
.ch5s1 (rl_ch5s1),
.ch0s2 (rl_ch0s2),
.ch1s2 (rl_ch1s2),
.ch2s2 (rl_ch2s2),
.ch3s2 (rl_ch3s2),
.ch4s2 (rl_ch4s2),
.ch5s2 (rl_ch5s2),
.ch0s3 (rl_ch0s3),
.ch1s3 (rl_ch1s3),
.ch2s3 (rl_ch2s3),
.ch3s3 (rl_ch3s3),
.ch4s3 (rl_ch4s3),
.ch5s3 (rl_ch5s3),
.ch0s4 (rl_ch0s4),
.ch1s4 (rl_ch1s4),
.ch2s4 (rl_ch2s4),
.ch3s4 (rl_ch3s4),
.ch4s4 (rl_ch4s4),
.ch5s4 (rl_ch5s4)
);
wire [2:0] fb_ch0s1, fb_ch1s1, fb_ch2s1, fb_ch3s1,
fb_ch4s1, fb_ch5s1, fb_ch0s2, fb_ch1s2,
fb_ch2s2, fb_ch3s2, fb_ch4s2, fb_ch5s2,
fb_ch0s3, fb_ch1s3, fb_ch2s3, fb_ch3s3,
fb_ch4s3, fb_ch5s3, fb_ch0s4, fb_ch1s4,
fb_ch2s4, fb_ch3s4, fb_ch4s4, fb_ch5s4;
sep24 #( .width(3), .pos0(0) ) fb_sep
(
.clk ( clk ),
.clk_en ( clk_en ),
.mixed ( fb_II ),
.mask ( 24'd0 ),
.cnt ( sep24_cnt ),
.ch0s1 (fb_ch0s1),
.ch1s1 (fb_ch1s1),
.ch2s1 (fb_ch2s1),
.ch3s1 (fb_ch3s1),
.ch4s1 (fb_ch4s1),
.ch5s1 (fb_ch5s1),
.ch0s2 (fb_ch0s2),
.ch1s2 (fb_ch1s2),
.ch2s2 (fb_ch2s2),
.ch3s2 (fb_ch3s2),
.ch4s2 (fb_ch4s2),
.ch5s2 (fb_ch5s2),
.ch0s3 (fb_ch0s3),
.ch1s3 (fb_ch1s3),
.ch2s3 (fb_ch2s3),
.ch3s3 (fb_ch3s3),
.ch4s3 (fb_ch4s3),
.ch5s3 (fb_ch5s3),
.ch0s4 (fb_ch0s4),
.ch1s4 (fb_ch1s4),
.ch2s4 (fb_ch2s4),
.ch3s4 (fb_ch3s4),
.ch4s4 (fb_ch4s4),
.ch5s4 (fb_ch5s4)
);
wire [2:0] alg_ch0s1, alg_ch1s1, alg_ch2s1, alg_ch3s1,
alg_ch4s1, alg_ch5s1, alg_ch0s2, alg_ch1s2,
alg_ch2s2, alg_ch3s2, alg_ch4s2, alg_ch5s2,
alg_ch0s3, alg_ch1s3, alg_ch2s3, alg_ch3s3,
alg_ch4s3, alg_ch5s3, alg_ch0s4, alg_ch1s4,
alg_ch2s4, alg_ch3s4, alg_ch4s4, alg_ch5s4;
sep24 #( .width(3), .pos0(1) ) alg_sep
(
.clk ( clk ),
.clk_en ( clk_en ),
.mixed ( alg ),
.mask ( 24'd0 ),
.cnt ( sep24_cnt ),
.ch0s1 (alg_ch0s1),
.ch1s1 (alg_ch1s1),
.ch2s1 (alg_ch2s1),
.ch3s1 (alg_ch3s1),
.ch4s1 (alg_ch4s1),
.ch5s1 (alg_ch5s1),
.ch0s2 (alg_ch0s2),
.ch1s2 (alg_ch1s2),
.ch2s2 (alg_ch2s2),
.ch3s2 (alg_ch3s2),
.ch4s2 (alg_ch4s2),
.ch5s2 (alg_ch5s2),
.ch0s3 (alg_ch0s3),
.ch1s3 (alg_ch1s3),
.ch2s3 (alg_ch2s3),
.ch3s3 (alg_ch3s3),
.ch4s3 (alg_ch4s3),
.ch5s3 (alg_ch5s3),
.ch0s4 (alg_ch0s4),
.ch1s4 (alg_ch1s4),
.ch2s4 (alg_ch2s4),
.ch3s4 (alg_ch3s4),
.ch4s4 (alg_ch4s4),
.ch5s4 (alg_ch5s4)
);
wire [2:0] dt1_ch0s1, dt1_ch1s1, dt1_ch2s1, dt1_ch3s1,
dt1_ch4s1, dt1_ch5s1, dt1_ch0s2, dt1_ch1s2,
dt1_ch2s2, dt1_ch3s2, dt1_ch4s2, dt1_ch5s2,
dt1_ch0s3, dt1_ch1s3, dt1_ch2s3, dt1_ch3s3,
dt1_ch4s3, dt1_ch5s3, dt1_ch0s4, dt1_ch1s4,
dt1_ch2s4, dt1_ch3s4, dt1_ch4s4, dt1_ch5s4;
sep24 #( .width(3), .pos0(0) ) dt1_sep
(
.clk ( clk ),
.clk_en ( clk_en ),
.mixed ( dt1_II ),
.mask ( 24'd0 ),
.cnt ( sep24_cnt ),
.ch0s1 (dt1_ch0s1),
.ch1s1 (dt1_ch1s1),
.ch2s1 (dt1_ch2s1),
.ch3s1 (dt1_ch3s1),
.ch4s1 (dt1_ch4s1),
.ch5s1 (dt1_ch5s1),
.ch0s2 (dt1_ch0s2),
.ch1s2 (dt1_ch1s2),
.ch2s2 (dt1_ch2s2),
.ch3s2 (dt1_ch3s2),
.ch4s2 (dt1_ch4s2),
.ch5s2 (dt1_ch5s2),
.ch0s3 (dt1_ch0s3),
.ch1s3 (dt1_ch1s3),
.ch2s3 (dt1_ch2s3),
.ch3s3 (dt1_ch3s3),
.ch4s3 (dt1_ch4s3),
.ch5s3 (dt1_ch5s3),
.ch0s4 (dt1_ch0s4),
.ch1s4 (dt1_ch1s4),
.ch2s4 (dt1_ch2s4),
.ch3s4 (dt1_ch3s4),
.ch4s4 (dt1_ch4s4),
.ch5s4 (dt1_ch5s4)
);
wire [3:0] mul_ch0s1, mul_ch1s1, mul_ch2s1, mul_ch3s1,
mul_ch4s1, mul_ch5s1, mul_ch0s2, mul_ch1s2,
mul_ch2s2, mul_ch3s2, mul_ch4s2, mul_ch5s2,
mul_ch0s3, mul_ch1s3, mul_ch2s3, mul_ch3s3,
mul_ch4s3, mul_ch5s3, mul_ch0s4, mul_ch1s4,
mul_ch2s4, mul_ch3s4, mul_ch4s4, mul_ch5s4;
sep24 #( .width(4), .pos0(21) ) mul_sep
(
.clk ( clk ),
.clk_en ( clk_en ),
.mixed ( mul_V ),
.mask ( 24'd0 ),
.cnt ( sep24_cnt ),
.ch0s1 (mul_ch0s1),
.ch1s1 (mul_ch1s1),
.ch2s1 (mul_ch2s1),
.ch3s1 (mul_ch3s1),
.ch4s1 (mul_ch4s1),
.ch5s1 (mul_ch5s1),
.ch0s2 (mul_ch0s2),
.ch1s2 (mul_ch1s2),
.ch2s2 (mul_ch2s2),
.ch3s2 (mul_ch3s2),
.ch4s2 (mul_ch4s2),
.ch5s2 (mul_ch5s2),
.ch0s3 (mul_ch0s3),
.ch1s3 (mul_ch1s3),
.ch2s3 (mul_ch2s3),
.ch3s3 (mul_ch3s3),
.ch4s3 (mul_ch4s3),
.ch5s3 (mul_ch5s3),
.ch0s4 (mul_ch0s4),
.ch1s4 (mul_ch1s4),
.ch2s4 (mul_ch2s4),
.ch3s4 (mul_ch3s4),
.ch4s4 (mul_ch4s4),
.ch5s4 (mul_ch5s4)
);
wire [6:0] tl_ch0s1, tl_ch1s1, tl_ch2s1, tl_ch3s1,
tl_ch4s1, tl_ch5s1, tl_ch0s2, tl_ch1s2,
tl_ch2s2, tl_ch3s2, tl_ch4s2, tl_ch5s2,
tl_ch0s3, tl_ch1s3, tl_ch2s3, tl_ch3s3,
tl_ch4s3, tl_ch5s3, tl_ch0s4, tl_ch1s4,
tl_ch2s4, tl_ch3s4, tl_ch4s4, tl_ch5s4;
sep24 #( .width(7), .pos0(22) ) tl_step
(
.clk ( clk ),
.clk_en ( clk_en ),
.mixed ( tl_IV ),
.mask ( 24'd0 ),
.cnt ( sep24_cnt ),
.ch0s1 (tl_ch0s1),
.ch1s1 (tl_ch1s1),
.ch2s1 (tl_ch2s1),
.ch3s1 (tl_ch3s1),
.ch4s1 (tl_ch4s1),
.ch5s1 (tl_ch5s1),
.ch0s2 (tl_ch0s2),
.ch1s2 (tl_ch1s2),
.ch2s2 (tl_ch2s2),
.ch3s2 (tl_ch3s2),
.ch4s2 (tl_ch4s2),
.ch5s2 (tl_ch5s2),
.ch0s3 (tl_ch0s3),
.ch1s3 (tl_ch1s3),
.ch2s3 (tl_ch2s3),
.ch3s3 (tl_ch3s3),
.ch4s3 (tl_ch4s3),
.ch5s3 (tl_ch5s3),
.ch0s4 (tl_ch0s4),
.ch1s4 (tl_ch1s4),
.ch2s4 (tl_ch2s4),
.ch3s4 (tl_ch3s4),
.ch4s4 (tl_ch4s4),
.ch5s4 (tl_ch5s4)
);
wire [4:0] ar_ch0s1, ar_ch1s1, ar_ch2s1, ar_ch3s1,
ar_ch4s1, ar_ch5s1, ar_ch0s2, ar_ch1s2,
ar_ch2s2, ar_ch3s2, ar_ch4s2, ar_ch5s2,
ar_ch0s3, ar_ch1s3, ar_ch2s3, ar_ch3s3,
ar_ch4s3, ar_ch5s3, ar_ch0s4, ar_ch1s4,
ar_ch2s4, ar_ch3s4, ar_ch4s4, ar_ch5s4;
sep24 #( .width(5), .pos0(1) ) ar_step
(
.clk ( clk ),
.clk_en ( clk_en ),
.mixed ( ar_I ),
.mask ( 24'd0 ),
.cnt ( sep24_cnt ),
.ch0s1 (ar_ch0s1),
.ch1s1 (ar_ch1s1),
.ch2s1 (ar_ch2s1),
.ch3s1 (ar_ch3s1),
.ch4s1 (ar_ch4s1),
.ch5s1 (ar_ch5s1),
.ch0s2 (ar_ch0s2),
.ch1s2 (ar_ch1s2),
.ch2s2 (ar_ch2s2),
.ch3s2 (ar_ch3s2),
.ch4s2 (ar_ch4s2),
.ch5s2 (ar_ch5s2),
.ch0s3 (ar_ch0s3),
.ch1s3 (ar_ch1s3),
.ch2s3 (ar_ch2s3),
.ch3s3 (ar_ch3s3),
.ch4s3 (ar_ch4s3),
.ch5s3 (ar_ch5s3),
.ch0s4 (ar_ch0s4),
.ch1s4 (ar_ch1s4),
.ch2s4 (ar_ch2s4),
.ch3s4 (ar_ch3s4),
.ch4s4 (ar_ch4s4),
.ch5s4 (ar_ch5s4)
);
wire [4:0] d1r_ch0s1, d1r_ch1s1, d1r_ch2s1, d1r_ch3s1,
d1r_ch4s1, d1r_ch5s1, d1r_ch0s2, d1r_ch1s2,
d1r_ch2s2, d1r_ch3s2, d1r_ch4s2, d1r_ch5s2,
d1r_ch0s3, d1r_ch1s3, d1r_ch2s3, d1r_ch3s3,
d1r_ch4s3, d1r_ch5s3, d1r_ch0s4, d1r_ch1s4,
d1r_ch2s4, d1r_ch3s4, d1r_ch4s4, d1r_ch5s4;
sep24 #( .width(5), .pos0(1) ) d1r_step
(
.clk ( clk ),
.clk_en ( clk_en ),
.mixed ( d1r_I ),
.mask ( 24'd0 ),
.cnt ( sep24_cnt ),
.ch0s1 (d1r_ch0s1),
.ch1s1 (d1r_ch1s1),
.ch2s1 (d1r_ch2s1),
.ch3s1 (d1r_ch3s1),
.ch4s1 (d1r_ch4s1),
.ch5s1 (d1r_ch5s1),
.ch0s2 (d1r_ch0s2),
.ch1s2 (d1r_ch1s2),
.ch2s2 (d1r_ch2s2),
.ch3s2 (d1r_ch3s2),
.ch4s2 (d1r_ch4s2),
.ch5s2 (d1r_ch5s2),
.ch0s3 (d1r_ch0s3),
.ch1s3 (d1r_ch1s3),
.ch2s3 (d1r_ch2s3),
.ch3s3 (d1r_ch3s3),
.ch4s3 (d1r_ch4s3),
.ch5s3 (d1r_ch5s3),
.ch0s4 (d1r_ch0s4),
.ch1s4 (d1r_ch1s4),
.ch2s4 (d1r_ch2s4),
.ch3s4 (d1r_ch3s4),
.ch4s4 (d1r_ch4s4),
.ch5s4 (d1r_ch5s4)
);
wire [4:0] d2r_ch0s1, d2r_ch1s1, d2r_ch2s1, d2r_ch3s1,
d2r_ch4s1, d2r_ch5s1, d2r_ch0s2, d2r_ch1s2,
d2r_ch2s2, d2r_ch3s2, d2r_ch4s2, d2r_ch5s2,
d2r_ch0s3, d2r_ch1s3, d2r_ch2s3, d2r_ch3s3,
d2r_ch4s3, d2r_ch5s3, d2r_ch0s4, d2r_ch1s4,
d2r_ch2s4, d2r_ch3s4, d2r_ch4s4, d2r_ch5s4;
sep24 #( .width(5), .pos0(1) ) d2r_step
(
.clk ( clk ),
.clk_en ( clk_en ),
.mixed ( d2r_I ),
.mask ( 24'd0 ),
.cnt ( sep24_cnt ),
.ch0s1 (d2r_ch0s1),
.ch1s1 (d2r_ch1s1),
.ch2s1 (d2r_ch2s1),
.ch3s1 (d2r_ch3s1),
.ch4s1 (d2r_ch4s1),
.ch5s1 (d2r_ch5s1),
.ch0s2 (d2r_ch0s2),
.ch1s2 (d2r_ch1s2),
.ch2s2 (d2r_ch2s2),
.ch3s2 (d2r_ch3s2),
.ch4s2 (d2r_ch4s2),
.ch5s2 (d2r_ch5s2),
.ch0s3 (d2r_ch0s3),
.ch1s3 (d2r_ch1s3),
.ch2s3 (d2r_ch2s3),
.ch3s3 (d2r_ch3s3),
.ch4s3 (d2r_ch4s3),
.ch5s3 (d2r_ch5s3),
.ch0s4 (d2r_ch0s4),
.ch1s4 (d2r_ch1s4),
.ch2s4 (d2r_ch2s4),
.ch3s4 (d2r_ch3s4),
.ch4s4 (d2r_ch4s4),
.ch5s4 (d2r_ch5s4)
);
wire [3:0] rr_ch0s1, rr_ch1s1, rr_ch2s1, rr_ch3s1,
rr_ch4s1, rr_ch5s1, rr_ch0s2, rr_ch1s2,
rr_ch2s2, rr_ch3s2, rr_ch4s2, rr_ch5s2,
rr_ch0s3, rr_ch1s3, rr_ch2s3, rr_ch3s3,
rr_ch4s3, rr_ch5s3, rr_ch0s4, rr_ch1s4,
rr_ch2s4, rr_ch3s4, rr_ch4s4, rr_ch5s4;
sep24 #( .width(4), .pos0(1) ) rr_step
(
.clk ( clk ),
.clk_en ( clk_en ),
.mixed ( rr_I ),
.mask ( 24'd0 ),
.cnt ( sep24_cnt ),
.ch0s1 (rr_ch0s1),
.ch1s1 (rr_ch1s1),
.ch2s1 (rr_ch2s1),
.ch3s1 (rr_ch3s1),
.ch4s1 (rr_ch4s1),
.ch5s1 (rr_ch5s1),
.ch0s2 (rr_ch0s2),
.ch1s2 (rr_ch1s2),
.ch2s2 (rr_ch2s2),
.ch3s2 (rr_ch3s2),
.ch4s2 (rr_ch4s2),
.ch5s2 (rr_ch5s2),
.ch0s3 (rr_ch0s3),
.ch1s3 (rr_ch1s3),
.ch2s3 (rr_ch2s3),
.ch3s3 (rr_ch3s3),
.ch4s3 (rr_ch4s3),
.ch5s3 (rr_ch5s3),
.ch0s4 (rr_ch0s4),
.ch1s4 (rr_ch1s4),
.ch2s4 (rr_ch2s4),
.ch3s4 (rr_ch3s4),
.ch4s4 (rr_ch4s4),
.ch5s4 (rr_ch5s4)
);
wire [3:0] d1l_ch0s1, d1l_ch1s1, d1l_ch2s1, d1l_ch3s1,
d1l_ch4s1, d1l_ch5s1, d1l_ch0s2, d1l_ch1s2,
d1l_ch2s2, d1l_ch3s2, d1l_ch4s2, d1l_ch5s2,
d1l_ch0s3, d1l_ch1s3, d1l_ch2s3, d1l_ch3s3,
d1l_ch4s3, d1l_ch5s3, d1l_ch0s4, d1l_ch1s4,
d1l_ch2s4, d1l_ch3s4, d1l_ch4s4, d1l_ch5s4;
sep24 #( .width(4), .pos0(1) ) d1l_step
(
.clk ( clk ),
.clk_en ( clk_en ),
.mixed ( sl_I ),
.mask ( 24'd0 ),
.cnt ( sep24_cnt ),
.ch0s1 (d1l_ch0s1),
.ch1s1 (d1l_ch1s1),
.ch2s1 (d1l_ch2s1),
.ch3s1 (d1l_ch3s1),
.ch4s1 (d1l_ch4s1),
.ch5s1 (d1l_ch5s1),
.ch0s2 (d1l_ch0s2),
.ch1s2 (d1l_ch1s2),
.ch2s2 (d1l_ch2s2),
.ch3s2 (d1l_ch3s2),
.ch4s2 (d1l_ch4s2),
.ch5s2 (d1l_ch5s2),
.ch0s3 (d1l_ch0s3),
.ch1s3 (d1l_ch1s3),
.ch2s3 (d1l_ch2s3),
.ch3s3 (d1l_ch3s3),
.ch4s3 (d1l_ch4s3),
.ch5s3 (d1l_ch5s3),
.ch0s4 (d1l_ch0s4),
.ch1s4 (d1l_ch1s4),
.ch2s4 (d1l_ch2s4),
.ch3s4 (d1l_ch3s4),
.ch4s4 (d1l_ch4s4),
.ch5s4 (d1l_ch5s4)
);
wire [1:0] ks_ch0s1, ks_ch1s1, ks_ch2s1, ks_ch3s1,
ks_ch4s1, ks_ch5s1, ks_ch0s2, ks_ch1s2,
ks_ch2s2, ks_ch3s2, ks_ch4s2, ks_ch5s2,
ks_ch0s3, ks_ch1s3, ks_ch2s3, ks_ch3s3,
ks_ch4s3, ks_ch5s3, ks_ch0s4, ks_ch1s4,
ks_ch2s4, ks_ch3s4, ks_ch4s4, ks_ch5s4;
sep24 #( .width(2), .pos0(0) ) ks_step
(
.clk ( clk ),
.clk_en ( clk_en ),
.mixed ( ks_II ),
.mask ( 24'd0 ),
.cnt ( sep24_cnt ),
.ch0s1 (ks_ch0s1),
.ch1s1 (ks_ch1s1),
.ch2s1 (ks_ch2s1),
.ch3s1 (ks_ch3s1),
.ch4s1 (ks_ch4s1),
.ch5s1 (ks_ch5s1),
.ch0s2 (ks_ch0s2),
.ch1s2 (ks_ch1s2),
.ch2s2 (ks_ch2s2),
.ch3s2 (ks_ch3s2),
.ch4s2 (ks_ch4s2),
.ch5s2 (ks_ch5s2),
.ch0s3 (ks_ch0s3),
.ch1s3 (ks_ch1s3),
.ch2s3 (ks_ch2s3),
.ch3s3 (ks_ch3s3),
.ch4s3 (ks_ch4s3),
.ch5s3 (ks_ch5s3),
.ch0s4 (ks_ch0s4),
.ch1s4 (ks_ch1s4),
.ch2s4 (ks_ch2s4),
.ch3s4 (ks_ch3s4),
.ch4s4 (ks_ch4s4),
.ch5s4 (ks_ch5s4)
);
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,
ssg_ch2s2, ssg_ch3s2, ssg_ch4s2, ssg_ch5s2,
ssg_ch0s3, ssg_ch1s3, ssg_ch2s3, ssg_ch3s3,
ssg_ch4s3, ssg_ch5s3, ssg_ch0s4, ssg_ch1s4,
ssg_ch2s4, ssg_ch3s4, ssg_ch4s4, ssg_ch5s4;
sep24 #( .width(4), .pos0(1) ) ssg_step
(
.clk ( clk ),
.clk_en ( clk_en ),
.mixed ( ssg_I ),
.mask ( 24'd0 ),
.cnt ( sep24_cnt ),
.ch0s1 (ssg_ch0s1),
.ch1s1 (ssg_ch1s1),
.ch2s1 (ssg_ch2s1),
.ch3s1 (ssg_ch3s1),
.ch4s1 (ssg_ch4s1),
.ch5s1 (ssg_ch5s1),
.ch0s2 (ssg_ch0s2),
.ch1s2 (ssg_ch1s2),
.ch2s2 (ssg_ch2s2),
.ch3s2 (ssg_ch3s2),
.ch4s2 (ssg_ch4s2),
.ch5s2 (ssg_ch5s2),
.ch0s3 (ssg_ch0s3),
.ch1s3 (ssg_ch1s3),
.ch2s3 (ssg_ch2s3),
.ch3s3 (ssg_ch3s3),
.ch4s3 (ssg_ch4s3),
.ch5s3 (ssg_ch5s3),
.ch0s4 (ssg_ch0s4),
.ch1s4 (ssg_ch1s4),
.ch2s4 (ssg_ch2s4),
.ch3s4 (ssg_ch3s4),
.ch4s4 (ssg_ch4s4),
.ch5s4 (ssg_ch5s4)
);
wire kon_ch0s1, kon_ch1s1, kon_ch2s1, kon_ch3s1,
kon_ch4s1, kon_ch5s1, kon_ch0s2, kon_ch1s2,
kon_ch2s2, kon_ch3s2, kon_ch4s2, kon_ch5s2,
kon_ch0s3, kon_ch1s3, kon_ch2s3, kon_ch3s3,
kon_ch4s3, kon_ch5s3, kon_ch0s4, kon_ch1s4,
kon_ch2s4, kon_ch3s4, kon_ch4s4, kon_ch5s4;
sep24 #( .width(1), .pos0(1) ) konstep
(
.clk ( clk ),
.clk_en ( clk_en ),
.mixed ( keyon_I ),
.mask ( 24'd0 ),
.cnt ( sep24_cnt ),
.ch0s1 (kon_ch0s1),
.ch1s1 (kon_ch1s1),
.ch2s1 (kon_ch2s1),
.ch3s1 (kon_ch3s1),
.ch4s1 (kon_ch4s1),
.ch5s1 (kon_ch5s1),
.ch0s2 (kon_ch0s2),
.ch1s2 (kon_ch1s2),
.ch2s2 (kon_ch2s2),
.ch3s2 (kon_ch3s2),
.ch4s2 (kon_ch4s2),
.ch5s2 (kon_ch5s2),
.ch0s3 (kon_ch0s3),
.ch1s3 (kon_ch1s3),
.ch2s3 (kon_ch2s3),
.ch3s3 (kon_ch3s3),
.ch4s3 (kon_ch4s3),
.ch5s3 (kon_ch5s3),
.ch0s4 (kon_ch0s4),
.ch1s4 (kon_ch1s4),
.ch2s4 (kon_ch2s4),
.ch3s4 (kon_ch3s4),
.ch4s4 (kon_ch4s4),
.ch5s4 (kon_ch5s4)
);
/* Dump all registers on request */
integer fmmr;
initial begin
fmmr=$fopen("mmr_dump.log","w");
end
always @(posedge clk )
if (mmr_dump ) begin
$fdisplay( fmmr, "-------------------------------");
// Channel 0
$fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x",
block_ch0s1, fnum_ch0s1, rl_ch0s1, fb_ch0s1, alg_ch0s1,
dt1_ch0s1, mul_ch0s1, tl_ch0s1, ar_ch0s1, d1r_ch0s1,
d2r_ch0s1, rr_ch0s1, d1l_ch0s1, ks_ch0s1, ssg_ch0s1,
kon_ch0s1 );
$fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x",
block_ch0s2, fnum_ch0s2, rl_ch0s2, fb_ch0s2, alg_ch0s2,
dt1_ch0s2, mul_ch0s2, tl_ch0s2, ar_ch0s2, d1r_ch0s2,
d2r_ch0s2, rr_ch0s2, d1l_ch0s2, ks_ch0s2, ssg_ch0s2,
kon_ch0s2 );
$fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x",
block_ch0s1, fnum_ch0s3, rl_ch0s3, fb_ch0s3, alg_ch0s3,
dt1_ch0s3, mul_ch0s3, tl_ch0s3, ar_ch0s3, d1r_ch0s3,
d2r_ch0s3, rr_ch0s3, d1l_ch0s3, ks_ch0s3, ssg_ch0s3,
kon_ch0s3 );
$fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x",
block_ch0s4, fnum_ch0s4, rl_ch0s4, fb_ch0s4, alg_ch0s4,
dt1_ch0s4, mul_ch0s4, tl_ch0s4, ar_ch0s4, d1r_ch0s4,
d2r_ch0s4, rr_ch0s4, d1l_ch0s4, ks_ch0s4, ssg_ch0s4,
kon_ch0s4 );
// Channel 1
$fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x",
block_ch1s1, fnum_ch1s1, rl_ch1s1, fb_ch1s1, alg_ch1s1,
dt1_ch1s1, mul_ch1s1, tl_ch1s1, ar_ch1s1, d1r_ch1s1,
d2r_ch1s1, rr_ch1s1, d1l_ch1s1, ks_ch1s1, ssg_ch1s1,
kon_ch1s1 );
$fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x",
block_ch1s2, fnum_ch1s2, rl_ch1s2, fb_ch1s2, alg_ch1s2,
dt1_ch1s2, mul_ch1s2, tl_ch1s2, ar_ch1s2, d1r_ch1s2,
d2r_ch1s2, rr_ch1s2, d1l_ch1s2, ks_ch1s2, ssg_ch1s2,
kon_ch1s2 );
$fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x",
block_ch1s3, fnum_ch1s3, rl_ch1s3, fb_ch1s3, alg_ch1s3,
dt1_ch1s3, mul_ch1s3, tl_ch1s3, ar_ch1s3, d1r_ch1s3,
d2r_ch1s3, rr_ch1s3, d1l_ch1s3, ks_ch1s3, ssg_ch1s3,
kon_ch1s3 );
$fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x",
block_ch1s4, fnum_ch1s4, rl_ch1s4, fb_ch1s4, alg_ch1s4,
dt1_ch1s4, mul_ch1s4, tl_ch1s4, ar_ch1s4, d1r_ch1s4,
d2r_ch1s4, rr_ch1s4, d1l_ch1s4, ks_ch1s4, ssg_ch1s4,
kon_ch1s4 );
// Channel 2
$fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x",
block_ch2s1, fnum_ch2s1, rl_ch2s1, fb_ch2s1, alg_ch2s1,
dt1_ch2s1, mul_ch2s1, tl_ch2s1, ar_ch2s1, d1r_ch2s1,
d2r_ch2s1, rr_ch2s1, d1l_ch2s1, ks_ch2s1, ssg_ch2s1,
kon_ch2s1 );
$fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x",
block_ch2s2, fnum_ch2s2, rl_ch2s2, fb_ch2s2, alg_ch2s2,
dt1_ch2s2, mul_ch2s2, tl_ch2s2, ar_ch2s2, d1r_ch2s2,
d2r_ch2s2, rr_ch2s2, d1l_ch2s2, ks_ch2s2, ssg_ch2s2,
kon_ch2s2 );
$fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x",
block_ch2s3, fnum_ch2s3, rl_ch2s3, fb_ch2s3, alg_ch2s3,
dt1_ch2s3, mul_ch2s3, tl_ch2s3, ar_ch2s3, d1r_ch2s3,
d2r_ch2s3, rr_ch2s3, d1l_ch2s3, ks_ch2s3, ssg_ch2s3,
kon_ch2s3 );
$fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x",
block_ch2s4, fnum_ch2s4, rl_ch2s4, fb_ch2s4, alg_ch2s4,
dt1_ch2s4, mul_ch2s4, tl_ch2s4, ar_ch2s4, d1r_ch2s4,
d2r_ch2s4, rr_ch2s4, d1l_ch2s4, ks_ch2s4, ssg_ch2s4,
kon_ch2s4 );
// Channel 3
$fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x",
block_ch3s1, fnum_ch3s1, rl_ch3s1, fb_ch3s1, alg_ch3s1,
dt1_ch3s1, mul_ch3s1, tl_ch3s1, ar_ch3s1, d1r_ch3s1,
d2r_ch3s1, rr_ch3s1, d1l_ch3s1, ks_ch3s1, ssg_ch3s1,
kon_ch3s1 );
$fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x",
block_ch3s2, fnum_ch3s2, rl_ch3s2, fb_ch3s2, alg_ch3s2,
dt1_ch3s2, mul_ch3s2, tl_ch3s2, ar_ch3s2, d1r_ch3s2,
d2r_ch3s2, rr_ch3s2, d1l_ch3s2, ks_ch3s2, ssg_ch3s2,
kon_ch3s2 );
$fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x",
block_ch3s3, fnum_ch3s3, rl_ch3s3, fb_ch3s3, alg_ch3s3,
dt1_ch3s3, mul_ch3s3, tl_ch3s3, ar_ch3s3, d1r_ch3s3,
d2r_ch3s3, rr_ch3s3, d1l_ch3s3, ks_ch3s3, ssg_ch3s3,
kon_ch3s3 );
$fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x",
block_ch3s4, fnum_ch3s4, rl_ch3s4, fb_ch3s4, alg_ch3s4,
dt1_ch3s4, mul_ch3s4, tl_ch3s4, ar_ch3s4, d1r_ch3s4,
d2r_ch3s4, rr_ch3s4, d1l_ch3s4, ks_ch3s4, ssg_ch3s4,
kon_ch3s4 );
// Channel 4
$fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x",
block_ch4s1, fnum_ch4s1, rl_ch4s1, fb_ch4s1, alg_ch4s1,
dt1_ch4s1, mul_ch4s1, tl_ch4s1, ar_ch4s1, d1r_ch4s1,
d2r_ch4s1, rr_ch4s1, d1l_ch4s1, ks_ch4s1, ssg_ch4s1,
kon_ch4s1 );
$fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x",
block_ch4s2, fnum_ch4s2, rl_ch4s2, fb_ch4s2, alg_ch4s2,
dt1_ch4s2, mul_ch4s2, tl_ch4s2, ar_ch4s2, d1r_ch4s2,
d2r_ch4s2, rr_ch4s2, d1l_ch4s2, ks_ch4s2, ssg_ch4s2,
kon_ch4s2 );
$fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x",
block_ch4s3, fnum_ch4s3, rl_ch4s3, fb_ch4s3, alg_ch4s3,
dt1_ch4s3, mul_ch4s3, tl_ch4s3, ar_ch4s3, d1r_ch4s3,
d2r_ch4s3, rr_ch4s3, d1l_ch4s3, ks_ch4s3, ssg_ch4s3,
kon_ch4s3 );
$fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x",
block_ch4s4, fnum_ch4s4, rl_ch4s4, fb_ch4s4, alg_ch4s4,
dt1_ch4s4, mul_ch4s4, tl_ch4s4, ar_ch4s4, d1r_ch4s4,
d2r_ch4s4, rr_ch4s4, d1l_ch4s4, ks_ch4s4, ssg_ch4s4,
kon_ch4s4 );
// Channel 5
$fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x",
block_ch5s1, fnum_ch5s1, rl_ch5s1, fb_ch5s1, alg_ch5s1,
dt1_ch5s1, mul_ch5s1, tl_ch5s1, ar_ch5s1, d1r_ch5s1,
d2r_ch5s1, rr_ch5s1, d1l_ch5s1, ks_ch5s1, ssg_ch5s1,
kon_ch5s1 );
$fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x",
block_ch5s2, fnum_ch5s2, rl_ch5s2, fb_ch5s2, alg_ch5s2,
dt1_ch5s2, mul_ch5s2, tl_ch5s2, ar_ch5s2, d1r_ch5s2,
d2r_ch5s2, rr_ch5s2, d1l_ch5s2, ks_ch5s2, ssg_ch5s2,
kon_ch5s2 );
$fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x",
block_ch5s3, fnum_ch5s3, rl_ch5s3, fb_ch5s3, alg_ch5s3,
dt1_ch5s3, mul_ch5s3, tl_ch5s3, ar_ch5s3, d1r_ch5s3,
d2r_ch5s3, rr_ch5s3, d1l_ch5s3, ks_ch5s3, ssg_ch5s3,
kon_ch5s3 );
$fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x",
block_ch5s4, fnum_ch5s4, rl_ch5s4, fb_ch5s4, alg_ch5s4,
dt1_ch5s4, mul_ch5s4, tl_ch5s4, ar_ch5s4, d1r_ch5s4,
d2r_ch5s4, rr_ch5s4, d1l_ch5s4, ks_ch5s4, ssg_ch5s4,
kon_ch5s4 );
end
/* verilator lint_on PINMISSING */
`endif

View File

@ -1,4 +1,3 @@
`timescale 1ns / 1ps
/* This file is part of JT12.
@ -140,16 +139,14 @@ generate
end
endgenerate
`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
// 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
endmodule

View File

@ -1,4 +1,3 @@
`timescale 1ns / 1ps
/* This file is part of JT12.
@ -29,7 +28,7 @@
module jt12_op(
input rst,
input clk,
input clk_en,
input clk_en /* synthesis direct_enable */,
input [9:0] pg_phase_VIII,
input [9:0] eg_atten_IX, // output from envelope generator
input [2:0] fb_II, // voice feedback
@ -51,6 +50,8 @@ module jt12_op(
output signed [13:0] full_result
);
parameter num_ch = 6;
/* enters exits
S1 S2
S3 S4
@ -64,8 +65,6 @@ reg [11:0] atten_internal_IX;
assign op_result = op_result_internal[13:5];
assign full_result = op_result_internal;
parameter num_ch = 6;
reg signbit_IX, signbit_X, signbit_XI;
reg [11:0] totalatten_X;
@ -271,235 +270,62 @@ always @(posedge clk) if( clk_en ) begin
end
`ifdef SIMULATION
/* verilator lint_off PINMISSING */
reg [4:0] sep24_cnt;
reg signed [13:0] op_sep2_0;
reg signed [13:0] op_sep4_0;
reg signed [13:0] op_sep5_0;
reg signed [13:0] op_sep6_0;
reg signed [13:0] op_sep0_0;
reg signed [13:0] op_sep1_0;
reg signed [13:0] op_sep2_1;
reg signed [13:0] op_sep4_1;
reg signed [13:0] op_sep5_1;
reg signed [13:0] op_sep6_1;
reg signed [13:0] op_sep0_1;
reg signed [13:0] op_sep1_1;
reg signed [13:0] op_sep2_2;
reg signed [13:0] op_sep4_2;
reg signed [13:0] op_sep5_2;
reg signed [13:0] op_sep6_2;
reg signed [13:0] op_sep0_2;
reg signed [13:0] op_sep1_2;
reg signed [13:0] op_sep2_3;
reg signed [13:0] op_sep4_3;
reg signed [13:0] op_sep5_3;
reg signed [13:0] op_sep6_3;
reg signed [13:0] op_sep0_3;
reg signed [13:0] op_sep1_3;
reg [ 4:0] sepcnt;
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;
always @(posedge clk ) if( clk_en ) begin
sep24_cnt <= !zero ? sep24_cnt+1'b1 : 5'd0;
always @(posedge clk) if(clk_en) begin
sepcnt <= zero ? 5'd0 : sepcnt+5'd1;
case( (sepcnt+14)%24 )
0: op_sep0_0 <= op_XII;
1: op_sep1_0 <= op_XII;
2: op_sep2_0 <= op_XII;
3: op_sep4_0 <= op_XII;
4: op_sep5_0 <= op_XII;
5: op_sep6_0 <= op_XII;
6: op_sep0_2 <= op_XII;
7: op_sep1_2 <= op_XII;
8: op_sep2_2 <= op_XII;
9: op_sep4_2 <= op_XII;
10: op_sep5_2 <= op_XII;
11: op_sep6_2 <= op_XII;
12: op_sep0_1 <= op_XII;
13: op_sep1_1 <= op_XII;
14: op_sep2_1 <= op_XII;
15: op_sep4_1 <= op_XII;
16: op_sep5_1 <= op_XII;
17: op_sep6_1 <= op_XII;
18: op_sep0_3 <= op_XII;
19: op_sep1_3 <= op_XII;
20: op_sep2_3 <= op_XII;
21: op_sep4_3 <= op_XII;
22: op_sep5_3 <= op_XII;
23: op_sep6_3 <= op_XII;
endcase
end
sep24 #( .width(14), .pos0(13)) opsep
(
.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),
.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)
);
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;
sep24 #( .width(9), .pos0(13)) accsep
(
.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),
.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)
);
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;
sep24 #( .width(10), .pos0( 18 ) ) pmsep
(
.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),
.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)
);
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;
sep24 #( .width(10), .pos0( 18 ) ) phsep
(
.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),
.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)
);
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;
sep24 #( .width(10), .pos0(17) ) egsep
(
.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),
.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)
);
/* verilator lint_on PINMISSING */
`endif
endmodule

View File

@ -1,109 +0,0 @@
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

@ -24,7 +24,6 @@ http://gendev.spritesmind.net/forum/viewtopic.php?t=386&postdays=0&postorder=asc
*/
`timescale 1ns / 1ps
/*
@ -34,7 +33,7 @@ http://gendev.spritesmind.net/forum/viewtopic.php?t=386&postdays=0&postorder=asc
module jt12_pg(
input clk,
input clk_en,
input clk_en /* synthesis direct_enable */,
input rst,
// Channel frequency
input [10:0] fnum_I,

View File

@ -1,49 +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 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: 2-11-2018
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: 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
*/
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,
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
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];
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

@ -17,10 +17,7 @@
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.
@ -38,18 +35,144 @@ 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_lut [0:63];
reg [2: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);
lfo_sh1_lut[6'h00] = 3'd7;
lfo_sh1_lut[6'h01] = 3'd7;
lfo_sh1_lut[6'h02] = 3'd7;
lfo_sh1_lut[6'h03] = 3'd7;
lfo_sh1_lut[6'h04] = 3'd7;
lfo_sh1_lut[6'h05] = 3'd7;
lfo_sh1_lut[6'h06] = 3'd7;
lfo_sh1_lut[6'h07] = 3'd7;
lfo_sh1_lut[6'h08] = 3'd7;
lfo_sh1_lut[6'h09] = 3'd7;
lfo_sh1_lut[6'h0A] = 3'd7;
lfo_sh1_lut[6'h0B] = 3'd7;
lfo_sh1_lut[6'h0C] = 3'd7;
lfo_sh1_lut[6'h0D] = 3'd7;
lfo_sh1_lut[6'h0E] = 3'd7;
lfo_sh1_lut[6'h0F] = 3'd7;
lfo_sh1_lut[6'h10] = 3'd7;
lfo_sh1_lut[6'h11] = 3'd7;
lfo_sh1_lut[6'h12] = 3'd7;
lfo_sh1_lut[6'h13] = 3'd7;
lfo_sh1_lut[6'h14] = 3'd7;
lfo_sh1_lut[6'h15] = 3'd7;
lfo_sh1_lut[6'h16] = 3'd1;
lfo_sh1_lut[6'h17] = 3'd1;
lfo_sh1_lut[6'h18] = 3'd7;
lfo_sh1_lut[6'h19] = 3'd7;
lfo_sh1_lut[6'h1A] = 3'd7;
lfo_sh1_lut[6'h1B] = 3'd7;
lfo_sh1_lut[6'h1C] = 3'd1;
lfo_sh1_lut[6'h1D] = 3'd1;
lfo_sh1_lut[6'h1E] = 3'd1;
lfo_sh1_lut[6'h1F] = 3'd1;
lfo_sh1_lut[6'h20] = 3'd7;
lfo_sh1_lut[6'h21] = 3'd7;
lfo_sh1_lut[6'h22] = 3'd7;
lfo_sh1_lut[6'h23] = 3'd1;
lfo_sh1_lut[6'h24] = 3'd1;
lfo_sh1_lut[6'h25] = 3'd1;
lfo_sh1_lut[6'h26] = 3'd1;
lfo_sh1_lut[6'h27] = 3'd0;
lfo_sh1_lut[6'h28] = 3'd7;
lfo_sh1_lut[6'h29] = 3'd7;
lfo_sh1_lut[6'h2A] = 3'd1;
lfo_sh1_lut[6'h2B] = 3'd1;
lfo_sh1_lut[6'h2C] = 3'd0;
lfo_sh1_lut[6'h2D] = 3'd0;
lfo_sh1_lut[6'h2E] = 3'd0;
lfo_sh1_lut[6'h2F] = 3'd0;
lfo_sh1_lut[6'h30] = 3'd7;
lfo_sh1_lut[6'h31] = 3'd7;
lfo_sh1_lut[6'h32] = 3'd1;
lfo_sh1_lut[6'h33] = 3'd1;
lfo_sh1_lut[6'h34] = 3'd0;
lfo_sh1_lut[6'h35] = 3'd0;
lfo_sh1_lut[6'h36] = 3'd0;
lfo_sh1_lut[6'h37] = 3'd0;
lfo_sh1_lut[6'h38] = 3'd7;
lfo_sh1_lut[6'h39] = 3'd7;
lfo_sh1_lut[6'h3A] = 3'd1;
lfo_sh1_lut[6'h3B] = 3'd1;
lfo_sh1_lut[6'h3C] = 3'd0;
lfo_sh1_lut[6'h3D] = 3'd0;
lfo_sh1_lut[6'h3E] = 3'd0;
lfo_sh1_lut[6'h3F] = 3'd0;
lfo_sh2_lut[6'h00] = 3'd7;
lfo_sh2_lut[6'h01] = 3'd7;
lfo_sh2_lut[6'h02] = 3'd7;
lfo_sh2_lut[6'h03] = 3'd7;
lfo_sh2_lut[6'h04] = 3'd7;
lfo_sh2_lut[6'h05] = 3'd7;
lfo_sh2_lut[6'h06] = 3'd7;
lfo_sh2_lut[6'h07] = 3'd7;
lfo_sh2_lut[6'h08] = 3'd7;
lfo_sh2_lut[6'h09] = 3'd7;
lfo_sh2_lut[6'h0A] = 3'd7;
lfo_sh2_lut[6'h0B] = 3'd7;
lfo_sh2_lut[6'h0C] = 3'd2;
lfo_sh2_lut[6'h0D] = 3'd2;
lfo_sh2_lut[6'h0E] = 3'd2;
lfo_sh2_lut[6'h0F] = 3'd2;
lfo_sh2_lut[6'h10] = 3'd7;
lfo_sh2_lut[6'h11] = 3'd7;
lfo_sh2_lut[6'h12] = 3'd7;
lfo_sh2_lut[6'h13] = 3'd2;
lfo_sh2_lut[6'h14] = 3'd2;
lfo_sh2_lut[6'h15] = 3'd2;
lfo_sh2_lut[6'h16] = 3'd7;
lfo_sh2_lut[6'h17] = 3'd7;
lfo_sh2_lut[6'h18] = 3'd7;
lfo_sh2_lut[6'h19] = 3'd7;
lfo_sh2_lut[6'h1A] = 3'd2;
lfo_sh2_lut[6'h1B] = 3'd2;
lfo_sh2_lut[6'h1C] = 3'd7;
lfo_sh2_lut[6'h1D] = 3'd7;
lfo_sh2_lut[6'h1E] = 3'd2;
lfo_sh2_lut[6'h1F] = 3'd2;
lfo_sh2_lut[6'h20] = 3'd7;
lfo_sh2_lut[6'h21] = 3'd7;
lfo_sh2_lut[6'h22] = 3'd2;
lfo_sh2_lut[6'h23] = 3'd7;
lfo_sh2_lut[6'h24] = 3'd7;
lfo_sh2_lut[6'h25] = 3'd7;
lfo_sh2_lut[6'h26] = 3'd2;
lfo_sh2_lut[6'h27] = 3'd7;
lfo_sh2_lut[6'h28] = 3'd7;
lfo_sh2_lut[6'h29] = 3'd7;
lfo_sh2_lut[6'h2A] = 3'd7;
lfo_sh2_lut[6'h2B] = 3'd2;
lfo_sh2_lut[6'h2C] = 3'd7;
lfo_sh2_lut[6'h2D] = 3'd7;
lfo_sh2_lut[6'h2E] = 3'd2;
lfo_sh2_lut[6'h2F] = 3'd1;
lfo_sh2_lut[6'h30] = 3'd7;
lfo_sh2_lut[6'h31] = 3'd7;
lfo_sh2_lut[6'h32] = 3'd7;
lfo_sh2_lut[6'h33] = 3'd2;
lfo_sh2_lut[6'h34] = 3'd7;
lfo_sh2_lut[6'h35] = 3'd7;
lfo_sh2_lut[6'h36] = 3'd2;
lfo_sh2_lut[6'h37] = 3'd1;
lfo_sh2_lut[6'h38] = 3'd7;
lfo_sh2_lut[6'h39] = 3'd7;
lfo_sh2_lut[6'h3A] = 3'd7;
lfo_sh2_lut[6'h3B] = 3'd2;
lfo_sh2_lut[6'h3C] = 3'd7;
lfo_sh2_lut[6'h3D] = 3'd7;
lfo_sh2_lut[6'h3E] = 3'd2;
lfo_sh2_lut[6'h3F] = 3'd1;
end
always @(*) begin
lfo_sh1 = lfo_sh1_lut[{pms,index}][2:0];
lfo_sh2 = lfo_sh2_lut[{pms,index}][2:0];
lfo_sh1 = lfo_sh1_lut[{pms,index}];
lfo_sh2 = lfo_sh2_lut[{pms,index}];
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 };

View File

@ -23,30 +23,35 @@
module jt12_reg(
input rst,
input clk,
input clk_en,
input [7:0] din,
input clk_en /* synthesis direct_enable */,
input [2:0] ch,
input [2:0] ch, // channel to update
input [1:0] op,
input csm,
input flag_A,
input overflow_A,
input up_keyon,
// channel udpates
input [2:0] ch_sel,
input [7:0] ch_din,
input up_alg,
input up_fnumlo,
// operator updates
input [7:0] din,
input up_keyon,
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 reg ch6op, // 1 when the operator belongs to CH6
output reg ch6op, // 1 when the operator belongs to CH6
output reg [2:0] cur_ch,
output reg [1:0] cur_op,
// CH3 Effect-mode operation
input effect,
@ -105,8 +110,8 @@ module jt12_reg(
parameter num_ch=6; // Use only 3 (YM2203/YM2610) or 6 (YM2612/YM2608)
reg [1:0] next_op, cur_op;
reg [2:0] next_ch, cur_ch;
reg [1:0] next_op;
reg [2:0] next_ch;
reg last;
`ifdef SIMULATION
@ -117,6 +122,8 @@ reg last;
initial begin
cur_op = 2'd0;
cur_ch = 3'd0;
next_op = 2'd0;
next_ch = 3'd1;
last = 1'b0;
zero = 1'b1;
end
@ -155,11 +162,9 @@ assign block_I =( {3{effect_on_s1}} & block_ch3op1 ) |
( {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;
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) );
@ -179,24 +184,6 @@ wire update_op_IV = cur == req_opch_IV;
// key on/off
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 [7:0] fnlo_in = din;
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 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;
wire up_ams_ch = up_pms & update_ch_IV;
always @(*) begin
// next = cur==5'd23 ? 5'd0 : cur +1'b1;
@ -216,6 +203,7 @@ always @(posedge clk) begin : up_counter
end
end
`ifndef NOFM
jt12_kon #(.num_ch(num_ch)) u_kon(
.rst ( rst ),
.clk ( clk ),
@ -325,46 +313,27 @@ assign { tl_IV, dt1_I, mul_II, ks_II,
// 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.
localparam regch_width=25;
wire [regch_width-1:0] regch_out;
wire [regch_width-1:0] regch_in = {
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
};
jt12_reg_ch #(.NUM_CH(num_ch)) u_regch(
.rst ( rst ),
.clk ( clk ),
.cen ( clk_en ),
.din ( ch_din ),
assign { block_I_raw, fnum_I_raw,
fb_I, alg_I, ams_IV, pms_I } = regch_out;
.up_ch ( ch_sel ),
.latch_fnum ( latch_fnum ),
.up_fnumlo ( up_fnumlo ),
.up_alg ( up_alg ),
.up_pms ( up_pms ),
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 )
.ch ( next_ch ), // next active channel
.block ( block_I_raw ),
.fnum ( fnum_I_raw ),
.fb ( fb_I ),
.alg ( alg_I ),
.rl ( rl ),
.ams_IV ( ams_IV ),
.pms ( pms_I )
);
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
`endif
endmodule

View File

@ -0,0 +1,128 @@
/* 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: 23-10-2019
*/
// Channel data is not stored in a CSR as operators
// Proof of that is the Splatter House arcade writes
// channel and operator data in two consequitive accesses
// without enough time in between to have the eight
// channels go through the CSR. So the channel data
// cannot be CSR, but regular registers.
module jt12_reg_ch(
input rst,
input clk,
input cen,
input [ 7:0] din,
input [ 2:0] up_ch,
input [ 5:0] latch_fnum,
input up_fnumlo,
input up_alg,
input up_pms,
input [ 2:0] ch, // next active channel
output reg [ 2:0] block,
output reg [10:0] fnum,
output reg [ 2:0] fb,
output reg [ 2:0] alg,
output reg [ 1:0] rl,
output reg [ 1:0] ams_IV,
output reg [ 2:0] pms
);
parameter NUM_CH=6;
localparam M=NUM_CH==3?2:3;
reg [ 2:0] reg_block[0:NUM_CH-1];
reg [10:0] reg_fnum [0:NUM_CH-1];
reg [ 2:0] reg_fb [0:NUM_CH-1];
reg [ 2:0] reg_alg [0:NUM_CH-1];
reg [ 1:0] reg_rl [0:NUM_CH-1];
reg [ 1:0] reg_ams [0:NUM_CH-1];
reg [ 2:0] reg_pms [0:NUM_CH-1];
reg [ 2:0] ch_IV;
wire [M-1:0] ch_sel, out_sel;
function [M-1:0] chtr( input [2:0] chin );
reg [2:0] aux;
begin
aux = chin[M-1] ? {1'b0,chin[1:0]}+3'd3 : // upper channels
{1'b0,chin[1:0]}; // lower
chtr = NUM_CH==3 ? chin[M-1:0] : aux[M-1:0];
end
endfunction
assign ch_sel = chtr(up_ch);
assign out_sel = chtr(ch);
integer i;
/* verilator lint_off WIDTHEXPAND */
always @* begin
ch_IV = ch;
if( NUM_CH==6 )
case(out_sel)
0: ch_IV = 3;
1: ch_IV = 4;
2: ch_IV = 5;
3: ch_IV = 0;
4: ch_IV = 1;
5: ch_IV = 2;
default: ch_IV = 0;
endcase
end
/* verilator lint_on WIDTHEXPAND */
always @(posedge clk) if(cen) begin
block <= reg_block[out_sel];
fnum <= reg_fnum [out_sel];
fb <= reg_fb [out_sel];
alg <= reg_alg [out_sel];
rl <= reg_rl [out_sel];
ams_IV<= reg_ams [ch_IV[M-1:0]];
pms <= reg_pms [out_sel];
if( NUM_CH==3 ) rl <= 3; // YM2203 has no stereo output
end
always @(posedge clk, posedge rst) begin
if( rst ) for(i=0;i<NUM_CH;i=i+1) begin
reg_block[i] <= 0;
reg_fnum [i] <= 0;
reg_fb [i] <= 0;
reg_alg [i] <= 0;
reg_rl [i] <= 3;
reg_ams [i] <= 0;
reg_pms [i] <= 0;
end else begin
i = 0; // prevents latch warning in Quartus
if( up_fnumlo ) { reg_block[ch_sel], reg_fnum[ch_sel] } <= {latch_fnum,din};
if( up_alg ) begin
reg_fb [ch_sel] <= din[5:3];
reg_alg[ch_sel] <= din[2:0];
end
if( up_pms ) begin
reg_rl [ch_sel] <= din[7:6];
reg_ams[ch_sel] <= din[5:4];
reg_pms[ch_sel] <= din[2:0];
end
end
end
endmodule

View File

@ -18,13 +18,12 @@
Date: 1-31-2017
*/
`timescale 1ns / 1ps
// stages must be greater than 2
module jt12_sh #(parameter width=5, stages=24 )
(
input clk,
input clk_en,
input clk_en /* synthesis direct_enable */,
input [width-1:0] din,
output [width-1:0] drop
);

View File

@ -18,12 +18,11 @@
Date: 1-31-2017
*/
`timescale 1ns / 1ps
module jt12_sh24 #(parameter width=5 )
(
input clk,
input clk_en,
input clk_en /* synthesis direct_enable */,
input [width-1:0] din,
output reg [width-1:0] st1,
output reg [width-1:0] st2,

View File

@ -18,37 +18,26 @@
Date: 1-31-2017
*/
`timescale 1ns / 1ps
// stages must be greater than 2
module jt12_sh_rst #(parameter width=5, stages=32, rstval=1'b0 )
(
input rst,
input clk,
input clk_en,
input clk_en /* synthesis direct_enable */,
input [width-1:0] din,
output [width-1:0] drop
);
reg [stages-1:0] bits[width-1:0];
wire [width-1:0] din_mx = rst ? {width{rstval[0]}} : din;
genvar i;
integer k;
generate
initial
for (k=0; k < width; k=k+1) begin
bits[k] = { stages{rstval}};
end
endgenerate
generate
for (i=0; i < width; i=i+1) begin: bit_shifter
always @(posedge clk)
if( rst ) begin
bits[i] <= {stages{rstval}};
end else if(clk_en) begin
bits[i] <= {bits[i][stages-2:0], din[i]};
end
always @(posedge clk) if(clk_en) begin
bits[i] <= {bits[i][stages-2:0], din_mx[i]};
end
assign drop[i] = bits[i][stages-1];
end
endgenerate

View File

@ -20,16 +20,19 @@
*/
`timescale 1ns / 1ps
// Accumulates an arbitrary number of inputs with saturation
// restart the sum when input "zero" is high
module jt12_single_acc #(parameter win=14, // input data width
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,
input clk,
input clk_en /* synthesis direct_enable */,
input [win-1:0] op_result,
input sum_en,
input zero,
output reg [wout-1:0] snd
);

View File

@ -18,7 +18,6 @@
Date: 1-31-2017
*/
`timescale 1ns / 1ps
/* The input is {op[1:0], ch[2:0]}
it adds 1 to the channel and overflow to the operator correctly */

View File

@ -1,113 +1,140 @@
/* 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
YM3438_APL.pdf
Timer A = 144*(1024-NA)/Phi M
Timer B = 2304*(256-NB)/Phi M
*/
YM3438_APL.pdf
Timer A = 144*(1024-NA)/Phi M
Timer B = 2304*(256-NB)/Phi M
*/
`timescale 1ns / 1ps
module jt12_timers(
input clk,
input rst,
input clk_en, // clock enable
input [9:0] value_A,
input [7:0] value_B,
input load_A,
input load_B,
input clr_flag_A,
input clr_flag_B,
input enable_irq_A,
input enable_irq_B,
output flag_A,
output flag_B,
output overflow_A,
output irq_n
input clk,
input rst,
input clk_en /* synthesis direct_enable */,
input zero,
input [9:0] value_A,
input [7:0] value_B,
input load_A,
input load_B,
input clr_flag_A,
input clr_flag_B,
input enable_irq_A,
input enable_irq_B,
output flag_A,
output flag_B,
output overflow_A,
output irq_n
);
parameter num_ch = 6;
assign irq_n = ~( (flag_A&enable_irq_A) | (flag_B&enable_irq_B) );
jt12_timer #(.mult_width(5), .mult_max(24), .counter_width(10))
timer_A(
.clk ( clk ),
.rst ( rst ),
.clk_en ( clk_en ),
.start_value( value_A ),
.load ( load_A ),
.clr_flag ( clr_flag_A),
.flag ( flag_A ),
.overflow ( overflow_A)
);
/*
reg zero2;
jt12_timer #(.mult_width(9), .mult_max(384), .counter_width(8))
timer_B(
.clk ( clk ),
.rst ( rst ),
.clk_en ( clk_en ),
.start_value( value_B ),
.load ( load_B ),
.clr_flag ( clr_flag_B),
.flag ( flag_B ),
.overflow ( )
);
endmodule
module jt12_timer #(parameter counter_width = 10, mult_width=5, mult_max=4 )
(
input clk,
input rst,
(* direct_enable *) input clk_en,
input [counter_width-1:0] start_value,
input load,
input clr_flag,
output reg flag,
output reg overflow
);
reg [ mult_width-1:0] mult;
reg [counter_width-1:0] cnt;
always@(posedge clk)
if( clr_flag || rst)
flag <= 1'b0;
else if(overflow) flag<=1'b1;
reg [mult_width+counter_width-1:0] next, init;
always @(*) begin
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}} };
always @(posedge clk, posedge rst) begin
if( rst )
zero2 <= 0;
else if(clk_en) begin
if( zero ) zero2 <= ~zero;
end
end
always @(posedge clk)
if( ~load || rst) begin
mult <= { (mult_width){1'b0} };
cnt <= start_value;
end
else if( clk_en )
{ cnt, mult } <= overflow ? init : next;
wire zero = num_ch == 6 ? zero : (zero2&zero);
*/
jt12_timer #(.CW(10)) timer_A(
.clk ( clk ),
.rst ( rst ),
.cen ( clk_en ),
.zero ( zero ),
.start_value( value_A ),
.load ( load_A ),
.clr_flag ( clr_flag_A ),
.flag ( flag_A ),
.overflow ( overflow_A )
);
jt12_timer #(.CW(8),.FREE_EN(1)) timer_B(
.clk ( clk ),
.rst ( rst ),
.cen ( clk_en ),
.zero ( zero ),
.start_value( value_B ),
.load ( load_B ),
.clr_flag ( clr_flag_B ),
.flag ( flag_B ),
.overflow ( )
);
endmodule
module jt12_timer #(parameter
CW = 8, // counter bit width. This is the counter that can be loaded
FW = 4, // number of bits for the free-running counter
FREE_EN = 0 // enables a 4-bit free enable count
) (
input rst,
input clk,
input cen,
input zero,
input [CW-1:0] start_value,
input load,
input clr_flag,
output reg flag,
output reg overflow
);
/* verilator lint_off WIDTH */
reg load_l;
reg [CW-1:0] cnt, next;
reg [FW-1:0] free_cnt, free_next;
reg free_ov;
always@(posedge clk, posedge rst)
if( rst )
flag <= 1'b0;
else /*if(cen)*/ begin
if( clr_flag )
flag <= 1'b0;
else if( cen && zero && load && overflow ) flag<=1'b1;
end
always @(*) begin
{free_ov, free_next} = { 1'b0, free_cnt} + 1'b1;
{overflow, next } = { 1'b0, cnt } + (FREE_EN ? free_ov : 1'b1);
end
always @(posedge clk) begin
load_l <= load;
if( !load_l && load ) begin
cnt <= start_value;
end else if( cen && zero && load )
cnt <= overflow ? start_value : next;
end
// Free running counter
always @(posedge clk) begin
if( rst ) begin
free_cnt <= 0;
end else if( cen && zero ) begin
free_cnt <= free_next;
end
end
/* verilator lint_on WIDTH */
endmodule

View File

@ -12,47 +12,76 @@
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
*/
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
(* direct_enable *) input cen, // optional clock enable, if 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,
// Configuration
input en_hifi_pcm, // high to enable PCM interpolation on YM2612 mode
// ADPCM pins
output [19:0] adpcma_addr, // real hardware has 10 pins multiplexed through RMPX pin
output [ 3:0] adpcma_bank,
output adpcma_roe_n, // ADPCM-A ROM output enable
input [ 7:0] adpcma_data, // Data from RAM
output [23:0] adpcmb_addr, // real hardware has 12 pins multiplexed through PMPX pin
input [ 7:0] adpcmb_data,
output adpcmb_roe_n, // ADPCM-B ROM output enable
// I/O pins used by YM2203 embedded YM2149 chip
input [7:0] IOA_in,
input [7:0] IOB_in,
output [7:0] IOA_out,
output [7:0] IOB_out,
output IOA_oe,
output IOB_oe,
// 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,
output signed [15:0] adpcmA_l,
output signed [15:0] adpcmA_r,
output signed [15:0] adpcmB_l,
output signed [15:0] adpcmB_r,
// 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
output snd_sample,
input [ 5:0] ch_enable, // ADPCM-A channels
input [ 7:0] debug_bus,
output [ 7:0] debug_view
);
parameter use_lfo=1, use_ssg=0, num_ch=6, use_pcm=1, use_lr=1; // defaults to YM2612
// parameters to select the features for each chip type
// defaults to YM2612
parameter use_lfo=1, use_ssg=0, num_ch=6, use_pcm=1;
parameter use_adpcm=0;
parameter JT49_DIV=2,
YM2203_LUMPED=0;
parameter mask_div=1;
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;
@ -103,7 +132,9 @@ wire [ 8:0] pcm;
// Test
wire pg_stop, eg_stop;
wire ch6op;
wire ch6op;
wire [ 2:0] cur_ch;
wire [ 1:0] cur_op;
// Operator
wire xuse_internal, yuse_internal;
@ -118,19 +149,171 @@ wire lfo_rst;
wire [3:0] psg_addr;
wire [7:0] psg_data, psg_dout;
wire psg_wr_n;
// ADPCM-A
wire [15:0] addr_a;
wire [ 2:0] up_addr, up_lracl;
wire up_start, up_end;
wire [ 7:0] aon_a, lracl;
wire [ 5:0] atl_a; // ADPCM Total Level
wire up_aon;
// APDCM-B
wire acmd_on_b; // Control - Process start, Key On
wire acmd_rep_b; // Control - Repeat
wire acmd_rst_b; // Control - Reset
wire acmd_up_b; // Control - New cmd received
wire [ 1:0] alr_b; // Left / Right
wire [15:0] astart_b; // Start address
wire [15:0] aend_b; // End address
wire [15:0] adeltan_b; // Delta-N
wire [ 7:0] aeg_b; // Envelope Generator Control
wire [ 5:0] adpcma_flags; // ADPMC-A read over flags
wire adpcmb_flag;
wire [ 6:0] flag_ctl;
wire [ 6:0] flag_mask;
wire [ 1:0] div_setting;
jt12_mmr #(.use_ssg(use_ssg),.num_ch(num_ch),.use_pcm(use_pcm))
wire clk_en_2, clk_en_666, clk_en_111, clk_en_55;
assign debug_view = { 4'd0, flag_B, flag_A, div_setting };
generate
if( use_adpcm==1 ) begin: gen_adpcm
wire rst_n;
jt12_rst u_rst(
.rst ( rst ),
.clk ( clk ),
.rst_n ( rst_n )
);
jt10_adpcm_drvA u_adpcm_a(
.rst_n ( rst_n ),
.clk ( clk ),
.cen ( cen ),
.cen6 ( clk_en_666 ), // clk & cen must be 666 kHz
.cen1 ( clk_en_111 ), // clk & cen must be 111 kHz
.addr ( adpcma_addr ), // real hardware has 10 pins multiplexed through RMPX pin
.bank ( adpcma_bank ),
.roe_n ( adpcma_roe_n ), // ADPCM-A ROM output enable
.datain ( adpcma_data ),
// Control Registers
.atl ( atl_a ), // ADPCM Total Level
.addr_in ( addr_a ),
.lracl_in ( lracl ),
.up_start ( up_start ),
.up_end ( up_end ),
.up_addr ( up_addr ),
.up_lracl ( up_lracl ),
.aon_cmd ( aon_a ), // ADPCM ON equivalent to key on for FM
.up_aon ( up_aon ),
// Flags
.flags ( adpcma_flags ),
.clr_flags ( flag_ctl[5:0] ),
.pcm55_l ( adpcmA_l ),
.pcm55_r ( adpcmA_r ),
.ch_enable ( ch_enable )
);
jt10_adpcm_drvB u_adpcm_b(
.rst_n ( rst_n ),
.clk ( clk ),
.cen ( cen ),
.cen55 ( clk_en_55 ),
// Control
.acmd_on_b ( acmd_on_b ), // Control - Process start, Key On
.acmd_rep_b ( acmd_rep_b ), // Control - Repeat
.acmd_rst_b ( acmd_rst_b ), // Control - Reset
.acmd_up_b ( acmd_up_b ), // Control - New command received
.alr_b ( alr_b ), // Left / Right
.astart_b ( astart_b ), // Start address
.aend_b ( aend_b ), // End address
.adeltan_b ( adeltan_b ), // Delta-N
.aeg_b ( aeg_b ), // Envelope Generator Control
// Flag
.flag ( adpcmb_flag ),
.clr_flag ( flag_ctl[6] ),
// memory
.addr ( adpcmb_addr ),
.data ( adpcmb_data ),
.roe_n ( adpcmb_roe_n ),
.pcm55_l ( adpcmB_l ),
.pcm55_r ( adpcmB_r )
);
assign snd_sample = zero;
jt10_acc u_acc(
.clk ( clk ),
.clk_en ( clk_en ),
.op_result ( op_result_hd ),
.rl ( rl ),
.zero ( zero ),
.s1_enters ( s2_enters ),
.s2_enters ( s1_enters ),
.s3_enters ( s4_enters ),
.s4_enters ( s3_enters ),
.cur_ch ( cur_ch ),
.cur_op ( cur_op ),
.alg ( alg_I ),
.adpcmA_l ( adpcmA_l ),
.adpcmA_r ( adpcmA_r ),
.adpcmB_l ( adpcmB_l ),
.adpcmB_r ( adpcmB_r ),
// combined output
.left ( fm_snd_left ),
.right ( fm_snd_right )
);
end else begin : gen_adpcm_no
assign adpcmA_l = 'd0;
assign adpcmA_r = 'd0;
assign adpcmB_l = 'd0;
assign adpcmB_r = 'd0;
assign adpcma_addr = 'd0;
assign adpcma_bank = 'd0;
assign adpcma_roe_n = 'b1;
assign adpcmb_addr = 'd0;
assign adpcmb_roe_n = 'd1;
assign adpcma_flags = 0;
assign adpcmb_flag = 0;
end
endgenerate
jt12_dout #(.use_ssg(use_ssg),.use_adpcm(use_adpcm)) u_dout(
// .rst_n ( rst_n ),
.clk ( clk ), // CPU clock
.flag_A ( flag_A ),
.flag_B ( flag_B ),
.busy ( busy ),
.adpcma_flags ( adpcma_flags & flag_mask[5:0] ),
.adpcmb_flag ( adpcmb_flag & flag_mask[6] ),
.psg_dout ( psg_dout ),
.addr ( addr ),
.dout ( dout )
);
jt12_mmr #(.use_ssg(use_ssg),.num_ch(num_ch),.use_pcm(use_pcm), .use_adpcm(use_adpcm), .mask_div(mask_div))
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
.clk_en ( clk_en ), // internal clock enable
.clk_en_2 ( clk_en_2 ), // input cen divided by 2
.clk_en_ssg ( clk_en_ssg), // internal clock enable
.clk_en_666 ( clk_en_666),
.clk_en_111 ( clk_en_111),
.clk_en_55 ( clk_en_55 ),
.din ( din ),
.write ( write ),
.addr ( addr ),
.busy ( busy ),
.ch6op ( ch6op ),
.cur_ch ( cur_ch ),
.cur_op ( cur_op ),
// LFO
.lfo_freq ( lfo_freq ),
.lfo_en ( lfo_en ),
@ -150,11 +333,32 @@ jt12_mmr #(.use_ssg(use_ssg),.num_ch(num_ch),.use_pcm(use_pcm))
.pcm ( pcm ),
.pcm_en ( pcm_en ),
.pcm_wr ( pcm_wr ),
// ADPCM-A
.aon_a ( aon_a ), // ON
.atl_a ( atl_a ), // TL
.addr_a ( addr_a ), // address latch
.lracl ( lracl ), // L/R ADPCM Channel Level
.up_start ( up_start ), // write enable start address latch
.up_end ( up_end ), // write enable end address latch
.up_addr ( up_addr ), // write enable end address latch
.up_lracl ( up_lracl ),
.up_aon ( up_aon ),
// ADPCM-B
.acmd_on_b ( acmd_on_b ), // Control - Process start, Key On
.acmd_rep_b ( acmd_rep_b ), // Control - Repeat
.acmd_rst_b ( acmd_rst_b ), // Control - Reset
.acmd_up_b ( acmd_up_b ), // Control - New command received
.alr_b ( alr_b ), // Left / Right
.astart_b ( astart_b ), // Start address
.aend_b ( aend_b ), // End address
.adeltan_b ( adeltan_b ), // Delta-N
.aeg_b ( aeg_b ), // Envelope Generator Control
.flag_ctl ( flag_ctl ),
.flag_mask ( flag_mask ),
// Operator
.xuse_prevprev1 ( xuse_prevprev1 ),
.xuse_internal ( xuse_internal ),
.yuse_internal ( yuse_internal ),
.yuse_internal ( yuse_internal ),
.xuse_prev2 ( xuse_prev2 ),
.yuse_prev1 ( yuse_prev1 ),
.yuse_prev2 ( yuse_prev2 ),
@ -180,7 +384,7 @@ jt12_mmr #(.use_ssg(use_ssg),.num_ch(num_ch),.use_pcm(use_pcm))
.sl_I ( sl_I ),
.ks_II ( ks_II ),
.eg_stop ( eg_stop ),
.eg_stop ( eg_stop ),
// SSG operation
.ssg_en_I ( ssg_en_I ),
.ssg_eg_I ( ssg_eg_I ),
@ -195,19 +399,25 @@ jt12_mmr #(.use_ssg(use_ssg),.num_ch(num_ch),.use_pcm(use_pcm))
// PSG interace
.psg_addr ( psg_addr ),
.psg_data ( psg_data ),
.psg_wr_n ( psg_wr_n )
.psg_wr_n ( psg_wr_n ),
.debug_bus ( debug_bus ),
.div_setting(div_setting)
);
jt12_timers u_timers(
// YM2203 seems to use a fixed cen/3 clock for the timers, regardless
// of the prescaler setting
wire timer_cen = fast_timers ? cen : clk_en;
jt12_timers #(.num_ch(num_ch)) u_timers (
.clk ( clk ),
.clk_en ( clk_en | fast_timers ),
.clk_en ( timer_cen ),
.rst ( rst ),
.zero ( zero ),
.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 ),
.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 ),
@ -218,7 +428,7 @@ jt12_timers u_timers(
// YM2203 does not have LFO
generate
if( use_lfo== 1)
if( use_lfo== 1) begin : gen_lfo
jt12_lfo u_lfo(
.rst ( rst ),
.clk ( clk ),
@ -233,43 +443,66 @@ if( use_lfo== 1)
.lfo_freq ( lfo_freq ),
.lfo_mod ( lfo_mod )
);
else
end else begin : gen_nolfo
assign lfo_mod = 7'd0;
end
endgenerate
// YM2203/YM2610 have a PSG
`ifndef NOSSG
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)
if( use_ssg==1 ) begin : gen_ssg
jt49 #(.COMP(3'b01), .CLKDIV(JT49_DIV), .YM2203_LUMPED(YM2203_LUMPED))
u_psg( // note that input ports are not multiplexed
.rst_n ( ~rst ),
.clk ( clk ), // signal on positive edge
.clk_en ( clk_en_ssg), // clock enable on negative edge
.addr ( psg_addr ),
.cs_n ( 1'b0 ),
.wr_n ( psg_wr_n ), // write
.din ( psg_data ),
.sound ( psg_snd ), // combined output
.A ( psg_A ),
.B ( psg_B ),
.C ( psg_C ),
.dout ( psg_dout ),
.sel ( 1'b1 ), // half clock speed
.IOA_out ( IOA_out ),
.IOB_out ( IOB_out ),
.IOA_in ( IOA_in ),
.IOB_in ( IOB_in ),
.IOA_oe ( IOA_oe ),
.IOB_oe ( IOB_oe ),
// Unused:
.sample ( )
);
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 snd_left = fm_snd_left + { 1'b0, psg_snd[9:0],5'd0};
assign snd_right = fm_snd_right + { 1'b0, psg_snd[9:0],5'd0};
end else begin : gen_nossg
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;
assign psg_A = 8'd0;
assign psg_B = 8'd0;
assign psg_C = 8'd0;
assign IOA_oe = 0;
assign IOB_oe = 0;
assign IOA_out = 0;
assign IOB_out = 0;
end
endgenerate
`else
assign psg_snd = 10'd0;
assign snd_left = fm_snd_left;
assign snd_right= fm_snd_right;
assign psg_dout = 8'd0;
`endif
`ifndef TIMERONLY
wire [ 8:0] op_result;
wire [13:0] op_result_hd;
`ifndef NOFM
jt12_pg #(.num_ch(num_ch)) u_pg(
.rst ( rst ),
@ -299,7 +532,7 @@ jt12_eg #(.num_ch(num_ch)) u_eg(
.clk ( clk ),
.clk_en ( clk_en ),
.zero ( zero ),
.eg_stop ( eg_stop ),
.eg_stop ( eg_stop ),
// envelope configuration
.keycode_II ( keycode_II ),
.arate_I ( ar_I ), // attack rate
@ -330,9 +563,6 @@ jt12_sh #(.width(10),.stages(4)) u_egpad(
.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 ),
@ -348,25 +578,30 @@ jt12_op #(.num_ch(num_ch)) u_op(
.s4_enters ( s4_enters ),
.xuse_prevprev1 ( xuse_prevprev1),
.xuse_internal ( xuse_internal ),
.yuse_internal ( yuse_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 )
.full_result ( op_result_hd )
);
`else
assign op_result = 'd0;
assign op_result_hd = 'd0;
`endif
generate
if( use_lr==1 ) begin
if( use_pcm==1 ) begin: gen_pcm_acc // YM2612 accumulator
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;
reg 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 ),
@ -376,14 +611,40 @@ generate
.pcm_wr ( pcm_wr ),
.pcm_resampled ( pcm2 )
);
*/
wire rst_pcm_n;
jt12_acc #(.num_ch(num_ch)) u_acc(
jt12_rst u_rst_pcm(
.rst ( rst ),
.clk ( clk ),
.rst_n ( rst_pcm_n )
);
`ifndef NOPCMLINEAR
wire signed [10:0] pcm_full;
always @(*)
pcm2 = en_hifi_pcm ? pcm_full[9:1] : pcm;
jt12_pcm_interpol #(.DW(11), .stepw(5)) u_pcm (
.rst_n ( rst_pcm_n ),
.clk ( clk ),
.cen ( clk_en ),
.cen55 ( clk_en_55 ),
.pcm_wr( pcm_wr ),
.pcmin ( {pcm[8],pcm, 1'b0} ),
.pcmout( pcm_full )
);
`else
assign pcm2 = pcm;
`endif
jt12_acc u_acc(
.rst ( rst ),
.clk ( clk ),
.clk_en ( clk_en ),
.op_result ( op_result ),
.rl ( rl ),
// note that the order changes to deal
// note that the order changes to deal
// with the operator pipeline delay
.zero ( zero ),
.s1_enters ( s2_enters ),
@ -398,7 +659,8 @@ generate
.left ( fm_snd_left [15:4] ),
.right ( fm_snd_right[15:4] )
);
end else begin
end
if( use_pcm==0 && use_adpcm==0 ) begin : gen_2203_acc // YM2203 accumulator
wire signed [15:0] mono_snd;
assign fm_snd_left = mono_snd;
assign fm_snd_right = mono_snd;
@ -407,8 +669,8 @@ generate
.rst ( rst ),
.clk ( clk ),
.clk_en ( clk_en ),
.op_result ( full_result ),
// note that the order changes to deal
.op_result ( op_result_hd ),
// note that the order changes to deal
// with the operator pipeline delay
.s1_enters ( s1_enters ),
.s2_enters ( s2_enters ),
@ -418,59 +680,18 @@ generate
.zero ( zero ),
// combined output
.snd ( mono_snd )
);
end
);
end
endgenerate
`ifdef SIMULATION
/* verilator lint_off PINMISSING */
reg [4:0] sep24_cnt;
integer fsnd;
initial begin
fsnd=$fopen("jt12.raw","wb");
end
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 */
always @(posedge zero) begin
$fwrite(fsnd,"%u", {snd_left, snd_right});
end
`endif
endmodule

View File

@ -1,64 +0,0 @@
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

@ -1,64 +0,0 @@
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

7
rtl/sound/jt49/jt49.qip Normal file
View File

@ -0,0 +1,7 @@
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt49.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt49_bus.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt49_div.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt49_cen.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt49_eg.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt49_exp.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt49_noise.v ]

258
rtl/sound/jt49/jt49.v Normal file
View File

@ -0,0 +1,258 @@
/* This file is part of JT49.
JT49 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.
JT49 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 JT49. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 10-Nov-2018
Based on sqmusic, by the same author
*/
module jt49 ( // note that input ports are not multiplexed
input rst_n,
input clk, // signal on positive edge
input clk_en /* synthesis direct_enable = 1 */,
input [3:0] addr,
input cs_n,
input wr_n, // write
input [7:0] din,
input sel, // if sel is low, the clock is divided by 2
output reg [7:0] dout,
output reg [9:0] sound, // combined channel output
output reg [7:0] A, // linearised channel output
output reg [7:0] B,
output reg [7:0] C,
output sample,
input [7:0] IOA_in,
output [7:0] IOA_out,
output IOA_oe,
input [7:0] IOB_in,
output [7:0] IOB_out,
output IOB_oe
);
parameter [2:0] COMP=3'b000;
parameter YM2203_LUMPED=0;
parameter CLKDIV=3;
wire [2:0] comp = COMP;
reg [7:0] regarray[15:0];
wire [7:0] port_A, port_B;
wire [4:0] envelope;
wire bitA, bitB, bitC;
wire noise;
reg Amix, Bmix, Cmix;
wire cen16, cen256;
assign IOA_out = regarray[14];
assign IOB_out = regarray[15];
assign port_A = IOA_in;
assign port_B = IOB_in;
assign IOA_oe = regarray[7][6];
assign IOB_oe = regarray[7][7];
assign sample = cen16;
jt49_cen #(.CLKDIV(CLKDIV)) u_cen(
.clk ( clk ),
.rst_n ( rst_n ),
.cen ( clk_en ),
.sel ( sel ),
.cen16 ( cen16 ),
.cen256 ( cen256 )
);
// internal modules operate at clk/16
jt49_div #(12) u_chA(
.clk ( clk ),
.rst_n ( rst_n ),
.cen ( cen16 ),
.period ( {regarray[1][3:0], regarray[0][7:0] } ),
.div ( bitA )
);
jt49_div #(12) u_chB(
.clk ( clk ),
.rst_n ( rst_n ),
.cen ( cen16 ),
.period ( {regarray[3][3:0], regarray[2][7:0] } ),
.div ( bitB )
);
jt49_div #(12) u_chC(
.clk ( clk ),
.rst_n ( rst_n ),
.cen ( cen16 ),
.period ( {regarray[5][3:0], regarray[4][7:0] } ),
.div ( bitC )
);
jt49_noise u_ng(
.clk ( clk ),
.cen ( cen16 ),
.rst_n ( rst_n ),
.period ( regarray[6][4:0] ),
.noise ( noise )
);
// envelope generator
wire eg_step;
wire [15:0] eg_period = {regarray[4'hc],regarray[4'hb]};
wire null_period = eg_period == 16'h0;
jt49_div #(16) u_envdiv(
.clk ( clk ),
.cen ( cen256 ),
.rst_n ( rst_n ),
.period ( eg_period ),
.div ( eg_step )
);
reg eg_restart;
jt49_eg u_env(
.clk ( clk ),
.cen ( cen256 ),
.step ( eg_step ),
.rst_n ( rst_n ),
.restart ( eg_restart ),
.null_period( null_period ),
.ctrl ( regarray[4'hD][3:0] ),
.env ( envelope )
);
reg [4:0] logA, logB, logC, log;
wire [7:0] lin;
jt49_exp u_exp(
.clk ( clk ),
.comp ( comp ),
.din ( log ),
.dout ( lin )
);
wire [4:0] volA = { regarray[ 8][3:0], regarray[ 8][3] };
wire [4:0] volB = { regarray[ 9][3:0], regarray[ 9][3] };
wire [4:0] volC = { regarray[10][3:0], regarray[10][3] };
wire use_envA = regarray[ 8][4];
wire use_envB = regarray[ 9][4];
wire use_envC = regarray[10][4];
wire use_noA = regarray[ 7][3];
wire use_noB = regarray[ 7][4];
wire use_noC = regarray[ 7][5];
reg [3:0] acc_st;
always @(posedge clk) if( clk_en ) begin
Amix <= (noise|use_noA) & (bitA|regarray[7][0]);
Bmix <= (noise|use_noB) & (bitB|regarray[7][1]);
Cmix <= (noise|use_noC) & (bitC|regarray[7][2]);
logA <= !Amix ? 5'd0 : (use_envA ? envelope : volA );
logB <= !Bmix ? 5'd0 : (use_envB ? envelope : volB );
logC <= !Cmix ? 5'd0 : (use_envC ? envelope : volC );
end
reg [9:0] acc;
wire [9:0] elin;
assign elin = {2'd0,lin};
always @(posedge clk, negedge rst_n) begin
if( !rst_n ) begin
acc_st <= 4'b1;
acc <= 10'd0;
A <= 8'd0;
B <= 8'd0;
C <= 8'd0;
sound <= 10'd0;
end else if(clk_en) begin
acc_st <= { acc_st[2:0], acc_st[3] };
// Lumping the channel outputs for YM2203 will cause only the higher
// voltage to pass throuh, as the outputs seem to use a source follower.
acc <= YM2203_LUMPED==1 ? (acc>elin ? acc : elin) : acc + elin;
case( acc_st )
4'b0001: begin
log <= logA;
acc <= 10'd0;
sound <= acc;
end
4'b0010: begin
A <= lin;
log <= logB;
end
4'b0100: begin
B <= lin;
log <= logC;
end
4'b1000: begin // last sum
C <= lin;
end
default:;
endcase
end
end
reg [7:0] read_mask;
always @(*)
case(addr)
4'h0,4'h2,4'h4,4'h7,4'hb,4'hc,4'he,4'hf:
read_mask = 8'hff;
4'h1,4'h3,4'h5,4'hd:
read_mask = 8'h0f;
4'h6,4'h8,4'h9,4'ha:
read_mask = 8'h1f;
endcase // addr
// register array
wire write;
reg last_write;
wire wr_edge = write & ~last_write;
assign write = !wr_n && !cs_n;
always @(posedge clk, negedge rst_n) begin
if( !rst_n ) begin
dout <= 8'd0;
last_write <= 0;
eg_restart <= 0;
regarray[0]<=8'd0; regarray[4]<=8'd0; regarray[ 8]<=8'd0; regarray[12]<=8'd0;
regarray[1]<=8'd0; regarray[5]<=8'd0; regarray[ 9]<=8'd0; regarray[13]<=8'd0;
regarray[2]<=8'd0; regarray[6]<=8'd0; regarray[10]<=8'd0; regarray[14]<=8'd0;
regarray[3]<=8'd0; regarray[7]<=8'd0; regarray[11]<=8'd0; regarray[15]<=8'd0;
end else begin
last_write <= write;
// Data read
case( addr )
4'he: dout <= port_A;
4'hf: dout <= port_B;
default: dout <= regarray[ addr ] & read_mask;
endcase
// Data write
if( write ) begin
regarray[addr] <= din;
if ( addr == 4'hD && wr_edge ) eg_restart <= 1;
end else begin
eg_restart <= 0;
end
end
end
endmodule

105
rtl/sound/jt49/jt49_bus.v Normal file
View File

@ -0,0 +1,105 @@
/* This file is part of JT49.
JT49 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.
JT49 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 JT49. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 28-Jan-2019
Based on sqmusic, by the same author
*/
// This is a wrapper with the BDIR/BC1 pins
module jt49_bus ( // note that input ports are not multiplexed
input rst_n,
input clk, // signal on positive edge
input clk_en /* synthesis direct_enable = 1 */,
// bus control pins of original chip
input bdir,
input bc1,
input [7:0] din,
input sel, // if sel is low, the clock is divided by 2
output [7:0] dout,
output [9:0] sound, // combined channel output
output [7:0] A, // linearised channel output
output [7:0] B,
output [7:0] C,
output sample,
input [7:0] IOA_in,
output [7:0] IOA_out,
output IOA_oe,
input [7:0] IOB_in,
output [7:0] IOB_out,
output IOB_oe
);
parameter [2:0] COMP=3'b000;
reg wr_n, cs_n;
reg [3:0] addr;
reg addr_ok;
reg [7:0] din_latch;
always @(posedge clk)
if( !rst_n ) begin
wr_n <= 1'b1;
cs_n <= 1'b1;
addr <= 4'd0;
addr_ok <= 1'b1;
end else begin // I/O cannot use clk_en
// addr must be
case( {bdir,bc1} )
2'b00: { wr_n, cs_n } <= 2'b11;
2'b01: { wr_n, cs_n } <= addr_ok ? 2'b10 : 2'b11;
2'b10: begin
{ wr_n, cs_n } <= addr_ok ? 2'b00 : 2'b11;
din_latch <= din;
end
2'b11: begin
{ wr_n, cs_n } <= 2'b11;
addr <= din[3:0];
addr_ok <= din[7:4] == 4'd0;
end
endcase // {bdir,bc1}
end
jt49 #(.COMP(COMP)) u_jt49( // note that input ports are not multiplexed
.rst_n ( rst_n ),
.clk ( clk ), // signal on positive edge
.clk_en ( clk_en ), // clock enable on negative edge
.addr ( addr[3:0] ),
.cs_n ( cs_n ),
.wr_n ( wr_n ), // write
.din ( din_latch ),
.sel ( sel ), // if sel is low, the clock is divided by 2
.dout ( dout ),
.sound ( sound ), // combined channel output
.sample ( sample ),
.A ( A ), // linearised channel output
.B ( B ),
.C ( C ),
.IOA_in ( IOA_in ),
.IOA_out( IOA_out ),
.IOA_oe ( IOA_oe ),
.IOB_in ( IOB_in ),
.IOB_out( IOB_out ),
.IOB_oe ( IOB_oe )
);
endmodule // jt49_bus

55
rtl/sound/jt49/jt49_cen.v Normal file
View File

@ -0,0 +1,55 @@
/* This file is part of JT49.
JT49 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.
JT49 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 JT49. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 10-Nov-2018
Based on sqmusic, by the same author
*/
module jt49_cen(
input clk,
input rst_n,
input cen, // base clock enable signal
input sel, // when low, divide by 2 once more
output reg cen16,
output reg cen256
);
reg [9:0] cencnt;
parameter CLKDIV = 3; // use 3 for standalone JT49 or 2
localparam eg = CLKDIV; //8;
wire toggle16 = sel ? ~|cencnt[CLKDIV-1:0] : ~|cencnt[CLKDIV:0];
wire toggle256= sel ? ~|cencnt[eg-2:0] : ~|cencnt[eg-1:0];
always @(posedge clk, negedge rst_n) begin
if(!rst_n)
cencnt <= 10'd0;
else begin
if(cen) cencnt <= cencnt+10'd1;
end
end
always @(posedge clk) begin
cen16 <= cen & toggle16;
cen256 <= cen & toggle256;
end
endmodule // jt49_cen

52
rtl/sound/jt49/jt49_div.v Normal file
View File

@ -0,0 +1,52 @@
/* This file is part of JT49.
JT49 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.
JT49 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 JT49. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 10-Nov-2018
Based on sqmusic, by the same author
*/
module jt49_div #(parameter W=12 )(
(* direct_enable *) input cen,
input clk, // this is the divided down clock from the core
input rst_n,
input [W-1:0] period,
output reg div
);
reg [W-1:0]count;
wire [W-1:0] one = { {W-1{1'b0}}, 1'b1};
always @(posedge clk, negedge rst_n ) begin
if( !rst_n) begin
count <= one;
div <= 1'b0;
end
else if(cen) begin
if( count>=period ) begin
count <= one;
div <= ~div;
end
else
/*if( period!={W{1'b0}} )*/ count <= count + one ;
end
end
endmodule

88
rtl/sound/jt49/jt49_eg.v Normal file
View File

@ -0,0 +1,88 @@
/* This file is part of JT49.
JT49 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.
JT49 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 JT49. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 10-Nov-2018
Based on sqmusic, by the same author
*/
module jt49_eg(
(* direct_enable *) input cen,
input clk, // this is the divided down clock from the core
input step,
input null_period,
input rst_n,
input restart,
input [3:0] ctrl,
output reg [4:0]env
);
reg inv, stop;
reg [4:0] gain;
wire CONT = ctrl[3];
wire ATT = ctrl[2];
wire ALT = ctrl[1];
wire HOLD = ctrl[0];
wire will_hold = !CONT || HOLD;
always @(posedge clk)
if( cen ) env <= inv ? ~gain : gain;
reg last_step;
wire step_edge = (step && !last_step) || null_period;
wire will_invert = (!CONT&&ATT) || (CONT&&ALT);
reg rst_latch, rst_clr;
always @(posedge clk) begin
if( restart ) rst_latch <= 1;
else if(rst_clr ) rst_latch <= 0;
end
always @( posedge clk, negedge rst_n )
if( !rst_n) begin
gain <= 5'h1F;
inv <= 0;
stop <= 0;
rst_clr <= 0;
end
else if( cen ) begin
last_step <= step;
if( rst_latch ) begin
gain <= 5'h1F;
inv <= ATT;
stop <= 1'b0;
rst_clr <= 1;
end
else begin
rst_clr <= 0;
if (step_edge && !stop) begin
if( gain==5'h00 ) begin
if( will_hold )
stop <= 1'b1;
else
gain <= gain-5'b1;
if( will_invert ) inv<=~inv;
end
else gain <= gain-5'b1;
end
end
end
endmodule

205
rtl/sound/jt49/jt49_exp.v Normal file
View File

@ -0,0 +1,205 @@
/* This file is part of JT49.
JT49 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.
JT49 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 JT49. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 10-Nov-2018
Based on sqmusic, by the same author
*/
// Compression vs dynamic range
// 0 -> 43.6dB
// 1 -> 29.1
// 2 -> 21.8
// 3 -> 13.4
module jt49_exp(
input clk,
input [2:0] comp, // compression
input [4:0] din,
output reg [7:0] dout
);
reg [7:0] lut[0:159];
always @(posedge clk)
dout <= lut[ {comp,din} ];
initial begin
lut[0] = 8'd0;
lut[1] = 8'd1;
lut[2] = 8'd1;
lut[3] = 8'd1;
lut[4] = 8'd2;
lut[5] = 8'd2;
lut[6] = 8'd3;
lut[7] = 8'd3;
lut[8] = 8'd4;
lut[9] = 8'd5;
lut[10] = 8'd6;
lut[11] = 8'd7;
lut[12] = 8'd9;
lut[13] = 8'd11;
lut[14] = 8'd13;
lut[15] = 8'd15;
lut[16] = 8'd18;
lut[17] = 8'd22;
lut[18] = 8'd26;
lut[19] = 8'd31;
lut[20] = 8'd37;
lut[21] = 8'd45;
lut[22] = 8'd53;
lut[23] = 8'd63;
lut[24] = 8'd75;
lut[25] = 8'd90;
lut[26] = 8'd107;
lut[27] = 8'd127;
lut[28] = 8'd151;
lut[29] = 8'd180;
lut[30] = 8'd214;
lut[31] = 8'd255;
lut[32] = 8'd0;
lut[33] = 8'd7;
lut[34] = 8'd8;
lut[35] = 8'd10;
lut[36] = 8'd11;
lut[37] = 8'd12;
lut[38] = 8'd14;
lut[39] = 8'd15;
lut[40] = 8'd17;
lut[41] = 8'd20;
lut[42] = 8'd22;
lut[43] = 8'd25;
lut[44] = 8'd28;
lut[45] = 8'd31;
lut[46] = 8'd35;
lut[47] = 8'd40;
lut[48] = 8'd45;
lut[49] = 8'd50;
lut[50] = 8'd56;
lut[51] = 8'd63;
lut[52] = 8'd71;
lut[53] = 8'd80;
lut[54] = 8'd90;
lut[55] = 8'd101;
lut[56] = 8'd113;
lut[57] = 8'd127;
lut[58] = 8'd143;
lut[59] = 8'd160;
lut[60] = 8'd180;
lut[61] = 8'd202;
lut[62] = 8'd227;
lut[63] = 8'd255;
lut[64] = 8'd0;
lut[65] = 8'd18;
lut[66] = 8'd20;
lut[67] = 8'd22;
lut[68] = 8'd24;
lut[69] = 8'd26;
lut[70] = 8'd29;
lut[71] = 8'd31;
lut[72] = 8'd34;
lut[73] = 8'd37;
lut[74] = 8'd41;
lut[75] = 8'd45;
lut[76] = 8'd49;
lut[77] = 8'd53;
lut[78] = 8'd58;
lut[79] = 8'd63;
lut[80] = 8'd69;
lut[81] = 8'd75;
lut[82] = 8'd82;
lut[83] = 8'd90;
lut[84] = 8'd98;
lut[85] = 8'd107;
lut[86] = 8'd116;
lut[87] = 8'd127;
lut[88] = 8'd139;
lut[89] = 8'd151;
lut[90] = 8'd165;
lut[91] = 8'd180;
lut[92] = 8'd196;
lut[93] = 8'd214;
lut[94] = 8'd233;
lut[95] = 8'd255;
lut[96] = 8'd0;
lut[97] = 8'd51;
lut[98] = 8'd54;
lut[99] = 8'd57;
lut[100] = 8'd60;
lut[101] = 8'd63;
lut[102] = 8'd67;
lut[103] = 8'd70;
lut[104] = 8'd74;
lut[105] = 8'd78;
lut[106] = 8'd83;
lut[107] = 8'd87;
lut[108] = 8'd92;
lut[109] = 8'd97;
lut[110] = 8'd103;
lut[111] = 8'd108;
lut[112] = 8'd114;
lut[113] = 8'd120;
lut[114] = 8'd127;
lut[115] = 8'd134;
lut[116] = 8'd141;
lut[117] = 8'd149;
lut[118] = 8'd157;
lut[119] = 8'd166;
lut[120] = 8'd175;
lut[121] = 8'd185;
lut[122] = 8'd195;
lut[123] = 8'd206;
lut[124] = 8'd217;
lut[125] = 8'd229;
lut[126] = 8'd241;
lut[127] = 8'd255;
lut[128] = 8'd0;
lut[129] = 8'd8;
lut[130] = 8'd10;
lut[131] = 8'd12;
lut[132] = 8'd16;
lut[133] = 8'd22;
lut[134] = 8'd29;
lut[135] = 8'd35;
lut[136] = 8'd44;
lut[137] = 8'd50;
lut[138] = 8'd56;
lut[139] = 8'd60;
lut[140] = 8'd64;
lut[141] = 8'd85;
lut[142] = 8'd97;
lut[143] = 8'd103;
lut[144] = 8'd108;
lut[145] = 8'd120;
lut[146] = 8'd127;
lut[147] = 8'd134;
lut[148] = 8'd141;
lut[149] = 8'd149;
lut[150] = 8'd157;
lut[151] = 8'd166;
lut[152] = 8'd175;
lut[153] = 8'd185;
lut[154] = 8'd195;
lut[155] = 8'd206;
lut[156] = 8'd217;
lut[157] = 8'd229;
lut[158] = 8'd241;
lut[159] = 8'd255;
end
endmodule

View File

@ -0,0 +1,62 @@
/* This file is part of JT49.
JT49 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.
JT49 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 JT49. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 10-Nov-2018
Based on sqmusic, by the same author
*/
module jt49_noise(
(* direct_enable *) input cen,
input clk,
input rst_n,
input [4:0] period,
output reg noise
);
reg [5:0]count;
reg [16:0]poly17;
wire poly17_zero = poly17==17'b0;
wire noise_en;
reg last_en;
wire noise_up = noise_en && !last_en;
always @(posedge clk ) if(cen) begin
noise <= ~poly17[0];
end
always @( posedge clk, negedge rst_n )
if( !rst_n )
poly17 <= 17'd0;
else if( cen ) begin
last_en <= noise_en;
if( noise_up )
poly17 <= { poly17[0] ^ poly17[3] ^ poly17_zero, poly17[16:1] };
end
jt49_div #(5) u_div(
.clk ( clk ),
.cen ( cen ),
.rst_n ( rst_n ),
.period ( period ),
.div ( noise_en )
);
endmodule

View File

@ -32,7 +32,14 @@ module turbosound
output [7:0] DO, // Data Out
output [11:0] CHANNEL_L, // Output channel L
output [11:0] CHANNEL_R // Output channel R
output [11:0] CHANNEL_R, // Output channel R
input [7:0] IOA_in,
input [7:0] IOB_in,
output [7:0] IOA_out,
output [7:0] IOB_out,
output IOA_oe,
output IOB_oe
);
@ -145,7 +152,14 @@ jt03 ym2203_1
.psg_B(psg_ch_b_1),
.psg_C(psg_ch_c_1),
.fm_snd(opn_1)
.fm_snd(opn_1),
.IOA_in(IOA_in),
.IOB_in(IOB_in),
.IOA_out(IOA_out),
.IOB_out(IOB_out),
.IOA_oe(IOA_oe),
.IOB_oe(IOB_oe)
);
assign DO = ay_select ? DO_1 : DO_0;

View File

@ -1,326 +0,0 @@
//
// Copyright (c) MikeJ - Jan 2005
// Copyright (c) 2016-2019 Sorgelig
//
// All rights reserved
//
// Redistribution and use in source and synthezised forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// Redistributions in synthesized form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// Neither the name of the author nor the names of other contributors may
// be used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS CODE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// BDIR BC MODE
// 0 0 inactive
// 0 1 read value
// 1 0 write value
// 1 1 set address
//
module ym2149
(
input CLK, // Global clock
input CE, // PSG Clock enable
input RESET, // Chip RESET (set all Registers to '0', active hi)
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 [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
input SEL,
input MODE,
output [5:0] ACTIVE,
input [7:0] IOA_in,
output [7:0] IOA_out,
input [7:0] IOB_in,
output [7:0] IOB_out
);
assign ACTIVE = ~ymreg[7][5:0];
assign IOA_out = ymreg[14];
assign IOB_out = ymreg[15];
reg [7:0] addr;
reg [7:0] ymreg[16];
// Write to PSG
reg env_reset;
always @(posedge CLK) begin
if(RESET) begin
ymreg <= '{default:0};
ymreg[7] <= '1;
addr <= '0;
env_reset <= 0;
end else begin
env_reset <= 0;
if(BDIR) begin
if(BC) addr <= DI;
else if(!addr[7:4]) begin
ymreg[addr[3:0]] <= DI;
env_reset <= (addr == 13);
end
end
end
end
// Read from PSG
assign DO = dout;
reg [7:0] dout;
always_comb begin
dout = 8'hFF;
if(~BDIR & BC & !addr[7:4]) begin
case(addr[3:0])
0: dout = ymreg[0];
1: dout = ymreg[1][3:0];
2: dout = ymreg[2];
3: dout = ymreg[3][3:0];
4: dout = ymreg[4];
5: dout = ymreg[5][3:0];
6: dout = ymreg[6][4:0];
7: dout = ymreg[7];
8: dout = ymreg[8][4:0];
9: dout = ymreg[9][4:0];
10: dout = ymreg[10][4:0];
11: dout = ymreg[11];
12: dout = ymreg[12];
13: dout = ymreg[13][3:0];
14: dout = ymreg[7][6] ? ymreg[14] : IOA_in;
15: dout = ymreg[7][7] ? ymreg[15] : IOB_in;
endcase
end
end
reg ena_div;
reg ena_div_noise;
// p_divider
always @(posedge CLK) begin
reg [3:0] cnt_div;
reg noise_div;
if(CE) begin
ena_div <= 0;
ena_div_noise <= 0;
if(!cnt_div) begin
cnt_div <= {SEL, 3'b111};
ena_div <= 1;
noise_div <= (~noise_div);
if (noise_div) ena_div_noise <= 1;
end else begin
cnt_div <= cnt_div - 1'b1;
end
end
end
reg [2:0] noise_gen_op;
// p_noise_gen
always @(posedge CLK) begin
reg [16:0] poly17;
reg [4:0] noise_gen_cnt;
if(CE) begin
if (ena_div_noise) begin
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
wire [11:0] tone_gen_freq[1:3];
assign tone_gen_freq[1] = {ymreg[1][3:0], ymreg[0]};
assign tone_gen_freq[2] = {ymreg[3][3:0], ymreg[2]};
assign tone_gen_freq[3] = {ymreg[5][3:0], ymreg[4]};
reg [3:1] tone_gen_op;
//p_tone_gens
always @(posedge CLK) begin
integer i;
reg [11:0] tone_gen_cnt[1:3];
if(CE) begin
// looks like real chips count up - we need to get the Exact behaviour ..
for (i = 1; i <= 3; i = i + 1) begin
if(ena_div) begin
if (tone_gen_freq[i]) begin
if (tone_gen_cnt[i] >= (tone_gen_freq[i] - 1'd1)) begin
tone_gen_cnt[i] <= 0;
tone_gen_op[i] <= ~tone_gen_op[i];
end else begin
tone_gen_cnt[i] <= tone_gen_cnt[i] + 1'd1;
end
end else begin
tone_gen_op[i] <= ~ymreg[7][i];
tone_gen_cnt[i] <= 0;
end
end
end
end
end
reg env_ena;
wire [15:0] env_gen_comp = {ymreg[12], ymreg[11]} ? {ymreg[12], ymreg[11]} - 1'd1 : 16'd0;
//p_envelope_freq
always @(posedge CLK) begin
reg [15:0] env_gen_cnt;
if(CE) begin
env_ena <= 0;
if(ena_div) begin
if (env_gen_cnt >= env_gen_comp) begin
env_gen_cnt <= 0;
env_ena <= 1;
end else begin
env_gen_cnt <= (env_gen_cnt + 1'd1);
end
end
end
end
reg [4:0] env_vol;
wire is_bot = (env_vol == 5'b00000);
wire is_bot_p1 = (env_vol == 5'b00001);
wire is_top_m1 = (env_vol == 5'b11110);
wire is_top = (env_vol == 5'b11111);
always @(posedge CLK) begin
reg env_hold;
reg env_inc;
// envelope shapes
// C AtAlH
// 0 0 x x \___
//
// 0 1 x x /___
//
// 1 0 0 0 \\\\
//
// 1 0 0 1 \___
//
// 1 0 1 0 \/\/
// ___
// 1 0 1 1 \
//
// 1 1 0 0 ////
// ___
// 1 1 0 1 /
//
// 1 1 1 0 /\/\
//
// 1 1 1 1 /___
if(env_reset | RESET) begin
// load initial state
if(!ymreg[13][2]) begin // attack
env_vol <= 5'b11111;
env_inc <= 0; // -1
end else begin
env_vol <= 5'b00000;
env_inc <= 1; // +1
end
env_hold <= 0;
end
else if(CE) begin
if (env_ena) begin
if (!env_hold) begin
if (env_inc) env_vol <= (env_vol + 5'b00001);
else env_vol <= (env_vol + 5'b11111);
end
// envelope shape control.
if(!ymreg[13][3]) begin
if(!env_inc) begin // down
if(is_bot_p1) env_hold <= 1;
end else if (is_top) env_hold <= 1;
end else if(ymreg[13][0]) begin // hold = 1
if(!env_inc) begin // down
if(ymreg[13][1]) begin // alt
if(is_bot) env_hold <= 1;
end else if(is_bot_p1) env_hold <= 1;
end else if(ymreg[13][1]) begin // alt
if(is_top) env_hold <= 1;
end else if(is_top_m1) env_hold <= 1;
end else if(ymreg[13][1]) begin // alternate
if(env_inc == 1'b0) begin // down
if(is_bot_p1) env_hold <= 1;
if(is_bot) begin
env_hold <= 0;
env_inc <= 1;
end
end else begin
if(is_top_m1) env_hold <= 1;
if(is_top) begin
env_hold <= 0;
env_inc <= 0;
end
end
end
end
end
end
reg [5:0] A,B,C;
always @(posedge CLK) begin
A <= {MODE, ~((ymreg[7][0] | tone_gen_op[1]) & (ymreg[7][3] | noise_gen_op[0])) ? 5'd0 : ymreg[8][4] ? env_vol[4:0] : { ymreg[8][3:0], ymreg[8][3]}};
B <= {MODE, ~((ymreg[7][1] | tone_gen_op[2]) & (ymreg[7][4] | noise_gen_op[1])) ? 5'd0 : ymreg[9][4] ? env_vol[4:0] : { ymreg[9][3:0], ymreg[9][3]}};
C <= {MODE, ~((ymreg[7][2] | tone_gen_op[3]) & (ymreg[7][5] | noise_gen_op[2])) ? 5'd0 : ymreg[10][4] ? env_vol[4:0] : {ymreg[10][3:0], ymreg[10][3]}};
end
wire [7:0] volTable[64] = '{
//YM2149
8'h00, 8'h01, 8'h01, 8'h02, 8'h02, 8'h03, 8'h03, 8'h04,
8'h06, 8'h07, 8'h09, 8'h0a, 8'h0c, 8'h0e, 8'h11, 8'h13,
8'h17, 8'h1b, 8'h20, 8'h25, 8'h2c, 8'h35, 8'h3e, 8'h47,
8'h54, 8'h66, 8'h77, 8'h88, 8'ha1, 8'hc0, 8'he0, 8'hff,
//AY8910
8'h00, 8'h00, 8'h03, 8'h03, 8'h04, 8'h04, 8'h06, 8'h06,
8'h0a, 8'h0a, 8'h0f, 8'h0f, 8'h15, 8'h15, 8'h22, 8'h22,
8'h28, 8'h28, 8'h41, 8'h41, 8'h5b, 8'h5b, 8'h72, 8'h72,
8'h90, 8'h90, 8'hb5, 8'hb5, 8'hd7, 8'hd7, 8'hff, 8'hff
};
assign CHANNEL_A = volTable[A];
assign CHANNEL_B = volTable[B];
assign CHANNEL_C = volTable[C];
endmodule