/* This file is part of JT12. JT12 is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. JT12 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with JT12. If not, see . Author: Jose Tejada Gomez. Twitter: @topapate Version: 1.0 Date: 14-2-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