blob: 6f898dfb53d59519e8fd20aaed13cf86c65a42dd [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
manarabdelaty08dd4832020-12-03 19:27:08 +020032 syncN <= `CLK_DIV; // Default to divide-by-2 on system reset
33 syncNp <= `CLK_DIV; // Default to divide-by-2 on system reset
Tim Edwards3245e2f2020-10-10 14:02:11 -040034 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
manarabdelaty08dd4832020-12-03 19:27:08 +020074 counter <= `CLK_DIV;
Tim Edwards3245e2f2020-10-10 14:02:11 -040075 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
manarabdelaty08dd4832020-12-03 19:27:08 +020090 // 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 localparam [SIZE:0] interm_3 = {1'b0,`CLK_DIV} + 2'b11;
93
Tim Edwards3245e2f2020-10-10 14:02:11 -040094 // Counter driven by negative edge of clock.
95
96 always @(negedge clk or negedge resetb) begin
97 if (resetb == 1'b0) begin
98 // reset the counter at system reset
manarabdelaty08dd4832020-12-03 19:27:08 +020099 counter2 <= `CLK_DIV;
Tim Edwards3245e2f2020-10-10 14:02:11 -0400100 initial_begin <= interm_3[SIZE:1];
101 out_counter2 <= 1;
102 end else if (rst_pulse) begin
103 // reset the counter at change of N.
104 counter2 <= N;
105 initial_begin <= interm_3[SIZE:1];
106 out_counter2 <= 1;
107 end else if ((initial_begin <= 1) && enable) begin
108
109 // Do normal logic after odd calibration.
110 // This is the same as the even counter.
111 if (counter2 == 1) begin
112 counter2 <= N;
113 out_counter2 <= ~out_counter2;
114 end else begin
115 counter2 <= counter2 - 1'b1;
116 end
117 end else if (enable) begin
118 initial_begin <= initial_begin - 1'b1;
119 end
120 end
121
122 //
123 // reset pulse generator:
124 // __ __ __ __ _
125 // clk: __/ \__/ \__/ \__/ \__/
126 // _ __________________________
127 // N: _X__________________________
128 // _____
129 // rst_pulse: __/ \___________________
130 //
131 // This block generates an internal reset for the odd divider in the
132 // form of a single pulse signal when the odd divider is enabled.
133
134 always @(posedge clk or negedge resetb) begin
135 if (resetb == 1'b0) begin
136 rst_pulse <= 0;
137 end else if (enable) begin
138 if (N != old_N) begin
139 // pulse when reset changes
140 rst_pulse <= 1;
141 end else begin
142 rst_pulse <= 0;
143 end
144 end
145 end
146
147 always @(posedge clk) begin
148 // always save the old N value to guarante reset from
149 // an even-to-odd transition.
150 old_N <= N;
151 end
152
153endmodule // odd
154
155/* Even divider */
156
157module even #(
158 parameter SIZE = 3
159) (
160 clk, out, N, resetb, not_zero, enable
161);
162 input clk; // fast input clock
163 output out; // slower divided clock
164 input [SIZE-1:0] N; // divide by factor 'N'
165 input resetb; // asynchronous reset
166 input not_zero; // if !not_zero divide by 1
167 input enable; // enable the even divider
168
169 reg [SIZE-1:0] counter;
170 reg out_counter;
171 wire [SIZE-1:0] div_2;
172
173 // if N=0 just output the clock, otherwise, divide it.
174 assign out = (clk & !not_zero) | (out_counter & not_zero);
175 assign div_2 = {1'b0, N[SIZE-1:1]};
176
177 // simple flip-flop even divider
178 always @(posedge clk or negedge resetb) begin
179 if (resetb == 1'b0) begin
180 counter <= 1;
181 out_counter <= 1;
182
183 end else if (enable) begin
184 // only use switching power if enabled
185 if (counter == 1) begin
186 // divide after counter has reached bottom
187 // of interval 'N' which will be value '1'
188 counter <= div_2;
189 out_counter <= ~out_counter;
190 end else begin
191 // decrement the counter and wait
192 counter <= counter-1; // to start next transition.
193 end
194 end
195 end
196
197endmodule //even
Tim Edwards581068f2020-11-19 12:45:25 -0500198`default_nettype wire