mirror of
https://github.com/aolofsson/oh.git
synced 2025-01-30 02:32:53 +08:00
6e93d0399a
-This needs to be resolved! Currently there is a simulation problem with the PLL and IDDR circuit, likely due to the clock divider. Amazingly enough the circuit works in sim and FPGA, but there was some redundant logic hiding this. -Need to take a closer look at this to get the non-blocking/blocking right in PLL and CLKDIV
204 lines
5.5 KiB
Verilog
204 lines
5.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
|
|
oh_clockdiv 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:
|
|
|