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