aboutsummaryrefslogtreecommitdiffstats
path: root/hdl/clock_divider.v
blob: adffe0e05960e171cecaf37b34d2ddb176bfb3b2 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
`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