?? phy_dq_align.vhd
字號:
-------------------------------------------------------------------------------
-- Copyright (c) 2006 Xilinx, Inc.
-- This design is confidential and proprietary of Xilinx, All Rights Reserved.
-------------------------------------------------------------------------------
-- ____ ____
-- / /\/ /
-- /___/ \ / Vendor: Xilinx
-- \ \ \/ Version: 1.1
-- \ \ Filename: phy_dq_align.vhd
-- / / Date Last Modified: 5/10/06
-- /___/ /\ Date Created:
-- \ \ / \
-- \___\/\___\
--
--Device: Virtex-5
--Purpose: Read-data capture calibration and alignment logic. Instantiates:
-- (1) IDELAY elements for both data and DQS strobe, (2) BUFIO local
-- clock buffer for incoming DQS, (3) IDDRs flops for incoming read
-- data capture, (4) 2nd and 3rd rank of flops (located in the FPGA
-- fabric) for transferring data to FPGA clock domain
--Reference:
-- XAPP851
--Revision History:
-- Rev 0.1 - Created. Author: Toshihiko Moriyama. 11/14/05.
-- Rev 1.0 - Internal release. Author: Toshihiko Moriyama. 4/29/06.
-- Rev 1.1 - External release. Added header. 5/10/06.
-------------------------------------------------------------------------------
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_arith.all;
use IEEE.std_logic_unsigned.all;
library work;
use work.ddr1_parameters.all;
library unisim ;
use unisim.vcomponents.all ;
entity phy_dq_align is
port(
rst : in std_logic;
clk0 : in std_logic;
DQS : in std_logic;
DQ : in std_logic_vector(dq_per_dqs - 1 downto 0);
rd_data : out std_logic_vector(dq_per_dqs*2 - 1 downto 0);
calib_start : in std_logic;
calib_done : out std_logic
);
end phy_dq_align;
-----------------------------------------------
architecture rtl of phy_dq_align is
TYPE ALIGNSTATE_TYPE is (
WAIT_ST, -- wait until 1st data pattern is available
FIRST_CAP_ST,
INCR_ST,
INCR_WAIT_ST,
CAPTURE_ST,
COMP_ST,
CALC_ST,
SET_ST,
SET_WAIT_ST,
RUN_ST
);
signal state_c : ALIGNSTATE_TYPE;
signal state_n : ALIGNSTATE_TYPE;
signal DQS_dly : std_logic;
signal DQS_dly_bufio : std_logic;
signal DQS_bufio : std_logic;
signal DQ_dly : std_logic_vector(dq_per_dqs - 1 downto 0);
signal DQ_iddr_r : std_logic_vector(dq_per_dqs - 1 downto 0);
signal DQ_iddr_f : std_logic_vector(dq_per_dqs - 1 downto 0);
signal DQ_iddr_r0 : std_logic_vector(dq_per_dqs - 1 downto 0);
signal DQ_iddr_f0 : std_logic_vector(dq_per_dqs - 1 downto 0);
signal DQ_iddr_r180 : std_logic_vector(dq_per_dqs - 1 downto 0);
signal DQ_iddr_f180 : std_logic_vector(dq_per_dqs - 1 downto 0);
signal DQ_iddr_r180_2 : std_logic_vector(dq_per_dqs - 1 downto 0);
signal rd_data_r : std_logic_vector(dq_per_dqs - 1 downto 0);
signal rd_data_f : std_logic_vector(dq_per_dqs - 1 downto 0);
signal use_clk0 : std_logic;
signal dly_ce : std_logic;
signal dly_rst : std_logic;
signal dly_inc : std_logic;
signal DQ_r_first : std_logic_vector(1 downto 0);
signal DQ_r_cur : std_logic_vector(1 downto 0);
signal dly_taps : unsigned(5 downto 0);
signal inc_cnt : unsigned(5 downto 0);
constant DLYTAP_RST : std_logic_vector(2 downto 0) := "001";
constant DLYTAP_INC : std_logic_vector(2 downto 0) := "110";
constant DLYTAP_DEC : std_logic_vector(2 downto 0) := "100";
constant DLYTAP_NOP : std_logic_vector(2 downto 0) := "000";
signal dlyTap_cmd : std_logic_vector(2 downto 0);
constant NUM_TAPS_90DEGREE : unsigned(5 downto 0) := "010000"; -- 16 taps at 200Mhz
-- Debug
signal dly_inc_dq : std_logic;
signal dly_ce_dq : std_logic;
signal dly_rst_dq : std_logic;
signal dly_inc_dqs : std_logic;
signal dly_ce_dqs : std_logic;
signal dly_rst_dqs : std_logic;
signal clk0_sel : std_logic;
signal calibration_done : std_logic;
signal LOGIC_0 : std_logic;
signal LOGIC_1 : std_logic;
begin
process (rst, clk0)
begin
if rst='1' then
dly_inc_dq <= '0';
dly_ce_dq <= '0';
dly_rst_dq <= '1';
dly_inc_dqs <= '0';
dly_ce_dqs <= '0';
dly_rst_dqs <= '1';
clk0_sel <= '0';
calib_done <= '0';
elsif clk0'event and clk0='1' then
dly_inc_dq <= dly_inc;
dly_ce_dq <= dly_ce;
dly_rst_dq <= dly_rst;
dly_inc_dqs <= dly_inc;
dly_ce_dqs <= dly_ce;
dly_rst_dqs <= dly_rst;
clk0_sel <= use_clk0;
calib_done <= calibration_done;
end if;
end process;
LOGIC_0 <= '0';
LOGIC_1 <= '1';
------------------------------------------------------------------
P_ALIGN_NEXT : process(clk0)
begin
if clk0'event and clk0='1' then
if rst='1' then
state_c <= WAIT_ST;
else
state_c <= state_n;
end if;
end if;
end process;
-------------------
-- STATE MACHINE --
-------------------
P_ALIGN_ST : process(rst, state_c, calib_start, DQ_r_cur, DQ_r_first, inc_cnt, dly_taps)
begin
if rst='1' then
state_n <= WAIT_ST;
else
case state_c is
when WAIT_ST =>
if calib_start='1' then
state_n <= FIRST_CAP_ST;
else
state_n <= WAIT_ST;
end if;
when FIRST_CAP_ST =>
state_n <= INCR_ST;
when INCR_ST =>
state_n <= INCR_WAIT_ST;
when INCR_WAIT_ST =>
if inc_cnt = 5 then
state_n <= CAPTURE_ST;
else
state_n <= INCR_WAIT_ST;
end if;
when CAPTURE_ST =>
state_n <= COMP_ST;
when COMP_ST =>
if (((DQ_r_cur(0) xor DQ_r_cur(1)) = '1') xor ((DQ_r_first(0) xor DQ_r_first(1)) = '1' ))
or (dly_taps = 31 ) then
state_n <= CALC_ST;
else
state_n <= INCR_ST;
end if;
when CALC_ST =>
state_n <= SET_ST;
when SET_ST =>
if inc_cnt = dly_taps then
state_n <= SET_WAIT_ST;
else
state_n <= SET_ST;
end if;
when SET_WAIT_ST =>
if inc_cnt = 5 then
state_n <= RUN_ST;
else
state_n <= SET_WAIT_ST;
end if;
when RUN_ST =>
state_n <= RUN_ST;
when others =>
state_n <= WAIT_ST;
end case;
end if;
end process;
-- delay increment
P_ALIGN : process( clk0 )
begin
if clk0'event and clk0='1' then
if rst='1' then
dlyTap_cmd <= DLYTAP_RST;
dly_taps <= (others => '0');
inc_cnt <= (others => '0');
use_clk0 <= '0';
else
case state_c is
when WAIT_ST =>
dlyTap_cmd <= DLYTAP_NOP;
dly_taps <= (others => '0');
inc_cnt <= (others => '0');
when FIRST_CAP_ST =>
dlyTap_cmd <= DLYTAP_NOP;
dly_taps <= (others => '0');
inc_cnt <= (others => '0');
when INCR_ST =>
dlyTap_cmd <= DLYTAP_INC;
inc_cnt <= (others => '0');
dly_taps <= dly_taps + 1;
when INCR_WAIT_ST =>
dlyTap_cmd <= DLYTAP_NOP;
dly_taps <= dly_taps;
inc_cnt <= inc_cnt + 1;
when CAPTURE_ST =>
dlyTap_cmd <= DLYTAP_NOP;
dly_taps <= dly_taps;
inc_cnt <= (others => '0');
when COMP_ST =>
dlyTap_cmd <= DLYTAP_NOP;
dly_taps <= dly_taps;
inc_cnt <= (others => '0');
when CALC_ST =>
if dly_taps >= NUM_TAPS_90DEGREE then
dly_taps <= dly_taps - NUM_TAPS_90DEGREE;
if (DQ_r_first(0) xor DQ_r_first(1)) = '1' then
use_clk0 <= '0';
else
use_clk0 <= '1';
end if;
else
dly_taps <= dly_taps + NUM_TAPS_90DEGREE;
if (DQ_r_first(0) xor DQ_r_first(1)) = '1' then
use_clk0 <= '1';
else
use_clk0 <= '0';
end if;
end if;
-- reset the idelay to default setting
dlyTap_cmd <= DLYTAP_RST;
inc_cnt <= (others => '0');
when SET_ST =>
if inc_cnt = dly_taps then
dlyTap_cmd <= DLYTAP_NOP;
inc_cnt <= (others => '0');
else
dlyTap_cmd <= DLYTAP_INC;
inc_cnt <= inc_cnt + 1;
end if;
dly_taps <= dly_taps;
when SET_WAIT_ST =>
dlyTap_cmd <= DLYTAP_NOP;
dly_taps <= dly_taps;
inc_cnt <= inc_cnt + 1;
when RUN_ST =>
dlyTap_cmd <= DLYTAP_NOP;
when others =>
dlyTap_cmd <= DLYTAP_NOP;
end case;
end if;
end if;
end process;
dly_rst <= dlyTap_cmd(0);
dly_inc <= dlyTap_cmd(1);
dly_ce <= dlyTap_cmd(2);
--
P_FIRST_CAP : process( clk0 )
begin
if clk0'event and clk0='1' then
if rst='1' then
DQ_r_first <= (others => '0');
else
case state_c is
when FIRST_CAP_ST =>
-- Uses data from first FFs in CLB
DQ_r_first <= DQ_iddr_r180(0) & DQ_iddr_r0(0);
when others =>
DQ_r_first <= DQ_r_first;
end case;
end if;
end if;
end process;
--
P_DATA_CAP : process( clk0 )
begin
if clk0'event and clk0='1' then
if rst='1' then
DQ_r_cur <= (others => '0');
else
case state_c is
when CAPTURE_ST =>
DQ_r_cur <= DQ_iddr_r180(0) & DQ_iddr_r0(0);
when others =>
DQ_r_cur <= DQ_r_cur;
end case;
end if;
end if;
end process;
--
P_CALIB_DONE : process( clk0 )
begin
if clk0'event and clk0='1' then
if rst='1' then
calibration_done <= '0';
else
case state_c is
when RUN_ST =>
calibration_done <= '1';
when others =>
calibration_done <= '0';
end case;
end if;
end if;
end process;
-----------------------------------------------------
-- IOB components instantiation
-----------------------------------------------------
IDELAY_DQS : IDELAY
generic map (
IOBDELAY_TYPE => "VARIABLE",
IOBDELAY_VALUE => 0)
port map (
O => DQS_dly,
C => clk0,
CE => dly_ce_dqs,
I => DQS,
INC => dly_inc_dqs,
RST => dly_rst_dqs
);
BUFIO_DQS : BUFIO
port map ( O => DQS_dly_bufio, I => DQS_dly );
DQS_bufio <= DQS_dly_bufio after 100 ps;
G_DQ_IDDR : for I in 0 to dq_per_dqs - 1 generate
IDELAY_DQ : IDELAY
generic map (
IOBDELAY_TYPE => "VARIABLE",
IOBDELAY_VALUE => 0)
port map (
O => DQ_dly(I),
C => clk0,
CE => dly_ce_dq,
I => DQ(I),
INC => dly_inc_dq,
RST => dly_rst_dq
);
IDDR_DQ : IDDR
generic map (
DDR_CLK_EDGE => "OPPOSITE_EDGE",
INIT_Q1 => '0',
INIT_Q2 => '0',
SRTYPE => "SYNC")
port map (
Q1 => DQ_iddr_r(I),
Q2 => DQ_iddr_f(I),
C => DQS_bufio,
CE => LOGIC_1,
D => DQ_dly(I),
R => LOGIC_0,
S => LOGIC_0
);
end generate;
G_RD_FF : for I in 0 to dq_per_dqs - 1 generate
-----------------------------------------
-- clk0 data path
FD_DQ_IDDR_R0 : FD
port map (
Q => DQ_iddr_r0(I),
C => clk0,
D => DQ_iddr_r(I)
);
FD_DQ_IDDR_F0 : FD_1
port map (
Q => DQ_iddr_f0(I),
C => clk0,
D => DQ_iddr_f(I)
);
-----------------------------------------
-- clk180 data path
FD_DQ_IDDR_R180 : FD_1
port map (
Q => DQ_iddr_r180(I),
C => clk0,
D => DQ_iddr_r(I)
);
FD_DQ_IDDR_R180_2 : FD
port map (
Q => DQ_iddr_r180_2(I),
C => clk0,
D => DQ_iddr_r180(I)
);
FD_DQ_IDDR_F180 : FD
port map (
Q => DQ_iddr_f180(I),
C => clk0,
D => DQ_iddr_f(I)
);
end generate;
rd_data_r <= DQ_iddr_r0 when clk0_sel='1' else DQ_iddr_r180_2;
rd_data_f <= DQ_iddr_f0 when clk0_sel='1' else DQ_iddr_f180;
P_RD_DATA : process( clk0 )
begin
if clk0'event and clk0='1' then
if rst='1' then
rd_data <= (others => '0');
else
rd_data <= rd_data_f & rd_data_r;
end if;
end if;
end process;
end rtl;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -