Co-authored-by: Andrew Moch <Andrew.Moch@ni.com> Co-authored-by: Daniel Jepson <daniel.jepson@ni.com> Co-authored-by: Javier Valenzuela <javier.valenzuela@ni.com> Co-authored-by: Joerg Hofrichter <joerg.hofrichter@ni.com> Co-authored-by: Kumaran Subramoniam <kumaran.subramoniam@ni.com> Co-authored-by: Max Köhler <max.koehler@ni.com> Co-authored-by: Michael Auchter <michael.auchter@ni.com> Co-authored-by: Paul Butler <paul.butler@ni.com> Co-authored-by: Wade Fife <wade.fife@ettus.com> Co-authored-by: Hector Rubio <hrubio@ni.com> Original-commit: 6d3765605262016a80f71e36357f749ea35cbe5a
217 lines
11 KiB
VHDL
217 lines
11 KiB
VHDL
--
|
|
-- 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;
|