fpga: x400: Add support for X410 motherboard FPGA
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
This commit is contained in:
committed by
Aaron Rossetto
co-authored by
Andrew Moch
Daniel Jepson
Javier Valenzuela
Joerg Hofrichter
Kumaran Subramoniam
Max Köhler
Michael Auchter
Paul Butler
Hector Rubio
parent
bfef20ea45
commit
61782b02d7
@@ -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;
|
||||
Reference in New Issue
Block a user