1
0
mirror of https://github.com/aolofsson/oh.git synced 2025-01-30 02:32:53 +08:00
oh/xilibs/dv/PLLE2_ADV.v
aolofsson 289024fd89 Flattening directory tree (again)
- Creating an arbitrary 'src' directory really doesn't help much...
- Goal is to make each folder self contained
- Make meta repos and individual repos have the same directory structure
2022-06-21 14:48:48 -04:00

270 lines
7.5 KiB
Verilog

/* verilator lint_off STMTDLY */
/* verilator lint_off WIDTH */
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
CLKDIV clkdiv (// Outputs
.clkout (CLKOUT_DIV[i]),
// Inputs
.clkin (vco_clk),
.divcfg (DIVCFG[i]),
.reset (reset));
end
endgenerate
reg [5:0] CLKOUT_DIV_LOCK;
`ifdef TARGET_VERILATOR
initial
begin
$display("ERROR: PLL divider not implemented");
end
`else
always @ (posedge (CLKIN1 & vco_clk) or negedge (CLKIN1&~vco_clk))
begin
CLKOUT_DIV_LOCK[5:0] = CLKOUT_DIV[5:0];
end
`endif
//##############
//#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:
// ###############################################################
// # FUNCTION: Synchronous clock divider that divides by integer
// ###############################################################
module oh_clockdiv_model(/*AUTOARG*/
// Outputs
clkout,
// Inputs
clkin, divcfg, reset
);
input clkin; // Input clock
input [3:0] divcfg; // Divide factor (1-128)
input reset; // Counter init
output clkout; // Divided clock phase aligned with clkin
reg clkout_reg;
reg [7:0] counter;
reg [7:0] divcfg_dec;
reg [3:0] divcfg_reg;
wire div_bp;
wire posedge_match;
wire negedge_match;
// ###################
// # Decode divcfg
// ###################
always @ (divcfg[3:0])
casez (divcfg[3:0])
4'b0001 : divcfg_dec[7:0] = 8'b00000010; // Divide by 2
4'b0010 : divcfg_dec[7:0] = 8'b00000100; // Divide by 4
4'b0011 : divcfg_dec[7:0] = 8'b00001000; // Divide by 8
4'b0100 : divcfg_dec[7:0] = 8'b00010000; // Divide by 16
4'b0101 : divcfg_dec[7:0] = 8'b00100000; // Divide by 32
4'b0110 : divcfg_dec[7:0] = 8'b01000000; // Divide by 64
4'b0111 : divcfg_dec[7:0] = 8'b10000000; // Divide by 128
default : divcfg_dec[7:0] = 8'b00000000; // others
endcase
always @ (posedge clkin or posedge reset)
if(reset)
counter[7:0] <= 8'b00000001;
else if(posedge_match)
counter[7:0] <= 8'b00000001;// Self resetting
else
counter[7:0] <= (counter[7:0] + 8'b00000001);
assign posedge_match = (counter[7:0]==divcfg_dec[7:0]);
assign negedge_match = (counter[7:0]=={1'b0,divcfg_dec[7:1]});
always @ (posedge clkin or posedge reset)
if(reset)
clkout_reg <= 1'b0;
else if(posedge_match)
clkout_reg <= 1'b1;
else if(negedge_match)
clkout_reg <= 1'b0;
//Divide by one bypass
assign div_bp = (divcfg[3:0]==4'b0000);
assign clkout = div_bp ? clkin : clkout_reg;
endmodule // oh_clockdiv