//////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////
|
// //
|
// //
|
// Clock and Resets //
|
// Clock and Resets //
|
// //
|
// //
|
// This file is part of the Amber project //
|
// This file is part of the Amber project //
|
// http://www.opencores.org/project,amber //
|
// http://www.opencores.org/project,amber //
|
// //
|
// //
|
// Description //
|
// Description //
|
// Takes in the 200MHx board clock and generates the main //
|
// Takes in the 200MHx board clock and generates the main //
|
// system clock. For the FPGA this is done with a PLL. //
|
// system clock. For the FPGA this is done with a PLL. //
|
// //
|
// //
|
// Author(s): //
|
// Author(s): //
|
// - Conor Santifort, csantifort.amber@gmail.com //
|
// - Conor Santifort, csantifort.amber@gmail.com //
|
// //
|
// //
|
//////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////
|
// //
|
// //
|
// Copyright (C) 2010 Authors and OPENCORES.ORG //
|
// Copyright (C) 2010 Authors and OPENCORES.ORG //
|
// //
|
// //
|
// This source file may be used and distributed without //
|
// This source file may be used and distributed without //
|
// restriction provided that this copyright statement is not //
|
// restriction provided that this copyright statement is not //
|
// removed from the file and that any derivative work contains //
|
// removed from the file and that any derivative work contains //
|
// the original copyright notice and the associated disclaimer. //
|
// the original copyright notice and the associated disclaimer. //
|
// //
|
// //
|
// This source file is free software; you can redistribute it //
|
// This source file is free software; you can redistribute it //
|
// and/or modify it under the terms of the GNU Lesser General //
|
// and/or modify it under the terms of the GNU Lesser General //
|
// Public License as published by the Free Software Foundation; //
|
// Public License as published by the Free Software Foundation; //
|
// either version 2.1 of the License, or (at your option) any //
|
// either version 2.1 of the License, or (at your option) any //
|
// later version. //
|
// later version. //
|
// //
|
// //
|
// This source is distributed in the hope that it will be //
|
// This source is distributed in the hope that it will be //
|
// useful, but WITHOUT ANY WARRANTY; without even the implied //
|
// useful, but WITHOUT ANY WARRANTY; without even the implied //
|
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //
|
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //
|
// PURPOSE. See the GNU Lesser General Public License for more //
|
// PURPOSE. See the GNU Lesser General Public License for more //
|
// details. //
|
// details. //
|
// //
|
// //
|
// You should have received a copy of the GNU Lesser General //
|
// You should have received a copy of the GNU Lesser General //
|
// Public License along with this source; if not, download it //
|
// Public License along with this source; if not, download it //
|
// from http://www.opencores.org/lgpl.shtml //
|
// from http://www.opencores.org/lgpl.shtml //
|
// //
|
// //
|
//////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
//
|
// Clocks and Resets Module
|
// Clocks and Resets Module
|
//
|
//
|
|
|
module clocks_resets (
|
module clocks_resets (
|
input i_brd_rst,
|
input i_brd_rst,
|
input i_brd_clk_n,
|
input i_brd_clk_n,
|
input i_brd_clk_p,
|
input i_brd_clk_p,
|
input i_ddr_calib_done,
|
input i_ddr_calib_done,
|
output o_sys_rst,
|
output o_sys_rst,
|
output o_sys_clk,
|
output o_sys_clk,
|
output o_clk_200
|
output o_clk_200
|
|
|
);
|
);
|
|
|
|
|
wire calib_done_33mhz;
|
wire calib_done_33mhz;
|
wire rst0;
|
wire rst0;
|
|
|
assign o_sys_rst = rst0 || !calib_done_33mhz;
|
assign o_sys_rst = rst0 || !calib_done_33mhz;
|
|
|
|
|
|
|
`ifdef XILINX_FPGA
|
`ifdef XILINX_FPGA
|
|
|
localparam RST_SYNC_NUM = 25;
|
localparam RST_SYNC_NUM = 25;
|
wire pll_locked;
|
wire pll_locked;
|
wire clkfbout_clkfbin;
|
wire clkfbout_clkfbin;
|
reg [RST_SYNC_NUM-1:0] rst0_sync_r /* synthesis syn_maxfan = 10 */;
|
reg [RST_SYNC_NUM-1:0] rst0_sync_r /* synthesis syn_maxfan = 10 */;
|
reg [RST_SYNC_NUM-1:0] ddr_calib_done_sync_r /* synthesis syn_maxfan = 10 */;
|
reg [RST_SYNC_NUM-1:0] ddr_calib_done_sync_r /* synthesis syn_maxfan = 10 */;
|
wire rst_tmp;
|
wire rst_tmp;
|
wire pll_clk;
|
wire pll_clk;
|
|
|
(* KEEP = "TRUE" *) wire brd_clk_ibufg;
|
(* KEEP = "TRUE" *) wire brd_clk_ibufg;
|
|
|
|
|
IBUFGDS # (
|
IBUFGDS # (
|
.DIFF_TERM ( "TRUE" ),
|
.DIFF_TERM ( "TRUE" ),
|
.IOSTANDARD ( "LVDS_25" )) // SP605 on chip termination of LVDS clock
|
.IOSTANDARD ( "LVDS_25" )) // SP605 on chip termination of LVDS clock
|
u_ibufgds_brd
|
u_ibufgds_brd
|
(
|
(
|
.I ( i_brd_clk_p ),
|
.I ( i_brd_clk_p ),
|
.IB ( i_brd_clk_n ),
|
.IB ( i_brd_clk_n ),
|
.O ( brd_clk_ibufg )
|
.O ( brd_clk_ibufg )
|
);
|
);
|
|
|
|
|
assign rst0 = rst0_sync_r[RST_SYNC_NUM-1];
|
assign rst0 = rst0_sync_r[RST_SYNC_NUM-1];
|
assign calib_done_33mhz = ddr_calib_done_sync_r[RST_SYNC_NUM-1];
|
assign calib_done_33mhz = ddr_calib_done_sync_r[RST_SYNC_NUM-1];
|
assign o_clk_200 = brd_clk_ibufg;
|
assign o_clk_200 = brd_clk_ibufg;
|
|
|
|
|
`ifdef XILINX_SPARTAN6_FPGA
|
`ifdef XILINX_SPARTAN6_FPGA
|
// ======================================
|
// ======================================
|
// Xilinx Spartan-6 PLL
|
// Xilinx Spartan-6 PLL
|
// ======================================
|
// ======================================
|
PLL_ADV #
|
PLL_ADV #
|
(
|
(
|
.BANDWIDTH ( "OPTIMIZED" ),
|
.BANDWIDTH ( "OPTIMIZED" ),
|
.CLKIN1_PERIOD ( 5 ),
|
.CLKIN1_PERIOD ( 5 ),
|
.CLKIN2_PERIOD ( 1 ),
|
.CLKIN2_PERIOD ( 1 ),
|
.CLKOUT0_DIVIDE ( 1 ),
|
.CLKOUT0_DIVIDE ( 1 ),
|
.CLKOUT1_DIVIDE ( ),
|
.CLKOUT1_DIVIDE ( ),
|
.CLKOUT2_DIVIDE ( `AMBER_CLK_DIVIDER ), // = 800 MHz / LP_CLK_DIVIDER
|
.CLKOUT2_DIVIDE ( `AMBER_CLK_DIVIDER ), // = 800 MHz / LP_CLK_DIVIDER
|
.CLKOUT3_DIVIDE ( 1 ),
|
.CLKOUT3_DIVIDE ( 1 ),
|
.CLKOUT4_DIVIDE ( 1 ),
|
.CLKOUT4_DIVIDE ( 1 ),
|
.CLKOUT5_DIVIDE ( 1 ),
|
.CLKOUT5_DIVIDE ( 1 ),
|
.CLKOUT0_PHASE ( 0.000 ),
|
.CLKOUT0_PHASE ( 0.000 ),
|
.CLKOUT1_PHASE ( 0.000 ),
|
.CLKOUT1_PHASE ( 0.000 ),
|
.CLKOUT2_PHASE ( 0.000 ),
|
.CLKOUT2_PHASE ( 0.000 ),
|
.CLKOUT3_PHASE ( 0.000 ),
|
.CLKOUT3_PHASE ( 0.000 ),
|
.CLKOUT4_PHASE ( 0.000 ),
|
.CLKOUT4_PHASE ( 0.000 ),
|
.CLKOUT5_PHASE ( 0.000 ),
|
.CLKOUT5_PHASE ( 0.000 ),
|
.CLKOUT0_DUTY_CYCLE ( 0.500 ),
|
.CLKOUT0_DUTY_CYCLE ( 0.500 ),
|
.CLKOUT1_DUTY_CYCLE ( 0.500 ),
|
.CLKOUT1_DUTY_CYCLE ( 0.500 ),
|
.CLKOUT2_DUTY_CYCLE ( 0.500 ),
|
.CLKOUT2_DUTY_CYCLE ( 0.500 ),
|
.CLKOUT3_DUTY_CYCLE ( 0.500 ),
|
.CLKOUT3_DUTY_CYCLE ( 0.500 ),
|
.CLKOUT4_DUTY_CYCLE ( 0.500 ),
|
.CLKOUT4_DUTY_CYCLE ( 0.500 ),
|
.CLKOUT5_DUTY_CYCLE ( 0.500 ),
|
.CLKOUT5_DUTY_CYCLE ( 0.500 ),
|
.COMPENSATION ( "INTERNAL" ),
|
.COMPENSATION ( "INTERNAL" ),
|
.DIVCLK_DIVIDE ( 1 ),
|
.DIVCLK_DIVIDE ( 1 ),
|
.CLKFBOUT_MULT ( 4 ), // 200 MHz clock input, x4 to get 800 MHz MCB
|
.CLKFBOUT_MULT ( 4 ), // 200 MHz clock input, x4 to get 800 MHz MCB
|
.CLKFBOUT_PHASE ( 0.0 ),
|
.CLKFBOUT_PHASE ( 0.0 ),
|
.REF_JITTER ( 0.005000 )
|
.REF_JITTER ( 0.005000 )
|
)
|
)
|
u_pll_adv
|
u_pll_adv
|
(
|
(
|
.CLKFBIN ( clkfbout_clkfbin ),
|
.CLKFBIN ( clkfbout_clkfbin ),
|
.CLKINSEL ( 1'b1 ),
|
.CLKINSEL ( 1'b1 ),
|
.CLKIN1 ( brd_clk_ibufg ),
|
.CLKIN1 ( brd_clk_ibufg ),
|
.CLKIN2 ( 1'b0 ),
|
.CLKIN2 ( 1'b0 ),
|
.DADDR ( 5'b0 ),
|
.DADDR ( 5'b0 ),
|
.DCLK ( 1'b0 ),
|
.DCLK ( 1'b0 ),
|
.DEN ( 1'b0 ),
|
.DEN ( 1'b0 ),
|
.DI ( 16'b0 ),
|
.DI ( 16'b0 ),
|
.DWE ( 1'b0 ),
|
.DWE ( 1'b0 ),
|
.REL ( 1'b0 ),
|
.REL ( 1'b0 ),
|
.RST ( i_brd_rst ),
|
.RST ( i_brd_rst ),
|
.CLKFBDCM ( ),
|
.CLKFBDCM ( ),
|
.CLKFBOUT ( clkfbout_clkfbin ),
|
.CLKFBOUT ( clkfbout_clkfbin ),
|
.CLKOUTDCM0 ( ),
|
.CLKOUTDCM0 ( ),
|
.CLKOUTDCM1 ( ),
|
.CLKOUTDCM1 ( ),
|
.CLKOUTDCM2 ( ),
|
.CLKOUTDCM2 ( ),
|
.CLKOUTDCM3 ( ),
|
.CLKOUTDCM3 ( ),
|
.CLKOUTDCM4 ( ),
|
.CLKOUTDCM4 ( ),
|
.CLKOUTDCM5 ( ),
|
.CLKOUTDCM5 ( ),
|
.CLKOUT0 ( ),
|
.CLKOUT0 ( ),
|
.CLKOUT1 ( ),
|
.CLKOUT1 ( ),
|
.CLKOUT2 ( pll_clk ),
|
.CLKOUT2 ( pll_clk ),
|
.CLKOUT3 ( ),
|
.CLKOUT3 ( ),
|
.CLKOUT4 ( ),
|
.CLKOUT4 ( ),
|
.CLKOUT5 ( ),
|
.CLKOUT5 ( ),
|
.DO ( ),
|
.DO ( ),
|
.DRDY ( ),
|
.DRDY ( ),
|
.LOCKED ( pll_locked )
|
.LOCKED ( pll_locked )
|
);
|
);
|
`endif
|
`endif
|
|
|
|
|
`ifdef XILINX_VIRTEX6_FPGA
|
`ifdef XILINX_VIRTEX6_FPGA
|
// ======================================
|
// ======================================
|
// Xilinx Virtex-6 PLL
|
// Xilinx Virtex-6 PLL
|
// ======================================
|
// ======================================
|
MMCM_ADV #
|
MMCM_ADV #
|
(
|
(
|
.CLKIN1_PERIOD ( 5 ), // 200 MHz
|
.CLKIN1_PERIOD ( 5 ), // 200 MHz
|
.CLKOUT2_DIVIDE ( `AMBER_CLK_DIVIDER ),
|
.CLKOUT2_DIVIDE ( `AMBER_CLK_DIVIDER ),
|
.CLKFBOUT_MULT_F ( 5 ) // 200 MHz x 5 = 1000 MHz
|
.CLKFBOUT_MULT_F ( 5 ) // 200 MHz x 5 = 1000 MHz
|
)
|
)
|
u_pll_adv
|
u_pll_adv
|
(
|
(
|
.CLKFBOUT ( clkfbout_clkfbin ),
|
.CLKFBOUT ( clkfbout_clkfbin ),
|
.CLKFBOUTB ( ),
|
.CLKFBOUTB ( ),
|
.CLKFBSTOPPED ( ),
|
.CLKFBSTOPPED ( ),
|
.CLKINSTOPPED ( ),
|
.CLKINSTOPPED ( ),
|
.CLKOUT0 ( ),
|
.CLKOUT0 ( ),
|
.CLKOUT0B ( ),
|
.CLKOUT0B ( ),
|
.CLKOUT1 ( ),
|
.CLKOUT1 ( ),
|
.CLKOUT1B ( ),
|
.CLKOUT1B ( ),
|
.CLKOUT2 ( pll_clk ),
|
.CLKOUT2 ( pll_clk ),
|
.CLKOUT2B ( ),
|
.CLKOUT2B ( ),
|
.CLKOUT3 ( ),
|
.CLKOUT3 ( ),
|
.CLKOUT3B ( ),
|
.CLKOUT3B ( ),
|
.CLKOUT4 ( ),
|
.CLKOUT4 ( ),
|
.CLKOUT5 ( ),
|
.CLKOUT5 ( ),
|
.CLKOUT6 ( ),
|
.CLKOUT6 ( ),
|
.DRDY ( ),
|
.DRDY ( ),
|
.LOCKED ( pll_locked ),
|
.LOCKED ( pll_locked ),
|
.PSDONE ( ),
|
.PSDONE ( ),
|
.DO ( ),
|
.DO ( ),
|
.CLKFBIN ( clkfbout_clkfbin ),
|
.CLKFBIN ( clkfbout_clkfbin ),
|
.CLKIN1 ( brd_clk_ibufg ),
|
.CLKIN1 ( brd_clk_ibufg ),
|
.CLKIN2 ( 1'b0 ),
|
.CLKIN2 ( 1'b0 ),
|
.CLKINSEL ( 1'b1 ),
|
.CLKINSEL ( 1'b1 ),
|
.DCLK ( 1'b0 ),
|
.DCLK ( 1'b0 ),
|
.DEN ( 1'b0 ),
|
.DEN ( 1'b0 ),
|
.DWE ( 1'b0 ),
|
.DWE ( 1'b0 ),
|
.PSCLK ( 1'd0 ),
|
.PSCLK ( 1'd0 ),
|
.PSEN ( 1'd0 ),
|
.PSEN ( 1'd0 ),
|
.PSINCDEC ( 1'd0 ),
|
.PSINCDEC ( 1'd0 ),
|
.PWRDWN ( 1'd0 ),
|
.PWRDWN ( 1'd0 ),
|
.RST ( i_brd_rst ),
|
.RST ( i_brd_rst ),
|
.DI ( 16'b0 ),
|
.DI ( 16'b0 ),
|
.DADDR ( 7'b0 )
|
.DADDR ( 7'b0 )
|
);
|
);
|
`endif
|
`endif
|
|
|
|
|
BUFG u_bufg_sys_clk (
|
BUFG u_bufg_sys_clk (
|
.O ( o_sys_clk ),
|
.O ( o_sys_clk ),
|
.I ( pll_clk )
|
.I ( pll_clk )
|
);
|
);
|
|
|
|
|
// ======================================
|
// ======================================
|
// Synchronous reset generation
|
// Synchronous reset generation
|
// ======================================
|
// ======================================
|
assign rst_tmp = i_brd_rst | ~pll_locked;
|
assign rst_tmp = i_brd_rst | ~pll_locked;
|
|
|
// synthesis attribute max_fanout of rst0_sync_r is 10
|
// synthesis attribute max_fanout of rst0_sync_r is 10
|
always @(posedge o_sys_clk or posedge rst_tmp)
|
always @(posedge o_sys_clk or posedge rst_tmp)
|
if (rst_tmp)
|
if (rst_tmp)
|
rst0_sync_r <= {RST_SYNC_NUM{1'b1}};
|
rst0_sync_r <= {RST_SYNC_NUM{1'b1}};
|
else
|
else
|
// logical left shift by one (pads with 0)
|
// logical left shift by one (pads with 0)
|
rst0_sync_r <= rst0_sync_r << 1;
|
rst0_sync_r <= rst0_sync_r << 1;
|
|
|
always @(posedge o_sys_clk or posedge rst_tmp)
|
always @(posedge o_sys_clk or posedge rst_tmp)
|
if (rst_tmp)
|
if (rst_tmp)
|
ddr_calib_done_sync_r <= {RST_SYNC_NUM{1'b0}};
|
ddr_calib_done_sync_r <= {RST_SYNC_NUM{1'b0}};
|
else
|
else
|
ddr_calib_done_sync_r <= {ddr_calib_done_sync_r[RST_SYNC_NUM-2:0], i_ddr_calib_done};
|
ddr_calib_done_sync_r <= {ddr_calib_done_sync_r[RST_SYNC_NUM-2:0], i_ddr_calib_done};
|
|
|
`endif
|
`endif
|
|
|
|
|
|
|
`ifndef XILINX_FPGA
|
`ifndef XILINX_FPGA
|
|
|
localparam [7:0] FULL_COUNT = `AMBER_CLK_DIVIDER / 4;
|
real brd_clk_period = 6000; // use starting value of 6000pS
|
localparam [7:0] HALF_COUNT = FULL_COUNT / 2;
|
real pll_clk_period = 1000; // use starting value of 1000pS
|
|
real brd_temp;
|
// e.g. Divide clock by 6 to get 33MHz
|
reg pll_clk_beh;
|
reg [7:0] clk_div_count;
|
reg sys_clk_beh;
|
|
integer pll_div_count = 0;
|
|
|
|
// measure input clock period
|
initial
|
initial
|
begin
|
begin
|
clk_div_count <= FULL_COUNT - 1'd3;
|
@ (posedge i_brd_clk_p)
|
forever @ (posedge i_brd_clk_p)
|
brd_temp = $time;
|
if ( clk_div_count == ( FULL_COUNT - 1'd1 ) )
|
@ (posedge i_brd_clk_p)
|
clk_div_count <= 8'h0;
|
brd_clk_period = $time - brd_temp;
|
|
pll_clk_period = brd_clk_period / 4;
|
|
end
|
|
|
|
// Generate an 800MHz pll clock based off the input clock
|
|
always @( posedge i_brd_clk_p )
|
|
begin
|
|
pll_clk_beh = 1'd1;
|
|
# ( pll_clk_period / 2 )
|
|
pll_clk_beh = 1'd0;
|
|
# ( pll_clk_period / 2 )
|
|
|
|
pll_clk_beh = 1'd1;
|
|
# ( pll_clk_period / 2 )
|
|
pll_clk_beh = 1'd0;
|
|
# ( pll_clk_period / 2 )
|
|
|
|
pll_clk_beh = 1'd1;
|
|
# ( pll_clk_period / 2 )
|
|
pll_clk_beh = 1'd0;
|
|
# ( pll_clk_period / 2 )
|
|
|
|
pll_clk_beh = 1'd1;
|
|
# ( pll_clk_period / 2 )
|
|
pll_clk_beh = 1'd0;
|
|
|
|
end
|
|
|
|
// Divide the pll clock down to get the system clock
|
|
always @( pll_clk_beh )
|
|
begin
|
|
if ( pll_div_count == (
|
|
`AMBER_CLK_DIVIDER
|
|
* 2 ) - 1 )
|
|
pll_div_count <= 'd0;
|
else
|
else
|
clk_div_count <= clk_div_count + 1'd1;
|
pll_div_count <= pll_div_count + 1'd1;
|
|
|
|
if ( pll_div_count == 0 )
|
|
sys_clk_beh = 1'd1;
|
|
else if ( pll_div_count ==
|
|
`AMBER_CLK_DIVIDER
|
|
)
|
|
sys_clk_beh = 1'd0;
|
end
|
end
|
|
|
assign o_sys_clk = clk_div_count < HALF_COUNT;
|
assign o_sys_clk = sys_clk_beh;
|
assign rst0 = i_brd_rst;
|
assign rst0 = i_brd_rst;
|
assign calib_done_33mhz = 1'd1;
|
assign calib_done_33mhz = 1'd1;
|
assign o_clk_200 = i_brd_clk_p;
|
assign o_clk_200 = i_brd_clk_p;
|
|
|
`endif
|
`endif
|
|
|
|
|
endmodule
|
endmodule
|
|
|
|
|
|
|