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

@ -12,7 +12,6 @@ set_global_assignment -name VERILOG_FILE rtl/common/zclock.v
set_global_assignment -name VERILOG_FILE rtl/rtc/mc146818a.v set_global_assignment -name VERILOG_FILE rtl/rtc/mc146818a.v
set_global_assignment -name VHDL_FILE rtl/sound/soundrive.vhd set_global_assignment -name VHDL_FILE rtl/sound/soundrive.vhd
set_global_assignment -name QIP_FILE rtl/sound/jt12/jt03.qip set_global_assignment -name QIP_FILE rtl/sound/jt12/jt03.qip
set_global_assignment -name SYSTEMVERILOG_FILE rtl/sound/ym2149.sv
set_global_assignment -name SYSTEMVERILOG_FILE rtl/sound/turbosound.sv set_global_assignment -name SYSTEMVERILOG_FILE rtl/sound/turbosound.sv
set_global_assignment -name VERILOG_FILE rtl/sound/gs.v set_global_assignment -name VERILOG_FILE rtl/sound/gs.v
set_global_assignment -name SYSTEMVERILOG_FILE rtl/sound/saa1099.sv set_global_assignment -name SYSTEMVERILOG_FILE rtl/sound/saa1099.sv

View File

@ -13,7 +13,6 @@ set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_eg
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_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_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_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_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_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_mod.v ]
@ -27,8 +26,11 @@ set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_pg
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_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_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.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.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_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_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_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_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

@ -21,12 +21,10 @@
// Wrapper to output only combined channels. Defaults to YM2203 mode. // Wrapper to output only combined channels. Defaults to YM2203 mode.
module jt03( module jt03(
input rst, // rst should be at least 6 clk&cen cycles long input rst, // rst should be at least 6 clk&cen cycles long
input clk, // CPU clock 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 [7:0] din,
input addr, input addr,
input cs_n, input cs_n,
@ -34,6 +32,13 @@ module jt03(
output [7:0] dout, output [7:0] dout,
output irq_n, 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 // Separated output
output [ 7:0] psg_A, output [ 7:0] psg_A,
output [ 7:0] psg_B, output [ 7:0] psg_B,
@ -42,10 +47,17 @@ module jt03(
// combined output // combined output
output [ 9:0] psg_snd, output [ 9:0] psg_snd,
output signed [15:0] 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( u_jt12(
.rst ( rst ), // rst should be at least 6 clk&cen cycles long .rst ( rst ), // rst should be at least 6 clk&cen cycles long
.clk ( clk ), // CPU clock .clk ( clk ), // CPU clock
@ -54,9 +66,26 @@ u_jt12(
.addr ( {1'b0, addr} ), .addr ( {1'b0, addr} ),
.cs_n ( cs_n ), .cs_n ( cs_n ),
.wr_n ( wr_n ), .wr_n ( wr_n ),
.ch_enable ( 6'd0 ),
.dout ( dout ), .dout ( dout ),
.irq_n ( irq_n ), .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 // Separated output
.psg_A ( psg_A ), .psg_A ( psg_A ),
.psg_B ( psg_B ), .psg_B ( psg_B ),
@ -64,10 +93,18 @@ u_jt12(
.psg_snd ( psg_snd ), .psg_snd ( psg_snd ),
.fm_snd_left ( fm_snd ), .fm_snd_left ( fm_snd ),
.fm_snd_right (), .fm_snd_right (),
.adpcmA_l (),
.adpcmA_r (),
.adpcmB_l (),
.adpcmB_r (),
.snd_right ( snd ), .snd_right ( snd ),
.snd_left (), .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 // Use for YM2203
no left/right channels // no left/right channels
full operator resolution // full operator resolution
clamped to maximum output of signed 16 bits */ // 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 module jt03_acc
( (
input rst, input rst,
input clk, input clk,
input clk_en, input clk_en /* synthesis direct_enable */,
input signed [13:0] op_result, input signed [13:0] op_result,
input s1_enters, input s1_enters,
input s2_enters, input s2_enters,
@ -54,6 +56,11 @@ always @(*) begin
endcase endcase
end 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( jt12_single_acc #(.win(14),.wout(16)) u_mono(
.clk ( clk ), .clk ( clk ),
.clk_en ( clk_en ), .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); dout : out std_logic_vector(7 downto 0);
irq_n : out std_logic; irq_n : out std_logic;
en_hifi_pcm: in std_logic; -- set high to use interpolation on PCM samples
-- combined output -- combined output
snd_right : out std_logic_vector(15 downto 0); -- signed 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 module jt12_csr( // Circular Shift Register + input mux
input rst, input rst,
input clk, input clk,
input clk_en, input clk_en /* synthesis direct_enable */,
input [ 7:0] din, input [ 7:0] din,
input [43:0] shift_in, input [43:0] shift_in,
output [43:0] shift_out, output [43:0] shift_out,

View File

@ -18,49 +18,97 @@
Date: 14-2-2017 Date: 14-2-2017
*/ */
`timescale 1ns / 1ps
module jt12_div( module jt12_div(
input rst, input rst,
input clk, input clk,
input cen, input cen /* synthesis direct_enable */,
input [1:0] div_setting, input [1:0] div_setting,
output reg clk_en, output reg clk_en, // after prescaler
output reg clk_en_ssg 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 [3:0] opn_pres, opn_cnt=4'd0;
reg [2:0] ssg_pres, ssg_cnt; reg [2:0] ssg_pres, ssg_cnt=3'd0;
reg cen_int, cen_ssg_int; 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 @(*) // prescaler values for FM
if( num_ch==6 ) begin // reset: 1/3
opn_pres = 4'd5; // sel1/sel2
ssg_pres = 3'd3; // unused, really // 0 0 1/3
end // 0 1 1/2
else // 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 ) casez( div_setting )
2'b0?: { opn_pres, ssg_pres } = { 4'd2-4'd1, 3'd0 }; // 2 2'b0?: begin // FM 1/2 - SSG 1/1
2'b10: { opn_pres, ssg_pres } = { 4'd6-4'd1, 3'd3 }; // 6 - Default for YM2608 opn_pres = 4'd2-4'd1;
2'b11: { opn_pres, ssg_pres } = { 4'd3-4'd1, 3'd1 }; // 3 - Default for YM2203 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 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 always @(negedge clk) begin
cen_int <= opn_cnt == 4'd0; cen_int <= opn_cnt == 4'd0;
cen_ssg_int <= ssg_cnt == 3'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 `ifdef FASTDIV
// always enabled for fast sims (use with GYM output, timer will not work well) // always enabled for fast sims (use with GYM output, the timers will not work well)
clk_en <= 1'b1; clk_en <= 1'b1;
clk_en_2 <= 1'b1;
clk_en_ssg <= 1'b1; clk_en_ssg <= 1'b1;
clk_en_666 <= 1'b1;
clk_en_55 <= 1'b1;
`else `else
clk_en <= cen & cen_int; 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_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 `endif
end end
// Div/2
always @(posedge clk)
if( cen ) begin
div2 <= div2==2'b10 ? 2'b00 : (div2+2'b01);
end
// OPN // OPN
always @(posedge clk) always @(posedge clk)
if( cen ) begin if( cen ) begin
@ -79,4 +127,15 @@ always @(posedge clk)
else ssg_cnt <= ssg_cnt + 3'd1; else ssg_cnt <= ssg_cnt + 3'd1;
end 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 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 ( module jt12_eg (
input rst, input rst,
input clk, input clk,
input clk_en, input clk_en /* synthesis direct_enable */,
input zero, input zero,
input eg_stop, input eg_stop,
// envelope configuration // envelope configuration

View File

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

View File

@ -99,7 +99,7 @@ always @(*)
ssg_inv_out = ssg_en & (ssg_alt ^ ssg_inv_in); ssg_inv_out = ssg_en & (ssg_alt ^ ssg_inv_in);
end end
else begin 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; state_next = DECAY;
ssg_inv_out = ssg_inv_in; ssg_inv_out = ssg_inv_in;
end end

View File

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

View File

@ -1,4 +1,3 @@
`timescale 1ns / 1ps
/* This file is part of JT12. /* This file is part of JT12.
@ -26,7 +25,7 @@
module jt12_kon( module jt12_kon(
input rst, input rst,
input clk, input clk,
input clk_en, input clk_en /* synthesis direct_enable */,
input [3:0] keyon_op, input [3:0] keyon_op,
input [2:0] keyon_ch, input [2:0] keyon_ch,
input [1:0] next_op, input [1:0] next_op,
@ -41,23 +40,8 @@ module jt12_kon(
parameter num_ch=6; parameter num_ch=6;
reg din;
wire csr_out; 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 generate
if(num_ch==6) begin if(num_ch==6) begin
// capture overflow signal so it lasts long enough // capture overflow signal so it lasts long enough
@ -73,39 +57,82 @@ if(num_ch==6) begin
end end
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; keyon_I <= (csm&&next_ch==3'd2&&overflow2) || csr_out;
always @(*) begin reg up_keyon_reg;
case( {~next_op[1], next_op[0]} ) reg [3:0] tkeyon_op;
2'd0: next_op6_hot = 4'b0001; // S1 reg [2:0] tkeyon_ch;
2'd1: next_op6_hot = 4'b0100; // S3 wire key_upnow;
2'd2: next_op6_hot = 4'b0010; // S2
2'd3: next_op6_hot = 4'b1000; // S4 assign key_upnow = up_keyon_reg && (tkeyon_ch==next_ch) && (next_op == 2'd3);
endcase
mid_din = keyon_ch==next_ch && up_keyon ? |(keyon_op&next_op6_hot) : middle; 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 end
jt12_sh_rst #(.width(1),.stages(12),.rstval(1'b0)) u_konch0(
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 ( clk ),
.clk_en ( clk_en ), .clk_en ( clk_en ),
.rst ( rst ), .rst ( rst ),
.din ( din ), .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 ( clk ),
.clk_en ( clk_en ), .clk_en ( clk_en ),
.rst ( rst ), .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 ) .drop ( csr_out )
); );
end end
else begin // 3 channels else begin // 3 channels
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 ) always @(posedge clk) if( clk_en )
keyon_I <= csr_out; // No CSM for YM2203 keyon_I <= csr_out; // No CSM for YM2203

View File

@ -18,7 +18,6 @@
Date: 25-2-2017 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 Date: 14-2-2017
*/ */
`timescale 1ns / 1ps
module jt12_mmr( module jt12_mmr(
input rst, input rst,
input clk, input clk,
input cen, input cen /* synthesis direct_enable */,
output clk_en, output clk_en,
output clk_en_2,
output clk_en_ssg, output clk_en_ssg,
output clk_en_666,
output clk_en_111,
output clk_en_55,
input [7:0] din, input [7:0] din,
input write, input write,
input [1:0] addr, input [1:0] addr,
output reg busy, output reg busy,
output ch6op, output ch6op,
output [2:0] cur_ch,
output [1:0] cur_op,
// LFO // LFO
output reg [2:0] lfo_freq, output reg [2:0] lfo_freq,
output reg lfo_en, output reg lfo_en,
@ -46,10 +51,33 @@ module jt12_mmr(
output reg fast_timers, output reg fast_timers,
input flag_A, input flag_A,
input overflow_A, input overflow_A,
output reg [1:0] div_setting,
// PCM // PCM
output reg [8:0] pcm, output reg [8:0] pcm,
output reg pcm_en, output reg pcm_en,
output reg pcm_wr, // high for one clock cycle when PCM is written 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 // Operator
output xuse_prevprev1, output xuse_prevprev1,
output xuse_internal, output xuse_internal,
@ -85,7 +113,6 @@ module jt12_mmr(
output keyon_I, output keyon_I,
// output [ 1:0] cur_op,
// Operator // Operator
output zero, output zero,
output s1_enters, output s1_enters,
@ -96,33 +123,27 @@ module jt12_mmr(
// PSG interace // PSG interace
output [3:0] psg_addr, output [3:0] psg_addr,
output [7:0] psg_data, 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 jt12_div #(.use_ssg(use_ssg)) u_div (
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 ), .rst ( rst ),
.clk ( clk ), .clk ( clk ),
.cen ( cen ), .cen ( cen ),
.div_setting ( div_setting ), .div_setting ( div_setting ),
.clk_en ( clk_en ), .clk_en ( clk_en ),
.clk_en_ssg ( clk_en_ssg ) .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 [7:0] selected_register;
//reg sch; // 0 => CH1~CH3 only available. 1=>CH4~CH6
/* /*
reg irq_zero_en, irq_brdy_en, irq_eos_en, reg irq_zero_en, irq_brdy_en, irq_eos_en,
irq_tb_en, irq_ta_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 [2:0] up_chreg; // hot-one encoding. tells which channel register gets updated next
reg up_keyon; reg up_keyon;
wire busy_reg; localparam REG_TESTYM = 8'h21,
parameter REG_TESTYM = 8'h21,
REG_LFO = 8'h22, REG_LFO = 8'h22,
REG_CLKA1 = 8'h24, REG_CLKA1 = 8'h24,
REG_CLKA2 = 8'h25, REG_CLKA2 = 8'h25,
@ -146,8 +165,11 @@ parameter REG_TESTYM = 8'h21,
REG_DACTEST = 8'h2C, REG_DACTEST = 8'h2C,
REG_CLK_N6 = 8'h2D, REG_CLK_N6 = 8'h2D,
REG_CLK_N3 = 8'h2E, 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; reg csm, effect;
@ -159,16 +181,12 @@ reg [ 5:0] latch_fnum;
reg [2:0] up_ch; reg [2:0] up_ch;
reg [1:0] up_op; reg [1:0] up_op;
reg old_write; reg [7:0] op_din, ch_din;
reg [7:0] din_copy;
always @(posedge clk)
old_write <= write;
generate generate
if( use_ssg ) begin if( use_ssg ) begin
assign psg_addr = selected_register[3:0]; assign psg_addr = selected_register[3:0];
assign psg_data = din_copy; assign psg_data = ch_din;
end else begin end else begin
assign psg_addr = 4'd0; assign psg_addr = 4'd0;
assign psg_data = 8'd0; assign psg_data = 8'd0;
@ -177,50 +195,104 @@ endgenerate
reg part; 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 // 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 always @(posedge clk) begin : memory_mapped_registers
if( rst ) begin if( rst ) begin
selected_register <= 8'h0; selected_register <= 0;
div_setting <= 2'b11; div_setting <= 2'b10; // FM=1/6, SSG=1/4
up_ch <= 3'd0; up_ch <= 0;
up_op <= 2'd0; up_op <= 0;
up_keyon <= 1'd0; up_keyon <= 0;
up_opreg <= 7'd0; up_opreg <= 0;
up_chreg <= 3'd0; up_chreg <= 0;
// IRQ Mask // IRQ Mask
/*{ irq_zero_en, irq_brdy_en, irq_eos_en, /*{ irq_zero_en, irq_brdy_en, irq_eos_en,
irq_tb_en, irq_ta_en } = 5'h1f; */ irq_tb_en, irq_ta_en } = 5'h1f; */
// timers // timers
{ value_A, value_B } <= 18'd0; { value_A, value_B } <= 0;
{ clr_flag_B, clr_flag_A, { clr_flag_B, clr_flag_A,
enable_irq_B, enable_irq_A, load_B, load_A } <= 6'd0; enable_irq_B, enable_irq_A, load_B, load_A } <= 0;
fast_timers <= 1'b0; fast_timers <= 0;
// LFO // LFO
lfo_freq <= 3'd0; lfo_freq <= 0;
lfo_en <= 1'b0; lfo_en <= 0;
csm <= 1'b0; csm <= 0;
effect <= 1'b0; effect <= 0;
// PCM // PCM
pcm <= 9'h0; pcm <= 0;
pcm_en <= 1'b0; pcm_en <= 0;
pcm_wr <= 1'b0; pcm_wr <= 0;
// sch <= 1'b0; // 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 // Original test features
eg_stop <= 1'b0; eg_stop <= 0;
pg_stop <= 1'b0; pg_stop <= 0;
psg_wr_n <= 1'b1; 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 end else begin
up_chreg <= 0;
// WRITE IN REGISTERS // WRITE IN REGISTERS
if( write ) begin if( write ) begin
if( !addr[0] ) begin if( !addr[0] ) begin
selected_register <= din; 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 end else begin
// Global registers // Global registers
din_copy <= din; ch_din <= din;
up_keyon <= selected_register == REG_KON; if( selected_register == REG_KON && !part ) begin
up_ch <= {part, selected_register[1:0]}; up_keyon <= 1;
up_op <= selected_register[3:2]; // 0=S1,1=S3,2=S2,3=S4 op_din <= din;
end else begin
up_keyon <= 0;
end
// General control (<0x20 registers and A0==0)
if(!part) begin
casez( selected_register) casez( selected_register)
//REG_TEST: lfo_rst <= 1'b1; // regardless of din //REG_TEST: lfo_rst <= 1'b1; // regardless of din
8'h0?: psg_wr_n <= 1'b0; 8'h0?: psg_wr_n <= 1'b0;
@ -242,11 +314,12 @@ always @(posedge clk) begin : memory_mapped_registers
`ifndef NOLFO `ifndef NOLFO
REG_LFO: { lfo_en, lfo_freq } <= din[3:0]; REG_LFO: { lfo_en, lfo_freq } <= din[3:0];
`endif `endif
// clock divider default:;
REG_CLK_N6: div_setting[1] <= 1'b1; endcase
REG_CLK_N3: div_setting[0] <= 1'b1; end
REG_CLK_N2: div_setting <= 2'b0;
// CH3 special registers // CH3 special registers
casez( selected_register)
8'hA9: { block_ch3op1, fnum_ch3op1 } <= { latch_fnum, din }; 8'hA9: { block_ch3op1, fnum_ch3op1 } <= { latch_fnum, din };
8'hA8: { block_ch3op3, fnum_ch3op3 } <= { latch_fnum, din }; 8'hA8: { block_ch3op3, fnum_ch3op3 } <= { latch_fnum, din };
8'hAA: { block_ch3op2, fnum_ch3op2 } <= { 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]; 8'hA4, 8'hA5, 8'hA6, 8'hAD, 8'hAC, 8'hAE: latch_fnum <= din[5:0];
default:; // avoid incomplete-case warning default:; // avoid incomplete-case warning
endcase endcase
if( use_pcm==1 ) begin // for YM2612 only
// YM2612 PCM support
if( use_pcm==1 ) begin
casez( selected_register) casez( selected_register)
REG_DACTEST: pcm[0] <= din[3]; REG_DACTEST: pcm[0] <= din[3];
REG_PCM: REG_PCM:
@ -265,9 +340,60 @@ always @(posedge clk) begin : memory_mapped_registers
endcase endcase
pcm_wr <= selected_register==REG_PCM; pcm_wr <= selected_register==REG_PCM;
end 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 ) if( selected_register[1:0]==2'b11 )
{ up_chreg, up_opreg } <= { 3'h0, 7'h0 }; { up_chreg, up_opreg } <= { 3'h0, 7'h0 };
else else begin
casez( selected_register ) casez( selected_register )
// channel registers // channel registers
8'hA0, 8'hA1, 8'hA2: { up_chreg, up_opreg } <= { 3'h1, 7'd0 }; // up_fnumlo 8'hA0, 8'hA1, 8'hA2: { up_chreg, up_opreg } <= { 3'h1, 7'd0 }; // up_fnumlo
@ -284,6 +410,12 @@ always @(posedge clk) begin : memory_mapped_registers
8'h9?: { up_chreg, up_opreg } <= { 3'h0, 7'h40 }; // up_ssgeg 8'h9?: { up_chreg, up_opreg } <= { 3'h0, 7'h40 }; // up_ssgeg
default: { up_chreg, up_opreg } <= { 3'h0, 7'h0 }; default: { up_chreg, up_opreg } <= { 3'h0, 7'h0 };
endcase // selected_register 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
end end
else if(clk_en) begin /* clear once-only bits */ else if(clk_en) begin /* clear once-only bits */
@ -291,25 +423,28 @@ always @(posedge clk) begin : memory_mapped_registers
{ clr_flag_B, clr_flag_A } <= 2'd0; { clr_flag_B, clr_flag_A } <= 2'd0;
psg_wr_n <= 1'b1; 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 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 if( rst ) begin
busy <= 1'b0; busy <= 0;
busy_cnt <= 5'd0; 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
else begin
if (!old_write && write && addr[0] ) begin // only set for data writes
busy <= 1'b1;
busy_cnt <= 5'd0;
end
else if(clk_en) begin
if( busy_cnt == 5'd31 ) busy <= 1'b0;
busy_cnt <= busy_cnt+5'd1;
end end
end end
@ -317,12 +452,17 @@ jt12_reg #(.num_ch(num_ch)) u_reg(
.rst ( rst ), .rst ( rst ),
.clk ( clk ), // P1 .clk ( clk ), // P1
.clk_en ( clk_en ), .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_fnumlo ( up_chreg[0] ),
.up_alg ( up_chreg[1] ), .up_alg ( up_chreg[1] ),
.up_pms ( up_chreg[2] ), .up_pms ( up_chreg[2] ),
// operator updates
.din ( op_din ),
.up_keyon ( up_keyon ),
.up_dt1 ( up_opreg[0] ), .up_dt1 ( up_opreg[0] ),
.up_tl ( up_opreg[1] ), .up_tl ( up_opreg[1] ),
.up_ks_ar ( up_opreg[2] ), .up_ks_ar ( up_opreg[2] ),
@ -339,6 +479,8 @@ jt12_reg #(.num_ch(num_ch)) u_reg(
.overflow_A ( overflow_A), .overflow_A ( overflow_A),
.ch6op ( ch6op ), .ch6op ( ch6op ),
.cur_ch ( cur_ch ),
.cur_op ( cur_op ),
// CH3 Effect-mode operation // CH3 Effect-mode operation
.effect ( effect ), // allows independent freq. for CH 3 .effect ( effect ), // allows independent freq. for CH 3
.fnum_ch3op2( fnum_ch3op2 ), .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. /* This file is part of JT12.
@ -140,16 +139,14 @@ generate
end end
endgenerate endgenerate
`ifdef SIMULATION
// Control signals for simulation: should be 2'b0 or 2'b1 // Control signals for simulation: should be 2'b0 or 2'b1
wire [1:0] xusage = xuse_prevprev1+xuse_prev2+xuse_internal; // wire [1:0] xusage = xuse_prevprev1+xuse_prev2+xuse_internal;
wire [1:0] yusage = yuse_prev1+yuse_internal; // wire [1:0] yusage = yuse_prev1+yuse_internal;
//
always @(xusage,yusage) // always @(xusage,yusage)
if( xusage>2'b1 || yusage>2'b1 ) begin // if( xusage>2'b1 || yusage>2'b1 ) begin
$display("ERROR: x/y over use in jt12_mod"); // $display("ERROR: x/y over use in jt12_mod");
$finish; // $finish;
end // end
`endif
endmodule endmodule

View File

@ -1,4 +1,3 @@
`timescale 1ns / 1ps
/* This file is part of JT12. /* This file is part of JT12.
@ -29,7 +28,7 @@
module jt12_op( module jt12_op(
input rst, input rst,
input clk, input clk,
input clk_en, input clk_en /* synthesis direct_enable */,
input [9:0] pg_phase_VIII, input [9:0] pg_phase_VIII,
input [9:0] eg_atten_IX, // output from envelope generator input [9:0] eg_atten_IX, // output from envelope generator
input [2:0] fb_II, // voice feedback input [2:0] fb_II, // voice feedback
@ -51,6 +50,8 @@ module jt12_op(
output signed [13:0] full_result output signed [13:0] full_result
); );
parameter num_ch = 6;
/* enters exits /* enters exits
S1 S2 S1 S2
S3 S4 S3 S4
@ -64,8 +65,6 @@ reg [11:0] atten_internal_IX;
assign op_result = op_result_internal[13:5]; assign op_result = op_result_internal[13:5];
assign full_result = op_result_internal; assign full_result = op_result_internal;
parameter num_ch = 6;
reg signbit_IX, signbit_X, signbit_XI; reg signbit_IX, signbit_X, signbit_XI;
reg [11:0] totalatten_X; reg [11:0] totalatten_X;
@ -271,235 +270,62 @@ always @(posedge clk) if( clk_en ) begin
end end
`ifdef SIMULATION `ifdef SIMULATION
/* verilator lint_off PINMISSING */ reg signed [13:0] op_sep2_0;
reg [4:0] sep24_cnt; reg signed [13:0] op_sep4_0;
reg signed [13:0] op_sep5_0;
wire signed [13:0] op_ch0s1, op_ch1s1, op_ch2s1, op_ch3s1, reg signed [13:0] op_sep6_0;
op_ch4s1, op_ch5s1, op_ch0s2, op_ch1s2, reg signed [13:0] op_sep0_0;
op_ch2s2, op_ch3s2, op_ch4s2, op_ch5s2, reg signed [13:0] op_sep1_0;
op_ch0s3, op_ch1s3, op_ch2s3, op_ch3s3, reg signed [13:0] op_sep2_1;
op_ch4s3, op_ch5s3, op_ch0s4, op_ch1s4, reg signed [13:0] op_sep4_1;
op_ch2s4, op_ch3s4, op_ch4s4, op_ch5s4; 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;
always @(posedge clk) if(clk_en) begin always @(posedge clk) if(clk_en) begin
sep24_cnt <= !zero ? sep24_cnt+1'b1 : 5'd0; 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 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 `endif
endmodule 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( module jt12_pg(
input clk, input clk,
input clk_en, input clk_en /* synthesis direct_enable */,
input rst, input rst,
// Channel frequency // Channel frequency
input [10:0] fnum_I, input [10:0] fnum_I,

View File

@ -18,9 +18,6 @@
Date: 14-10-2018 Date: 14-10-2018
*/ */
// altera message_off 10030
`timescale 1ns / 1ps
// This implementation follows that of Alexey Khokholov (Nuke.YKT) in C language. // 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]; wire [2:0] index = lfo_mod[3] ? (~lfo_mod[2:0]) : lfo_mod[2:0];
reg [3:0] lfo_sh1_lut [0:63]; reg [2:0] lfo_sh1_lut [0:63];
reg [3:0] lfo_sh2_lut [0:63]; reg [2:0] lfo_sh2_lut [0:63];
reg [2:0] lfo_sh1, lfo_sh2; reg [2:0] lfo_sh1, lfo_sh2;
initial begin initial begin
$readmemh("lfo_sh1_lut.hex",lfo_sh1_lut); lfo_sh1_lut[6'h00] = 3'd7;
$readmemh("lfo_sh2_lut.hex",lfo_sh2_lut); 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 end
always @(*) begin always @(*) begin
lfo_sh1 = lfo_sh1_lut[{pms,index}][2:0]; lfo_sh1 = lfo_sh1_lut[{pms,index}];
lfo_sh2 = lfo_sh2_lut[{pms,index}][2:0]; lfo_sh2 = lfo_sh2_lut[{pms,index}];
pm_base = ({1'b0,fnum[10:4]}>>lfo_sh1) + ({1'b0,fnum[10:4]}>>lfo_sh2); pm_base = ({1'b0,fnum[10:4]}>>lfo_sh1) + ({1'b0,fnum[10:4]}>>lfo_sh2);
case( pms ) case( pms )
default: pm_shifted = { 2'b0, pm_base }; default: pm_shifted = { 2'b0, pm_base };

View File

@ -23,30 +23,35 @@
module jt12_reg( module jt12_reg(
input rst, input rst,
input clk, input clk,
input clk_en, input clk_en /* synthesis direct_enable */,
input [7:0] din,
input [2:0] ch, input [2:0] ch, // channel to update
input [1:0] op, input [1:0] op,
input csm, input csm,
input flag_A, input flag_A,
input overflow_A, input overflow_A,
input up_keyon, // channel udpates
input [2:0] ch_sel,
input [7:0] ch_din,
input up_alg, input up_alg,
input up_fnumlo, input up_fnumlo,
// operator updates
input [7:0] din,
input up_keyon,
input up_pms, input up_pms,
input up_dt1, input up_dt1,
input up_tl, input up_tl,
input up_ks_ar, input up_ks_ar,
input up_amen_dr, input up_amen_dr,
input up_sr, input up_sr,
input up_sl_rr, input up_sl_rr,
input up_ssgeg, 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 // CH3 Effect-mode operation
input effect, input effect,
@ -105,8 +110,8 @@ module jt12_reg(
parameter num_ch=6; // Use only 3 (YM2203/YM2610) or 6 (YM2612/YM2608) parameter num_ch=6; // Use only 3 (YM2203/YM2610) or 6 (YM2612/YM2608)
reg [1:0] next_op, cur_op; reg [1:0] next_op;
reg [2:0] next_ch, cur_ch; reg [2:0] next_ch;
reg last; reg last;
`ifdef SIMULATION `ifdef SIMULATION
@ -117,6 +122,8 @@ reg last;
initial begin initial begin
cur_op = 2'd0; cur_op = 2'd0;
cur_ch = 3'd0; cur_ch = 3'd0;
next_op = 2'd0;
next_ch = 3'd1;
last = 1'b0; last = 1'b0;
zero = 1'b1; zero = 1'b1;
end end
@ -155,11 +162,9 @@ assign block_I =( {3{effect_on_s1}} & block_ch3op1 ) |
( {3{effect_on_s3}} & block_ch3op3 ) | ( {3{effect_on_s3}} & block_ch3op3 ) |
( {3{noeffect}} & block_I_raw ); ( {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_I = { op, ch };
wire [4:0] req_opch_II, req_opch_III, 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_II ( .chin(req_opch_I ), .chout(req_opch_II ) );
jt12_sumch #(.num_ch(num_ch)) u_opch_III( .chin(req_opch_II ), .chout(req_opch_III) ); jt12_sumch #(.num_ch(num_ch)) u_opch_III( .chin(req_opch_II ), .chout(req_opch_III) );
@ -179,24 +184,6 @@ wire update_op_IV = cur == req_opch_IV;
// key on/off // key on/off
wire [3:0] keyon_op = din[7:4]; wire [3:0] keyon_op = din[7:4];
wire [2:0] keyon_ch = din[2:0]; 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 always @(*) begin
// next = cur==5'd23 ? 5'd0 : cur +1'b1; // next = cur==5'd23 ? 5'd0 : cur +1'b1;
@ -216,6 +203,7 @@ always @(posedge clk) begin : up_counter
end end
end end
`ifndef NOFM
jt12_kon #(.num_ch(num_ch)) u_kon( jt12_kon #(.num_ch(num_ch)) u_kon(
.rst ( rst ), .rst ( rst ),
.clk ( clk ), .clk ( clk ),
@ -325,46 +313,27 @@ assign { tl_IV, dt1_I, mul_II, ks_II,
// memory for CH registers // memory for CH registers
// Block/fnum data is latched until fnum low byte is written to jt12_reg_ch #(.NUM_CH(num_ch)) u_regch(
// 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
};
assign { block_I_raw, fnum_I_raw,
fb_I, alg_I, ams_IV, pms_I } = regch_out;
jt12_sh_rst #(.width(regch_width),.stages(num_ch)) u_regch(
.clk ( clk ),
.clk_en ( clk_en ),
.rst ( rst ), .rst ( rst ),
.din ( regch_in ), .clk ( clk ),
.drop ( regch_out ) .cen ( clk_en ),
.din ( ch_din ),
.up_ch ( ch_sel ),
.latch_fnum ( latch_fnum ),
.up_fnumlo ( up_fnumlo ),
.up_alg ( up_alg ),
.up_pms ( up_pms ),
.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 `endif
if( num_ch==6 ) begin
// RL is on a different register to
// have the reset to 1
wire [1:0] rl_in = din[7:6];
jt12_sh_rst #(.width(2),.stages(num_ch),.rstval(1'b1)) u_regch_rl(
.clk ( clk ),
.clk_en ( clk_en ),
.rst ( rst ),
.din ( up_pms_ch ? rl_in : rl ),
.drop ( rl )
);
end else begin // YM2203 has no stereo output
assign rl=2'b11;
end
endgenerate
endmodule 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 Date: 1-31-2017
*/ */
`timescale 1ns / 1ps
// stages must be greater than 2 // stages must be greater than 2
module jt12_sh #(parameter width=5, stages=24 ) module jt12_sh #(parameter width=5, stages=24 )
( (
input clk, input clk,
input clk_en, input clk_en /* synthesis direct_enable */,
input [width-1:0] din, input [width-1:0] din,
output [width-1:0] drop output [width-1:0] drop
); );

View File

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

View File

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

View File

@ -20,13 +20,16 @@
*/ */
`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 wout=16 // output data width
)( )(
input clk, input clk,
input clk_en, input clk_en /* synthesis direct_enable */,
input [win-1:0] op_result, input [win-1:0] op_result,
input sum_en, input sum_en,
input zero, input zero,

View File

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

View File

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

View File

@ -27,7 +27,7 @@ http://gendev.spritesmind.net/forum/viewtopic.php?t=386&postdays=0&postorder=asc
module jt12_top ( module jt12_top (
input rst, // rst should be at least 6 clk&cen cycles long input rst, // rst should be at least 6 clk&cen cycles long
input clk, // CPU clock 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 [7:0] din,
input [1:0] addr, input [1:0] addr,
input cs_n, input cs_n,
@ -35,24 +35,53 @@ module jt12_top (
output [7:0] dout, output [7:0] dout,
output irq_n, 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 // Separated output
output [ 7:0] psg_A, output [ 7:0] psg_A,
output [ 7:0] psg_B, output [ 7:0] psg_B,
output [ 7:0] psg_C, output [ 7:0] psg_C,
output signed [15:0] fm_snd_left, output signed [15:0] fm_snd_left,
output signed [15:0] fm_snd_right, 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 // combined output
output [ 9:0] psg_snd, output [ 9:0] psg_snd,
output signed [15:0] snd_right, // FM+PSG output signed [15:0] snd_right, // FM+PSG
output signed [15:0] snd_left, // 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 flag_A, flag_B, busy;
wire [7:0] fm_dout = { busy, 5'd0, flag_B, flag_A };
wire write = !cs_n && !wr_n; wire write = !cs_n && !wr_n;
wire clk_en, clk_en_ssg; wire clk_en, clk_en_ssg;
@ -104,6 +133,8 @@ wire [ 8:0] pcm;
wire pg_stop, eg_stop; wire pg_stop, eg_stop;
wire ch6op; wire ch6op;
wire [ 2:0] cur_ch;
wire [ 1:0] cur_op;
// Operator // Operator
wire xuse_internal, yuse_internal; wire xuse_internal, yuse_internal;
@ -118,19 +149,171 @@ wire lfo_rst;
wire [3:0] psg_addr; wire [3:0] psg_addr;
wire [7:0] psg_data, psg_dout; wire [7:0] psg_data, psg_dout;
wire psg_wr_n; 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( u_mmr(
.rst ( rst ), .rst ( rst ),
.clk ( clk ), .clk ( clk ),
.cen ( cen ), // external clock enable .cen ( cen ), // external clock enable
.clk_en ( clk_en ), // 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_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 ), .din ( din ),
.write ( write ), .write ( write ),
.addr ( addr ), .addr ( addr ),
.busy ( busy ), .busy ( busy ),
.ch6op ( ch6op ), .ch6op ( ch6op ),
.cur_ch ( cur_ch ),
.cur_op ( cur_op ),
// LFO // LFO
.lfo_freq ( lfo_freq ), .lfo_freq ( lfo_freq ),
.lfo_en ( lfo_en ), .lfo_en ( lfo_en ),
@ -150,7 +333,28 @@ jt12_mmr #(.use_ssg(use_ssg),.num_ch(num_ch),.use_pcm(use_pcm))
.pcm ( pcm ), .pcm ( pcm ),
.pcm_en ( pcm_en ), .pcm_en ( pcm_en ),
.pcm_wr ( pcm_wr ), .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 // Operator
.xuse_prevprev1 ( xuse_prevprev1 ), .xuse_prevprev1 ( xuse_prevprev1 ),
.xuse_internal ( xuse_internal ), .xuse_internal ( xuse_internal ),
@ -195,19 +399,25 @@ jt12_mmr #(.use_ssg(use_ssg),.num_ch(num_ch),.use_pcm(use_pcm))
// PSG interace // PSG interace
.psg_addr ( psg_addr ), .psg_addr ( psg_addr ),
.psg_data ( psg_data ), .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 ( clk ),
.clk_en ( clk_en | fast_timers ), .clk_en ( timer_cen ),
.rst ( rst ), .rst ( rst ),
.zero ( zero ),
.value_A ( value_A ), .value_A ( value_A ),
.value_B ( value_B ), .value_B ( value_B ),
.load_A ( load_A ), .load_A ( load_A ),
.load_B ( load_B ), .load_B ( load_B ),
.enable_irq_A( enable_irq_B ), .enable_irq_A( enable_irq_A ),
.enable_irq_B( enable_irq_A ), .enable_irq_B( enable_irq_B ),
.clr_flag_A ( clr_flag_A ), .clr_flag_A ( clr_flag_A ),
.clr_flag_B ( clr_flag_B ), .clr_flag_B ( clr_flag_B ),
.flag_A ( flag_A ), .flag_A ( flag_A ),
@ -218,7 +428,7 @@ jt12_timers u_timers(
// YM2203 does not have LFO // YM2203 does not have LFO
generate generate
if( use_lfo== 1) if( use_lfo== 1) begin : gen_lfo
jt12_lfo u_lfo( jt12_lfo u_lfo(
.rst ( rst ), .rst ( rst ),
.clk ( clk ), .clk ( clk ),
@ -233,43 +443,66 @@ if( use_lfo== 1)
.lfo_freq ( lfo_freq ), .lfo_freq ( lfo_freq ),
.lfo_mod ( lfo_mod ) .lfo_mod ( lfo_mod )
); );
else end else begin : gen_nolfo
assign lfo_mod = 7'd0; assign lfo_mod = 7'd0;
end
endgenerate endgenerate
// YM2203/YM2610 have a PSG // YM2203/YM2610 have a PSG
`ifndef NOSSG
generate generate
if( use_ssg==1 ) begin if( use_ssg==1 ) begin : gen_ssg
ym2149 u_psg jt49 #(.COMP(3'b01), .CLKDIV(JT49_DIV), .YM2203_LUMPED(YM2203_LUMPED))
( u_psg( // note that input ports are not multiplexed
.CLK(clk), .rst_n ( ~rst ),
.CE(clk_en_ssg), .clk ( clk ), // signal on positive edge
.RESET(rst), .clk_en ( clk_en_ssg), // clock enable on negative edge
.addr ( psg_addr ),
.BDIR(write), .cs_n ( 1'b0 ),
.BC(~addr[0] | ~write), .wr_n ( psg_wr_n ), // write
.DI(din), .din ( psg_data ),
.DO(psg_dout), .sound ( psg_snd ), // combined output
.CHANNEL_A(psg_A), .A ( psg_A ),
.CHANNEL_B(psg_B), .B ( psg_B ),
.CHANNEL_C(psg_C) .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 + { 1'b0, psg_snd[9:0],5'd0};
assign snd_left = fm_snd_left + { 2'b0, psg_snd[9:1],5'd0}; assign snd_right = fm_snd_right + { 1'b0, psg_snd[9:0],5'd0};
assign snd_right = fm_snd_right + { 2'b0, psg_snd[9:1],5'd0}; end else begin : gen_nossg
assign dout = addr[0] ? psg_dout : fm_dout;
end else begin
assign psg_snd = 10'd0; assign psg_snd = 10'd0;
assign snd_left = fm_snd_left; assign snd_left = fm_snd_left;
assign snd_right= fm_snd_right; assign snd_right= fm_snd_right;
assign psg_dout = 8'd0; 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 end
endgenerate 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
wire [ 8:0] op_result;
`ifndef TIMERONLY wire [13:0] op_result_hd;
`ifndef NOFM
jt12_pg #(.num_ch(num_ch)) u_pg( jt12_pg #(.num_ch(num_ch)) u_pg(
.rst ( rst ), .rst ( rst ),
@ -330,9 +563,6 @@ jt12_sh #(.width(10),.stages(4)) u_egpad(
.drop ( eg_IX ) .drop ( eg_IX )
); );
wire [ 8:0] op_result;
wire [13:0] full_result;
jt12_op #(.num_ch(num_ch)) u_op( jt12_op #(.num_ch(num_ch)) u_op(
.rst ( rst ), .rst ( rst ),
.clk ( clk ), .clk ( clk ),
@ -354,19 +584,24 @@ jt12_op #(.num_ch(num_ch)) u_op(
.yuse_prev2 ( yuse_prev2 ), .yuse_prev2 ( yuse_prev2 ),
.zero ( zero ), .zero ( zero ),
.op_result ( op_result ), .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 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_right[3:0] = 4'd0;
assign fm_snd_left [3:0] = 4'd0; assign fm_snd_left [3:0] = 4'd0;
assign snd_sample = zero; assign snd_sample = zero;
wire signed [8:0] pcm2; reg signed [8:0] pcm2;
// interpolate PCM samples with automatic sample rate detection // interpolate PCM samples with automatic sample rate detection
// this feature is not present in original YM2612 // this feature is not present in original YM2612
// this improves PCM sample sound greatly // this improves PCM sample sound greatly
/*
jt12_pcm u_pcm( jt12_pcm u_pcm(
.rst ( rst ), .rst ( rst ),
.clk ( clk ), .clk ( clk ),
@ -376,8 +611,34 @@ generate
.pcm_wr ( pcm_wr ), .pcm_wr ( pcm_wr ),
.pcm_resampled ( pcm2 ) .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 ), .rst ( rst ),
.clk ( clk ), .clk ( clk ),
.clk_en ( clk_en ), .clk_en ( clk_en ),
@ -398,7 +659,8 @@ generate
.left ( fm_snd_left [15:4] ), .left ( fm_snd_left [15:4] ),
.right ( fm_snd_right[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; wire signed [15:0] mono_snd;
assign fm_snd_left = mono_snd; assign fm_snd_left = mono_snd;
assign fm_snd_right = mono_snd; assign fm_snd_right = mono_snd;
@ -407,7 +669,7 @@ generate
.rst ( rst ), .rst ( rst ),
.clk ( clk ), .clk ( clk ),
.clk_en ( clk_en ), .clk_en ( clk_en ),
.op_result ( full_result ), .op_result ( op_result_hd ),
// note that the order changes to deal // note that the order changes to deal
// with the operator pipeline delay // with the operator pipeline delay
.s1_enters ( s1_enters ), .s1_enters ( s1_enters ),
@ -423,54 +685,13 @@ generate
endgenerate endgenerate
`ifdef SIMULATION `ifdef SIMULATION
/* verilator lint_off PINMISSING */ integer fsnd;
reg [4:0] sep24_cnt; initial begin
fsnd=$fopen("jt12.raw","wb");
end
wire [9:0] eg_ch0s1, eg_ch1s1, eg_ch2s1, eg_ch3s1, eg_ch4s1, eg_ch5s1, always @(posedge zero) begin
eg_ch0s2, eg_ch1s2, eg_ch2s2, eg_ch3s2, eg_ch4s2, eg_ch5s2, $fwrite(fsnd,"%u", {snd_left, snd_right});
eg_ch0s3, eg_ch1s3, eg_ch2s3, eg_ch3s3, eg_ch4s3, eg_ch5s3, end
eg_ch0s4, eg_ch1s4, eg_ch2s4, eg_ch3s4, eg_ch4s4, eg_ch5s4;
always @(posedge clk) if( clk_en )
sep24_cnt <= !zero ? sep24_cnt+1'b1 : 5'd0;
sep24 #( .width(10), .pos0(5'd0)) egsep
(
.clk ( clk ),
.clk_en ( clk_en ),
.mixed ( eg_IX ),
.mask ( 24'd0 ),
.cnt ( sep24_cnt ),
.ch0s1 (eg_ch0s1),
.ch1s1 (eg_ch1s1),
.ch2s1 (eg_ch2s1),
.ch3s1 (eg_ch3s1),
.ch4s1 (eg_ch4s1),
.ch5s1 (eg_ch5s1),
.ch0s2 (eg_ch0s2),
.ch1s2 (eg_ch1s2),
.ch2s2 (eg_ch2s2),
.ch3s2 (eg_ch3s2),
.ch4s2 (eg_ch4s2),
.ch5s2 (eg_ch5s2),
.ch0s3 (eg_ch0s3),
.ch1s3 (eg_ch1s3),
.ch2s3 (eg_ch2s3),
.ch3s3 (eg_ch3s3),
.ch4s3 (eg_ch4s3),
.ch5s3 (eg_ch5s3),
.ch0s4 (eg_ch0s4),
.ch1s4 (eg_ch1s4),
.ch2s4 (eg_ch2s4),
.ch3s4 (eg_ch3s4),
.ch4s4 (eg_ch4s4),
.ch5s4 (eg_ch5s4)
);
`endif
/* verilator lint_on PINMISSING */
`endif `endif
endmodule 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 [7:0] DO, // Data Out
output [11:0] CHANNEL_L, // Output channel L 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_B(psg_ch_b_1),
.psg_C(psg_ch_c_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; 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