CLKDLL.v
`timescale 1 ps / 1 ps
module CLKDLL (CLK0, CLK90, CLK180, CLK270, CLK2X, CLKDV, LOCKED,
CLKIN, CLKFB, RST);
parameter CLKDV_DIVIDE = 2.0;
parameter DUTY_CYCLE_CORRECTION = "TRUE";
parameter MAXPERCLKIN = 100000;
input CLKIN, CLKFB, RST;
output CLK0, CLK90, CLK180, CLK270, CLK2X, CLKDV, LOCKED;
reg CLK0, CLK90, CLK180, CLK270, CLK2X, 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 [1:0] count3;
reg [2:0] count5;
reg [32:1] divider;
reg [7:0] divide_type;
reg clk1x_type;
reg rst_1, rst_2;
reg notifier;
initial begin
lock_period <= 0;
lock_delay <= 0;
clkin_edge[0] <= 0;
clkin_edge[1] <= 0;
delay_found <= 0;
period <= 0;
delay <= 0;
delay_fb <= 0;
clkin_window <= 0;
clkfb_window <= 0;
clk1x <= 0;
clkin_5050 <= 0;
clk1x_5050 <= 0;
clk1x_shift125 <= 0;
clk1x_shift250 <= 0;
clk2x_shift <= 0;
count3 <= 0;
count5 <= 0;
divider <= 0;
case (DUTY_CYCLE_CORRECTION)
"false" : clk1x_type <= 0;
"FALSE" : clk1x_type <= 0;
"true" : clk1x_type <= 1;
"TRUE" : clk1x_type <= 1;
default : begin
$display("Error : DUTY_CYCLE_CORRECTION = %s is neither TRUE nor FALSE.", DUTY_CYCLE_CORRECTION);
$finish;
end
endcase
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("Error : CLKDV_DIVIDE = %f is not 1.5, 2.0, 2.5, 3.0, 4.0, 5.0, 8.0 or 16.0.", CLKDV_DIVIDE);
$finish;
end
endcase
end
//
// input wire delays
//
buf b_clkin (clkin_in, CLKIN);
buf 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
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
lock_period <= 1;
end
always @(posedge lock_period) begin
if (period > MAXPERCLKIN) begin
$display(" \$maxperiod( posedge CLKIN:%0.3f", $time/1000, "ns, %0d", MAXPERCLKIN, " : %0.3f", period/1000, "ns );");
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;
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_2) begin
lock_period <= 0;
lock_delay <= 0;
delay_found <= 0;
period <= 0;
delay <= 0;
delay_fb <= 0;
clk1x <= 0;
clkin_5050 <= 0;
clk1x_5050 <= 0;
clk1x_shift125 <= 0;
clk1x_shift250 <= 0;
clk2x_shift <= 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)
lock_clkin <= 1;
else
lock_clkin <= 0;
end
always @ (posedge clkfb_in) begin
#1
if (clkin_window && delay_found)
lock_clkfb <= 1;
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 clkin_in) begin
{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
count3 <= 0;
count5 <= 0;
divider[3] <= 0;
divider[4] <= 0;
divider[5] <= 0;
end
always @(posedge clk4x_int) begin
if (count3 == 2'b0)
divider[3] <= divider[3] + 1;
count3 <= (count3 + 1) % 3;
end
always @(posedge clk0_int) begin
if (locked_out)
divider[4] <= divider[4] + 1;
end
always @(posedge clk4x_int) begin
if (count5 == 3'b0)
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 @ (rst_2 or clk0_int) begin
if (rst_2)
CLK0 <= #period 0;
else
CLK0 <= clk0_int;
end
always @ (rst_2 or clk0_int) begin
if (rst_2)
CLK90 <= #period 0;
else
CLK90 <= #(period/4) clk0_int;
end
always @ (rst_2 or clk0_int) begin
if (rst_2)
CLK180 <= #period 0;
else
CLK180 <= #(period/2) clk0_int;
end
always @ (rst_2 or clk0_int) begin
if (rst_2)
CLK270 <= #period 0;
else
CLK270 <= #(3*period/4) clk0_int;
end
always @ (rst_2 or clk2x_int) begin
if (rst_2)
CLK2X <= #period 0;
else
CLK2X <= clk2x_int;
end
always @ (rst_2 or clkdv_int) begin
if (rst_2)
CLKDV <= #period 0;
else
CLKDV <= clkdv_int;
end
specify
specparam CLKFBDLYLH = 0:0:0, CLKFBDLYHL = 0:0:0;
specparam CLKINDLYLH = 0:0:0, CLKINDLYHL = 0:0:0;
specparam LOCKEDDLYLH = 0:0:0, LOCKEDDLYHL = 0:0:0;
specparam RSTDLYLH = 0:0:0, RSTDLYHL = 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);
endspecify
endmodule
HDLMaker Generated Files
CLKDLL.job |
Synopsys script file |