blob: 4b698a465769041cd30f0f7bfd2dca682f0966df [file] [log] [blame]
Tim Edwards3245e2f2020-10-10 14:02:11 -04001/* Integer-N clock divider */
Tim Edwards581068f2020-11-19 12:45:25 -05002`default_nettype none
Tim Edwards3245e2f2020-10-10 14:02:11 -04003
4module clock_div #(
5 parameter SIZE = 3 // Number of bits for the divider value
6) (
7 in, out, N, resetb
8);
9 input in; // input clock
10 input [SIZE-1:0] N; // the number to be divided by
11 input resetb; // asynchronous reset (sense negative)
12 output out; // divided output clock
13
14 wire out_odd; // output of odd divider
15 wire out_even; // output of even divider
16 wire not_zero; // signal to find divide by 0 case
17 wire enable_even; // enable of even divider
18 wire enable_odd; // enable of odd divider
19
20 reg [SIZE-1:0] syncN; // N synchronized to output clock
21 reg [SIZE-1:0] syncNp; // N synchronized to output clock
22
23 assign not_zero = | syncN[SIZE-1:1];
24
25 assign out = (out_odd & syncN[0] & not_zero) | (out_even & !syncN[0]);
26 assign enable_odd = syncN[0] & not_zero;
27 assign enable_even = !syncN[0];
28
29 // Divider value synchronization (double-synchronized to avoid metastability)
30 always @(posedge out or negedge resetb) begin
31 if (resetb == 1'b0) begin
32 syncN <= 'd2; // Default to divide-by-2 on system reset
33 syncNp <= 'd2; // Default to divide-by-2 on system reset
34 end else begin
35 syncNp <= N;
36 syncN <= syncNp;
37 end
38 end
39
40 // Even divider
41 even even_0(in, out_even, syncN, resetb, not_zero, enable_even);
42 // Odd divider
43 odd odd_0(in, out_odd, syncN, resetb, enable_odd);
44
45endmodule // clock_div
46
47/* Odd divider */
48
49module odd #(
50 parameter SIZE = 3
51) (
52 clk, out, N, resetb, enable
53);
54 input clk; // slow clock
55 output out; // fast output clock
56 input [SIZE-1:0] N; // division factor
57 input resetb; // synchronous reset
58 input enable; // odd enable
59
60 reg [SIZE-1:0] counter; // these 2 counters are used
61 reg [SIZE-1:0] counter2; // to non-overlapping signals
62 reg out_counter; // positive edge triggered counter
63 reg out_counter2; // negative edge triggered counter
64 reg rst_pulse; // pulse generated when vector N changes
65 reg [SIZE-1:0] old_N; // gets set to old N when N is changed
66 wire not_zero; // if !not_zero, we devide by 1
67
68 // xor to generate 50% duty, half-period waves of final output
69 assign out = out_counter2 ^ out_counter;
70
71 // positive edge counter/divider
72 always @(posedge clk or negedge resetb) begin
73 if (resetb == 1'b0) begin
74 counter <= N;
75 out_counter <= 1;
76 end else if (rst_pulse) begin
77 counter <= N;
78 out_counter <= 1;
79 end else if (enable) begin
80 if (counter == 1) begin
81 counter <= N;
82 out_counter <= ~out_counter;
83 end else begin
84 counter <= counter - 1'b1;
85 end
86 end
87 end
88
89 reg [SIZE-1:0] initial_begin; // this is used to offset the negative edge counter
90 wire [SIZE:0] interm_3; // from the positive edge counter in order to
91 assign interm_3 = {1'b0,N} + 2'b11; // guarante 50% duty cycle.
92
93 // Counter driven by negative edge of clock.
94
95 always @(negedge clk or negedge resetb) begin
96 if (resetb == 1'b0) begin
97 // reset the counter at system reset
98 counter2 <= N;
99 initial_begin <= interm_3[SIZE:1];
100 out_counter2 <= 1;
101 end else if (rst_pulse) begin
102 // reset the counter at change of N.
103 counter2 <= N;
104 initial_begin <= interm_3[SIZE:1];
105 out_counter2 <= 1;
106 end else if ((initial_begin <= 1) && enable) begin
107
108 // Do normal logic after odd calibration.
109 // This is the same as the even counter.
110 if (counter2 == 1) begin
111 counter2 <= N;
112 out_counter2 <= ~out_counter2;
113 end else begin
114 counter2 <= counter2 - 1'b1;
115 end
116 end else if (enable) begin
117 initial_begin <= initial_begin - 1'b1;
118 end
119 end
120
121 //
122 // reset pulse generator:
123 // __ __ __ __ _
124 // clk: __/ \__/ \__/ \__/ \__/
125 // _ __________________________
126 // N: _X__________________________
127 // _____
128 // rst_pulse: __/ \___________________
129 //
130 // This block generates an internal reset for the odd divider in the
131 // form of a single pulse signal when the odd divider is enabled.
132
133 always @(posedge clk or negedge resetb) begin
134 if (resetb == 1'b0) begin
135 rst_pulse <= 0;
136 end else if (enable) begin
137 if (N != old_N) begin
138 // pulse when reset changes
139 rst_pulse <= 1;
140 end else begin
141 rst_pulse <= 0;
142 end
143 end
144 end
145
146 always @(posedge clk) begin
147 // always save the old N value to guarante reset from
148 // an even-to-odd transition.
149 old_N <= N;
150 end
151
152endmodule // odd
153
154/* Even divider */
155
156module even #(
157 parameter SIZE = 3
158) (
159 clk, out, N, resetb, not_zero, enable
160);
161 input clk; // fast input clock
162 output out; // slower divided clock
163 input [SIZE-1:0] N; // divide by factor 'N'
164 input resetb; // asynchronous reset
165 input not_zero; // if !not_zero divide by 1
166 input enable; // enable the even divider
167
168 reg [SIZE-1:0] counter;
169 reg out_counter;
170 wire [SIZE-1:0] div_2;
171
172 // if N=0 just output the clock, otherwise, divide it.
173 assign out = (clk & !not_zero) | (out_counter & not_zero);
174 assign div_2 = {1'b0, N[SIZE-1:1]};
175
176 // simple flip-flop even divider
177 always @(posedge clk or negedge resetb) begin
178 if (resetb == 1'b0) begin
179 counter <= 1;
180 out_counter <= 1;
181
182 end else if (enable) begin
183 // only use switching power if enabled
184 if (counter == 1) begin
185 // divide after counter has reached bottom
186 // of interval 'N' which will be value '1'
187 counter <= div_2;
188 out_counter <= ~out_counter;
189 end else begin
190 // decrement the counter and wait
191 counter <= counter-1; // to start next transition.
192 end
193 end
194 end
195
196endmodule //even
Tim Edwards581068f2020-11-19 12:45:25 -0500197`default_nettype wire