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