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,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;
|
||||
Reference in New Issue
Block a user