1
0
mirror of https://github.com/aolofsson/oh.git synced 2025-01-17 20:02:53 +08:00
oh/elink/hdl/erx_clocks.v
2015-11-06 11:25:05 -05:00

236 lines
6.7 KiB
Verilog

`include "elink_constants.v"
module erx_clocks (/*AUTOARG*/
// Outputs
rx_lclk, rx_lclk_div4, rx_active, erx_reset, erx_io_reset,
// Inputs
sys_reset, soft_reset, tx_active, sys_clk, rx_clkin
);
`ifdef TARGET_SIMPLE
parameter RCW = 4; // reset counter width
`else
parameter RCW = 8; // reset counter width
`endif
//Frequency Settings (Mhz)
parameter FREQ_SYSCLK = 100;
parameter FREQ_RXCLK = 300;
parameter FREQ_IDELAY = 200;
parameter RXCLK_PHASE = 0; //270; //-90 deg rxclk phase shift
parameter PLL_VCO_MULT = 4; //RX
//Don't touch these! (derived parameters)
localparam real RXCLK_PERIOD = 1000.000000/FREQ_RXCLK;
localparam integer IREF_DIVIDE = PLL_VCO_MULT * FREQ_RXCLK/FREQ_IDELAY;
localparam integer RXCLK_DIVIDE = PLL_VCO_MULT; //1:1
//Input clock, reset, config interface
input sys_reset; // por reset (hw)
input soft_reset; // rx enable signal (sw)
input tx_active; // tx active input
//Main input clocks
input sys_clk; // always on input clk cclk/TX MMCM
input rx_clkin; // input clk for RX only PLL
//RX Clocks
output rx_lclk; // rx high speed clock for DDR IO
output rx_lclk_div4; // rx slow clock for logic
//Reset
output rx_active; // rx active
output erx_reset; // reset for rx core logic
output erx_io_reset; // io reset (synced to high speed clock)
//############
//# WIRES
//############
//Idelay controller
wire idelay_reset;
wire idelay_ready; //ignore this?
wire idelay_ref_clk;
//pll outputs
wire rx_lclk_pll;
wire rx_lclk_div4_pll;
wire idelay_ref_clk_pll;
//PLL
wire rx_lclk_fb;
// wire rx_lclk_fb_out;
//###########################
// RESET STATE MACHINE
//###########################
reg [RCW:0] reset_counter = 'b0; //works b/c of free running counter!
reg heartbeat;
reg pll_locked_reg;
reg pll_locked_sync;
reg [2:0] reset_state;
wire pll_reset;
reg [1:0] reset_pipe_lclkb;
reg [1:0] reset_pipe_lclk_div4b;
//wrap around counter that generates a 1 cycle heartbeat
//free running counter...
always @ (posedge sys_clk)
begin
reset_counter[RCW-1:0] <= reset_counter[RCW-1:0]+1'b1;
heartbeat <= ~(|reset_counter[RCW-1:0]);
end
//two clock synchronizer
always @ (posedge sys_clk)
begin
pll_locked_reg <= pll_locked;
pll_locked_sync <= pll_locked_reg;
end
`define RESET_ALL 3'b000
`define START_PLL 3'b001
`define ACTIVE 3'b010
//Reset sequence state machine
always @ (posedge sys_clk or posedge reset_in)
if(reset_in)
reset_state[2:0] <= `RESET_ALL;
else if(heartbeat)
case(reset_state[2:0])
`RESET_ALL :
if(~soft_reset)
reset_state[2:0] <= `START_PLL;
`START_PLL :
if(pll_locked_sync & idelay_ready)
reset_state[2:0] <= `ACTIVE;
`ACTIVE:
if(soft_reset)
reset_state[2:0] <= `RESET_ALL; //stay there until next reset
endcase // case (reset_state[2:0])
//reset PLL during 'reset' and during quiet time around reset edge
assign reset_in = sys_reset | ~tx_active;
assign pll_reset = (reset_state[2:0]==`RESET_ALL);
assign idelay_reset = (reset_state[2:0]==`RESET_ALL);
//asynch rx reset
assign rx_reset = (reset_state[2:0] != `ACTIVE);
//active indicator
assign rx_active = (reset_state[2:0] == `ACTIVE);
//#############################
//#RESET SYNC
//#############################
//async assert
//sync deassert
//lclk sync
always @ (posedge rx_lclk or posedge rx_reset)
if(rx_reset)
reset_pipe_lclkb[1:0] <= 2'b00;
else
reset_pipe_lclkb[1:0] <= {reset_pipe_lclkb[0], 1'b1};
assign erx_io_reset = ~reset_pipe_lclkb[1];
//lclkdiv4 sync
always @ (posedge rx_lclk_div4 or posedge rx_reset)
if(rx_reset)
reset_pipe_lclk_div4b[1:0] <= 2'b00;
else
reset_pipe_lclk_div4b[1:0] <= {reset_pipe_lclk_div4b[0],1'b1};
assign erx_reset = ~reset_pipe_lclk_div4b[1];
`ifdef TARGET_XILINX
//###########################
// PLL RX
//###########################
PLLE2_ADV
#(
.BANDWIDTH("OPTIMIZED"),
.CLKFBOUT_MULT(PLL_VCO_MULT),
.CLKFBOUT_PHASE(0.0),
.CLKIN1_PERIOD(RXCLK_PERIOD),
.CLKOUT0_DIVIDE(128),
.CLKOUT1_DIVIDE(128),
.CLKOUT2_DIVIDE(128),
.CLKOUT3_DIVIDE(IREF_DIVIDE), // idelay ref clk
.CLKOUT4_DIVIDE(RXCLK_DIVIDE), // rx_lclk
.CLKOUT5_DIVIDE(RXCLK_DIVIDE*4), // rx_lclk_div4
.CLKOUT0_DUTY_CYCLE(0.5),
.CLKOUT1_DUTY_CYCLE(0.5),
.CLKOUT2_DUTY_CYCLE(0.5),
.CLKOUT3_DUTY_CYCLE(0.5),
.CLKOUT4_DUTY_CYCLE(0.5),
.CLKOUT5_DUTY_CYCLE(0.5),
.CLKOUT0_PHASE(0.0),
.CLKOUT1_PHASE(0.0),
.CLKOUT2_PHASE(0.0),
.CLKOUT3_PHASE(0.0),
.CLKOUT4_PHASE(0.0),//RXCLK_PHASE
.CLKOUT5_PHASE(0.0),//RXCLK_PHASE/4
.DIVCLK_DIVIDE(1.0),
.REF_JITTER1(0.01),
.STARTUP_WAIT("FALSE")
) pll_rx
(
.CLKOUT0(),
.CLKOUT1(),
.CLKOUT2(),
.CLKOUT3(idelay_ref_clk_pll),
.CLKOUT4(rx_lclk_pll),
.CLKOUT5(rx_lclk_div4_pll),
.PWRDWN(1'b0),
.RST(pll_reset),
.CLKFBIN(rx_lclk_fb),
.CLKFBOUT(rx_lclk_fb),
.CLKIN1(rx_clkin),
.CLKIN2(1'b0),
.CLKINSEL(1'b1),
.DADDR(7'b0),
.DCLK(1'b0),
.DEN(1'b0),
.DI(16'b0),
.DWE(1'b0),
.DRDY(),
.DO(),
.LOCKED(pll_locked)
);
//Clock network
BUFG i_lclk_bufg (.I(rx_lclk_pll), .O(rx_lclk)); //300Mhz
BUFG i_lclk_div4_bufg (.I(rx_lclk_div4_pll), .O(rx_lclk_div4)); //75 MHz (300/4)
BUFG i_idelay__bufg (.I(idelay_ref_clk_pll),.O(idelay_ref_clk));//idelay ctrl clock
// BUFG i_lclk_fb_bufg (.I(rx_lclk_fb_out), .O(rx_lclk_fb_in)); //feedback buffer
//###########################
// Idelay controller
//###########################
(* IODELAY_GROUP = "IDELAY_GROUP" *) // Group name for IDELAYCTRL
IDELAYCTRL idelayctrl_inst
(
.RDY(idelay_ready), // check ready flag in reset sequence?
.REFCLK(idelay_ref_clk),//200MHz clk (78ps tap delay)
.RST(idelay_reset));
`endif // `ifdef TARGET_XILINX
endmodule // eclocks
// Local Variables:
// verilog-library-directories:("." "../../common/hdl")
// End: