diff options
Diffstat (limited to 'fpga/usrp3/top/x400/rf/common/rf_reset.vhd')
| -rw-r--r-- | fpga/usrp3/top/x400/rf/common/rf_reset.vhd | 216 |
1 files changed, 216 insertions, 0 deletions
diff --git a/fpga/usrp3/top/x400/rf/common/rf_reset.vhd b/fpga/usrp3/top/x400/rf/common/rf_reset.vhd new file mode 100644 index 000000000..c1ef34d3c --- /dev/null +++ b/fpga/usrp3/top/x400/rf/common/rf_reset.vhd @@ -0,0 +1,216 @@ +-- +-- Copyright 2021 Ettus Research, a National Instruments Brand +-- +-- SPDX-License-Identifier: LGPL-3.0-or-later +-- +-- Module: rf_reset +-- +-- Description: +-- +-- Control RFDC, ADC, and DAC resets. +-- + +library IEEE; + use IEEE.std_logic_1164.all; + use IEEE.numeric_std.all; + +entity rf_reset is + port( + -- Clocks used in the data path. + DataClk : in std_logic; + PllRefClk : in std_logic; + RfClk : in std_logic; + RfClk2x : in std_logic; + DataClk2x : in std_logic; + + -- Master resets from the Radio. + dTimedReset : in std_logic; + dSwReset : in std_logic; + + -- Resets outputs. + dReset_n : out std_logic := '0'; + d2Reset_n : out std_logic := '0'; + r2Reset_n : out std_logic := '0'; + rAxiReset_n : out std_logic := '0'; + rReset_n : out std_logic := '0' + ); +end rf_reset; + + +architecture RTL of rf_reset is + + -- POR value for all resets are active high or low. + signal dResetPulseDly : std_logic_vector(2 downto 0) := "111"; + signal dResetPulseStretch : std_logic := '1'; + signal pResetPulseStretch : std_logic_vector(1 downto 0) := "11"; + signal pResetPulse_n : std_logic := '0'; + signal pAxiReset_n : std_logic := '0'; + + +begin + + ----------------------------------------------------------------------------- + -- Clock Phase Diagram + ----------------------------------------------------------------------------- + -- Before we look into the details of the clock alignment, here is the clock + -- frequencies of all the synchronous clocks that is used in the design. + -- PllRefClk is the reference clock for the FPGA PLL and all other clocks are + -- derived from PllRefClk. PllRefClk for X410 is ~62.5 MHz + -- PllRefClk = ~62.5 MHz (Sample clock/48. This is the X410 configuration and + -- could be different for other x4xx variants.) + -- DataClk = PllRefClk*2 + -- DataClkx2 = PllRefClk*4 + -- RfClk = PllRefClk*3 + -- RfClkx2 = PllRefClk*6 + -- DataClk = PllRefClk*4 for legacy mode. In legacy mode, we will not use + -- DataClkx2 as the clock frequency will be too high to close timing. + -- Five clocks with five different frequencies, all related and occasionally + -- aligned. Rising edge of all clocks are aligned to the rising edge of + -- PllRefClk. We will use the rising edge of PllRefClk as the reference to + -- assert synchronous reset for all clock domains. The synchronous reset + -- pulse is in the DataClk domain. As we can see from the timing diagram, the + -- DataClk rising edge is not always aligned to the rising edge of all the + -- other clocks. But, it is guaranteed that the DataClk will be aligned to + -- all the other clock on the rising edge of PLL reference clock. In case 1, + -- the synchronous reset pulse is on the DataClk edge where the data clock is + -- not aligned to RfClk. We stretch the pulse from DataClk domain and send + -- the reset out on the rising edge of PllRefClk where all the clocks rising + -- edge is aligned. In case 2, the synchronous reset is received on the + -- DataClk cycle where all the clocks are aligned. This is because, in + -- case 2, the synchronous reset is received on the rising edge of PllRefClk. + -- For case 1 and case 2, all the output resets are asserted only on the + -- PllRefClk rising edge to guarantee a known relationship between the resets + -- in different clock domains. + -- + -- Alignment * * * + -- ___________ ___________ ___________ ___________ ___________ + -- PllRefClk __| |___________| |___________| |___________| |___________| | + -- _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + -- RfClk2x __| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_ + -- ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ + -- RfClk __| |___| |___| |___| |___| |___| |___| |___| |___| |___| |___| |___| |___| |___| + -- __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ + -- DataClk2x __| |__| |__| |__| |__| |__| |__| |__| |__| |__| |__| |__| |__| |__| |__| |__| |__| |__| |__| + -- _____ _____ _____ _____ _____ _____ _____ _____ _____ + -- DataClk __| |_____| |_____| |_____| |_____| |_____| |_____| |_____| |_____| |_____| + -- . : : : : + -- --------- Case 1 ---------.-- : : : : + -- ^ : : ^ : + -- Reset Strobe --> | : Aligned reset strobe -->| : + -- ____________ : : : : + -- dResetPulse________| |______________________________________ : : + -- : _____________________________________________________________________________ + -- dResetPulseStretch ______________________| : + -- : ________________________________________________ + -- pResetPulseStretch ____________________________________________| : : |___ + -- _________________________________________________________________________ : + -- pResetPulse_n : |________________________________ + -- : : : : + -- --------- Case 2 ----------- : : : : + -- ^ : ^ : + -- Reset Strobe --> | : | <-- Aligned reset strobe + -- ____________ : : : + -- dResetPulse(0) ________| |______________________________________________________________________________ + -- _______________________________________________________________________________ + -- dResetPulseStretch ______________________| : + -- ________________________________________________________ + -- pResetPulseStretch ____________________________________________| : + -- _________________________________________________________________________ + -- pResetPulse_n |________________________________ + -- -------------------------------------------------------------------------- + + ----------------------------------------------------------------------------- + -- Implementation + ----------------------------------------------------------------------------- + + -- Since the dTimedReset is asserted only for one DataClk cycle, we need to + -- stretch the strobe to four DataClk cycles, so the strobe is wide enough to + -- be sampled by PllRefClk which is four times the DataClk period. Pulse + -- stretch is done for 4 DataClk periods to support the legacy mode. We also + -- do a logical OR on resets from software. Software resets are from the + -- ConfigClock domain which is a slower clock than the PllRefClk. So, we + -- don't have to stretch the software reset. + PulseStretch: process(DataClk) + begin + if rising_edge(DataClk) then + dResetPulseDly <= dResetPulseDly(1 downto 0) & (dTimedReset or dSwReset); + dResetPulseStretch <= '0'; + if (dResetPulseDly /= "000") or dTimedReset = '1' or dSwReset = '1' then + dResetPulseStretch <= '1'; + end if; + end if; + end process PulseStretch; + + -- Strobe reset pulse for 2 PllRefClk period to make sure we have the reset + -- asserted for longer period. The FIR filter is the only design that + -- requires reset to be asserted for 2 clock cycles. This requirement is + -- satisfied with one PllRefClk period. RFDC does not have any AXI stream + -- reset time requirement. We will reset all designs for two PllRefClk period + -- just to be on the safer side. The same strategy is used for DAC resets as + -- well. + ResetOut: process(PllRefClk) + begin + if rising_edge(PllRefClk) then + pResetPulseStretch <= pResetPulseStretch(0) & dResetPulseStretch; + pResetPulse_n <= not (pResetPulseStretch(1) or pResetPulseStretch(0)); + end if; + end process ResetOut; + + -- We are using PllRefClk as the reference and issuing resets to all the + -- other clock domains. We are not trying to align all the resets in + -- different clock domains. We are making sure that all resets will be + -- asserted with respect to each other at the same time from run to run. + DataClkReset: process(DataClk) + begin + if rising_edge(DataClk) then + dReset_n <= pResetPulse_n; + end if; + end process DataClkReset; + + DataClk2xReset: process(DataClk2x) + begin + if rising_edge(DataClk2x) then + d2Reset_n <= pResetPulse_n; + end if; + end process DataClk2xReset; + + Rfclk2xReset: process(RfClk2x) + begin + if rising_edge(RfClk2x) then + r2Reset_n <= pResetPulse_n; + end if; + end process Rfclk2xReset; + + RfclkReset: process(RfClk) + begin + if rising_edge(RfClk) then + rReset_n <= pResetPulse_n; + end if; + end process RfclkReset; + + ------------------------------------- + -- RF Resets + ------------------------------------- + -- RFDC resets are asserted only once and it should be done using the reset + -- from software. This is because we want the RFDC AXI-S interface in reset + -- until the RfClk is stable. The only way to know if the RfClk is stable is + -- by reading the lock status of sample clock PLL and MMCM used to generate + -- all clocks in the signal path. dSwReset is a software reset while is + -- asserted for a longer period of time and it does not require any pulse + -- stretch. + + RfdcReset: process(PllRefClk) + begin + if rising_edge(PllRefClk) then + pAxiReset_n <= not dSwReset; + end if; + end process RfdcReset; + + RfclkAxiReset: process(RfClk) + begin + if rising_edge(RfClk) then + rAxiReset_n <= pAxiReset_n; + end if; + end process RfclkAxiReset; + +end RTL; |
