CLKDLL.v
8.97 KB
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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
// $Header: /root/leakn64/depot/rf/hw/debug/xilinx/CLKDLL.v,v 1.1 2003/04/01 21:47:33 berndt Exp $
/*
FUNCTION : Clock Delay Locked Loop
*/
`timescale 1 ps / 1 ps
module CLKDLL (CLK0, CLK180, CLK270, CLK2X, CLK90, CLKDV, LOCKED,
CLKFB, CLKIN, RST);
parameter CLKDV_DIVIDE = 2.0;
parameter DUTY_CYCLE_CORRECTION = "TRUE";
parameter FACTORY_JF = 16'hC080; // non-simulatable
parameter MAXPERCLKIN = 100000;
parameter STARTUP_WAIT = "FALSE"; // non-simulatable
input CLKFB, CLKIN, RST;
output CLK0, CLK180, CLK270, CLK2X, CLK90, CLKDV, LOCKED;
reg CLK0, CLK180, CLK270, CLK2X, CLK90, CLKDV;
reg lock_period, lock_delay, lock_clkin, lock_clkfb;
reg delay_found;
time clkin_edge[0:1];
time delay_edge[0:1];
time period, delay, delay_fb;
wire clkin_in, clkfb_in, rst_in;
reg locked_out;
wire clk0_int, clk2x_int, clk4x_int, clkdv_int;
wire clk2x_2575, clk2x_5050;
reg clkin_window, clkfb_window;
reg clk1x, clkin_5050, clk1x_5050;
reg clk1x_shift125, clk1x_shift250;
reg clk2x_shift;
reg [7:0] count3, count4, count5;
reg [32:1] divider;
reg [7:0] divide_type;
reg clk1x_type;
reg rst_1, rst_2;
reg notifier;
initial begin
clk1x <= 0;
clk1x_5050 <= 0;
clk1x_shift125 <= 0;
clk1x_shift250 <= 0;
clk2x_shift <= 0;
clkfb_window <= 0;
clkin_5050 <= 0;
clkin_edge[0] <= 1'bx;
clkin_edge[1] <= 1'bx;
clkin_window <= 0;
count3 <= 0;
count4 <= 0;
count5 <= 0;
delay <= 0;
delay_fb <= 0;
delay_found <= 0;
divider <= 0;
lock_delay <= 0;
lock_period <= 0;
period <= 0;
case (CLKDV_DIVIDE)
1.5 : divide_type <= 'd3;
2.0 : divide_type <= 'd4;
2.5 : divide_type <= 'd5;
3.0 : divide_type <= 'd6;
4.0 : divide_type <= 'd8;
5.0 : divide_type <= 'd10;
8.0 : divide_type <= 'd16;
16.0 : divide_type <= 'd32;
default : begin
$display("Attribute Syntax Error : The attribute CLKDV_DIVIDE on CLKDLL instance %m is set to %0.1f. Legal values for this attribute are 1.5, 2.0, 2.5, 3.0, 4.0, 5.0, 8.0 or 16.0.", CLKDV_DIVIDE);
$finish;
end
endcase
case (DUTY_CYCLE_CORRECTION)
"false" : clk1x_type <= 0;
"FALSE" : clk1x_type <= 0;
"true" : clk1x_type <= 1;
"TRUE" : clk1x_type <= 1;
default : begin
$display("Attribute Syntax Error : The attribute DUTY_CYCLE_CORRECTION on CLKDLL instance %m is set to %s. Legal values for this attribute are TRUE or FALSE.", DUTY_CYCLE_CORRECTION);
$finish;
end
endcase
case (STARTUP_WAIT)
"false" : ;
"FALSE" : ;
"true" : ;
"TRUE" : ;
default : begin
$display("Attribute Syntax Error : The attribute STARTUP_WAIT on CLKDLL instance %m is set to %s. Legal values for this attribute are TRUE or FALSE.", STARTUP_WAIT);
$finish;
end
endcase
end
//
// input wire delays
//
buf b_clkin (clkin_in, CLKIN);
buf #0 b_clkfb (clkfb_in, CLKFB);
buf b_rst (rst_in, RST);
buf b_locked (LOCKED, locked_out);
//
// determine clock period
//
always @(posedge clkin_in) begin
clkin_edge[0] <= $time;
clkin_edge[1] <= clkin_edge[0];
if (rst_2)
period <= 0;
else if (period < clkin_edge[0] - clkin_edge[1] - 100)
period <= clkin_edge[0] - clkin_edge[1];
else if (period > clkin_edge[0] - clkin_edge[1] + 100)
period <= clkin_edge[0] - clkin_edge[1];
end
always @(period) begin // period changed reset everything
clk1x <= 0;
clk1x_5050 <= 0;
clk1x_shift125 <= 0;
clk1x_shift250 <= 0;
clk2x_shift <= 0;
clkin_5050 <= 0;
delay <= 0;
delay_fb <= 0;
delay_found <= 0;
lock_delay <= 0;
lock_period <= 0;
if (period < clkin_edge[0] - clkin_edge[1] - 100)
lock_period <= 0;
else if (period > clkin_edge[0] - clkin_edge[1] + 100)
lock_period <= 0;
else if ((clkin_edge[0] != 1'bx) && (clkin_edge[1] != 1'bx))
lock_period <= 1;
end
always @(posedge lock_period) begin
if (period > MAXPERCLKIN) begin
$display("Timing Violation Error : Input clock period of, %1.3f ns, on the CLKIN port of CLKDLL instance %m exceeds allotted value of %1.3f ns at simulation time %1.3f ns.", period/1000.0, MAXPERCLKIN/1000.0, $time/1000.0);
end
end
//
// determine clock delay
//
always @ (lock_period or delay_found) begin
if (lock_period && !delay_found) begin
assign CLK0 = 0; assign CLK2X = 0;
#period
assign CLK0 = 1; assign CLK2X = 1;
delay_edge[1] = $time;
@(posedge clkfb_in)
delay_edge[0] = $time;
#period
assign CLK0 = 0; assign CLK2X = 0;
#period
deassign CLK0; deassign CLK2X;
delay = (10 * period - (delay_edge[0] - delay_edge[1])) % period;
delay_found = 1;
end
end
always @ (lock_period or delay_found) begin
if (lock_period && delay_found) begin
for (delay_fb = 0; delay_fb < delay; delay_fb = delay_fb + 1000)
@(posedge clkin_in);
delay_fb <= delay;
end
end
always @ (posedge clkin_in) begin
if (rst_in) begin
clk1x <= 0;
clk1x_5050 <= 0;
clk1x_shift125 <= 0;
clk1x_shift250 <= 0;
clk2x_shift <= 0;
clkin_5050 <= 0;
count3 <= 0;
count4 <= 0;
count5 <= 0;
delay <= 0;
delay_fb <= 0;
delay_found <= 0;
divider <= 0;
locked_out <= 0;
lock_delay <= 0;
lock_period <= 0;
period <= 0;
end
end
always @ (posedge clkfb_in) begin
#0 clkfb_window = 1;
#100 clkfb_window = 0;
end
always @ (posedge clkin_in) begin
#0 clkin_window = 1;
#100 clkin_window = 0;
end
always @ (posedge clkin_in) begin
#1
if (clkfb_window && delay_found) begin
lock_clkfb <= 1;
lock_clkin <= 1;
end
else
lock_clkin <= 0;
end
always @ (posedge clkfb_in) begin
#1
if (clkin_window && delay_found) begin
lock_clkfb <= 1;
lock_clkin <= 1;
end
else
lock_clkfb <= 0;
@ (posedge clkfb_in);
end
always @ (lock_clkin or lock_clkfb) begin
if (lock_clkin || lock_clkfb)
lock_delay <= 1;
else
lock_delay <= 0;
end
//
// generate master reset signal
//
always @ (posedge rst_in) begin
rst_1 <= 1;
rst_2 <= 1;
locked_out <= 0;
end
always @ (posedge clkin_in) begin
if (rst_in == 0)
{rst_2,rst_1} <= {rst_1,rst_in};
end
//
// generate lock signal
//
always @ (posedge clkin_in) begin
locked_out <= lock_delay & lock_period & ~rst_2;
end
//
// generate the clk0_int
//
always @ (clkin_in) begin
if (delay_found)
clk1x <= #delay_fb clkin_in;
end
always @ (posedge clkin_in) begin
clkin_5050 <= 1;
#(period/2)
clkin_5050 <= 0;
end
always @ (clkin_5050) begin
if (delay_found)
clk1x_5050 <= #delay_fb clkin_5050;
end
assign clk0_int = (clk1x_type) ? clk1x_5050 : clk1x;
//
// generate the clk2x_int
//
always @(clk1x_5050) begin
clk1x_shift125 <= #(period/8) clk1x_5050;
clk1x_shift250 <= #(period/4) clk1x_5050;
end
assign clk2x_2575 = clk1x_5050 & ~clk1x_shift250;
assign clk2x_5050 = clk1x_5050 ^ clk1x_shift250;
assign clk2x_int = (locked_out) ? clk2x_5050 : clk2x_2575;
//
// generate the clk4x_int
//
always @(clk2x_5050) begin
clk2x_shift <= #(period/8) clk2x_5050;
end
assign clk4x_int = clk2x_5050 ^ clk2x_shift;
//
// generate the clkdv_int
//
always @ (negedge rst_2) begin
end
always @(posedge clk4x_int) begin
if (count3 == 0)
divider[3] <= divider[3] + 1;
count3 <= (count3 + 1) % 3;
end
always @(posedge clk4x_int) begin
if (count4 == 0)
divider[4] <= divider[4] + 1;
count4 <= (count4 + 1) % 4;
end
always @(posedge clk4x_int) begin
if (count5 == 0)
divider[5] <= divider[5] + 1;
count5 <= (count5 + 1) % 5;
end
always @(posedge divider[3]) begin
divider[6] <= divider[6] + 1;
end
always @(posedge divider[4]) begin
divider[8] <= divider[8] + 1;
end
always @(posedge divider[5]) begin
divider[10] <= divider[10] + 1;
end
always @(posedge divider[8]) begin
divider[16] <= divider[16] + 1;
end
always @(posedge divider[16]) begin
divider[32] <= divider[32] + 1;
end
assign clkdv_int = divider[divide_type];
//
// generate all output signal
//
always @ (clk0_int) begin
CLK0 <= clk0_int;
end
always @ (clk0_int) begin
CLK90 <= #(period/4) clk0_int;
end
always @ (clk0_int) begin
CLK180 <= #(period/2) clk0_int;
end
always @ (clk0_int) begin
CLK270 <= #(3*period/4) clk0_int;
end
always @ (clk2x_int) begin
CLK2X <= clk2x_int;
end
always @ (clkdv_int) begin
if (locked_out)
CLKDV <= clkdv_int;
else
CLKDV <= 0;
end
specify
specparam CLKFBDLYLH = 0:0:0, CLKFBDLYHL = 0:0:0;
specparam CLKINDLYLH = 0:0:0, CLKINDLYHL = 0:0:0;
specparam RSTDLYLH = 0:0:0, RSTDLYHL = 0:0:0;
specparam LOCKEDDLYLH = 0:0:0, LOCKEDDLYHL = 0:0:0;
specparam PWCLKINHI = 0:0:0, PWCLKINLO = 0:0:0;
specparam PWRSTHI = 0:0:0;
specparam MINPERCLKIN = 10:10:10;
(CLKIN => LOCKED) = (CLKINDLYLH + LOCKEDDLYLH, CLKINDLYHL + LOCKEDDLYHL);
$width (posedge CLKIN, PWCLKINHI, 0, notifier);
$width (negedge CLKIN, PWCLKINLO, 0, notifier);
$width (posedge RST, PWRSTHI, 0, notifier);
$period (posedge CLKIN, MINPERCLKIN, notifier);
specparam PATHPULSE$ = 0;
endspecify
endmodule