⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 phy_dq_align.vhd

📁 The xapp851.zip archive includes the following subdirectories. The specific contents of each subdi
💻 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 + -