diff options
author | Wade Fife <wade.fife@ettus.com> | 2021-06-08 19:40:46 -0500 |
---|---|---|
committer | Aaron Rossetto <aaron.rossetto@ni.com> | 2021-06-10 11:56:58 -0500 |
commit | 6d3765605262016a80f71e36357f749ea35cbe5a (patch) | |
tree | 7d62d6622befd4132ac1ee085effa1426f7f53e5 /fpga/usrp3/top/x400/rf/common/rf_nco_reset.vhd | |
parent | f706b89e6974e28ce76aadeeb06169becc86acba (diff) | |
download | uhd-6d3765605262016a80f71e36357f749ea35cbe5a.tar.gz uhd-6d3765605262016a80f71e36357f749ea35cbe5a.tar.bz2 uhd-6d3765605262016a80f71e36357f749ea35cbe5a.zip |
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>
Diffstat (limited to 'fpga/usrp3/top/x400/rf/common/rf_nco_reset.vhd')
-rw-r--r-- | fpga/usrp3/top/x400/rf/common/rf_nco_reset.vhd | 228 |
1 files changed, 228 insertions, 0 deletions
diff --git a/fpga/usrp3/top/x400/rf/common/rf_nco_reset.vhd b/fpga/usrp3/top/x400/rf/common/rf_nco_reset.vhd new file mode 100644 index 000000000..d891a8722 --- /dev/null +++ b/fpga/usrp3/top/x400/rf/common/rf_nco_reset.vhd @@ -0,0 +1,228 @@ +-- +-- Copyright 2021 Ettus Research, a National Instruments Brand +-- +-- SPDX-License-Identifier: LGPL-3.0-or-later +-- +-- Module: rf_nco_reset +-- +-- Description: +-- +-- This entity has the logic needed to synchronously reset the NCO inside the +-- RF section. +-- + +library IEEE; + use IEEE.std_logic_1164.all; + use IEEE.numeric_std.all; + +entity rf_nco_reset is + port( + -- AXI-lite clock used for RFDC configuration. + ConfigClk : in std_logic; + + -- Radio clock used in the converter data path. + DataClk : in std_logic; + + -- PL SYSREF + dSysref : in std_logic; + + --Strobe dNcoResetEn for one DataClk cycle to initiate NCO reset. + dStartNcoReset : in std_logic; + + --------------------------------------------------------------------------- + -- NCO reset controls and status + --------------------------------------------------------------------------- + -- Port naming convention: + -- cDac<Tile Number><Converter Number><signal name> + -- cAdc<Tile Number><Converter Number><signal name> + + ----------------------------------- + -- DAC Tile 228 + ----------------------------------- + -- DAC common NCO update controls and status. + cDac0xNcoUpdateBusy : in std_logic_vector(1 downto 0); + cDac0xNcoUpdateReq : out std_logic := '0'; + cDac0xSysrefIntGating : out std_logic := '0'; + cDac0xSysrefIntReenable : out std_logic := '0'; + + ----------------------------------- + -- DAC Tile 229 + ----------------------------------- + -- DAC common NCO update controls and status. + cDac1xNcoUpdateBusy : in std_logic; + cDac1xNcoUpdateReq : out std_logic := '0'; + + ----------------------------------- + --ADC Tile 224 + ----------------------------------- + -- ADC common NCO update controls and status. + cAdc0xNcoUpdateBusy : in std_logic; + cAdc0xNcoUpdateReq : out std_logic := '0'; + + ----------------------------------- + --ADC Tile 226 + ----------------------------------- + -- ADC common NCO update controls and status. + cAdc2xNcoUpdateBusy : in std_logic; + cAdc2xNcoUpdateReq : out std_logic := '0'; + + -- NCO reset can be initiated only when cNcoPhaseRst is set to '1' and + -- cNcoUpdateEn = 0x20. The FSM in this entity will set these values when + -- an NCO reset is initiated during synchronization. These ports are common + -- for all the converters. So, we will fan these signals out to each + -- converter outside this entity. + cNcoPhaseRst : out std_logic := '1'; + cNcoUpdateEn : out std_logic_vector(5 downto 0) := "100000"; + + -- NCO reset status back to the user. + dNcoResetDone : out std_logic := '0' + ); +end rf_nco_reset; + +architecture RTL of rf_nco_reset is + + -- State machine to sequence NCO reset across different RFDC tiles. + type ResetState_t is (Idle, ReqGating, CheckGating, CheckUpdateDone, + CheckResetDone, ResetDone); + signal cResetState : ResetState_t := Idle; + + signal dNcoResetDone_ms, cNcoResetDone : std_logic := '0'; + signal dStartNcoResetReg, cStartNcoReset_ms, cStartNcoReset : std_logic := '0'; + signal cSysref_ms, cSysref, cSysrefDlyd : std_logic := '0'; + signal cSysrefIntGating, dSysrefIntGating_ms, + dSysrefIntGating : std_logic := '0'; +begin + + -- NCO start signal from the user is a one DataClk cycle strobe. In this + -- process, we register the NCO start request from the user. This NCO start + -- request register is cleared after the NCO reset sequence is initiated. We + -- used the signal used to gate SYSREF to clear this register. + RegNcoStart: process(DataClk) + begin + if rising_edge(DataClk) then + dSysrefIntGating_ms <= cSysrefIntGating; + dSysrefIntGating <= dSysrefIntGating_ms; + if dSysrefIntGating = '1' then + dStartNcoResetReg <= '0'; + elsif dStartNcoReset = '1' then + dStartNcoResetReg <= '1'; + end if; + end if; + end process RegNcoStart; + + -- Irrespective of when NCO reset strobe is issued by the user, we need to + -- initiate NCO reset only on the rising edge of SYSREF. This is because, we + -- have to complete the reset within a SYSREF period. + ConfigClkCross: process(ConfigClk) + begin + if rising_edge(ConfigClk) then + cSysref_ms <= dSysref; + cSysref <= cSysref_ms; + cSysrefDlyd <= cSysref; + cStartNcoReset_ms <= dStartNcoResetReg; + cStartNcoReset <= cStartNcoReset_ms; + end if; + end process ConfigClkCross; + + -- These signals can be set to a constant value as NCO phase reset is only + -- initiated by *NcoUpdateReq signal. + cNcoPhaseRst <= '1'; + cNcoUpdateEn <= "100000"; + + -- ! STATE MACHINE STARTUP ! + -- The state machine starts in Idle state and does not change state until + -- cStartNcoReset is set to '1'. cStartNcoReset signal and cSysref are based + -- of ConfigClock so changing state from Idle cannot go metastable. State + -- machine to initiate NCO reset on all enabled RFDC tiles. This state + -- machine was written based of the information provided in "NCO frequency + -- hopping" section in PG269 (v2.2). We use multi-mode for NCO reset. + ResetFsm: process(ConfigClk) + begin + if rising_edge(ConfigClk) then + cResetState <= Idle; + cNcoResetDone <= '0'; + cDac0xNcoUpdateReq <= '0'; + cSysrefIntGating <= '0'; + cDac0xSysrefIntReenable <= '0'; + cDac1xNcoUpdateReq <= '0'; + cAdc0xNcoUpdateReq <= '0'; + cAdc2xNcoUpdateReq <= '0'; + case cResetState is + -- Stay in this state until NCO reset sequence is initiated. NCO reset + -- is initiated only on the rising edge of SYSREF. + when Idle => + if cSysref = '1' and cSysrefDlyd = '0' and cStartNcoReset = '1' then + cResetState <= ReqGating; + cSysrefIntGating <= '1'; + end if; + + -- When NCO reset is initiated, gate the RFDC internal SYSREF. To gate + -- internal SYSREF set cSysrefIntGating to '1'. To request NCO reset + -- strobe cDac0xNcoUpdateReq for one ConfigClk period. At this point, + -- we can only request NCO reset for RF-DAC tile 228. + when ReqGating => + cResetState <= CheckGating; + cDac0xNcoUpdateReq <= '1'; + cSysrefIntGating <= '1'; + + -- Since we are gating SYSREF inside RFDC, we need to wait until SYSREF + -- is gated internally. RFDC sets cDac0xNcoUpdateBusy[0] to '1' when + -- SYSREF is gated. cDac0xNcoUpdateBusy[1] is also set to '1' to + -- indicate that NCO reset is still in progress. After the SYSREF is + -- gated request NCO reset on all other converter tiles. + when CheckGating => + cSysrefIntGating <= '1'; + cResetState <= CheckGating; + if cDac0xNcoUpdateBusy = "11" then + cResetState <= CheckUpdateDone; + cDac1xNcoUpdateReq <= '1'; + cAdc0xNcoUpdateReq <= '1'; + cAdc2xNcoUpdateReq <= '1'; + end if; + + -- In this state, we check if the RFDC block is ready for NCO reset. + -- This check is done using the *Busy signal from RFDC. Once RFDC is + -- ready for NCO reset, disable internal SYSREF gating. + when CheckUpdateDone => + cSysrefIntGating <= '1'; + cResetState <= CheckUpdateDone; + if cDac0xNcoUpdateBusy = "10" and cAdc0xNcoUpdateBusy = '0' and + cAdc2xNcoUpdateBusy = '0' and cDac1xNcoUpdateBusy = '0' and + cSysref = '1' and cSysrefDlyd = '0' then + cDac0xSysrefIntReenable <= '1'; + cResetState <= CheckResetDone; + end if; + + -- NCO reset is done when cDac0xNcoUpdateBusy[1] is set to '0'. RFDC is + -- programmed from software to reset the NCO on a SYSREF rising edge. + when CheckResetDone => + cSysrefIntGating <= '1'; + cResetState <= CheckResetDone; + if cDac0xNcoUpdateBusy = "00" then + cResetState <= ResetDone; + end if; + + -- Wait in this state until another NCO reset request is issued. + when ResetDone => + cNcoResetDone <= '1'; + cResetState <= ResetDone; + if cSysref = '1' and cSysrefDlyd = '0' and cStartNcoReset = '1' then + cResetState <= ReqGating; + cSysrefIntGating <= '1'; + end if; + end case; + end if; + end process ResetFsm; + + cDac0xSysrefIntGating <= cSysrefIntGating; + + -- Move the NCO reset done status to DataClk domain. + DataClkCrossing: process(DataClk) + begin + if rising_edge(DataClk) then + dNcoResetDone_ms <= cNcoResetDone; + dNcoResetDone <= dNcoResetDone_ms; + end if; + end process DataClkCrossing; + +end RTL; |