blob: 49ff44bf6f7d7ec83ffaae1fa87f4fde75ca21ef [file] [log] [blame]
agorararmard6c766a82020-12-10 18:13:12 +02001// SPDX-FileCopyrightText: 2020 Efabless Corporation
agorararmarde5780bf2020-12-09 21:27:56 +00002//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
agorararmardafa96ea2020-12-09 23:37:31 +020014// SPDX-License-Identifier: Apache-2.0
agorararmarde5780bf2020-12-09 21:27:56 +000015
Tim Edwards3245e2f2020-10-10 14:02:11 -040016/* Integer-N clock divider */
Tim Edwards581068f2020-11-19 12:45:25 -050017`default_nettype none
Tim Edwards3245e2f2020-10-10 14:02:11 -040018
19module clock_div #(
20 parameter SIZE = 3 // Number of bits for the divider value
21) (
22 in, out, N, resetb
23);
24 input in; // input clock
25 input [SIZE-1:0] N; // the number to be divided by
26 input resetb; // asynchronous reset (sense negative)
27 output out; // divided output clock
28
29 wire out_odd; // output of odd divider
30 wire out_even; // output of even divider
31 wire not_zero; // signal to find divide by 0 case
32 wire enable_even; // enable of even divider
33 wire enable_odd; // enable of odd divider
34
35 reg [SIZE-1:0] syncN; // N synchronized to output clock
36 reg [SIZE-1:0] syncNp; // N synchronized to output clock
37
38 assign not_zero = | syncN[SIZE-1:1];
39
40 assign out = (out_odd & syncN[0] & not_zero) | (out_even & !syncN[0]);
41 assign enable_odd = syncN[0] & not_zero;
42 assign enable_even = !syncN[0];
43
44 // Divider value synchronization (double-synchronized to avoid metastability)
45 always @(posedge out or negedge resetb) begin
46 if (resetb == 1'b0) begin
manarabdelaty08dd4832020-12-03 19:27:08 +020047 syncN <= `CLK_DIV; // Default to divide-by-2 on system reset
48 syncNp <= `CLK_DIV; // Default to divide-by-2 on system reset
Tim Edwards3245e2f2020-10-10 14:02:11 -040049 end else begin
50 syncNp <= N;
51 syncN <= syncNp;
52 end
53 end
54
55 // Even divider
56 even even_0(in, out_even, syncN, resetb, not_zero, enable_even);
57 // Odd divider
58 odd odd_0(in, out_odd, syncN, resetb, enable_odd);
59
60endmodule // clock_div
61
62/* Odd divider */
63
64module odd #(
65 parameter SIZE = 3
66) (
67 clk, out, N, resetb, enable
68);
69 input clk; // slow clock
70 output out; // fast output clock
71 input [SIZE-1:0] N; // division factor
72 input resetb; // synchronous reset
73 input enable; // odd enable
74
75 reg [SIZE-1:0] counter; // these 2 counters are used
76 reg [SIZE-1:0] counter2; // to non-overlapping signals
77 reg out_counter; // positive edge triggered counter
78 reg out_counter2; // negative edge triggered counter
79 reg rst_pulse; // pulse generated when vector N changes
80 reg [SIZE-1:0] old_N; // gets set to old N when N is changed
81 wire not_zero; // if !not_zero, we devide by 1
82
83 // xor to generate 50% duty, half-period waves of final output
84 assign out = out_counter2 ^ out_counter;
85
86 // positive edge counter/divider
87 always @(posedge clk or negedge resetb) begin
88 if (resetb == 1'b0) begin
manarabdelaty08dd4832020-12-03 19:27:08 +020089 counter <= `CLK_DIV;
Tim Edwards3245e2f2020-10-10 14:02:11 -040090 out_counter <= 1;
91 end else if (rst_pulse) begin
92 counter <= N;
93 out_counter <= 1;
94 end else if (enable) begin
95 if (counter == 1) begin
96 counter <= N;
97 out_counter <= ~out_counter;
98 end else begin
99 counter <= counter - 1'b1;
100 end
101 end
102 end
103
104 reg [SIZE-1:0] initial_begin; // this is used to offset the negative edge counter
manarabdelaty08dd4832020-12-03 19:27:08 +0200105 // wire [SIZE:0] interm_3; // from the positive edge counter in order to
106 // assign interm_3 = {1'b0,N} + 2'b11; // guarante 50% duty cycle.
107 localparam [SIZE:0] interm_3 = {1'b0,`CLK_DIV} + 2'b11;
108
Tim Edwards3245e2f2020-10-10 14:02:11 -0400109 // Counter driven by negative edge of clock.
110
111 always @(negedge clk or negedge resetb) begin
112 if (resetb == 1'b0) begin
113 // reset the counter at system reset
manarabdelaty08dd4832020-12-03 19:27:08 +0200114 counter2 <= `CLK_DIV;
Tim Edwards3245e2f2020-10-10 14:02:11 -0400115 initial_begin <= interm_3[SIZE:1];
116 out_counter2 <= 1;
117 end else if (rst_pulse) begin
118 // reset the counter at change of N.
119 counter2 <= N;
120 initial_begin <= interm_3[SIZE:1];
121 out_counter2 <= 1;
122 end else if ((initial_begin <= 1) && enable) begin
123
124 // Do normal logic after odd calibration.
125 // This is the same as the even counter.
126 if (counter2 == 1) begin
127 counter2 <= N;
128 out_counter2 <= ~out_counter2;
129 end else begin
130 counter2 <= counter2 - 1'b1;
131 end
132 end else if (enable) begin
133 initial_begin <= initial_begin - 1'b1;
134 end
135 end
136
137 //
138 // reset pulse generator:
139 // __ __ __ __ _
140 // clk: __/ \__/ \__/ \__/ \__/
141 // _ __________________________
142 // N: _X__________________________
143 // _____
144 // rst_pulse: __/ \___________________
145 //
146 // This block generates an internal reset for the odd divider in the
147 // form of a single pulse signal when the odd divider is enabled.
148
149 always @(posedge clk or negedge resetb) begin
150 if (resetb == 1'b0) begin
151 rst_pulse <= 0;
152 end else if (enable) begin
153 if (N != old_N) begin
154 // pulse when reset changes
155 rst_pulse <= 1;
156 end else begin
157 rst_pulse <= 0;
158 end
159 end
160 end
161
162 always @(posedge clk) begin
163 // always save the old N value to guarante reset from
164 // an even-to-odd transition.
165 old_N <= N;
166 end
167
168endmodule // odd
169
170/* Even divider */
171
172module even #(
173 parameter SIZE = 3
174) (
175 clk, out, N, resetb, not_zero, enable
176);
177 input clk; // fast input clock
178 output out; // slower divided clock
179 input [SIZE-1:0] N; // divide by factor 'N'
180 input resetb; // asynchronous reset
181 input not_zero; // if !not_zero divide by 1
182 input enable; // enable the even divider
183
184 reg [SIZE-1:0] counter;
185 reg out_counter;
186 wire [SIZE-1:0] div_2;
187
188 // if N=0 just output the clock, otherwise, divide it.
189 assign out = (clk & !not_zero) | (out_counter & not_zero);
190 assign div_2 = {1'b0, N[SIZE-1:1]};
191
192 // simple flip-flop even divider
193 always @(posedge clk or negedge resetb) begin
194 if (resetb == 1'b0) begin
195 counter <= 1;
196 out_counter <= 1;
197
198 end else if (enable) begin
199 // only use switching power if enabled
200 if (counter == 1) begin
201 // divide after counter has reached bottom
202 // of interval 'N' which will be value '1'
203 counter <= div_2;
204 out_counter <= ~out_counter;
205 end else begin
206 // decrement the counter and wait
207 counter <= counter-1; // to start next transition.
208 end
209 end
210 end
211
212endmodule //even
Tim Edwards581068f2020-11-19 12:45:25 -0500213`default_nettype wire