mirror of
https://github.com/UzixLS/TSConf_MiST.git
synced 2025-07-19 15:21:47 +03:00
477 lines
14 KiB
Verilog
477 lines
14 KiB
Verilog
/* This file is part of JT12.
|
|
|
|
JT12 is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
JT12 is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with JT12. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
Author: Jose Tejada Gomez. Twitter: @topapate
|
|
Version: 1.0
|
|
Date: 14-2-2016
|
|
|
|
Based on information posted by Nemesis on:
|
|
http://gendev.spritesmind.net/forum/viewtopic.php?t=386&postdays=0&postorder=asc&start=167
|
|
|
|
Based on jt51_phasegen.v, from JT51
|
|
|
|
*/
|
|
|
|
module jt12_top (
|
|
input rst, // rst should be at least 6 clk&cen cycles long
|
|
input clk, // CPU clock
|
|
input cen, // optional clock enable, it not needed leave as 1'b1
|
|
input [7:0] din,
|
|
input [1:0] addr,
|
|
input cs_n,
|
|
input wr_n,
|
|
|
|
output [7:0] dout,
|
|
output irq_n,
|
|
// Separated output
|
|
output [ 7:0] psg_A,
|
|
output [ 7:0] psg_B,
|
|
output [ 7:0] psg_C,
|
|
output signed [15:0] fm_snd_left,
|
|
output signed [15:0] fm_snd_right,
|
|
// combined output
|
|
output [ 9:0] psg_snd,
|
|
output signed [15:0] snd_right, // FM+PSG
|
|
output signed [15:0] snd_left, // FM+PSG
|
|
output snd_sample
|
|
);
|
|
|
|
parameter use_lfo=1, use_ssg=0, num_ch=6, use_pcm=1, use_lr=1; // defaults to YM2612
|
|
|
|
wire flag_A, flag_B, busy;
|
|
|
|
wire [7:0] fm_dout = { busy, 5'd0, flag_B, flag_A };
|
|
wire write = !cs_n && !wr_n;
|
|
wire clk_en, clk_en_ssg;
|
|
|
|
// Timers
|
|
wire [9:0] value_A;
|
|
wire [7:0] value_B;
|
|
wire load_A, load_B;
|
|
wire enable_irq_A, enable_irq_B;
|
|
wire clr_flag_A, clr_flag_B;
|
|
wire overflow_A;
|
|
wire fast_timers;
|
|
|
|
wire zero; // Single-clock pulse at the begginig of s1_enters
|
|
// LFO
|
|
wire [2:0] lfo_freq;
|
|
wire lfo_en;
|
|
// Operators
|
|
wire amsen_IV;
|
|
wire [ 2:0] dt1_I;
|
|
wire [ 3:0] mul_II;
|
|
wire [ 6:0] tl_IV;
|
|
|
|
wire [ 4:0] keycode_II;
|
|
wire [ 4:0] ar_I;
|
|
wire [ 4:0] d1r_I;
|
|
wire [ 4:0] d2r_I;
|
|
wire [ 3:0] rr_I;
|
|
wire [ 3:0] sl_I;
|
|
wire [ 1:0] ks_II;
|
|
// SSG operation
|
|
wire ssg_en_I;
|
|
wire [2:0] ssg_eg_I;
|
|
// envelope operation
|
|
wire keyon_I;
|
|
wire [9:0] eg_IX;
|
|
wire pg_rst_II;
|
|
// Channel
|
|
wire [10:0] fnum_I;
|
|
wire [ 2:0] block_I;
|
|
wire [ 1:0] rl;
|
|
wire [ 2:0] fb_II;
|
|
wire [ 2:0] alg_I;
|
|
wire [ 2:0] pms_I;
|
|
wire [ 1:0] ams_IV;
|
|
// PCM
|
|
wire pcm_en, pcm_wr;
|
|
wire [ 8:0] pcm;
|
|
// Test
|
|
wire pg_stop, eg_stop;
|
|
|
|
wire ch6op;
|
|
|
|
// Operator
|
|
wire xuse_internal, yuse_internal;
|
|
wire xuse_prevprev1, xuse_prev2, yuse_prev1, yuse_prev2;
|
|
wire [ 9:0] phase_VIII;
|
|
wire s1_enters, s2_enters, s3_enters, s4_enters;
|
|
wire rst_int;
|
|
// LFO
|
|
wire [6:0] lfo_mod;
|
|
wire lfo_rst;
|
|
// PSG
|
|
wire [3:0] psg_addr;
|
|
wire [7:0] psg_data, psg_dout;
|
|
wire psg_wr_n;
|
|
|
|
jt12_mmr #(.use_ssg(use_ssg),.num_ch(num_ch),.use_pcm(use_pcm))
|
|
u_mmr(
|
|
.rst ( rst ),
|
|
.clk ( clk ),
|
|
.cen ( cen ), // external clock enable
|
|
.clk_en ( clk_en ), // internal clock enable
|
|
.clk_en_ssg ( clk_en_ssg), // internal clock enable
|
|
.din ( din ),
|
|
.write ( write ),
|
|
.addr ( addr ),
|
|
.busy ( busy ),
|
|
.ch6op ( ch6op ),
|
|
// LFO
|
|
.lfo_freq ( lfo_freq ),
|
|
.lfo_en ( lfo_en ),
|
|
// Timers
|
|
.value_A ( value_A ),
|
|
.value_B ( value_B ),
|
|
.load_A ( load_A ),
|
|
.load_B ( load_B ),
|
|
.enable_irq_A ( enable_irq_A ),
|
|
.enable_irq_B ( enable_irq_B ),
|
|
.clr_flag_A ( clr_flag_A ),
|
|
.clr_flag_B ( clr_flag_B ),
|
|
.flag_A ( flag_A ),
|
|
.overflow_A ( overflow_A ),
|
|
.fast_timers( fast_timers ),
|
|
// PCM
|
|
.pcm ( pcm ),
|
|
.pcm_en ( pcm_en ),
|
|
.pcm_wr ( pcm_wr ),
|
|
|
|
// Operator
|
|
.xuse_prevprev1 ( xuse_prevprev1 ),
|
|
.xuse_internal ( xuse_internal ),
|
|
.yuse_internal ( yuse_internal ),
|
|
.xuse_prev2 ( xuse_prev2 ),
|
|
.yuse_prev1 ( yuse_prev1 ),
|
|
.yuse_prev2 ( yuse_prev2 ),
|
|
// PG
|
|
.fnum_I ( fnum_I ),
|
|
.block_I ( block_I ),
|
|
.pg_stop ( pg_stop ),
|
|
// EG
|
|
.rl ( rl ),
|
|
.fb_II ( fb_II ),
|
|
.alg_I ( alg_I ),
|
|
.pms_I ( pms_I ),
|
|
.ams_IV ( ams_IV ),
|
|
.amsen_IV ( amsen_IV ),
|
|
.dt1_I ( dt1_I ),
|
|
.mul_II ( mul_II ),
|
|
.tl_IV ( tl_IV ),
|
|
|
|
.ar_I ( ar_I ),
|
|
.d1r_I ( d1r_I ),
|
|
.d2r_I ( d2r_I ),
|
|
.rr_I ( rr_I ),
|
|
.sl_I ( sl_I ),
|
|
.ks_II ( ks_II ),
|
|
|
|
.eg_stop ( eg_stop ),
|
|
// SSG operation
|
|
.ssg_en_I ( ssg_en_I ),
|
|
.ssg_eg_I ( ssg_eg_I ),
|
|
|
|
.keyon_I ( keyon_I ),
|
|
// Operator
|
|
.zero ( zero ),
|
|
.s1_enters ( s1_enters ),
|
|
.s2_enters ( s2_enters ),
|
|
.s3_enters ( s3_enters ),
|
|
.s4_enters ( s4_enters ),
|
|
// PSG interace
|
|
.psg_addr ( psg_addr ),
|
|
.psg_data ( psg_data ),
|
|
.psg_wr_n ( psg_wr_n )
|
|
);
|
|
|
|
jt12_timers u_timers(
|
|
.clk ( clk ),
|
|
.clk_en ( clk_en | fast_timers ),
|
|
.rst ( rst ),
|
|
.value_A ( value_A ),
|
|
.value_B ( value_B ),
|
|
.load_A ( load_A ),
|
|
.load_B ( load_B ),
|
|
.enable_irq_A( enable_irq_B ),
|
|
.enable_irq_B( enable_irq_A ),
|
|
.clr_flag_A ( clr_flag_A ),
|
|
.clr_flag_B ( clr_flag_B ),
|
|
.flag_A ( flag_A ),
|
|
.flag_B ( flag_B ),
|
|
.overflow_A ( overflow_A ),
|
|
.irq_n ( irq_n )
|
|
);
|
|
|
|
// YM2203 does not have LFO
|
|
generate
|
|
if( use_lfo== 1)
|
|
jt12_lfo u_lfo(
|
|
.rst ( rst ),
|
|
.clk ( clk ),
|
|
.clk_en ( clk_en ),
|
|
.zero ( zero ),
|
|
`ifdef NOLFO
|
|
.lfo_rst ( 1'b1 ),
|
|
`else
|
|
.lfo_rst ( 1'b0 ),
|
|
`endif
|
|
.lfo_en ( lfo_en ),
|
|
.lfo_freq ( lfo_freq ),
|
|
.lfo_mod ( lfo_mod )
|
|
);
|
|
else
|
|
assign lfo_mod = 7'd0;
|
|
endgenerate
|
|
|
|
// YM2203/YM2610 have a PSG
|
|
|
|
generate
|
|
if( use_ssg==1 ) begin
|
|
ym2149 u_psg
|
|
(
|
|
.CLK(clk),
|
|
.CE(clk_en_ssg),
|
|
.RESET(rst),
|
|
|
|
.BDIR(write),
|
|
.BC(~addr[0] | ~write),
|
|
.DI(din),
|
|
.DO(psg_dout),
|
|
.CHANNEL_A(psg_A),
|
|
.CHANNEL_B(psg_B),
|
|
.CHANNEL_C(psg_C)
|
|
);
|
|
assign psg_snd = {2'b00, psg_A} + {2'b00, psg_B} + {2'b00, psg_C};
|
|
assign snd_left = fm_snd_left + { 2'b0, psg_snd[9:1],5'd0};
|
|
assign snd_right = fm_snd_right + { 2'b0, psg_snd[9:1],5'd0};
|
|
assign dout = addr[0] ? psg_dout : fm_dout;
|
|
end else begin
|
|
assign psg_snd = 10'd0;
|
|
assign snd_left = fm_snd_left;
|
|
assign snd_right= fm_snd_right;
|
|
assign psg_dout = 8'd0;
|
|
assign dout = fm_dout;
|
|
end
|
|
endgenerate
|
|
|
|
|
|
`ifndef TIMERONLY
|
|
|
|
jt12_pg #(.num_ch(num_ch)) u_pg(
|
|
.rst ( rst ),
|
|
.clk ( clk ),
|
|
.clk_en ( clk_en ),
|
|
// Channel frequency
|
|
.fnum_I ( fnum_I ),
|
|
.block_I ( block_I ),
|
|
// Operator multiplying
|
|
.mul_II ( mul_II ),
|
|
// Operator detuning
|
|
.dt1_I ( dt1_I ), // same as JT51's DT1
|
|
// Phase modulation by LFO
|
|
.lfo_mod ( lfo_mod ),
|
|
.pms_I ( pms_I ),
|
|
// phase operation
|
|
.pg_rst_II ( pg_rst_II ),
|
|
.pg_stop ( pg_stop ),
|
|
.keycode_II ( keycode_II ),
|
|
.phase_VIII ( phase_VIII )
|
|
);
|
|
|
|
wire [9:0] eg_V;
|
|
|
|
jt12_eg #(.num_ch(num_ch)) u_eg(
|
|
.rst ( rst ),
|
|
.clk ( clk ),
|
|
.clk_en ( clk_en ),
|
|
.zero ( zero ),
|
|
.eg_stop ( eg_stop ),
|
|
// envelope configuration
|
|
.keycode_II ( keycode_II ),
|
|
.arate_I ( ar_I ), // attack rate
|
|
.rate1_I ( d1r_I ), // decay rate
|
|
.rate2_I ( d2r_I ), // sustain rate
|
|
.rrate_I ( rr_I ), // release rate
|
|
.sl_I ( sl_I ), // sustain level
|
|
.ks_II ( ks_II ), // key scale
|
|
// SSG operation
|
|
.ssg_en_I ( ssg_en_I ),
|
|
.ssg_eg_I ( ssg_eg_I ),
|
|
// envelope operation
|
|
.keyon_I ( keyon_I ),
|
|
// envelope number
|
|
.lfo_mod ( lfo_mod ),
|
|
.tl_IV ( tl_IV ),
|
|
.ams_IV ( ams_IV ),
|
|
.amsen_IV ( amsen_IV ),
|
|
|
|
.eg_V ( eg_V ),
|
|
.pg_rst_II ( pg_rst_II )
|
|
);
|
|
|
|
jt12_sh #(.width(10),.stages(4)) u_egpad(
|
|
.clk ( clk ),
|
|
.clk_en ( clk_en ),
|
|
.din ( eg_V ),
|
|
.drop ( eg_IX )
|
|
);
|
|
|
|
wire [ 8:0] op_result;
|
|
wire [13:0] full_result;
|
|
|
|
jt12_op #(.num_ch(num_ch)) u_op(
|
|
.rst ( rst ),
|
|
.clk ( clk ),
|
|
.clk_en ( clk_en ),
|
|
.pg_phase_VIII ( phase_VIII ),
|
|
.eg_atten_IX ( eg_IX ),
|
|
.fb_II ( fb_II ),
|
|
|
|
.test_214 ( 1'b0 ),
|
|
.s1_enters ( s1_enters ),
|
|
.s2_enters ( s2_enters ),
|
|
.s3_enters ( s3_enters ),
|
|
.s4_enters ( s4_enters ),
|
|
.xuse_prevprev1 ( xuse_prevprev1),
|
|
.xuse_internal ( xuse_internal ),
|
|
.yuse_internal ( yuse_internal ),
|
|
.xuse_prev2 ( xuse_prev2 ),
|
|
.yuse_prev1 ( yuse_prev1 ),
|
|
.yuse_prev2 ( yuse_prev2 ),
|
|
.zero ( zero ),
|
|
.op_result ( op_result ),
|
|
.full_result ( full_result )
|
|
);
|
|
|
|
generate
|
|
if( use_lr==1 ) begin
|
|
assign fm_snd_right[3:0] = 4'd0;
|
|
assign fm_snd_left [3:0] = 4'd0;
|
|
assign snd_sample = zero;
|
|
wire signed [8:0] pcm2;
|
|
|
|
// interpolate PCM samples with automatic sample rate detection
|
|
// this feature is not present in original YM2612
|
|
// this improves PCM sample sound greatly
|
|
jt12_pcm u_pcm(
|
|
.rst ( rst ),
|
|
.clk ( clk ),
|
|
.clk_en ( clk_en ),
|
|
.zero ( zero ),
|
|
.pcm ( pcm ),
|
|
.pcm_wr ( pcm_wr ),
|
|
.pcm_resampled ( pcm2 )
|
|
);
|
|
|
|
jt12_acc #(.num_ch(num_ch)) u_acc(
|
|
.rst ( rst ),
|
|
.clk ( clk ),
|
|
.clk_en ( clk_en ),
|
|
.op_result ( op_result ),
|
|
.rl ( rl ),
|
|
// note that the order changes to deal
|
|
// with the operator pipeline delay
|
|
.zero ( zero ),
|
|
.s1_enters ( s2_enters ),
|
|
.s2_enters ( s1_enters ),
|
|
.s3_enters ( s4_enters ),
|
|
.s4_enters ( s3_enters ),
|
|
.ch6op ( ch6op ),
|
|
.pcm_en ( pcm_en ), // only enabled for channel 6
|
|
.pcm ( pcm2 ),
|
|
.alg ( alg_I ),
|
|
// combined output
|
|
.left ( fm_snd_left [15:4] ),
|
|
.right ( fm_snd_right[15:4] )
|
|
);
|
|
end else begin
|
|
wire signed [15:0] mono_snd;
|
|
assign fm_snd_left = mono_snd;
|
|
assign fm_snd_right = mono_snd;
|
|
assign snd_sample = zero;
|
|
jt03_acc u_acc(
|
|
.rst ( rst ),
|
|
.clk ( clk ),
|
|
.clk_en ( clk_en ),
|
|
.op_result ( full_result ),
|
|
// note that the order changes to deal
|
|
// with the operator pipeline delay
|
|
.s1_enters ( s1_enters ),
|
|
.s2_enters ( s2_enters ),
|
|
.s3_enters ( s3_enters ),
|
|
.s4_enters ( s4_enters ),
|
|
.alg ( alg_I ),
|
|
.zero ( zero ),
|
|
// combined output
|
|
.snd ( mono_snd )
|
|
);
|
|
end
|
|
endgenerate
|
|
|
|
`ifdef SIMULATION
|
|
/* verilator lint_off PINMISSING */
|
|
reg [4:0] sep24_cnt;
|
|
|
|
wire [9:0] eg_ch0s1, eg_ch1s1, eg_ch2s1, eg_ch3s1, eg_ch4s1, eg_ch5s1,
|
|
eg_ch0s2, eg_ch1s2, eg_ch2s2, eg_ch3s2, eg_ch4s2, eg_ch5s2,
|
|
eg_ch0s3, eg_ch1s3, eg_ch2s3, eg_ch3s3, eg_ch4s3, eg_ch5s3,
|
|
eg_ch0s4, eg_ch1s4, eg_ch2s4, eg_ch3s4, eg_ch4s4, eg_ch5s4;
|
|
|
|
always @(posedge clk) if( clk_en )
|
|
sep24_cnt <= !zero ? sep24_cnt+1'b1 : 5'd0;
|
|
|
|
sep24 #( .width(10), .pos0(5'd0)) egsep
|
|
(
|
|
.clk ( clk ),
|
|
.clk_en ( clk_en ),
|
|
.mixed ( eg_IX ),
|
|
.mask ( 24'd0 ),
|
|
.cnt ( sep24_cnt ),
|
|
|
|
.ch0s1 (eg_ch0s1),
|
|
.ch1s1 (eg_ch1s1),
|
|
.ch2s1 (eg_ch2s1),
|
|
.ch3s1 (eg_ch3s1),
|
|
.ch4s1 (eg_ch4s1),
|
|
.ch5s1 (eg_ch5s1),
|
|
|
|
.ch0s2 (eg_ch0s2),
|
|
.ch1s2 (eg_ch1s2),
|
|
.ch2s2 (eg_ch2s2),
|
|
.ch3s2 (eg_ch3s2),
|
|
.ch4s2 (eg_ch4s2),
|
|
.ch5s2 (eg_ch5s2),
|
|
|
|
.ch0s3 (eg_ch0s3),
|
|
.ch1s3 (eg_ch1s3),
|
|
.ch2s3 (eg_ch2s3),
|
|
.ch3s3 (eg_ch3s3),
|
|
.ch4s3 (eg_ch4s3),
|
|
.ch5s3 (eg_ch5s3),
|
|
|
|
.ch0s4 (eg_ch0s4),
|
|
.ch1s4 (eg_ch1s4),
|
|
.ch2s4 (eg_ch2s4),
|
|
.ch3s4 (eg_ch3s4),
|
|
.ch4s4 (eg_ch4s4),
|
|
.ch5s4 (eg_ch5s4)
|
|
);
|
|
`endif
|
|
/* verilator lint_on PINMISSING */
|
|
`endif
|
|
endmodule
|