1
0
mirror of https://github.com/aolofsson/oh.git synced 2025-01-17 20:02:53 +08:00
oh/xilibs/hdl/PLLE2_ADV.v
2015-10-07 19:17:59 -04:00

196 lines
5.4 KiB
Verilog

module PLLE2_ADV #(
parameter BANDWIDTH = "OPTIMIZED",
parameter integer CLKFBOUT_MULT = 5,
parameter real CLKFBOUT_PHASE = 0.000,
parameter real CLKIN1_PERIOD = 0.000,
parameter real CLKIN2_PERIOD = 0.000,
parameter integer CLKOUT0_DIVIDE = 1,
parameter real CLKOUT0_DUTY_CYCLE = 0.500,
parameter real CLKOUT0_PHASE = 0.000,
parameter integer CLKOUT1_DIVIDE = 1,
parameter real CLKOUT1_DUTY_CYCLE = 0.500,
parameter real CLKOUT1_PHASE = 0.000,
parameter integer CLKOUT2_DIVIDE = 1,
parameter real CLKOUT2_DUTY_CYCLE = 0.500,
parameter real CLKOUT2_PHASE = 0.000,
parameter integer CLKOUT3_DIVIDE = 1,
parameter real CLKOUT3_DUTY_CYCLE = 0.500,
parameter real CLKOUT3_PHASE = 0.000,
parameter integer CLKOUT4_DIVIDE = 1,
parameter real CLKOUT4_DUTY_CYCLE = 0.500,
parameter real CLKOUT4_PHASE = 0.000,
parameter integer CLKOUT5_DIVIDE = 1,
parameter real CLKOUT5_DUTY_CYCLE = 0.500,
parameter real CLKOUT5_PHASE = 0.000,
parameter COMPENSATION = "ZHOLD",
parameter integer DIVCLK_DIVIDE = 1,
parameter [0:0] IS_CLKINSEL_INVERTED = 1'b0,
parameter [0:0] IS_PWRDWN_INVERTED = 1'b0,
parameter [0:0] IS_RST_INVERTED = 1'b0,
parameter real REF_JITTER1 = 0.010,
parameter real REF_JITTER2 = 0.010,
parameter STARTUP_WAIT = "FALSE"
)(
output CLKOUT0,
output CLKOUT1,
output CLKOUT2,
output CLKOUT3,
output CLKOUT4,
output CLKOUT5,
output [15:0] DO,
output DRDY,
output LOCKED,
output CLKFBOUT,
input CLKFBIN,
input CLKIN1,
input CLKIN2,
input CLKINSEL,
input [6:0] DADDR,
input DCLK,
input DEN,
input [15:0] DI,
input DWE,
input PWRDWN,
input RST
);
//#LOCAL DERIVED PARAMETERS
localparam real VCO_PERIOD = (CLKIN1_PERIOD * DIVCLK_DIVIDE) / CLKFBOUT_MULT;
localparam real CLK0_DELAY = VCO_PERIOD * CLKOUT0_DIVIDE * (CLKOUT0_PHASE/360);
localparam real CLK1_DELAY = VCO_PERIOD * CLKOUT1_DIVIDE * (CLKOUT1_PHASE/360);
localparam real CLK2_DELAY = VCO_PERIOD * CLKOUT2_DIVIDE * (CLKOUT2_PHASE/360);
localparam real CLK3_DELAY = VCO_PERIOD * CLKOUT3_DIVIDE * (CLKOUT3_PHASE/360);
localparam real CLK4_DELAY = VCO_PERIOD * CLKOUT4_DIVIDE * (CLKOUT4_PHASE/360);
localparam real CLK5_DELAY = VCO_PERIOD * CLKOUT5_DIVIDE * (CLKOUT5_PHASE/360);
localparam phases = CLKFBOUT_MULT / DIVCLK_DIVIDE;
//########################################################################
//# POR
//########################################################################
//ugly POR reset
reg POR;
initial
begin
POR=1'b1;
#1
POR=1'b0;
end
//async reset
wire reset;
assign reset = POR | RST;
//########################################################################
//# CLOCK MULTIPLIER
//########################################################################
//TODO: implement DIVCLK_DIVIDE
//
integer j;
reg [2*phases-1:0] delay;
always @ (CLKIN1 or reset)
if(reset)
for(j=0; j<(2*phases); j=j+1)
delay[j] <= 1'b0;
else
for(j=0; j<(2*phases); j=j+1)
delay[j] <= #(CLKIN1_PERIOD*j/(2*phases)) CLKIN1;
reg [(phases)-1:0] clk_comb;
always @ (delay)
begin
for(j=0; j<(phases); j=j+1)
clk_comb[j] <= ~reset & delay[2*j] & ~delay[2*j+1];
end
reg vco_clk;
integer k;
always @*
begin
vco_clk = 1'b0;
for(k=0; k<(phases); k=k+1)
vco_clk = vco_clk | clk_comb[k];
end
//##############
//#DIVIDERS
//##############
wire [3:0] DIVCFG[5:0];
wire [5:0] CLKOUT_DIV;
assign DIVCFG[0] = $clog2(CLKOUT0_DIVIDE);
assign DIVCFG[1] = $clog2(CLKOUT1_DIVIDE);
assign DIVCFG[2] = $clog2(CLKOUT2_DIVIDE);
assign DIVCFG[3] = $clog2(CLKOUT3_DIVIDE);
assign DIVCFG[4] = $clog2(CLKOUT4_DIVIDE);
assign DIVCFG[5] = $clog2(CLKOUT5_DIVIDE);
genvar i;
generate for(i=0; i<6; i=i+1)
begin : gen_clkdiv
clock_divider clkdiv (/*AUTOINST*/
// Outputs
.clkout (CLKOUT_DIV[i]),
// Inputs
.clkin (vco_clk),
.divcfg (DIVCFG[i]),
.reset (reset));
end
endgenerate
reg [5:0] CLKOUT_DIV_LOCK;
always @ (posedge (CLKIN1&vco_clk) or negedge (CLKIN1&~vco_clk))
begin
CLKOUT_DIV_LOCK[5:0] <= CLKOUT_DIV[5:0];
end
//##############
//#SUB PHASE DELAY
//##############
reg CLKOUT0;
reg CLKOUT1;
reg CLKOUT2;
reg CLKOUT3;
reg CLKOUT4;
reg CLKOUT5;
always @ (CLKOUT_DIV_LOCK)
begin
CLKOUT0 <= #(CLK0_DELAY) ~reset & CLKOUT_DIV_LOCK[0];
CLKOUT1 <= #(CLK1_DELAY) ~reset & CLKOUT_DIV_LOCK[1];
CLKOUT2 <= #(CLK2_DELAY) ~reset & CLKOUT_DIV_LOCK[2];
CLKOUT3 <= #(CLK3_DELAY) ~reset & CLKOUT_DIV_LOCK[3];
CLKOUT4 <= #(CLK4_DELAY) ~reset & CLKOUT_DIV_LOCK[4];
CLKOUT5 <= #(CLK5_DELAY) ~reset & CLKOUT_DIV_LOCK[5];
end
//##############
//#DUMMY DRIVES
//##############
assign CLKFBOUT=CLKIN1;
//###########################
//#SANITY CHECK LOCK COUNTER
//############################
localparam LCW=4;
reg [LCW-1:0] lock_counter;
always @ (posedge CLKIN1 or posedge reset)
if(reset)
lock_counter[LCW-1:0] <= {(LCW){1'b1}};
else if(~LOCKED)
lock_counter[LCW-1:0] <= lock_counter[LCW-1:0] - 1'b1;
assign LOCKED = ~(|lock_counter[LCW-1:0]);
endmodule // PLLE2_ADV
// Local Variables:
// verilog-library-directories:("." "../../common/hdl")
// End: