`timescale 1ns / 1ps module clock_divider ( input wire clk_in, input wire rst_n, output wire clk_12mhz, output wire clk_50mhz, output wire clk_sdio, output wire clk_spi ); reg [1:0] div_counter_50mhz; reg [7:0] div_counter_sdio; reg [7:0] div_counter_spi; reg clk_50mhz_reg; reg clk_sdio_reg; reg clk_spi_reg; reg [7:0] sdio_div_ratio; reg [7:0] spi_div_ratio; reg sdio_clk_en; reg spi_clk_en; assign clk_12mhz = clk_in; assign clk_50mhz = clk_50mhz_reg; assign clk_sdio = sdio_clk_en ? clk_sdio_reg : 1'b0; assign clk_spi = spi_clk_en ? clk_spi_reg : 1'b0; always @(posedge clk_in or negedge rst_n) begin if (!rst_n) begin div_counter_50mhz <= 2'b00; clk_50mhz_reg <= 1'b0; end else begin div_counter_50mhz <= div_counter_50mhz + 1; case (div_counter_50mhz) 2'b00: clk_50mhz_reg <= 1'b1; 2'b01: clk_50mhz_reg <= 1'b1; 2'b10: clk_50mhz_reg <= 1'b0; 2'b11: clk_50mhz_reg <= 1'b0; endcase end end always @(posedge clk_50mhz_reg or negedge rst_n) begin if (!rst_n) begin div_counter_sdio <= 8'd0; clk_sdio_reg <= 1'b0; sdio_div_ratio <= 8'd1; end else if (sdio_clk_en) begin if (div_counter_sdio >= sdio_div_ratio) begin div_counter_sdio <= 8'd0; clk_sdio_reg <= ~clk_sdio_reg; end else begin div_counter_sdio <= div_counter_sdio + 1; end end else begin div_counter_sdio <= 8'd0; clk_sdio_reg <= 1'b0; end end always @(posedge clk_50mhz_reg or negedge rst_n) begin if (!rst_n) begin div_counter_spi <= 8'd0; clk_spi_reg <= 1'b0; spi_div_ratio <= 8'd1; end else if (spi_clk_en) begin if (div_counter_spi >= spi_div_ratio) begin div_counter_spi <= 8'd0; clk_spi_reg <= ~clk_spi_reg; end else begin div_counter_spi <= div_counter_spi + 1; end end else begin div_counter_spi <= 8'd0; clk_spi_reg <= 1'b0; end end always @(posedge clk_50mhz_reg or negedge rst_n) begin if (!rst_n) begin sdio_clk_en <= 1'b0; spi_clk_en <= 1'b0; end else begin sdio_clk_en <= 1'b1; spi_clk_en <= 1'b1; end end task set_sdio_frequency; input [7:0] divider; begin sdio_div_ratio <= divider; end endtask task set_spi_frequency; input [7:0] divider; begin spi_div_ratio <= divider; end endtask task enable_sdio_clock; input enable; begin sdio_clk_en <= enable; end endtask task enable_spi_clock; input enable; begin spi_clk_en <= enable; end endtask function [7:0] calc_sdio_divider; input [7:0] freq_mhz; begin if (freq_mhz == 0) calc_sdio_divider = 8'd0; else calc_sdio_divider = 8'd25 / freq_mhz; end endfunction function [7:0] calc_spi_divider; input [7:0] freq_mhz; begin if (freq_mhz == 0) calc_spi_divider = 8'd0; else calc_spi_divider = 8'd25 / freq_mhz; end endfunction initial begin sdio_div_ratio = calc_sdio_divider(8'd25); spi_div_ratio = calc_spi_divider(8'd25); end endmodule