📄 phy_ptn_gen.vhd
字号:
-------------------------------------------------------------------------------
-- Copyright (c) 2006 Xilinx, Inc.
-- This design is confidential and proprietary of Xilinx, All Rights Reserved.
-------------------------------------------------------------------------------
-- ____ ____
-- / /\/ /
-- /___/ \ / Vendor: Xilinx
-- \ \ \/ Version: 1.1
-- \ \ Filename: phy_ptn_gen.vhd
-- / / Date Last Modified: 5/10/06
-- /___/ /\ Date Created:
-- \ \ / \
-- \___\/\___\
--
--Device: Virtex-5
--Purpose: Pattern generator for read-capture timing calibration
--Reference:
-- XAPP851
--Revision History:
-- Rev 0.1 - Created. Author: Toshihiko Moriyama. 1/06/06.
-- 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_ptn_gen is
port(
rst : in std_logic;
clk0 : in std_logic;
-- Handshaking signals with controller
init_done : in std_logic;
calib_start0 : out std_logic; -- calib_start
calib_start1 : out std_logic;
calib_done0 : in std_logic;
calib_done1 : in std_logic;
rd_rdy : out std_logic;
cs_n_o : out std_logic;
ras_n_o : out std_logic;
cas_n_o : out std_logic;
we_n_o : out std_logic;
addr_o : out std_logic_vector(row_address - 1 downto 0);
bank_o : out std_logic_vector(bank_address - 1 downto 0);
wr_data_o : out std_logic_vector(data_width*2 - 1 downto 0);
wr_en_o : out std_logic
);
end phy_ptn_gen;
-----------------------------------------------
architecture rtl of phy_ptn_gen is
TYPE STATE_TYPE is (
IDLE_ST, -- wait until data is valid
ACTIVATE_ST, -- Bank activation
WR_PTN0_1_ST, -- write training pattern 0 and 1
RD_PTN0_ST, -- read out training pattern 0
RD_PTN1_ST, -- read out training pattern 1
PRECHARGE_ST, -- Close the row
AUTOREF_ST, -- Auto refresh
DONE_ST -- calibration done
);
signal CALIB_STATE : STATE_TYPE;
signal CALIB_STATE_N : STATE_TYPE;
signal command : std_logic_vector(3 downto 0); -- CS_n & RAS_n & CAS_n & WE_n
-- commands used in init phase
constant DESEL_CMD : std_logic_vector(3 downto 0) := "1111";
constant NOP_CMD : std_logic_vector(3 downto 0) := "0111";
constant BSTP_CMD : std_logic_vector(3 downto 0) := "0110";
constant PRECHARGE_CMD : std_logic_vector(3 downto 0) := "0010";
constant AUTOREF_CMD : std_logic_vector(3 downto 0) := "0001";
constant LMR_CMD : std_logic_vector(3 downto 0) := "0000";
constant ACT_CMD : std_logic_vector(3 downto 0) := "0011";
constant RD_CMD : std_logic_vector(3 downto 0) := "0101"; -- not auto precharge
constant WR_CMD : std_logic_vector(3 downto 0) := "0100"; -- not auto precharge
signal counter5 : std_logic_vector(4 downto 0);
signal wr_data : std_logic_vector(7 downto 0);
signal calib_start0_i : std_logic;
signal calib_start1_i : std_logic;
signal wr_data4r : std_logic_vector(3 downto 0);
signal wr_data4f : std_logic_vector(3 downto 0);
signal wr_en : std_logic;
signal burst_length : std_logic_vector(2 downto 0);
constant TRAIN_PTN0_R : std_logic_vector(3 downto 0) := X"5";
constant TRAIN_PTN0_F : std_logic_vector(3 downto 0) := X"A";
constant TRAIN_PTN1_R : std_logic_vector(3 downto 0) := X"C";
constant TRAIN_PTN1_F : std_logic_vector(3 downto 0) := X"3";
begin
burst_length <= load_mode_register(2 downto 0);
-- For 4-bit component
G_WR_DATA4: if dq_per_dqs = 4 generate
G1_WR_DATA4 : for I in 0 to no_of_comps * dqs_per_comp - 1 generate
wr_data_o(8*I+3 downto 8*I) <= wr_data4r;
wr_data_o(8*I+7 downto 8*I+4) <= wr_data4f;
end generate;
end generate;
-- For 8-bit component
G_WR_DATA8: if dq_per_dqs = 8 generate
G1_WR_DATA8 : for I in 0 to no_of_comps * dqs_per_comp - 1 generate
wr_data_o(16*I+3 downto 16*I) <= wr_data4r;
wr_data_o(16*I+7 downto 16*I+4) <= wr_data4r;
wr_data_o(16*I+11 downto 16*I+8) <= wr_data4f;
wr_data_o(16*I+15 downto 16*I+12) <= wr_data4f;
end generate;
end generate;
-- For 16-bit component
G_WR_DATA16: if dq_per_dqs = 16 generate
G1_WR_DATA16 : for I in 0 to no_of_comps * dqs_per_comp - 1 generate
wr_data_o(32*I+15 downto 32*I) <= wr_data4r & wr_data4r & wr_data4r & wr_data4r;
wr_data_o(32*I+31 downto 32*I+16) <= wr_data4f & wr_data4f & wr_data4f & wr_data4f;
end generate;
end generate;
cs_n_o <= command(3);
ras_n_o <= command(2);
cas_n_o <= command(1);
we_n_o <= command(0);
wr_data4r <= wr_data(3 downto 0);
wr_data4f <= wr_data(7 downto 4);
wr_en_o <= wr_en;
-------------------
-- STATE MACHINE --
-------------------
P_STATE_NEXT : process(clk0)
begin
if clk0'event and clk0='1' then
if rst='1' then
CALIB_STATE <= IDLE_ST;
else
CALIB_STATE <= CALIB_STATE_N;
end if;
end if;
end process;
P_STATE : process(rst, CALIB_STATE, init_done, counter5, calib_done0, calib_done1)
begin
if rst='1' then
CALIB_STATE_N <= IDLE_ST;
else
case CALIB_STATE is
when IDLE_ST =>
if init_done = '1' then
CALIB_STATE_N <= ACTIVATE_ST;
else
CALIB_STATE_N <= IDLE_ST;
end if;
when ACTIVATE_ST =>
if counter5 = X"1F" then
CALIB_STATE_N <= WR_PTN0_1_ST;
else
CALIB_STATE_N <= ACTIVATE_ST;
end if;
when WR_PTN0_1_ST =>
if counter5 = X"1F" then
CALIB_STATE_N <= RD_PTN0_ST;
else
CALIB_STATE_N <= WR_PTN0_1_ST;
end if;
when RD_PTN0_ST =>
if (counter5 = X"1F") and (calib_done0 = '1') then
CALIB_STATE_N <= RD_PTN1_ST;
else
CALIB_STATE_N <= RD_PTN0_ST;
end if;
when RD_PTN1_ST =>
if (counter5 = X"1F") and (calib_done1 = '1') then
CALIB_STATE_N <= PRECHARGE_ST;
else
CALIB_STATE_N <= RD_PTN1_ST;
end if;
when PRECHARGE_ST =>
if counter5 = X"1F" then
CALIB_STATE_N <= AUTOREF_ST;
else
CALIB_STATE_N <= PRECHARGE_ST;
end if;
when AUTOREF_ST =>
if counter5 = X"1F" then
CALIB_STATE_N <= DONE_ST;
else
CALIB_STATE_N <= AUTOREF_ST;
end if;
when DONE_ST =>
CALIB_STATE_N <= DONE_ST;
when others =>
CALIB_STATE_N <= DONE_ST;
end case;
end if;
end process;
-- command, address and data outputs
P_CMD : process( clk0 )
begin
if clk0'event and clk0='1' then
if rst='1' then
command <= DESEL_CMD;
addr_o <= (others => '1');
bank_o <= (others => '1');
else
case CALIB_STATE is
when IDLE_ST =>
command <= DESEL_CMD;
addr_o <= (others => '0');
bank_o <= (others => '0');
wr_data <= (others => '0');
wr_en <= '0';
when ACTIVATE_ST =>
if counter5 = 0 then
command <= ACT_CMD;
else
command <= DESEL_CMD;
end if;
addr_o <= (others => '0');
bank_o <= (others => '0');
wr_data <= (others => '0');
wr_en <= '0';
when WR_PTN0_1_ST => -- write training pattern to memory
case counter5 is
when "00000" =>
command <= WR_CMD;
addr_o(3 downto 0) <= "0000"; -- 0000/0001
wr_data <= (others => '0');
wr_en <= '1';
when "00001" =>
if burst_length = "001" then -- burst length = 2
command <= WR_CMD;
addr_o(3 downto 0) <= "0010"; -- 0010/0011
else
command <= DESEL_CMD;
addr_o(3 downto 0) <= (others => '0'); -- 0010/0011
end if;
wr_data <= (others => '1');
wr_en <= '1';
when "00010" =>
if burst_length = "011" then -- burst length = 8
command <= DESEL_CMD;
addr_o(3 downto 0) <= (others => '0'); -- 0100/0101
else -- busrt lenth = 2 or 4
command <= WR_CMD;
addr_o(3 downto 0) <= "0100"; -- 0100/0101
end if;
wr_data <= (others => '0');
wr_en <= '1';
when "00011" =>
if burst_length = "001" then -- burst length = 2
command <= WR_CMD;
addr_o(3 downto 0) <= "0110"; -- 0110/0111
else
command <= DESEL_CMD;
addr_o(3 downto 0) <= (others => '0'); -- 0010/0011
end if;
wr_data <= (others => '1');
wr_en <= '1';
-- Pattern for step 2
when "00100" =>
command <= WR_CMD;
addr_o(3 downto 0) <= "1000"; -- 1000/1001
wr_data <= TRAIN_PTN0_F & TRAIN_PTN0_R;
wr_en <= '1';
when "00101" =>
if burst_length = "001" then -- burst length = 2
command <= WR_CMD;
addr_o(3 downto 0) <= "1010"; -- 1010/1011
else
command <= DESEL_CMD;
addr_o(3 downto 0) <= (others => '0');
end if;
wr_data <= TRAIN_PTN1_F & TRAIN_PTN1_R;
wr_en <= '1';
when "00110" |"00111" =>
command <= DESEL_CMD;
addr_o(3 downto 0) <= (others => '0');
wr_data <= (others => '0');
if burst_length = "011" then -- burst length = 8
wr_en <= '1';
else -- busrt lenth = 2 or 4
wr_en <= '0';
end if;
when others =>
command <= DESEL_CMD;
addr_o(3 downto 0) <= (others => '0');
wr_data <= (others => '0');
wr_en <= '0';
end case;
addr_o(row_address - 1 downto 4) <= (others => '0');
bank_o <= (others => '0');
when RD_PTN0_ST => -- read from memory
case counter5(1 downto 0) is
when "00" =>
command <= RD_CMD;
addr_o(3 downto 0) <= "0000";
when "01" =>
if burst_length = "001" then -- burst length = 2
command <= RD_CMD;
addr_o(3 downto 0) <= "0010";
else
command <= DESEL_CMD;
addr_o(3 downto 0) <= (others => '0');
end if;
when "10" =>
if burst_length = "011" then -- burst length = 8
command <= DESEL_CMD;
addr_o(3 downto 0) <= (others => '0');
else -- burst length = 2 or 4
command <= RD_CMD;
addr_o(3 downto 0) <= "0100";
end if;
when "11" =>
if burst_length = "001" then -- burst length = 2
command <= RD_CMD;
addr_o(3 downto 0) <= "0110";
else
command <= DESEL_CMD;
addr_o(3 downto 0) <= (others => '0');
end if;
when others =>
command <= DESEL_CMD;
addr_o(3 downto 0) <= (others => '0');
end case;
addr_o(row_address - 1 downto 4) <= (others => '0'); -- Set A10 to 0. Auto precharge is disabled
wr_data <= (others => '0');
wr_en <= '0';
when RD_PTN1_ST => -- read from memory
case counter5 is
when "00000" =>
command <= RD_CMD;
addr_o(3 downto 0) <= "1000";
when "00001" =>
if burst_length = "001" then -- burst length = 2
command <= RD_CMD;
addr_o(3 downto 0) <= "1010";
else
command <= DESEL_CMD;
addr_o(3 downto 0) <= (others => '0');
end if;
when others =>
command <= DESEL_CMD;
addr_o(3 downto 0) <= (others => '0');
end case;
addr_o(row_address - 1 downto 4) <= (others => '0'); -- Set A10 to 0. Auto precharge is disabled
wr_data <= (others => '0');
wr_en <= '0';
when PRECHARGE_ST => -- close the bank
if counter5 = "00000" then
command <= PRECHARGE_CMD; -- will be available after tRP
else
command <= DESEL_CMD;
end if;
addr_o(row_address - 1 downto 4) <= (others => '0'); -- precharge current bank. A10=0
wr_data <= (others => '0');
wr_en <= '0';
when AUTOREF_ST =>
if counter5 = "00000" then
command <= AUTOREF_CMD; -- will be available after tRP
else
command <= DESEL_CMD;
end if;
addr_o(row_address - 1 downto 4) <= (others => '0'); -- precharge current bank. A10=0
wr_data <= (others => '0');
wr_en <= '0';
when DONE_ST =>
command <= DESEL_CMD;
addr_o(row_address - 1 downto 4) <= (others => '0'); -- precharge current bank. A10=0
wr_data <= (others => '0');
when others =>
command <= DESEL_CMD;
addr_o(row_address - 1 downto 4) <= (others => '0'); -- precharge current bank. A10=0
wr_data <= (others => '0');
wr_en <= '0';
end case;
end if;
end if;
end process;
-- counter for command execution
P_CNT : process( clk0 )
begin
if clk0'event and clk0='1' then
if rst='1' then
counter5 <= (others => '0');
else
case CALIB_STATE is
when ACTIVATE_ST
| WR_PTN0_1_ST
| RD_PTN0_ST
| RD_PTN1_ST
| PRECHARGE_ST
| AUTOREF_ST =>
counter5 <= counter5 + 1;
when others =>
counter5 <= (others => '0');
end case;
end if;
end if;
end process;
-- Hankshaking
P_HAND : process( clk0 )
begin
if clk0'event and clk0='1' then
if rst='1' then
calib_start0_i <= '0';
calib_start1_i <= '0';
else
case CALIB_STATE is
when IDLE_ST =>
calib_start0_i <= '0';
calib_start1_i <= '0';
when RD_PTN0_ST =>
if counter5 = X"1F" then
calib_start0_i <= '1';
else
calib_start0_i <= calib_start0_i;
end if;
calib_start1_i <= calib_start1_i;
when RD_PTN1_ST =>
calib_start0_i <= calib_start0_i;
if counter5 = X"1F" then
calib_start1_i <= '1';
else
calib_start1_i <= calib_start1_i;
end if;
when others =>
calib_start0_i <= calib_start0_i;
calib_start1_i <= calib_start1_i;
end case;
end if;
end if;
end process;
calib_start0 <= calib_start0_i;
calib_start1 <= calib_start1_i;
P_RD_RDY : process( clk0 )
begin
if clk0'event and clk0='1' then
if rst='1' then
rd_rdy <= '0';
else
case CALIB_STATE is
when DONE_ST =>
rd_rdy <= '1';
when others =>
rd_rdy <= '0';
end case;
end if;
end if;
end process;
end rtl;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -