360 lines
12 KiB
VHDL
360 lines
12 KiB
VHDL
--#############################################################
|
|
-- Author : Boris Keil, Stefan Ritt
|
|
-- Contents : Use external 33 MHz to generate internal clocks
|
|
-- via DCMs
|
|
-- $Id: usr_clocks.vhd 8369 2007-07-06 14:47:25Z ritt@PSI.CH $
|
|
--#############################################################
|
|
|
|
library ieee;
|
|
use ieee.std_logic_1164.all;
|
|
use ieee.std_logic_arith.all;
|
|
use ieee.std_logic_unsigned.all;
|
|
use ieee.numeric_std.all;
|
|
-- synopsys translate_off
|
|
library UNISIM;
|
|
use UNISIM.Vcomponents.all;
|
|
-- synopsys translate_on
|
|
|
|
entity usr_clocks is
|
|
port (
|
|
P_I_CLK33 : in std_logic;
|
|
P_I_CLK66 : in std_logic;
|
|
O_CLK33 : out std_logic;
|
|
O_CLK33_NODLL : out std_logic;
|
|
O_CLK66 : out std_logic;
|
|
O_CLK132 : out std_logic;
|
|
O_CLK264 : out std_logic;
|
|
I_PS_VALUE : in std_logic_vector(7 downto 0);
|
|
O_CLK_PS : out std_logic;
|
|
O_LOCKED : out std_logic;
|
|
O_DEBUG1 : out std_logic;
|
|
O_DEBUG2 : out std_logic
|
|
);
|
|
end usr_clocks;
|
|
|
|
architecture arch of usr_clocks is
|
|
attribute BOX_TYPE : STRING ;
|
|
|
|
-- xilinx cores
|
|
|
|
component IBUFGDS_LVDS_25
|
|
port(
|
|
O : out std_ulogic;
|
|
I : in std_ulogic;
|
|
IB : in std_ulogic
|
|
);
|
|
end component;
|
|
attribute BOX_TYPE of IBUFGDS_LVDS_25 : component is "PRIMITIVE";
|
|
|
|
component BUFG
|
|
port(
|
|
O : out std_ulogic;
|
|
I : in std_ulogic
|
|
);
|
|
end component;
|
|
attribute BOX_TYPE of BUFG : component is "PRIMITIVE";
|
|
|
|
-- !!! WARNING !!! : The Virtex2Pro has a bug in the DCM
|
|
-- (a silicon bug, i.e. real hardware), the PLL does not
|
|
-- lock properly if the CLK2x output is used for
|
|
-- feedback -> always use CLK1x !!! (Call from Memec,
|
|
-- C. Grivet, 17.12.03)
|
|
|
|
component DCM
|
|
generic (
|
|
CLKDV_DIVIDE : real := 2.0;
|
|
CLKFX_DIVIDE : integer := 1;
|
|
CLKFX_MULTIPLY : integer := 4;
|
|
CLKIN_DIVIDE_BY_2 : boolean := false;
|
|
CLKIN_PERIOD : real := 0.0; --non-simulatable, in nanoseconds
|
|
CLKOUT_PHASE_SHIFT : string := "NONE";
|
|
CLK_FEEDBACK : string := "1X";
|
|
DESKEW_ADJUST : string := "SYSTEM_SYNCHRONOUS"; --non-simulatable
|
|
DFS_FREQUENCY_MODE : string := "LOW";
|
|
DLL_FREQUENCY_MODE : string := "LOW";
|
|
DSS_MODE : string := "NONE"; --non-simulatable
|
|
DUTY_CYCLE_CORRECTION : boolean := true;
|
|
-- MAXPERCLKIN : time := 1000000 ps; --simulation parameter
|
|
-- MAXPERPSCLK : time := 100000000 ps; --simulation parameter
|
|
PHASE_SHIFT : integer := 0;
|
|
-- SIM_CLKIN_CYCLE_JITTER : time := 300 ps; --simulation parameter
|
|
-- SIM_CLKIN_PERIOD_JITTER : time := 1000 ps; --simulation parameter
|
|
STARTUP_WAIT : boolean := false --non-simulatable
|
|
);
|
|
port (
|
|
CLK0 : out std_ulogic := '0';
|
|
CLK180 : out std_ulogic := '0';
|
|
CLK270 : out std_ulogic := '0';
|
|
CLK2X : out std_ulogic := '0';
|
|
CLK2X180 : out std_ulogic := '0';
|
|
CLK90 : out std_ulogic := '0';
|
|
CLKDV : out std_ulogic := '0';
|
|
CLKFX : out std_ulogic := '0';
|
|
CLKFX180 : out std_ulogic := '0';
|
|
LOCKED : out std_ulogic := '0';
|
|
PSDONE : out std_ulogic := '0';
|
|
STATUS : out std_logic_vector(7 downto 0) := "00000000";
|
|
|
|
CLKFB : in std_ulogic := '0';
|
|
CLKIN : in std_ulogic := '0';
|
|
DSSEN : in std_ulogic := '0';
|
|
PSCLK : in std_ulogic := '0';
|
|
PSEN : in std_ulogic := '0';
|
|
PSINCDEC : in std_ulogic := '0';
|
|
RST : in std_ulogic := '0'
|
|
);
|
|
end component;
|
|
attribute BOX_TYPE of DCM : component is "PRIMITIVE";
|
|
|
|
signal clk33_i, clk33, clk66_dcm1, clk66_dcm2, clk132, clk_ps : std_logic;
|
|
signal clk33_tmp, clk66_dcm1_tmp, clk66_dcm2_tmp, clk132_tmp, clk_ps_tmp : std_logic;
|
|
signal locked_dcm1, locked_dcm2, locked_dcm3: std_logic;
|
|
signal dcm2_reset, dcm2_reset_n: std_logic;
|
|
signal dcm2_reset_delay_n: std_logic_vector(4 downto 0);
|
|
|
|
type type_ps_state is (idle, incdec);
|
|
signal ps_state : type_ps_state;
|
|
signal ps_enable, ps_incdec, ps_done: std_logic;
|
|
signal ps_shadow: std_logic_vector(7 downto 0);
|
|
|
|
signal GND: std_logic;
|
|
signal VCC: std_logic;
|
|
|
|
begin
|
|
GND <= '0';
|
|
VCC <= '1';
|
|
|
|
-- Drive clock buffer with input pad oscillator signal
|
|
|
|
inst_bufg_clk33_i: BUFG
|
|
port map (
|
|
I => P_I_CLK33,
|
|
O => clk33_i
|
|
);
|
|
|
|
O_CLK33_NODLL <= clk33_i;
|
|
|
|
-- Use clock buffers for DCM outputs
|
|
|
|
inst_bufg_clk33_dcm1: BUFG
|
|
port map (
|
|
I => clk33_tmp,
|
|
O => clk33
|
|
);
|
|
|
|
inst_bufg_clk66_dcm1: BUFG
|
|
port map (
|
|
I => clk66_dcm1_tmp,
|
|
O => clk66_dcm1
|
|
);
|
|
|
|
inst_bufg_clk66_dcm2: BUFG
|
|
port map (
|
|
I => clk66_dcm2_tmp,
|
|
O => clk66_dcm2
|
|
);
|
|
|
|
inst_bufg_clk132: BUFG
|
|
port map (
|
|
I => clk132_tmp,
|
|
O => clk132
|
|
);
|
|
|
|
inst_bufg_clk_ps: BUFG
|
|
port map (
|
|
I => clk_ps_tmp,
|
|
O => clk_ps
|
|
);
|
|
|
|
Inst_dcm1_clk132: DCM
|
|
generic map (
|
|
CLKDV_DIVIDE => 2.0,
|
|
CLKFX_DIVIDE => 1,
|
|
CLKFX_MULTIPLY => 4,
|
|
CLKIN_DIVIDE_BY_2 => false,
|
|
CLKIN_PERIOD => 30.0, -- in nanoseconds
|
|
CLKOUT_PHASE_SHIFT => "NONE",
|
|
CLK_FEEDBACK => "1X", -- 2X has a silicon bug ...
|
|
DESKEW_ADJUST => "SYSTEM_SYNCHRONOUS", -- OK ?? non-simulatable
|
|
DFS_FREQUENCY_MODE => "LOW",
|
|
DLL_FREQUENCY_MODE => "LOW",
|
|
DSS_MODE => "NONE", --non-simulatable
|
|
DUTY_CYCLE_CORRECTION => true,
|
|
-- MAXPERCLKIN => 1000000 ps, --simulation parameter
|
|
-- MAXPERPSCLK => 100000000 ps, --simulation parameter
|
|
PHASE_SHIFT => 0,
|
|
-- SIM_CLKIN_CYCLE_JITTER => 300 ps, --simulation parameter
|
|
-- SIM_CLKIN_PERIOD_JITTER => 1000 ps, --simulation parameter
|
|
STARTUP_WAIT => true --non-simulatable
|
|
)
|
|
port map (
|
|
-- inputs
|
|
CLKFB => clk33,
|
|
CLKIN => clk33_i,
|
|
DSSEN => GND,
|
|
PSCLK => GND,
|
|
PSEN => GND,
|
|
PSINCDEC => GND,
|
|
RST => GND,
|
|
-- outputs
|
|
CLK0 => clk33_tmp,
|
|
CLK180 => open,
|
|
CLK270 => open,
|
|
CLK2X => clk66_dcm1_tmp,
|
|
CLK2X180 => open,
|
|
CLK90 => open,
|
|
CLKDV => open,
|
|
CLKFX => open,
|
|
CLKFX180 => open,
|
|
LOCKED => locked_dcm1,
|
|
PSDONE => open,
|
|
STATUS => open
|
|
|
|
);
|
|
|
|
Inst_dcm2_clk132: DCM
|
|
generic map (
|
|
CLKDV_DIVIDE => 2.0,
|
|
CLKFX_DIVIDE => 1,
|
|
CLKFX_MULTIPLY => 2,
|
|
CLKIN_DIVIDE_BY_2 => false,
|
|
CLKIN_PERIOD => 15.0, -- in nanoseconds
|
|
CLKOUT_PHASE_SHIFT => "NONE",
|
|
CLK_FEEDBACK => "1X", -- 2X has a silicon bug ...
|
|
DESKEW_ADJUST => "SYSTEM_SYNCHRONOUS", -- OK ?? non-simulatable
|
|
DFS_FREQUENCY_MODE => "LOW",
|
|
DLL_FREQUENCY_MODE => "HIGH",
|
|
DSS_MODE => "NONE", --non-simulatable
|
|
DUTY_CYCLE_CORRECTION => true,
|
|
-- MAXPERCLKIN => 1000000 ps, --simulation parameter
|
|
-- MAXPERPSCLK => 100000000 ps, --simulation parameter
|
|
PHASE_SHIFT => 0,
|
|
-- SIM_CLKIN_CYCLE_JITTER => 300 ps, --simulation parameter
|
|
-- SIM_CLKIN_PERIOD_JITTER => 1000 ps, --simulation parameter
|
|
STARTUP_WAIT => false --non-simulatable
|
|
)
|
|
port map (
|
|
-- inputs
|
|
CLKFB => clk66_dcm2,
|
|
CLKIN => P_I_CLK66,
|
|
DSSEN => GND,
|
|
PSCLK => GND,
|
|
PSEN => GND,
|
|
PSINCDEC => GND,
|
|
RST => dcm2_reset,
|
|
-- outputs
|
|
CLK0 => clk66_dcm2_tmp,
|
|
CLK180 => open,
|
|
CLK270 => open,
|
|
CLK2X => open,
|
|
CLK2X180 => open,
|
|
CLK90 => open,
|
|
CLKDV => open,
|
|
CLKFX => clk132_tmp,
|
|
CLKFX180 => open,
|
|
LOCKED => locked_dcm2,
|
|
PSDONE => open,
|
|
STATUS => open
|
|
|
|
);
|
|
|
|
Inst_dcm3_clk_ps: DCM
|
|
generic map (
|
|
CLKDV_DIVIDE => 2.0,
|
|
CLKFX_DIVIDE => 1,
|
|
CLKFX_MULTIPLY => 2,
|
|
CLKIN_DIVIDE_BY_2 => false,
|
|
CLKIN_PERIOD => 30.0, -- in nanoseconds
|
|
CLKOUT_PHASE_SHIFT => "VARIABLE", -- turn on phase shifting
|
|
CLK_FEEDBACK => "1X",
|
|
DESKEW_ADJUST => "SYSTEM_SYNCHRONOUS",
|
|
DFS_FREQUENCY_MODE => "LOW",
|
|
DLL_FREQUENCY_MODE => "LOW",
|
|
DSS_MODE => "NONE",
|
|
DUTY_CYCLE_CORRECTION => true,
|
|
PHASE_SHIFT => 0,
|
|
STARTUP_WAIT => true
|
|
)
|
|
port map (
|
|
-- inputs
|
|
CLKFB => clk_ps,
|
|
CLKIN => clk33_i,
|
|
DSSEN => GND,
|
|
PSCLK => P_I_CLK33,
|
|
PSEN => ps_enable,
|
|
PSINCDEC => ps_incdec,
|
|
RST => GND,
|
|
-- outputs
|
|
CLK0 => clk_ps_tmp,
|
|
CLK180 => open,
|
|
CLK270 => open,
|
|
CLK2X => open,
|
|
CLK2X180 => open,
|
|
CLK90 => open,
|
|
CLKDV => open,
|
|
CLKFX => open,
|
|
CLKFX180 => open,
|
|
LOCKED => locked_dcm3,
|
|
PSDONE => ps_done,
|
|
STATUS => open
|
|
|
|
);
|
|
|
|
-- DCM2 is reset while DCM1 is not locked, because DCM1 feeds DCM2.
|
|
-- A shift register guarantees a decent (i.e. long) reset pulse.
|
|
proc_delayed_reset: process (P_I_CLK33)
|
|
begin
|
|
if rising_edge(P_I_CLK33) then
|
|
if (locked_dcm1 = '0') then
|
|
dcm2_reset_delay_n <= (others => '0');
|
|
dcm2_reset_n <= '0';
|
|
else
|
|
dcm2_reset_delay_n <= dcm2_reset_delay_n(dcm2_reset_delay_n'high-1 downto 0) & '1';
|
|
dcm2_reset_n <= dcm2_reset_delay_n(dcm2_reset_delay_n'high);
|
|
dcm2_reset <= not dcm2_reset_n;
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
proc_phase_shift: process (P_I_CLK33)
|
|
begin
|
|
if (locked_dcm1 = '0') then
|
|
ps_state <= idle;
|
|
ps_enable <= '0';
|
|
ps_shadow <= (others => '0');
|
|
elsif rising_edge(P_I_CLK33) then
|
|
case (ps_state) is
|
|
when idle =>
|
|
if (TO_SIGNED(CONV_INTEGER(I_PS_VALUE), 8) > TO_SIGNED(CONV_INTEGER(ps_shadow), 8)) then
|
|
ps_enable <= '1';
|
|
ps_incdec <= '1';
|
|
ps_state <= incdec;
|
|
ps_shadow <= ps_shadow + 1;
|
|
elsif (TO_SIGNED(CONV_INTEGER(I_PS_VALUE), 8) < TO_SIGNED(CONV_INTEGER(ps_shadow), 8)) then
|
|
ps_enable <= '1';
|
|
ps_incdec <= '0';
|
|
ps_state <= incdec;
|
|
ps_shadow <= ps_shadow - 1;
|
|
end if;
|
|
when incdec =>
|
|
ps_enable <= '0';
|
|
if (ps_done = '1') then
|
|
ps_state <= idle;
|
|
end if;
|
|
end case;
|
|
end if;
|
|
end process;
|
|
|
|
-- Debug outputs
|
|
O_DEBUG1 <= clk66_dcm1;
|
|
O_DEBUG2 <= clk132;
|
|
|
|
-- DCM outputs
|
|
O_CLK33 <= clk33;
|
|
O_CLK66 <= clk66_dcm1;
|
|
O_CLK132 <= clk132;
|
|
O_CLK264 <= '0';
|
|
O_CLK_PS <= clk_ps;
|
|
O_LOCKED <= locked_dcm1 and locked_dcm3;
|
|
end arch;
|