hdet/fpga/src/vendor/xilinx/atlys_ddr2/ddr2/example_design/rtl/mcb_soft_calibration.vhd

1775 lines
90 KiB
VHDL
Executable File

--*****************************************************************************
-- (c) Copyright 2009 Xilinx, Inc. All rights reserved.
--
-- This file contains confidential and proprietary information
-- of Xilinx, Inc. and is protected under U.S. and
-- international copyright and other intellectual property
-- laws.
--
-- DISCLAIMER
-- This disclaimer is not a license and does not grant any
-- rights to the materials distributed herewith. Except as
-- otherwise provided in a valid license issued to you by
-- Xilinx, and to the maximum extent permitted by applicable
-- law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
-- WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
-- AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
-- BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
-- INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
-- (2) Xilinx shall not be liable (whether in contract or tort,
-- including negligence, or under any other theory of
-- liability) for any loss or damage of any kind or nature
-- related to, arising under or in connection with these
-- materials, including for any direct, or any indirect,
-- special, incidental, or consequential loss or damage
-- (including loss of data, profits, goodwill, or any type of
-- loss or damage suffered as a result of any action brought
-- by a third party) even if such damage or loss was
-- reasonably foreseeable or Xilinx had been advised of the
-- possibility of the same.
--
-- CRITICAL APPLICATIONS
-- Xilinx products are not designed or intended to be fail-
-- safe, or for use in any application requiring fail-safe
-- performance, such as life-support or safety devices or
-- systems, Class III medical devices, nuclear facilities,
-- applications related to the deployment of airbags, or any
-- other applications that could lead to death, personal
-- injury, or severe property or environmental damage
-- (individually and collectively, "Critical
-- Applications"). Customer assumes the sole risk and
-- liability of any use of Xilinx products in Critical
-- Applications, subject only to applicable laws and
-- regulations governing limitations on product liability.
--
-- THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
-- PART OF THIS FILE AT ALL TIMES.
--
--*****************************************************************************
-- ____ ____
-- / /\/ /
-- /___/ \ / Vendor: Xilinx
-- \ \ \/ Version: %version
-- \ \ Application: MIG
-- / / Filename: mcb_soft_calibration.vhd
-- /___/ /\ Date Last Modified: $Date: 2011/06/02 07:17:26 $
-- \ \ / \ Date Created: Mon Feb 9 2009
-- \___\/\___\
--
--Device: Spartan6
--Design Name: DDR/DDR2/DDR3/LPDDR
--Purpose: Xilinx reference design for MCB Soft
-- Calibration
--Reference:
--
-- Revision: Date: Comment
-- 1.0: 2/06/09: Initial version for MIG wrapper.
-- 1.1: 2/09/09: moved Max_Value_Previous assignments to be completely inside CASE statement for next-state logic (needed to get it working
-- correctly)
-- 1.2: 2/12/09: Many other changes.
-- 1.3: 2/26/09: Removed section with Max_Value_pre and DQS_COUNT_PREVIOUS_pre, and instead added PREVIOUS_STATE reg and moved assignment to within
-- STATE
-- 1.4: 3/02/09: Removed comments out of sensitivity list of always block to mux SDI, SDO, CS, and ADD.Also added reg declaration for PREVIOUS_STATE
-- 1.5: 3/16/09: Added pll_lock port, and using it to gate reset. Changing RST (except input port) to RST_reg and gating it with pll_lock.
-- 1.6: 6/05/09: Added START_DYN_CAL_PRE with pulse on SYSRST; removed MCB_UIDQCOUNT.
-- 1.7: 6/24/09: Gave RZQ and ZIO each their own unique ADD and SDI nets
-- 2.6: 12/15/09: Changed STATE from 7-bit to 6-bit. Dropped (* FSM_ENCODING="BINARY" *) for STATE. Moved MCB_UICMDEN = 0 from OFF_RZQ_PTERM to
-- RST_DELAY.
-- Changed the "reset" always block so that RST_reg is always set to 1 when the PLL loses lock, and is now held in reset for at least
-- 16 clocks. Added PNSKEW option.
-- 2.7: 12/23/09: Added new states "SKEW" and "MULTIPLY_DIVIDE" to help with timing.
-- 2.8: 01/14/10: Added functionality to allow for SUSPEND. Changed MCB_SYSRST port from wire to reg.
-- 2.9: 02/01/10: More changes to SUSPEND and Reset logic to handle SUSPEND properly. Also - eliminated 2's comp DQS_COUNT_VIRTUAL, and replaced
-- with 8bit TARGET_DQS_DELAY which
-- will track most recnet Max_Value. Eliminated DQS_COUNT_PREVIOUS. Combined DQS_COUNT_INITIAL and DQS_DELAY into DQS_DELAY_INITIAL.
-- Changed DQS_COUNT* to DQS_DELAY*.
-- Changed MCB_SYSRST port back to wire (from reg).
-- 3.0: 02/10/10: Added count_inc and count_dec to add few (4) UI_CLK cycles latency to the INC and DEC signals(to deal with latency on UOREFRSHFLAG)
-- 3.1: 02/23/10: Registered the DONE_SOFTANDHARD_CAL for timing.
-- 3.2: 02/28/10: Corrected the WAIT_SELFREFRESH_EXIT_DQS_CAL logic;
-- 3.3: 03/02/10: Changed PNSKEW to default on (1'b1)
-- 3.4: 03/04/10: Recoded the RST_Reg logic.
-- 3.5: 03/05/10: Changed Result register to be 16-bits. Changed DQS_NUMERATOR/DENOMINATOR values to 3/8 (from 6/16)
-- 3.6 03/10/10: Improvements to Reset logic.
-- 3.7: 04/26/10: Added DDR2 Initialization fix to meet 400 ns wait as outlined in step d) of JEDEC DDR2 spec .
-- 3.8: 05/05/10: Added fixes for the CR# 559092 (updated Mult_Divide function) and 555416 (added IOB attribute to DONE_SOFTANDHARD_CAL).
-- 3.9: 05/24/10: Added 200us Wait logic to control CKE_Train. The 200us Wait counter assumes UI_CLK freq not higher than 100 MHz.
-- 3.10 10/22/10: Fixed PERFORM_START_DYN_CAL_AFTER_SELFREFRESH logic.
-- 3.11 2/14/11: Apply a different skkew for the P and N inputs for the differential LDQS and UDQS signals to provide more noise immunity.
-- 4.1 03/08/12: Fixed SELFREFRESH_MCB_REQ logic. It should not need depend on the SM STATE so that
-- MCB can come out of selfresh mode. SM requires refresh cycle to update the DQS value.
-- 4.2 05/10/12: All P/N terms of input and bidir memory pins are initialized with value of ZERO. TZQINIT_MAXCNT
-- are set to 8 for LPDDR,DDR and DDR2 interface .
-- Keep the UICMDEN in assertion state when SM is in RST_DELAY state so that MCB will not start doing
-- Premable detection until the second deassertion of MCB_SYSRST.
-- End Revision
--**********************************************************************************
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
USE ieee.numeric_std.all;
entity mcb_soft_calibration is
generic (
C_MEM_TZQINIT_MAXCNT : std_logic_vector(9 downto 0) := "1000000000"; -- DDR3 Minimum delay between resets
SKIP_IN_TERM_CAL : integer := 0; -- provides option to skip the input termination calibration
SKIP_DYNAMIC_CAL : integer := 0; -- provides option to skip the dynamic delay calibration
SKIP_DYN_IN_TERM : integer := 1; -- provides option to skip the input termination calibration
C_MC_CALIBRATION_MODE : string := "CALIBRATION"; -- if set to CALIBRATION will reset DQS IDELAY to DQS_NUMERATOR/DQS_DENOMINATOR local_param value
-- if set to NOCALIBRATION then defaults to hard cal blocks setting of C_MC_CALBRATION_DELAY
-- (Quarter, etc)
C_SIMULATION : string := "FALSE"; -- Tells us whether the design is being simulated or implemented
C_MEM_TYPE : string := "DDR"
);
port (
UI_CLK : in std_logic; -- main clock input for logic and IODRP CLK pins. At top level, this should also connect to IODRP2_MCB
-- CLK pins
RST : in std_logic; -- main system reset for both the Soft Calibration block - also will act as a passthrough to MCB's SYSRST
DONE_SOFTANDHARD_CAL : out std_logic; -- active high flag signals soft calibration of input delays is complete and MCB_UODONECAL is high (MCB
-- hard calib complete)
PLL_LOCK : in std_logic; -- Lock signal from PLL
SELFREFRESH_REQ : in std_logic;
SELFREFRESH_MCB_MODE : in std_logic;
SELFREFRESH_MCB_REQ : out std_logic;
SELFREFRESH_MODE : out std_logic;
IODRP_ADD : out std_logic; -- IODRP ADD port
IODRP_SDI : out std_logic; -- IODRP SDI port
RZQ_IN : in std_logic; -- RZQ pin from board - expected to have a 2*R resistor to ground
RZQ_IODRP_SDO : in std_logic; -- RZQ IODRP's SDO port
RZQ_IODRP_CS : out std_logic := '0'; -- RZQ IODRP's CS port
ZIO_IN : in std_logic; -- Z-stated IO pin - garanteed not to be driven externally
ZIO_IODRP_SDO : in std_logic; -- ZIO IODRP's SDO port
ZIO_IODRP_CS : out std_logic := '0'; -- ZIO IODRP's CS port
MCB_UIADD : out std_logic; -- to MCB's UIADD port
MCB_UISDI : out std_logic; -- to MCB's UISDI port
MCB_UOSDO : in std_logic; -- from MCB's UOSDO port (User output SDO)
MCB_UODONECAL : in std_logic; -- indicates when MCB hard calibration process is complete
MCB_UOREFRSHFLAG : in std_logic; -- high during refresh cycle and time when MCB is innactive
MCB_UICS : out std_logic; -- to MCB's UICS port (User Input CS)
MCB_UIDRPUPDATE : out std_logic := '1'; -- MCB's UIDRPUPDATE port (gets passed to IODRP2_MCB's MEMUPDATE port: this controls shadow latch used
-- during IODRP2_MCB writes). Currently just trasnparent
MCB_UIBROADCAST : out std_logic; -- only to MCB's UIBROADCAST port (User Input BROADCAST - gets passed to IODRP2_MCB's BKST port)
MCB_UIADDR : out std_logic_vector(4 downto 0) := "00000"; -- to MCB's UIADDR port (gets passed to IODRP2_MCB's AUXADDR port
MCB_UICMDEN : out std_logic := '1'; -- set to 1 to take control of UI interface - removes control from internal calib block
MCB_UIDONECAL : out std_logic := '0'; -- set to 0 to "tell" controller that it's still in a calibrate state
MCB_UIDQLOWERDEC : out std_logic ;
MCB_UIDQLOWERINC : out std_logic ;
MCB_UIDQUPPERDEC : out std_logic ;
MCB_UIDQUPPERINC : out std_logic ;
MCB_UILDQSDEC : out std_logic := '0';
MCB_UILDQSINC : out std_logic := '0';
MCB_UIREAD : out std_logic; -- enables read w/o writing by turning on a SDO->SDI loopback inside the IODRP2_MCBs (doesn't exist in
-- regular IODRP2). IODRPCTRLR_R_WB becomes don't-care.
MCB_UIUDQSDEC : out std_logic := '0';
MCB_UIUDQSINC : out std_logic := '0';
MCB_RECAL : out std_logic ; -- future hook to drive MCB's RECAL pin - initiates a hard re-calibration sequence when high
MCB_UICMD : out std_logic;
MCB_UICMDIN : out std_logic;
MCB_UIDQCOUNT : out std_logic_vector(3 downto 0);
MCB_UODATA : in std_logic_vector(7 downto 0);
MCB_UODATAVALID : in std_logic;
MCB_UOCMDREADY : in std_logic;
MCB_UO_CAL_START : in std_logic;
MCB_SYSRST : out std_logic; -- drives the MCB's SYSRST pin - the main reset for MCB
Max_Value : out std_logic_vector(7 downto 0);
CKE_Train : out std_logic
);
end entity mcb_soft_calibration;
architecture trans of mcb_soft_calibration is
constant IOI_DQ0 : std_logic_vector(4 downto 0) := ("0000" & '1');
constant IOI_DQ1 : std_logic_vector(4 downto 0) := ("0000" & '0');
constant IOI_DQ2 : std_logic_vector(4 downto 0) := ("0001" & '1');
constant IOI_DQ3 : std_logic_vector(4 downto 0) := ("0001" & '0');
constant IOI_DQ4 : std_logic_vector(4 downto 0) := ("0010" & '1');
constant IOI_DQ5 : std_logic_vector(4 downto 0) := ("0010" & '0');
constant IOI_DQ6 : std_logic_vector(4 downto 0) := ("0011" & '1');
constant IOI_DQ7 : std_logic_vector(4 downto 0) := ("0011" & '0');
constant IOI_DQ8 : std_logic_vector(4 downto 0) := ("0100" & '1');
constant IOI_DQ9 : std_logic_vector(4 downto 0) := ("0100" & '0');
constant IOI_DQ10 : std_logic_vector(4 downto 0) := ("0101" & '1');
constant IOI_DQ11 : std_logic_vector(4 downto 0) := ("0101" & '0');
constant IOI_DQ12 : std_logic_vector(4 downto 0) := ("0110" & '1');
constant IOI_DQ13 : std_logic_vector(4 downto 0) := ("0110" & '0');
constant IOI_DQ14 : std_logic_vector(4 downto 0) := ("0111" & '1');
constant IOI_DQ15 : std_logic_vector(4 downto 0) := ("0111" & '0');
constant IOI_UDM : std_logic_vector(4 downto 0) := ("1000" & '1');
constant IOI_LDM : std_logic_vector(4 downto 0) := ("1000" & '0');
constant IOI_CK_P : std_logic_vector(4 downto 0) := ("1001" & '1');
constant IOI_CK_N : std_logic_vector(4 downto 0) := ("1001" & '0');
constant IOI_RESET : std_logic_vector(4 downto 0) := ("1010" & '1');
constant IOI_A11 : std_logic_vector(4 downto 0) := ("1010" & '0');
constant IOI_WE : std_logic_vector(4 downto 0) := ("1011" & '1');
constant IOI_BA2 : std_logic_vector(4 downto 0) := ("1011" & '0');
constant IOI_BA0 : std_logic_vector(4 downto 0) := ("1100" & '1');
constant IOI_BA1 : std_logic_vector(4 downto 0) := ("1100" & '0');
constant IOI_RASN : std_logic_vector(4 downto 0) := ("1101" & '1');
constant IOI_CASN : std_logic_vector(4 downto 0) := ("1101" & '0');
constant IOI_UDQS_CLK : std_logic_vector(4 downto 0) := ("1110" & '1');
constant IOI_UDQS_PIN : std_logic_vector(4 downto 0) := ("1110" & '0');
constant IOI_LDQS_CLK : std_logic_vector(4 downto 0) := ("1111" & '1');
constant IOI_LDQS_PIN : std_logic_vector(4 downto 0) := ("1111" & '0');
constant START : std_logic_vector(5 downto 0) := "000000";
constant LOAD_RZQ_NTERM : std_logic_vector(5 downto 0) := "000001";
constant WAIT1 : std_logic_vector(5 downto 0) := "000010";
constant LOAD_RZQ_PTERM : std_logic_vector(5 downto 0) := "000011";
constant WAIT2 : std_logic_vector(5 downto 0) := "000100";
constant INC_PTERM : std_logic_vector(5 downto 0) := "000101";
constant MULTIPLY_DIVIDE : std_logic_vector(5 downto 0) := "000110";
constant LOAD_ZIO_PTERM : std_logic_vector(5 downto 0) := "000111";
constant WAIT3 : std_logic_vector(5 downto 0) := "001000";
constant LOAD_ZIO_NTERM : std_logic_vector(5 downto 0) := "001001";
constant WAIT4 : std_logic_vector(5 downto 0) := "001010";
constant INC_NTERM : std_logic_vector(5 downto 0) := "001011";
constant SKEW : std_logic_vector(5 downto 0) := "001100";
constant WAIT_FOR_START_BROADCAST : std_logic_vector(5 downto 0) := "001101";
constant BROADCAST_PTERM : std_logic_vector(5 downto 0) := "001110";
constant WAIT5 : std_logic_vector(5 downto 0) := "001111";
constant BROADCAST_NTERM : std_logic_vector(5 downto 0) := "010000";
constant WAIT6 : std_logic_vector(5 downto 0) := "010001";
constant LDQS_CLK_WRITE_P_TERM : std_logic_vector(5 downto 0) := "010010";
constant LDQS_CLK_P_TERM_WAIT : std_logic_vector(5 downto 0) := "010011";
constant LDQS_CLK_WRITE_N_TERM : std_logic_vector(5 downto 0) := "010100";
constant LDQS_CLK_N_TERM_WAIT : std_logic_vector(5 downto 0) := "010101";
constant LDQS_PIN_WRITE_P_TERM : std_logic_vector(5 downto 0) := "010110";
constant LDQS_PIN_P_TERM_WAIT : std_logic_vector(5 downto 0) := "010111";
constant LDQS_PIN_WRITE_N_TERM : std_logic_vector(5 downto 0) := "011000";
constant LDQS_PIN_N_TERM_WAIT : std_logic_vector(5 downto 0) := "011001";
constant UDQS_CLK_WRITE_P_TERM : std_logic_vector(5 downto 0) := "011010";
constant UDQS_CLK_P_TERM_WAIT : std_logic_vector(5 downto 0) := "011011";
constant UDQS_CLK_WRITE_N_TERM : std_logic_vector(5 downto 0) := "011100";
constant UDQS_CLK_N_TERM_WAIT : std_logic_vector(5 downto 0) := "011101";
constant UDQS_PIN_WRITE_P_TERM : std_logic_vector(5 downto 0) := "011110";
constant UDQS_PIN_P_TERM_WAIT : std_logic_vector(5 downto 0) := "011111";
constant UDQS_PIN_WRITE_N_TERM : std_logic_vector(5 downto 0) := "100000";
constant UDQS_PIN_N_TERM_WAIT : std_logic_vector(5 downto 0) := "100001";
constant OFF_RZQ_PTERM : std_logic_vector(5 downto 0) := "100010";
constant WAIT7 : std_logic_vector(5 downto 0) := "100011";
constant OFF_ZIO_NTERM : std_logic_vector(5 downto 0) := "100100";
constant WAIT8 : std_logic_vector(5 downto 0) := "100101";
constant RST_DELAY : std_logic_vector(5 downto 0) := "100110";
constant START_DYN_CAL_PRE : std_logic_vector(5 downto 0) := "100111";
constant WAIT_FOR_UODONE : std_logic_vector(5 downto 0) := "101000";
constant LDQS_WRITE_POS_INDELAY : std_logic_vector(5 downto 0) := "101001";
constant LDQS_WAIT1 : std_logic_vector(5 downto 0) := "101010";
constant LDQS_WRITE_NEG_INDELAY : std_logic_vector(5 downto 0) := "101011";
constant LDQS_WAIT2 : std_logic_vector(5 downto 0) := "101100";
constant UDQS_WRITE_POS_INDELAY : std_logic_vector(5 downto 0) := "101101";
constant UDQS_WAIT1 : std_logic_vector(5 downto 0) := "101110";
constant UDQS_WRITE_NEG_INDELAY : std_logic_vector(5 downto 0) := "101111";
constant UDQS_WAIT2 : std_logic_vector(5 downto 0) := "110000";
constant START_DYN_CAL : std_logic_vector(5 downto 0) := "110001";
constant WRITE_CALIBRATE : std_logic_vector(5 downto 0) := "110010";
constant WAIT9 : std_logic_vector(5 downto 0) := "110011";
constant READ_MAX_VALUE : std_logic_vector(5 downto 0) := "110100";
constant WAIT10 : std_logic_vector(5 downto 0) := "110101";
constant ANALYZE_MAX_VALUE : std_logic_vector(5 downto 0) := "110110";
constant FIRST_DYN_CAL : std_logic_vector(5 downto 0) := "110111";
constant INCREMENT : std_logic_vector(5 downto 0) := "111000";
constant DECREMENT : std_logic_vector(5 downto 0) := "111001";
constant DONE : std_logic_vector(5 downto 0) := "111010";
--constant INCREMENT_TA : std_logic_vector(5 downto 0) := "111011";
constant RZQ : std_logic_vector(1 downto 0) := "00";
constant ZIO : std_logic_vector(1 downto 0) := "01";
constant MCB_PORT : std_logic_vector(1 downto 0) := "11";
constant WRITE_MODE : std_logic := '0';
constant READ_MODE : std_logic := '1';
-- IOI Registers
constant NoOp : std_logic_vector(7 downto 0) := "00000000";
constant DelayControl : std_logic_vector(7 downto 0) := "00000001";
constant PosEdgeInDly : std_logic_vector(7 downto 0) := "00000010";
constant NegEdgeInDly : std_logic_vector(7 downto 0) := "00000011";
constant PosEdgeOutDly : std_logic_vector(7 downto 0) := "00000100";
constant NegEdgeOutDly : std_logic_vector(7 downto 0) := "00000101";
constant MiscCtl1 : std_logic_vector(7 downto 0) := "00000110";
constant MiscCtl2 : std_logic_vector(7 downto 0) := "00000111";
constant MaxValue : std_logic_vector(7 downto 0) := "00001000";
-- IOB Registers
constant PDrive : std_logic_vector(7 downto 0) := "10000000";
constant PTerm : std_logic_vector(7 downto 0) := "10000001";
constant NDrive : std_logic_vector(7 downto 0) := "10000010";
constant NTerm : std_logic_vector(7 downto 0) := "10000011";
constant SlewRateCtl : std_logic_vector(7 downto 0) := "10000100";
constant LVDSControl : std_logic_vector(7 downto 0) := "10000101";
constant MiscControl : std_logic_vector(7 downto 0) := "10000110";
constant InputControl : std_logic_vector(7 downto 0) := "10000111";
constant TestReadback : std_logic_vector(7 downto 0) := "10001000";
-- No multi/divide is required when a 55 ohm resister is used on RZQ
-- localparam MULT = 1;
-- localparam DIV = 1;
-- use 7/4 scaling factor when the 100 ohm RZQ is used
constant MULT : integer := 7;
constant DIV : integer := 4;
constant PNSKEW : std_logic := '1'; -- Default is 1'b1. Change to 1'b0 if PSKEW and NSKEW are not required
constant PNSKEWDQS : std_logic := '1';
constant MULT_S : integer := 9;
constant DIV_S : integer := 8;
constant MULT_W : integer := 7;
constant DIV_W : integer := 8;
constant DQS_NUMERATOR : integer := 3;
constant DQS_DENOMINATOR : integer := 8;
constant INCDEC_THRESHOLD : std_logic_vector(7 downto 0) := X"03";
-- parameter for the threshold which triggers an inc/dec to occur. 2 for half, 4 for quarter,
-- 3 for three eighths
constant RST_CNT : std_logic_vector(9 downto 0) := "0000010000";
constant IN_TERM_PASS : std_logic := '0';
constant DYN_CAL_PASS : std_logic := '1';
function TZQINIT_MAXCNT_W return std_logic_vector is
variable temp : std_logic_vector(9 downto 0) := (others=>'0');
begin
if (C_MEM_TYPE = "DDR3") then
temp := C_MEM_TZQINIT_MAXCNT + RST_CNT;
else
temp := 8 + RST_CNT;
end if;
return temp(9 downto 0);
end function;
constant TZQINIT_MAXCNT : std_logic_vector(9 downto 0) := TZQINIT_MAXCNT_W;
component iodrp_mcb_controller is
port (
memcell_address : in std_logic_vector(7 downto 0);
write_data : in std_logic_vector(7 downto 0);
read_data : out std_logic_vector(7 downto 0);
rd_not_write : in std_logic;
cmd_valid : in std_logic;
rdy_busy_n : out std_logic;
use_broadcast : in std_logic;
drp_ioi_addr : in std_logic_vector(4 downto 0);
sync_rst : in std_logic;
DRP_CLK : in std_logic;
DRP_CS : out std_logic;
DRP_SDI : out std_logic;
DRP_ADD : out std_logic;
DRP_BKST : out std_logic;
DRP_SDO : in std_logic;
MCB_UIREAD : out std_logic
);
end component;
component iodrp_controller is
port (
memcell_address : in std_logic_vector(7 downto 0);
write_data : in std_logic_vector(7 downto 0);
read_data : out std_logic_vector(7 downto 0);
rd_not_write : in std_logic;
cmd_valid : in std_logic;
rdy_busy_n : out std_logic;
use_broadcast : in std_logic;
sync_rst : in std_logic;
DRP_CLK : in std_logic;
DRP_CS : out std_logic;
DRP_SDI : out std_logic;
DRP_ADD : out std_logic;
DRP_BKST : out std_logic;
DRP_SDO : in std_logic
);
end component;
signal P_Term : std_logic_vector(5 downto 0) := "000000";
signal N_Term : std_logic_vector(6 downto 0) := "0000000";
signal P_Term_s : std_logic_vector(5 downto 0) := "000000";
signal N_Term_s : std_logic_vector(6 downto 0) := "0000000";
signal P_Term_w : std_logic_vector(5 downto 0) := "000000";
signal N_Term_w : std_logic_vector(6 downto 0) := "0000000";
signal P_Term_Prev : std_logic_vector(5 downto 0) := "000000";
signal N_Term_Prev : std_logic_vector(6 downto 0) := "0000000";
signal STATE : std_logic_vector(5 downto 0);
signal IODRPCTRLR_MEMCELL_ADDR : std_logic_vector(7 downto 0);
signal IODRPCTRLR_WRITE_DATA : std_logic_vector(7 downto 0);
signal Active_IODRP : std_logic_vector(1 downto 0);
signal IODRPCTRLR_R_WB : std_logic := '0';
signal IODRPCTRLR_CMD_VALID : std_logic := '0';
signal IODRPCTRLR_USE_BKST : std_logic := '0';
signal MCB_CMD_VALID : std_logic := '0';
signal MCB_USE_BKST : std_logic := '0';
signal Pre_SYSRST : std_logic := '1'; -- internally generated reset which will OR with RST input to drive MCB's
-- SYSRST pin (MCB_SYSRST)
signal IODRP_SDO : std_logic;
signal Max_Value_Previous : std_logic_vector(7 downto 0) := "00000000";
signal count : std_logic_vector(5 downto 0) := "000000"; -- counter for adding 18 extra clock cycles after setting Calibrate bit
signal counter_en : std_logic := '0'; -- counter enable for "count"
signal First_Dyn_Cal_Done : std_logic := '0'; -- flag - high after the very first dynamic calibration is done
signal START_BROADCAST : std_logic ; -- Trigger to start Broadcast to IODRP2_MCBs to set Input Impedance -
-- state machine will wait for this to be high
signal DQS_DELAY_INITIAL : std_logic_vector(7 downto 0) := "00000000";
signal DQS_DELAY : std_logic_vector(7 downto 0); -- contains the latest values written to LDQS and UDQS Input Delays
signal TARGET_DQS_DELAY : std_logic_vector(7 downto 0); -- used to track the target for DQS input delays - only gets updated if
-- the Max Value changes by more than the threshold
signal counter_inc : std_logic_vector(7 downto 0); -- used to delay Inc signal by several ui_clk cycles (to deal with
-- latency on UOREFRSHFLAG)
signal counter_dec : std_logic_vector(7 downto 0); -- used to delay Dec signal by several ui_clk cycles (to deal with
-- latency on UOREFRSHFLAG)
signal IODRPCTRLR_READ_DATA : std_logic_vector(7 downto 0);
signal IODRPCTRLR_RDY_BUSY_N : std_logic;
signal IODRP_CS : std_logic;
signal MCB_READ_DATA : std_logic_vector(7 downto 0);
signal RST_reg : std_logic;
signal Block_Reset : std_logic;
signal MCB_UODATAVALID_U : std_logic;
signal Inc_Dec_REFRSH_Flag : std_logic_vector(2 downto 0); -- 3-bit flag to show:Inc is needed, Dec needed, refresh cycle taking place
signal Max_Value_Delta_Up : std_logic_vector(7 downto 0); -- tracks amount latest Max Value has gone up from previous Max Value read
signal Half_MV_DU : std_logic_vector(7 downto 0); -- half of Max_Value_Delta_Up
signal Max_Value_Delta_Dn : std_logic_vector(7 downto 0); -- tracks amount latest Max Value has gone down from previous Max Value read
signal Half_MV_DD : std_logic_vector(7 downto 0); -- half of Max_Value_Delta_Dn
signal RstCounter : std_logic_vector(9 downto 0) := (others => '0');
signal rst_tmp : std_logic;
signal LastPass_DynCal : std_logic;
signal First_In_Term_Done : std_logic;
signal Inc_Flag : std_logic; -- flag to increment Dynamic Delay
signal Dec_Flag : std_logic; -- flag to decrement Dynamic Delay
signal CALMODE_EQ_CALIBRATION : std_logic; -- will calculate and set the DQS input delays if C_MC_CALIBRATION_MODE
-- parameter = "CALIBRATION"
signal DQS_DELAY_LOWER_LIMIT : std_logic_vector(7 downto 0); -- Lower limit for DQS input delays
signal DQS_DELAY_UPPER_LIMIT : std_logic_vector(7 downto 0); -- Upper limit for DQS input delays
signal SKIP_DYN_IN_TERMINATION : std_logic; -- wire to allow skipping dynamic input termination if either the
-- one-time or dynamic parameters are 1
signal SKIP_DYNAMIC_DQS_CAL : std_logic; -- wire allowing skipping dynamic DQS delay calibration if either
-- SKIP_DYNIMIC_CAL=1, or if C_MC_CALIBRATION_MODE=NOCALIBRATION
signal Quarter_Max_Value : std_logic_vector(7 downto 0);
signal Half_Max_Value : std_logic_vector(7 downto 0);
signal PLL_LOCK_R1 : std_logic;
signal PLL_LOCK_R2 : std_logic;
signal MCB_RDY_BUSY_N : std_logic;
signal SELFREFRESH_REQ_R1 : std_logic;
signal SELFREFRESH_REQ_R2 : std_logic;
signal SELFREFRESH_REQ_R3 : std_logic;
signal SELFREFRESH_MCB_MODE_R1 : std_logic;
signal SELFREFRESH_MCB_MODE_R2 : std_logic;
signal SELFREFRESH_MCB_MODE_R3 : std_logic;
signal WAIT_SELFREFRESH_EXIT_DQS_CAL : std_logic;
signal PERFORM_START_DYN_CAL_AFTER_SELFREFRESH : std_logic;
signal START_DYN_CAL_STATE_R1 : std_logic;
signal PERFORM_START_DYN_CAL_AFTER_SELFREFRESH_R1 : std_logic;
-- Declare intermediate signals for referenced outputs
signal IODRP_ADD_xilinx0 : std_logic;
signal IODRP_SDI_xilinx1 : std_logic;
signal MCB_UIADD_xilinx2 : std_logic;
signal MCB_UISDI_xilinx11 : std_logic;
signal MCB_UICS_xilinx6 : std_logic;
signal MCB_UIBROADCAST_xilinx4 : std_logic;
signal MCB_UIADDR_int : std_logic_vector(4 downto 0);
signal MCB_UIDONECAL_xilinx7 : std_logic;
signal MCB_UIREAD_xilinx10 : std_logic;
signal SELFREFRESH_MODE_xilinx11 : std_logic;
signal Max_Value_int : std_logic_vector(7 downto 0);
signal Rst_condition1 : std_logic;
--signal Rst_condition2 : std_logic;
signal non_violating_rst : std_logic;
signal WAIT_200us_COUNTER : std_logic_vector(15 downto 0);
signal WaitTimer : std_logic_vector(7 downto 0);
signal WarmEnough : std_logic;
signal WaitCountEnable : std_logic;
signal State_Start_DynCal_R1 : std_logic;
signal State_Start_DynCal : std_logic;
signal pre_sysrst_minpulse_width_ok : std_logic;
signal pre_sysrst_cnt : std_logic_vector(3 downto 0);
-- This function multiplies by a constant MULT and then divides by the DIV constant
function Mult_Divide (Input : std_logic_vector(7 downto 0); MULT : integer ; DIV : integer ) return std_logic_vector is
variable Result : integer := 0;
variable temp : std_logic_vector(14 downto 0) := "000000000000000";
begin
for count in 0 to (MULT-1) loop
temp := temp + ("0000000" & Input);
end loop;
Result := (to_integer(unsigned(temp))) / (DIV);
temp := std_logic_vector(to_unsigned(Result,15));
return temp(7 downto 0);
end function Mult_Divide;
attribute syn_preserve : boolean;
attribute syn_preserve of P_Term : signal is TRUE;
attribute syn_preserve of N_Term : signal is TRUE;
attribute syn_preserve of P_Term_s : signal is TRUE;
attribute syn_preserve of N_Term_s : signal is TRUE;
attribute syn_preserve of P_Term_w : signal is TRUE;
attribute syn_preserve of N_Term_w : signal is TRUE;
attribute syn_preserve of P_Term_Prev : signal is TRUE;
attribute syn_preserve of N_Term_Prev : signal is TRUE;
attribute syn_preserve of IODRPCTRLR_MEMCELL_ADDR : signal is TRUE;
attribute syn_preserve of IODRPCTRLR_WRITE_DATA : signal is TRUE;
attribute syn_preserve of Max_Value_Previous : signal is TRUE;
attribute syn_preserve of DQS_DELAY_INITIAL : signal is TRUE;
attribute iob : string;
attribute iob of DONE_SOFTANDHARD_CAL : signal is "FALSE";
begin
-- move the default assignment here to make FORMALITY happy.
START_BROADCAST <= '1';
MCB_RECAL <= '0';
MCB_UIDQLOWERDEC <= '0';
MCB_UIADDR <= MCB_UIADDR_int;
MCB_UIDQLOWERINC <= '0';
MCB_UIDQUPPERDEC <= '0';
MCB_UIDQUPPERINC <= '0';
Max_Value <= Max_Value_int;
-- Drive referenced outputs
IODRP_ADD <= IODRP_ADD_xilinx0;
IODRP_SDI <= IODRP_SDI_xilinx1;
MCB_UIADD <= MCB_UIADD_xilinx2;
MCB_UISDI <= MCB_UISDI_xilinx11;
MCB_UICS <= MCB_UICS_xilinx6;
MCB_UIBROADCAST <= MCB_UIBROADCAST_xilinx4;
MCB_UIDONECAL <= MCB_UIDONECAL_xilinx7;
MCB_UIREAD <= MCB_UIREAD_xilinx10;
SELFREFRESH_MODE <= SELFREFRESH_MODE_xilinx11;
Inc_Dec_REFRSH_Flag <= (Inc_Flag & Dec_Flag & MCB_UOREFRSHFLAG);
Max_Value_Delta_Up <= Max_Value_int - Max_Value_Previous;
Half_MV_DU <= ('0' & Max_Value_Delta_Up(7 downto 1));
Max_Value_Delta_Dn <= Max_Value_Previous - Max_Value_int;
Half_MV_DD <= ('0' & Max_Value_Delta_Dn(7 downto 1));
CALMODE_EQ_CALIBRATION <= '1' when (C_MC_CALIBRATION_MODE = "CALIBRATION") else '0'; -- will calculate and set the DQS input delays if = 1'b1
Half_Max_Value <= ('0' & Max_Value_int(7 downto 1));
Quarter_Max_Value <= ("00" & Max_Value_int(7 downto 2));
DQS_DELAY_LOWER_LIMIT <= Quarter_Max_Value; -- limit for DQS_DELAY for decrements; could optionally be assigned to any 8-bit hex value here
DQS_DELAY_UPPER_LIMIT <= Half_Max_Value; -- limit for DQS_DELAY for increments; could optionally be assigned to any 8-bit hex value here
SKIP_DYN_IN_TERMINATION <= '1' when ((SKIP_DYN_IN_TERM = 1) or (SKIP_IN_TERM_CAL = 1)) else '0';
-- skip dynamic input termination if either the one-time or dynamic parameters are 1
SKIP_DYNAMIC_DQS_CAL <= '1' when ((CALMODE_EQ_CALIBRATION = '0') or (SKIP_DYNAMIC_CAL = 1)) else '0';
-- skip dynamic DQS delay calibration if either SKIP_DYNAMIC_CAL=1, or if C_MC_CALIBRATION_MODE=NOCALIBRATION
process (UI_CLK)
begin
if (UI_CLK'event and UI_CLK = '1') then
if ((DQS_DELAY_INITIAL /= X"00") or (STATE = DONE)) then
DONE_SOFTANDHARD_CAL <= MCB_UODONECAL; -- high when either DQS input delays initialized, or STATE=DONE and UODONECAL high
else
DONE_SOFTANDHARD_CAL <= '0';
end if;
end if;
end process;
iodrp_controller_inst : iodrp_controller
port map (
memcell_address => IODRPCTRLR_MEMCELL_ADDR,
write_data => IODRPCTRLR_WRITE_DATA,
read_data => IODRPCTRLR_READ_DATA,
rd_not_write => IODRPCTRLR_R_WB,
cmd_valid => IODRPCTRLR_CMD_VALID,
rdy_busy_n => IODRPCTRLR_RDY_BUSY_N,
use_broadcast => '0',
sync_rst => RST_reg,
DRP_CLK => UI_CLK,
DRP_CS => IODRP_CS,
DRP_SDI => IODRP_SDI_xilinx1,
DRP_ADD => IODRP_ADD_xilinx0,
DRP_SDO => IODRP_SDO,
DRP_BKST => open
);
iodrp_mcb_controller_inst : iodrp_mcb_controller
port map (
memcell_address => IODRPCTRLR_MEMCELL_ADDR,
write_data => IODRPCTRLR_WRITE_DATA,
read_data => MCB_READ_DATA,
rd_not_write => IODRPCTRLR_R_WB,
cmd_valid => MCB_CMD_VALID,
rdy_busy_n => MCB_RDY_BUSY_N,
use_broadcast => MCB_USE_BKST,
drp_ioi_addr => MCB_UIADDR_int,
sync_rst => RST_reg,
DRP_CLK => UI_CLK,
DRP_CS => MCB_UICS_xilinx6,
DRP_SDI => MCB_UISDI_xilinx11,
DRP_ADD => MCB_UIADD_xilinx2,
DRP_BKST => MCB_UIBROADCAST_xilinx4,
DRP_SDO => MCB_UOSDO,
MCB_UIREAD => MCB_UIREAD_xilinx10
);
process (UI_CLK, RST) begin
if (RST = '1') then
if (C_SIMULATION = "TRUE") then
WAIT_200us_COUNTER <= X"7FF0";
else
WAIT_200us_COUNTER <= (others => '0');
end if;
elsif (UI_CLK'event and UI_CLK = '1') then
if (WAIT_200us_COUNTER(15) = '1') then
WAIT_200us_COUNTER <= WAIT_200us_COUNTER;
else
WAIT_200us_COUNTER <= WAIT_200us_COUNTER + '1';
end if;
end if;
end process;
-- init_sequence_skip: if (C_SIMULATION = "TRUE") generate
-- WAIT_200us_COUNTER <= X"FFFF";
-- process
-- begin
-- report "The 200 us wait period required before CKE goes active has been skipped in Simulation";
-- wait;
-- end process;
-- end generate;
gen_CKE_Train_a: if (C_MEM_TYPE = "DDR2") generate
process (UI_CLK, RST) begin
if (RST = '1') then
CKE_Train <= '0';
elsif (UI_CLK'event and UI_CLK = '1') then
if (STATE = WAIT_FOR_UODONE and MCB_UODONECAL = '1') then
CKE_Train <= '0';
elsif (WAIT_200us_COUNTER(15) = '1' and MCB_UODONECAL = '0') then
CKE_Train <= '1';
else
CKE_Train <= '0';
end if;
end if;
end process;
end generate ;
gen_CKE_Train_b: if (not(C_MEM_TYPE = "DDR2")) generate
process (UI_CLK) begin
if (UI_CLK'event and UI_CLK = '1') then
CKE_Train <= '0';
end if;
end process;
end generate ;
--********************************************
-- PLL_LOCK and RST signals
--********************************************
--MCB_SYSRST <= Pre_SYSRST or RST_reg; -- Pre_SYSRST is generated from the STATE state machine, and is OR'd with RST_reg input to drive MCB's
-- SYSRST pin (MCB_SYSRST)
rst_tmp <= not(SELFREFRESH_MODE_xilinx11) and not(PLL_LOCK_R2); -- rst_tmp becomes 1 if you lose Lock and the device is not in SUSPEND
process (UI_CLK, RST) begin
if (RST = '1') then
--Block_Reset <= '0';
--RstCounter <= (others => '0');
--elsif (UI_CLK'event and UI_CLK = '1') then
-- if (rst_tmp = '1') then -- this is to deal with not allowing the user-reset "RST" to violate TZQINIT_MAXCNT (min time between resets to DDR3)
Block_Reset <= '0';
RstCounter <= (others => '0');
elsif (UI_CLK'event and UI_CLK = '1') then
Block_Reset <= '0'; -- default to allow STATE to move out of RST_DELAY state
if (Pre_SYSRST = '1') then
RstCounter <= RST_CNT; -- whenever STATE wants to reset the MCB, set RstCounter to h10
else
if (RstCounter < TZQINIT_MAXCNT) then -- if RstCounter is less than d512 than this will execute
Block_Reset <= '1'; -- STATE won't exit RST_DELAY state
RstCounter <= RstCounter + "1"; -- and Rst_Counter increments
end if;
end if;
end if;
--end if;
end process;
-- Rst_contidtion1 is to make sure RESET will not happen again within TZQINIT_MAXCNT
non_violating_rst <= RST and Rst_condition1;
MCB_SYSRST <= Pre_SYSRST;
process (UI_CLK) begin
if (UI_CLK'event and UI_CLK = '1') then
if (RstCounter >= TZQINIT_MAXCNT) then
Rst_condition1 <= '1';
else
Rst_condition1 <= '0';
end if;
end if;
end process;
-- -- non_violating_rst asserts whenever (system-level reset) RST is asserted but must be after TZQINIT_MAXCNT is reached (min-time between resets for DDR3)
-- -- After power stablizes, we will hold MCB in reset state for at least 200us before beginning initialization process.
-- -- If the PLL loses lock during normal operation, no ui_clk will be present because mcb_drp_clk is from a BUFGCE which
-- is gated by pll's lock signal. When the PLL locks again, the RST_reg stays asserted for at least 200 us which
-- will cause MCB to reset and reinitialize the memory afterwards.
-- -- During SUSPEND operation, the PLL will lose lock but non_violating_rst remains low (de-asserted) and WAIT_200us_COUNTER stays at
-- its terminal count. The PLL_LOCK input does not come direct from PLL, rather it is driven by gated_pll_lock from mcb_raw_wrapper module
-- The gated_pll_lock in the mcb_raw_wrapper does not de-assert during SUSPEND operation, hence PLL_LOCK will not de-assert, and the soft calibration
-- state machine will not reset during SUSPEND.
-- -- RST_reg is the control signal that resets the mcb_soft_calibration's State Machine. The MCB_SYSRST is now equal to
-- Pre_SYSRST. When State Machine is performing "INPUT Termination Calibration", it holds the MCB in reset by assertign MCB_SYSRST.
-- It will deassert the MCB_SYSRST so that it can grab the bus to broadcast the P and N term value to all of the DQ pins. Once the calibrated INPUT
-- termination is set, the State Machine will issue another short MCB_SYSRST so that MCB will use the tuned input termination during DQS preamble calibration.
--process (UI_CLK) begin
-- if (UI_CLK'event and UI_CLK = '1') then
--
-- if (RstCounter < RST_CNT) then
-- Rst_condition2 <= '1';
-- else
-- Rst_condition2 <= '0';
-- end if;
-- end if;
--end process;
process (UI_CLK, non_violating_rst) begin
if (non_violating_rst = '1') then
RST_reg <= '1'; -- STATE and MCB_SYSRST will both be reset if you lose lock when the device is not in SUSPEND
elsif (UI_CLK'event and UI_CLK = '1') then
if (WAIT_200us_COUNTER(15) = '0') then
RST_reg <= '1';
else
--RST_reg <= Rst_condition2 or rst_tmp; -- insures RST_reg is at least h10 pulses long
RST_reg <= rst_tmp; -- insures RST_reg is at least h10 pulses long
end if;
end if;
end process;
--*************************************************************
-- Stretching the pre_sysrst to satisfy the minimum pulse width
--*************************************************************
process (UI_CLK) begin
if (UI_CLK'event and UI_CLK = '1') then
if (STATE = START_DYN_CAL_PRE) then
pre_sysrst_cnt <= pre_sysrst_cnt + '1';
else
pre_sysrst_cnt <= (others=>'0');
end if;
end if;
end process;
pre_sysrst_minpulse_width_ok <= pre_sysrst_cnt(3);
--********************************************
-- SUSPEND Logic
--********************************************
process (UI_CLK,RST)
begin
if (RST = '1') then
SELFREFRESH_MCB_MODE_R1 <= '0';
SELFREFRESH_MCB_MODE_R2 <= '0';
SELFREFRESH_MCB_MODE_R3 <= '0';
SELFREFRESH_REQ_R1 <= '0';
SELFREFRESH_REQ_R2 <= '0';
SELFREFRESH_REQ_R3 <= '0';
PLL_LOCK_R1 <= '0';
PLL_LOCK_R2 <= '0';
elsif (UI_CLK'event and UI_CLK = '1') then
-- SELFREFRESH_MCB_MODE is clocked by sysclk_2x_180
SELFREFRESH_MCB_MODE_R1 <= SELFREFRESH_MCB_MODE;
SELFREFRESH_MCB_MODE_R2 <= SELFREFRESH_MCB_MODE_R1;
SELFREFRESH_MCB_MODE_R3 <= SELFREFRESH_MCB_MODE_R2;
-- SELFREFRESH_REQ is clocked by user's application clock
SELFREFRESH_REQ_R1 <= SELFREFRESH_REQ;
SELFREFRESH_REQ_R2 <= SELFREFRESH_REQ_R1;
SELFREFRESH_REQ_R3 <= SELFREFRESH_REQ_R2;
PLL_LOCK_R1 <= PLL_LOCK;
PLL_LOCK_R2 <= PLL_LOCK_R1;
end if;
end process;
-- SELFREFRESH should only be deasserted after PLL_LOCK is asserted.
-- This is to make sure MCB get a locked sys_2x_clk before exiting
-- SELFREFRESH mode.
process (UI_CLK)
begin
if (UI_CLK'event and UI_CLK = '1') then
if (RST = '1') then
SELFREFRESH_MCB_REQ <= '0';
--elsif ((PLL_LOCK_R2 = '1') and (SELFREFRESH_REQ_R3 = '0') and (STATE = START_DYN_CAL)) then
elsif ((PLL_LOCK_R2 = '1') and (SELFREFRESH_REQ_R3 = '0')) then
SELFREFRESH_MCB_REQ <= '0';
elsif ((STATE = START_DYN_CAL) and (SELFREFRESH_REQ_R3 = '1')) then
SELFREFRESH_MCB_REQ <= '1';
end if;
end if;
end process;
process (UI_CLK)
begin
if (UI_CLK'event and UI_CLK = '1') then
if (RST = '1') then
WAIT_SELFREFRESH_EXIT_DQS_CAL <= '0';
elsif ((SELFREFRESH_MCB_MODE_R2 = '1') and (SELFREFRESH_MCB_MODE_R3 = '0')) then
WAIT_SELFREFRESH_EXIT_DQS_CAL <= '1';
elsif ((WAIT_SELFREFRESH_EXIT_DQS_CAL = '1') and (SELFREFRESH_REQ_R3 = '0') and (PERFORM_START_DYN_CAL_AFTER_SELFREFRESH = '1')) then
-- START_DYN_CAL is next state
WAIT_SELFREFRESH_EXIT_DQS_CAL <= '0';
end if;
end if;
end process;
-- Need to detect when SM entering START_DYN_CAL
process (UI_CLK)
begin
if (UI_CLK'event and UI_CLK = '1') then
if (RST = '1') then
PERFORM_START_DYN_CAL_AFTER_SELFREFRESH <= '0';
START_DYN_CAL_STATE_R1 <= '0';
else
-- register PERFORM_START_DYN_CAL_AFTER_SELFREFRESH to detect end of cycle
PERFORM_START_DYN_CAL_AFTER_SELFREFRESH_R1 <= PERFORM_START_DYN_CAL_AFTER_SELFREFRESH;
if (STATE = START_DYN_CAL) then
START_DYN_CAL_STATE_R1 <= '1';
else
START_DYN_CAL_STATE_R1 <= '0';
end if;
if ((WAIT_SELFREFRESH_EXIT_DQS_CAL = '1') and (STATE /= START_DYN_CAL) and (START_DYN_CAL_STATE_R1 = '1')) then
PERFORM_START_DYN_CAL_AFTER_SELFREFRESH <= '1';
elsif ((STATE = START_DYN_CAL) and (SELFREFRESH_MCB_MODE_R3 = '0')) then
PERFORM_START_DYN_CAL_AFTER_SELFREFRESH <= '0';
end if;
end if;
end if;
end process;
-- SELFREFRESH_MCB_MODE deasserted status is hold off
-- until Soft_Calib has at least done one loop of DQS update.
-- New logic WarmeEnough is added to make sure PLL_Lock is lockec and all IOs stable before
-- deassert the status of MCB's SELFREFRESH_MODE. This is to ensure all IOs are stable before
-- user logic sending new commands to MCB.
process (UI_CLK)
begin
if (UI_CLK'event and UI_CLK = '1') then
if (RST = '1') then
SELFREFRESH_MODE_xilinx11 <= '0';
elsif (SELFREFRESH_MCB_MODE_R2 = '1') then
SELFREFRESH_MODE_xilinx11 <= '1';
elsif (WarmEnough = '1') then
SELFREFRESH_MODE_xilinx11 <= '0';
end if;
end if;
end process;
process (UI_CLK)
begin
if (UI_CLK'event and UI_CLK = '1') then
if (RST = '1') then
WaitCountEnable <= '0';
elsif (SELFREFRESH_REQ_R2 = '0' and SELFREFRESH_REQ_R1 = '1') then
WaitCountEnable <= '0';
elsif ((PERFORM_START_DYN_CAL_AFTER_SELFREFRESH = '0') and (PERFORM_START_DYN_CAL_AFTER_SELFREFRESH_R1 = '1')) then
WaitCountEnable <= '1';
else
WaitCountEnable <= WaitCountEnable;
end if;
end if;
end process;
process (UI_CLK)
begin
if (UI_CLK'event and UI_CLK = '1') then
if (RST = '1') then
State_Start_DynCal <= '0';
elsif (STATE = START_DYN_CAL) then
State_Start_DynCal <= '1';
else
State_Start_DynCal <= '0';
end if;
end if;
end process;
process (UI_CLK)
begin
if (UI_CLK'event and UI_CLK = '1') then
if (RST = '1') then
State_Start_DynCal_R1 <= '0';
else
State_Start_DynCal_R1 <= State_Start_DynCal;
end if;
end if;
end process;
process (UI_CLK)
begin
if (UI_CLK'event and UI_CLK = '1') then
if (RST = '1') then
WaitTimer <= (others => '0');
WarmEnough <= '1';
elsif ((SELFREFRESH_REQ_R2 = '0') and (SELFREFRESH_REQ_R1 = '1')) then
WaitTimer <= (others => '0');
WarmEnough <= '0';
elsif (WaitTimer = X"04") then
WaitTimer <= WaitTimer ;
WarmEnough <= '1';
elsif (WaitCountEnable = '1') then
WaitTimer <= WaitTimer + '1';
else
WaitTimer <= WaitTimer ;
end if;
end if;
end process;
--********************************************
--Comparitor for Dynamic Calibration circuit
--********************************************
Dec_Flag <= '1' when (TARGET_DQS_DELAY < DQS_DELAY) else '0';
Inc_Flag <= '1' when (TARGET_DQS_DELAY > DQS_DELAY) else '0';
--*********************************************************************************************
--Counter for extra clock cycles injected after setting Calibrate bit in IODRP2 for Dynamic Cal
--*********************************************************************************************
process (UI_CLK)
begin
if (UI_CLK'event and UI_CLK = '1') then
if (RST_reg = '1') then
count <= "000000";
elsif (counter_en = '1') then
count <= count + "000001";
else
count <= "000000";
end if;
end if;
end process;
--*********************************************************************************************
-- Capture narrow MCB_UODATAVALID pulse - only one sysclk90 cycle wide
--*********************************************************************************************
process (UI_CLK, MCB_UODATAVALID)
begin
if(MCB_UODATAVALID = '1') then
MCB_UODATAVALID_U <= '1';
elsif(UI_CLK'event and UI_CLK = '1') then
MCB_UODATAVALID_U <= MCB_UODATAVALID;
end if;
end process;
--**************************************************************************************************************
--Always block to mux SDI, SDO, CS, and ADD depending on which IODRP is active: RZQ, ZIO or MCB's UI port (to IODRP2_MCBs)
--**************************************************************************************************************
process (Active_IODRP, IODRP_CS, RZQ_IODRP_SDO, ZIO_IODRP_SDO)
begin
case Active_IODRP is
when RZQ =>
RZQ_IODRP_CS <= IODRP_CS;
ZIO_IODRP_CS <= '0';
IODRP_SDO <= RZQ_IODRP_SDO;
when ZIO =>
RZQ_IODRP_CS <= '0';
ZIO_IODRP_CS <= IODRP_CS;
IODRP_SDO <= ZIO_IODRP_SDO;
when MCB_PORT =>
RZQ_IODRP_CS <= '0';
ZIO_IODRP_CS <= '0';
IODRP_SDO <= '0';
when others =>
RZQ_IODRP_CS <= '0';
ZIO_IODRP_CS <= '0';
IODRP_SDO <= '0';
end case;
end process;
--******************************************************************
--State Machine's Always block / Case statement for Next State Logic
--
--The WAIT1,2,etc states were required after every state where the
--DRP controller was used to do a write to the IODRPs - this is because
--there's a clock cycle latency on IODRPCTRLR_RDY_BUSY_N whenever the DRP controller
--sees IODRPCTRLR_CMD_VALID go high. OFF_RZQ_PTERM and OFF_ZIO_NTERM were added
--soley for the purpose of reducing power, particularly on RZQ as
--that pin is expected to have a permanent external resistor to gnd.
--******************************************************************
NEXT_STATE_LOGIC: process (UI_CLK)
begin
if (UI_CLK'event and UI_CLK = '1') then
if (RST_reg = '1') then -- Synchronous reset
MCB_CMD_VALID <= '0';
MCB_UIADDR_int <= "00000"; -- take control of UI/UO port
MCB_UICMDEN <= '1'; -- tells MCB that it is in Soft Cal.
MCB_UIDONECAL_xilinx7 <= '0';
MCB_USE_BKST <= '0';
MCB_UIDRPUPDATE <= '1';
Pre_SYSRST <= '1'; -- keeps MCB in reset
IODRPCTRLR_CMD_VALID <= '0';
IODRPCTRLR_MEMCELL_ADDR <= NoOp;
IODRPCTRLR_WRITE_DATA <= "00000000";
IODRPCTRLR_R_WB <= WRITE_MODE;
IODRPCTRLR_USE_BKST <= '0';
P_Term <= "000000";
N_Term <= "0000000";
P_Term_s <= "000000";
N_Term_w <= "0000000";
P_Term_w <= "000000";
N_Term_s <= "0000000";
P_Term_Prev <= "000000";
N_Term_Prev <= "0000000";
Active_IODRP <= RZQ;
MCB_UILDQSINC <= '0'; --no inc or dec
MCB_UIUDQSINC <= '0'; --no inc or dec
MCB_UILDQSDEC <= '0'; --no inc or dec
MCB_UIUDQSDEC <= '0';
counter_en <= '0'; --flag that the First Dynamic Calibration completed
First_Dyn_Cal_Done <= '0';
Max_Value_int <= "00000000";
Max_Value_Previous <= "00000000";
STATE <= START;
DQS_DELAY <= "00000000";
DQS_DELAY_INITIAL <= "00000000";
TARGET_DQS_DELAY <= "00000000";
LastPass_DynCal <= IN_TERM_PASS;
First_In_Term_Done <= '0';
MCB_UICMD <= '0';
MCB_UICMDIN <= '0';
MCB_UIDQCOUNT <= "0000";
counter_inc <= "00000000";
counter_dec <= "00000000";
else
counter_en <= '0';
IODRPCTRLR_CMD_VALID <= '0';
IODRPCTRLR_MEMCELL_ADDR <= NoOp;
IODRPCTRLR_R_WB <= READ_MODE;
IODRPCTRLR_USE_BKST <= '0';
MCB_CMD_VALID <= '0'; --no inc or dec
MCB_UILDQSINC <= '0'; --no inc or dec
MCB_UIUDQSINC <= '0'; --no inc or dec
MCB_UILDQSDEC <= '0'; --no inc or dec
MCB_UIUDQSDEC <= '0';
MCB_USE_BKST <= '0';
MCB_UICMDIN <= '0';
DQS_DELAY <= DQS_DELAY;
TARGET_DQS_DELAY <= TARGET_DQS_DELAY;
case STATE is
when START => --h00
MCB_UICMDEN <= '1'; -- take control of UI/UO port
MCB_UIDONECAL_xilinx7 <= '0'; -- tells MCB that it is in Soft Cal.
P_Term <= "000000";
N_Term <= "0000000";
Pre_SYSRST <= '1'; -- keeps MCB in reset
LastPass_DynCal <= IN_TERM_PASS;
if (SKIP_IN_TERM_CAL = 1) then
--STATE <= WRITE_CALIBRATE;
STATE <= WAIT_FOR_START_BROADCAST;
P_Term <= "000000";
N_Term <= "0000000";
elsif (IODRPCTRLR_RDY_BUSY_N = '1') then
STATE <= LOAD_RZQ_NTERM;
else
STATE <= START;
end if;
--***************************
-- IOB INPUT TERMINATION CAL
--***************************
when LOAD_RZQ_NTERM => --h01
Active_IODRP <= RZQ;
IODRPCTRLR_CMD_VALID <= '1';
IODRPCTRLR_MEMCELL_ADDR <= NTerm;
IODRPCTRLR_WRITE_DATA <= ('0' & N_Term);
IODRPCTRLR_R_WB <= WRITE_MODE;
if (IODRPCTRLR_RDY_BUSY_N = '1') then
STATE <= LOAD_RZQ_NTERM;
else
STATE <= WAIT1;
end if;
when WAIT1 => --h02
if (IODRPCTRLR_RDY_BUSY_N = '0') then
STATE <= WAIT1;
else
STATE <= LOAD_RZQ_PTERM;
end if;
when LOAD_RZQ_PTERM => --h03
IODRPCTRLR_CMD_VALID <= '1';
IODRPCTRLR_MEMCELL_ADDR <= PTerm;
IODRPCTRLR_WRITE_DATA <= ("00" & P_Term);
IODRPCTRLR_R_WB <= WRITE_MODE;
if (IODRPCTRLR_RDY_BUSY_N = '1') then
STATE <= LOAD_RZQ_PTERM;
else
STATE <= WAIT2;
end if;
when WAIT2 => --h04
if (IODRPCTRLR_RDY_BUSY_N = '0') then
STATE <= WAIT2;
elsif ((RZQ_IN = '1') or (P_Term = "111111")) then
STATE <= MULTIPLY_DIVIDE; -- LOAD_ZIO_PTERM
else
STATE <= INC_PTERM;
end if;
when INC_PTERM => --h05
P_Term <= P_Term + "000001";
STATE <= LOAD_RZQ_PTERM;
when MULTIPLY_DIVIDE => -- h06
-- 13/4/2011 compensate the added sync FF
P_Term <= Mult_Divide(("00" & (P_Term - '1')),MULT,DIV)(5 downto 0);
STATE <= LOAD_ZIO_PTERM;
when LOAD_ZIO_PTERM => --h07
Active_IODRP <= ZIO;
IODRPCTRLR_CMD_VALID <= '1';
IODRPCTRLR_MEMCELL_ADDR <= PTerm;
IODRPCTRLR_WRITE_DATA <= ("00" & P_Term);
IODRPCTRLR_R_WB <= WRITE_MODE;
if (IODRPCTRLR_RDY_BUSY_N = '1') then
STATE <= LOAD_ZIO_PTERM;
else
STATE <= WAIT3;
end if;
when WAIT3 => --h08
if ((not(IODRPCTRLR_RDY_BUSY_N)) = '1') then
STATE <= WAIT3;
else
STATE <= LOAD_ZIO_NTERM;
end if;
when LOAD_ZIO_NTERM => --h09
Active_IODRP <= ZIO;
IODRPCTRLR_CMD_VALID <= '1';
IODRPCTRLR_MEMCELL_ADDR <= NTerm;
IODRPCTRLR_WRITE_DATA <= ('0' & N_Term);
IODRPCTRLR_R_WB <= WRITE_MODE;
if (IODRPCTRLR_RDY_BUSY_N = '1') then
STATE <= LOAD_ZIO_NTERM;
else
STATE <= WAIT4;
end if;
when WAIT4 => --h0A
if ((not(IODRPCTRLR_RDY_BUSY_N)) = '1') then
STATE <= WAIT4;
elsif (((not(ZIO_IN))) = '1' or (N_Term = "1111111")) then
if (PNSKEW = '1') then
STATE <= SKEW;
else
STATE <= WAIT_FOR_START_BROADCAST;
end if;
else
STATE <= INC_NTERM;
end if;
when INC_NTERM => --h0B
N_Term <= N_Term + "0000001";
STATE <= LOAD_ZIO_NTERM;
when SKEW => -- h0C
P_Term_s <= Mult_Divide(("00" & P_Term), MULT_S, DIV_S)(5 downto 0);
N_Term_w <= Mult_Divide(('0' & (N_Term-'1')), MULT_W, DIV_W)(6 downto 0);
P_Term_w <= Mult_Divide(("00" & P_Term), MULT_W, DIV_W)(5 downto 0);
N_Term_s <= Mult_Divide(('0' & (N_Term-'1')), MULT_S, DIV_S)(6 downto 0);
P_Term <= Mult_Divide(("00" & P_Term), MULT_S, DIV_S)(5 downto 0);
N_Term <= Mult_Divide(('0' & (N_Term-'1')), MULT_W, DIV_W)(6 downto 0);
STATE <= WAIT_FOR_START_BROADCAST;
when WAIT_FOR_START_BROADCAST => --h0D
Pre_SYSRST <= '0'; -- release SYSRST, but keep UICMDEN=1 and UIDONECAL=0. This is needed to do Broadcast through UI interface, while
-- keeping the MCB in calibration mode
Active_IODRP <= MCB_PORT;
if ((START_BROADCAST and IODRPCTRLR_RDY_BUSY_N) = '1') then
if ((P_Term /= P_Term_Prev) or (SKIP_IN_TERM_CAL = 1)) then
STATE <= BROADCAST_PTERM;
P_Term_Prev <= P_Term;
elsif (N_Term /= N_Term_Prev) then
N_Term_Prev <= N_Term;
STATE <= BROADCAST_NTERM;
else
STATE <= OFF_RZQ_PTERM;
end if;
else
STATE <= WAIT_FOR_START_BROADCAST;
end if;
when BROADCAST_PTERM => --h0E
IODRPCTRLR_MEMCELL_ADDR <= PTerm;
IODRPCTRLR_WRITE_DATA <= ("00" & P_Term);
IODRPCTRLR_R_WB <= WRITE_MODE;
MCB_CMD_VALID <= '1';
MCB_UIDRPUPDATE <= not First_In_Term_Done; -- Set the update flag if this is the first time through
MCB_USE_BKST <= '1';
if (MCB_RDY_BUSY_N = '1') then
STATE <= BROADCAST_PTERM;
else
STATE <= WAIT5;
end if;
when WAIT5 => --h0F
if ((not(MCB_RDY_BUSY_N)) = '1') then
STATE <= WAIT5;
elsif (First_In_Term_Done = '1') then -- If first time through is already set, then this must be dynamic in term
if (MCB_UOREFRSHFLAG = '1')then
MCB_UIDRPUPDATE <= '1';
if (N_Term /= N_Term_Prev) then
N_Term_Prev <= N_Term;
STATE <= BROADCAST_NTERM;
else
STATE <= OFF_RZQ_PTERM;
end if;
else
STATE <= WAIT5; -- wait for a Refresh cycle
end if;
else
N_Term_Prev <= N_Term;
STATE <= BROADCAST_NTERM;
end if;
when BROADCAST_NTERM => -- h10
IODRPCTRLR_MEMCELL_ADDR <= NTerm;
IODRPCTRLR_WRITE_DATA <= ("0" & N_Term);
IODRPCTRLR_R_WB <= WRITE_MODE;
MCB_CMD_VALID <= '1';
MCB_USE_BKST <= '1';
MCB_UIDRPUPDATE <= not(First_In_Term_Done); -- Set the update flag if this is the first time through
if (MCB_RDY_BUSY_N = '1') then
STATE <= BROADCAST_NTERM;
else
STATE <= WAIT6;
end if;
when WAIT6 => -- h11
if (MCB_RDY_BUSY_N = '0') then
STATE <= WAIT6;
elsif (First_In_Term_Done = '1') then -- If first time through is already set, then this must be dynamic in term
if (MCB_UOREFRSHFLAG = '1')then
MCB_UIDRPUPDATE <= '1';
STATE <= OFF_RZQ_PTERM;
else
STATE <= WAIT6; -- wait for a Refresh cycle
end if;
else
-- if (PNSKEWDQS = '1') then
STATE <= LDQS_CLK_WRITE_P_TERM;
-- else
-- STATE <= OFF_RZQ_PTERM;
-- end if;
end if;
-- *********************
when LDQS_CLK_WRITE_P_TERM => -- h12
IODRPCTRLR_MEMCELL_ADDR <= PTerm;
IODRPCTRLR_R_WB <= WRITE_MODE;
IODRPCTRLR_WRITE_DATA <= "00" & P_Term_w;
MCB_UIADDR_int <= IOI_LDQS_CLK;
MCB_CMD_VALID <= '1';
if (MCB_RDY_BUSY_N = '1') then
STATE <= LDQS_CLK_WRITE_P_TERM;
else
STATE <= LDQS_CLK_P_TERM_WAIT;
end if;
when LDQS_CLK_P_TERM_WAIT => --7'h13
if (MCB_RDY_BUSY_N = '0') then
STATE <= LDQS_CLK_P_TERM_WAIT;
else
STATE <= LDQS_CLK_WRITE_N_TERM;
end if;
when LDQS_CLK_WRITE_N_TERM => --7'h14
IODRPCTRLR_MEMCELL_ADDR <= NTerm;
IODRPCTRLR_R_WB <= WRITE_MODE;
IODRPCTRLR_WRITE_DATA <= '0' & N_Term_s;
MCB_UIADDR_int <= IOI_LDQS_CLK;
MCB_CMD_VALID <= '1';
if (MCB_RDY_BUSY_N = '1') then
STATE <= LDQS_CLK_WRITE_N_TERM;
else
STATE <= LDQS_CLK_N_TERM_WAIT;
end if;
--**
when LDQS_CLK_N_TERM_WAIT => --7'h15
if (MCB_RDY_BUSY_N = '0') then
STATE <= LDQS_CLK_N_TERM_WAIT;
else
STATE <= LDQS_PIN_WRITE_P_TERM;
end if;
when LDQS_PIN_WRITE_P_TERM => --7'h16
IODRPCTRLR_MEMCELL_ADDR <= PTerm;
IODRPCTRLR_R_WB <= WRITE_MODE;
IODRPCTRLR_WRITE_DATA <= "00" & P_Term_s;
MCB_UIADDR_int <= IOI_LDQS_PIN;
MCB_CMD_VALID <= '1';
if (MCB_RDY_BUSY_N = '1') then
STATE <= LDQS_PIN_WRITE_P_TERM;
else
STATE <= LDQS_PIN_P_TERM_WAIT;
end if;
when LDQS_PIN_P_TERM_WAIT => --7'h17
if (MCB_RDY_BUSY_N = '0') then
STATE <= LDQS_PIN_P_TERM_WAIT;
else
STATE <= LDQS_PIN_WRITE_N_TERM;
end if;
when LDQS_PIN_WRITE_N_TERM => --7'h18
IODRPCTRLR_MEMCELL_ADDR <= NTerm;
IODRPCTRLR_R_WB <= WRITE_MODE;
IODRPCTRLR_WRITE_DATA <= '0' & N_Term_w;
MCB_UIADDR_int <= IOI_LDQS_PIN;
MCB_CMD_VALID <= '1';
if (MCB_RDY_BUSY_N = '1') then
STATE <= LDQS_PIN_WRITE_N_TERM;
else
STATE <= LDQS_PIN_N_TERM_WAIT;
end if;
when LDQS_PIN_N_TERM_WAIT => --7'h19
if (MCB_RDY_BUSY_N = '0') then
STATE <= LDQS_PIN_N_TERM_WAIT;
else
STATE <= UDQS_CLK_WRITE_P_TERM;
end if;
when UDQS_CLK_WRITE_P_TERM => --7'h1A
IODRPCTRLR_MEMCELL_ADDR <= PTerm;
IODRPCTRLR_R_WB <= WRITE_MODE;
IODRPCTRLR_WRITE_DATA <= "00" & P_Term_w;
MCB_UIADDR_int <= IOI_UDQS_CLK;
MCB_CMD_VALID <= '1';
if (MCB_RDY_BUSY_N = '1') then
STATE <= UDQS_CLK_WRITE_P_TERM;
else
STATE <= UDQS_CLK_P_TERM_WAIT;
end if;
when UDQS_CLK_P_TERM_WAIT => --7'h1B
if (MCB_RDY_BUSY_N = '0') then
STATE <= UDQS_CLK_P_TERM_WAIT;
else
STATE <= UDQS_CLK_WRITE_N_TERM;
end if;
when UDQS_CLK_WRITE_N_TERM => --7'h1C
IODRPCTRLR_MEMCELL_ADDR <= NTerm;
IODRPCTRLR_R_WB <= WRITE_MODE;
IODRPCTRLR_WRITE_DATA <= '0' & N_Term_s;
MCB_UIADDR_int <= IOI_UDQS_CLK;
MCB_CMD_VALID <= '1';
if (MCB_RDY_BUSY_N = '1') then
STATE <= UDQS_CLK_WRITE_N_TERM;
else
STATE <= UDQS_CLK_N_TERM_WAIT;
end if;
when UDQS_CLK_N_TERM_WAIT => --7'h1D
if (MCB_RDY_BUSY_N = '0') then
STATE <= UDQS_CLK_N_TERM_WAIT;
else
STATE <= UDQS_PIN_WRITE_P_TERM;
end if;
when UDQS_PIN_WRITE_P_TERM => --7'h1E
IODRPCTRLR_MEMCELL_ADDR <= PTerm;
IODRPCTRLR_R_WB <= WRITE_MODE;
IODRPCTRLR_WRITE_DATA <= "00" & P_Term_s;
MCB_UIADDR_int <= IOI_UDQS_PIN;
MCB_CMD_VALID <= '1';
if (MCB_RDY_BUSY_N = '1') then
STATE <= UDQS_PIN_WRITE_P_TERM;
else
STATE <= UDQS_PIN_P_TERM_WAIT;
end if;
when UDQS_PIN_P_TERM_WAIT => --7'h1F
if (MCB_RDY_BUSY_N = '0') then
STATE <= UDQS_PIN_P_TERM_WAIT;
else
STATE <= UDQS_PIN_WRITE_N_TERM;
end if;
when UDQS_PIN_WRITE_N_TERM => --7'h20
IODRPCTRLR_MEMCELL_ADDR <= NTerm;
IODRPCTRLR_R_WB <= WRITE_MODE;
IODRPCTRLR_WRITE_DATA <= '0' & N_Term_w;
MCB_UIADDR_int <= IOI_UDQS_PIN;
MCB_CMD_VALID <= '1';
if (MCB_RDY_BUSY_N = '1') then
STATE <= UDQS_PIN_WRITE_N_TERM;
else
STATE <= UDQS_PIN_N_TERM_WAIT;
end if;
when UDQS_PIN_N_TERM_WAIT => --7'h21
if (MCB_RDY_BUSY_N = '0') then
STATE <= UDQS_PIN_N_TERM_WAIT;
else
STATE <= OFF_RZQ_PTERM;
end if;
-- *********************
when OFF_RZQ_PTERM => -- h22
Active_IODRP <= RZQ;
IODRPCTRLR_CMD_VALID <= '1';
IODRPCTRLR_MEMCELL_ADDR <= PTerm;
IODRPCTRLR_WRITE_DATA <= "00000000";
IODRPCTRLR_R_WB <= WRITE_MODE;
P_Term <= "000000";
N_Term <= "0000000";
MCB_UIDRPUPDATE <= not(First_In_Term_Done); -- Set the update flag if this is the first time through
if (IODRPCTRLR_RDY_BUSY_N = '1') then
STATE <= OFF_RZQ_PTERM;
else
STATE <= WAIT7;
end if;
when WAIT7 => -- h23
if ((not(IODRPCTRLR_RDY_BUSY_N)) = '1') then
STATE <= WAIT7;
else
STATE <= OFF_ZIO_NTERM;
end if;
when OFF_ZIO_NTERM => -- h24
Active_IODRP <= ZIO;
IODRPCTRLR_CMD_VALID <= '1';
IODRPCTRLR_MEMCELL_ADDR <= NTerm;
IODRPCTRLR_WRITE_DATA <= "00000000";
IODRPCTRLR_R_WB <= WRITE_MODE;
if (IODRPCTRLR_RDY_BUSY_N = '1') then
STATE <= OFF_ZIO_NTERM;
else
STATE <= WAIT8;
end if;
when WAIT8 => -- h25
if (IODRPCTRLR_RDY_BUSY_N = '0') then
STATE <= WAIT8;
else
if (First_In_Term_Done = '1') then
STATE <= START_DYN_CAL; -- No need to reset the MCB if we are in InTerm tuning
else
STATE <= WRITE_CALIBRATE; -- go read the first Max_Value_int from RZQ
end if;
end if;
when RST_DELAY => -- h26
--MCB_UICMDEN <= '0'; -- release control of UI/UO port
if (Block_Reset = '1') then -- this ensures that more than 512 clock cycles occur since the last reset after MCB_WRITE_CALIBRATE ???
STATE <= RST_DELAY;
else
STATE <= START_DYN_CAL_PRE;
end if;
--***************************
--DYNAMIC CALIBRATION PORTION
--***************************
when START_DYN_CAL_PRE => -- h27
LastPass_DynCal <= IN_TERM_PASS;
MCB_UICMDEN <= '0'; -- release UICMDEN
MCB_UIDONECAL_xilinx7 <= '1'; -- release UIDONECAL - MCB will now initialize.
Pre_SYSRST <= '1'; -- SYSRST pulse
if (CALMODE_EQ_CALIBRATION = '0') then -- if C_MC_CALIBRATION_MODE is set to NOCALIBRATION
STATE <= START_DYN_CAL; -- we'll skip setting the DQS delays manually
elsif (pre_sysrst_minpulse_width_ok = '1') then
STATE <= WAIT_FOR_UODONE;
end if;
when WAIT_FOR_UODONE => -- h28
Pre_SYSRST <= '0'; -- SYSRST pulse
if ((IODRPCTRLR_RDY_BUSY_N and MCB_UODONECAL) = '1')then --IODRP Controller needs to be ready, & MCB needs to be done with hard calibration
MCB_UICMDEN <= '1'; -- grab UICMDEN
DQS_DELAY_INITIAL <= Mult_Divide(Max_Value_int, DQS_NUMERATOR, DQS_DENOMINATOR);
STATE <= LDQS_WRITE_POS_INDELAY;
else
STATE <= WAIT_FOR_UODONE;
end if;
when LDQS_WRITE_POS_INDELAY => -- h29
IODRPCTRLR_MEMCELL_ADDR <= PosEdgeInDly;
IODRPCTRLR_R_WB <= WRITE_MODE;
IODRPCTRLR_WRITE_DATA <= DQS_DELAY_INITIAL;
MCB_UIADDR_int <= IOI_LDQS_CLK;
MCB_CMD_VALID <= '1';
if (MCB_RDY_BUSY_N = '1') then
STATE <= LDQS_WRITE_POS_INDELAY;
else
STATE <= LDQS_WAIT1;
end if;
when LDQS_WAIT1 => -- h2A
if (MCB_RDY_BUSY_N = '0')then
STATE <= LDQS_WAIT1;
else
STATE <= LDQS_WRITE_NEG_INDELAY;
end if;
when LDQS_WRITE_NEG_INDELAY => -- h2B
IODRPCTRLR_MEMCELL_ADDR <= NegEdgeInDly;
IODRPCTRLR_R_WB <= WRITE_MODE;
IODRPCTRLR_WRITE_DATA <= DQS_DELAY_INITIAL;
MCB_UIADDR_int <= IOI_LDQS_CLK;
MCB_CMD_VALID <= '1';
if (MCB_RDY_BUSY_N = '1')then
STATE <= LDQS_WRITE_NEG_INDELAY;
else
STATE <= LDQS_WAIT2;
end if;
when LDQS_WAIT2 => -- 7'h2C
if(MCB_RDY_BUSY_N = '0')then
STATE <= LDQS_WAIT2;
else
STATE <= UDQS_WRITE_POS_INDELAY;
end if;
when UDQS_WRITE_POS_INDELAY => -- 7'h2D
IODRPCTRLR_MEMCELL_ADDR <= PosEdgeInDly;
IODRPCTRLR_R_WB <= WRITE_MODE;
IODRPCTRLR_WRITE_DATA <= DQS_DELAY_INITIAL;
MCB_UIADDR_int <= IOI_UDQS_CLK;
MCB_CMD_VALID <= '1';
if (MCB_RDY_BUSY_N = '1')then
STATE <= UDQS_WRITE_POS_INDELAY;
else
STATE <= UDQS_WAIT1;
end if;
when UDQS_WAIT1 => -- 7'h2E
if (MCB_RDY_BUSY_N = '0')then
STATE <= UDQS_WAIT1;
else
STATE <= UDQS_WRITE_NEG_INDELAY;
end if;
when UDQS_WRITE_NEG_INDELAY => -- 7'h2F
IODRPCTRLR_MEMCELL_ADDR <= NegEdgeInDly;
IODRPCTRLR_R_WB <= WRITE_MODE;
IODRPCTRLR_WRITE_DATA <= DQS_DELAY_INITIAL;
MCB_UIADDR_int <= IOI_UDQS_CLK;
MCB_CMD_VALID <= '1';
if (MCB_RDY_BUSY_N = '1')then
STATE <= UDQS_WRITE_NEG_INDELAY;
else
STATE <= UDQS_WAIT2;
end if;
when UDQS_WAIT2 => -- 7'h30
if (MCB_RDY_BUSY_N = '0')then
STATE <= UDQS_WAIT2;
else
DQS_DELAY <= DQS_DELAY_INITIAL;
TARGET_DQS_DELAY <= DQS_DELAY_INITIAL;
STATE <= START_DYN_CAL;
end if;
when START_DYN_CAL => -- h31
Pre_SYSRST <= '0'; -- SYSRST not driven
counter_inc <= (others => '0');
counter_dec <= (others => '0');
if (SKIP_DYNAMIC_DQS_CAL = '1' and SKIP_DYN_IN_TERMINATION = '1')then
STATE <= DONE; --if we're skipping both dynamic algorythms, go directly to DONE
elsif ((IODRPCTRLR_RDY_BUSY_N = '1') and (MCB_UODONECAL = '1') and (SELFREFRESH_REQ_R1 = '0')) then
--IODRP Controller needs to be ready, & MCB needs to be done with hard calibration
-- Alternate between Dynamic Input Termination and Dynamic Tuning routines
if ((SKIP_DYN_IN_TERMINATION = '0') and (LastPass_DynCal = DYN_CAL_PASS)) then
LastPass_DynCal <= IN_TERM_PASS;
STATE <= LOAD_RZQ_NTERM;
else
LastPass_DynCal <= DYN_CAL_PASS;
STATE <= WRITE_CALIBRATE;
end if;
else
STATE <= START_DYN_CAL;
end if;
when WRITE_CALIBRATE => -- h32
Pre_SYSRST <= '0';
IODRPCTRLR_CMD_VALID <= '1';
IODRPCTRLR_MEMCELL_ADDR <= DelayControl;
IODRPCTRLR_WRITE_DATA <= "00100000";
IODRPCTRLR_R_WB <= WRITE_MODE;
Active_IODRP <= RZQ;
if (IODRPCTRLR_RDY_BUSY_N = '1') then
STATE <= WRITE_CALIBRATE;
else
STATE <= WAIT9;
end if;
when WAIT9 => -- h33
counter_en <= '1';
if (count < "100110") then -- this adds approximately 22 extra clock cycles after WRITE_CALIBRATE
STATE <= WAIT9;
else
STATE <= READ_MAX_VALUE;
end if;
when READ_MAX_VALUE => -- h34
IODRPCTRLR_CMD_VALID <= '1';
IODRPCTRLR_MEMCELL_ADDR <= MaxValue;
IODRPCTRLR_R_WB <= READ_MODE;
Max_Value_Previous <= Max_Value_int;
if (IODRPCTRLR_RDY_BUSY_N = '1') then
STATE <= READ_MAX_VALUE;
else
STATE <= WAIT10;
end if;
when WAIT10 => -- h35
if (IODRPCTRLR_RDY_BUSY_N = '0') then
STATE <= WAIT10;
else
Max_Value_int <= IODRPCTRLR_READ_DATA; --record the Max_Value_int from the IODRP controller
if (First_In_Term_Done = '0') then
STATE <= RST_DELAY;
First_In_Term_Done <= '1';
else
STATE <= ANALYZE_MAX_VALUE;
end if;
end if;
when ANALYZE_MAX_VALUE => -- h36 only do a Inc or Dec during a REFRESH cycle.
if (First_Dyn_Cal_Done = '0')then
STATE <= FIRST_DYN_CAL;
elsif ((Max_Value_int < Max_Value_Previous) and (Max_Value_Delta_Dn >= INCDEC_THRESHOLD)) then
STATE <= DECREMENT; -- May need to Decrement
TARGET_DQS_DELAY <= Mult_Divide(Max_Value_int, DQS_NUMERATOR, DQS_DENOMINATOR);
-- DQS_COUNT_VIRTUAL updated (could be negative value)
elsif ((Max_Value_int > Max_Value_Previous) and (Max_Value_Delta_Up >= INCDEC_THRESHOLD)) then
STATE <= INCREMENT; -- May need to Increment
TARGET_DQS_DELAY <= Mult_Divide(Max_Value_int, DQS_NUMERATOR, DQS_DENOMINATOR);
else
Max_Value_int <= Max_Value_Previous;
STATE <= START_DYN_CAL;
end if;
when FIRST_DYN_CAL => -- h37
First_Dyn_Cal_Done <= '1'; -- set flag that the First Dynamic Calibration has been completed
STATE <= START_DYN_CAL;
when INCREMENT => -- h38
STATE <= START_DYN_CAL; -- Default case: Inc is not high or no longer in REFRSH
MCB_UILDQSINC <= '0'; -- Default case: no inc or dec
MCB_UIUDQSINC <= '0'; -- Default case: no inc or dec
MCB_UILDQSDEC <= '0'; -- Default case: no inc or dec
MCB_UIUDQSDEC <= '0'; -- Default case: no inc or dec
case Inc_Dec_REFRSH_Flag is -- {Increment_Flag,Decrement_Flag,MCB_UOREFRSHFLAG},
when "101" =>
counter_inc <= counter_inc + '1';
STATE <= INCREMENT; -- Increment is still high, still in REFRSH cycle
if ((DQS_DELAY < DQS_DELAY_UPPER_LIMIT) and (counter_inc >= X"04")) then
-- if not at the upper limit yet, and you've waited 4 clks, increment
MCB_UILDQSINC <= '1';
MCB_UIUDQSINC <= '1';
DQS_DELAY <= DQS_DELAY + '1';
end if;
when "100" =>
if (DQS_DELAY < DQS_DELAY_UPPER_LIMIT) then
STATE <= INCREMENT; -- Increment is still high, REFRESH ended - wait for next REFRESH
end if;
when others =>
STATE <= START_DYN_CAL;
end case;
when DECREMENT => -- h39
STATE <= START_DYN_CAL; -- Default case: Dec is not high or no longer in REFRSH
MCB_UILDQSINC <= '0'; -- Default case: no inc or dec
MCB_UIUDQSINC <= '0'; -- Default case: no inc or dec
MCB_UILDQSDEC <= '0'; -- Default case: no inc or dec
MCB_UIUDQSDEC <= '0'; -- Default case: no inc or dec
if (DQS_DELAY /= "00000000") then
case Inc_Dec_REFRSH_Flag is -- {Increment_Flag,Decrement_Flag,MCB_UOREFRSHFLAG},
when "011" =>
counter_dec <= counter_dec + '1';
STATE <= DECREMENT; -- Decrement is still high, still in REFRSH cycle
if ((DQS_DELAY > DQS_DELAY_LOWER_LIMIT) and (counter_dec >= X"04")) then
-- if not at the lower limit, and you've waited 4 clks, decrement
MCB_UILDQSDEC <= '1'; -- decrement
MCB_UIUDQSDEC <= '1'; -- decrement
DQS_DELAY <= DQS_DELAY - '1'; -- SBS
end if;
when "010" =>
if (DQS_DELAY > DQS_DELAY_LOWER_LIMIT) then --if not at the lower limit, decrement
STATE <= DECREMENT; --Decrement is still high, REFRESH ended - wait for next REFRESH
end if;
when others =>
STATE <= START_DYN_CAL;
end case;
end if;
when DONE => -- h3A
Pre_SYSRST <= '0'; -- SYSRST cleared
MCB_UICMDEN <= '0'; -- release UICMDEN
STATE <= DONE;
when others =>
MCB_UICMDEN <= '0'; -- release UICMDEN
MCB_UIDONECAL_xilinx7 <= '1'; -- release UIDONECAL - MCB will now initialize.
Pre_SYSRST <= '0'; -- SYSRST not driven
IODRPCTRLR_CMD_VALID <= '0';
IODRPCTRLR_MEMCELL_ADDR <= "00000000";
IODRPCTRLR_WRITE_DATA <= "00000000";
IODRPCTRLR_R_WB <= '0';
IODRPCTRLR_USE_BKST <= '0';
P_Term <= "000000";
N_Term <= "0000000";
Active_IODRP <= ZIO;
Max_Value_Previous <= "00000000";
MCB_UILDQSINC <= '0'; -- no inc or dec
MCB_UIUDQSINC <= '0'; -- no inc or dec
MCB_UILDQSDEC <= '0'; -- no inc or dec
MCB_UIUDQSDEC <= '0'; -- no inc or dec
counter_en <= '0';
First_Dyn_Cal_Done <= '0'; -- flag that the First Dynamic Calibration completed
Max_Value_int <= Max_Value_int;
STATE <= START;
end case;
end if;
end if;
end process;
end architecture trans;