aboutsummaryrefslogtreecommitdiffstats
path: root/fpga/usrp3/top/n3xx/dboards/common/sync/TdcWrapper.vhd
diff options
context:
space:
mode:
Diffstat (limited to 'fpga/usrp3/top/n3xx/dboards/common/sync/TdcWrapper.vhd')
-rw-r--r--fpga/usrp3/top/n3xx/dboards/common/sync/TdcWrapper.vhd397
1 files changed, 397 insertions, 0 deletions
diff --git a/fpga/usrp3/top/n3xx/dboards/common/sync/TdcWrapper.vhd b/fpga/usrp3/top/n3xx/dboards/common/sync/TdcWrapper.vhd
new file mode 100644
index 000000000..1ab235fe2
--- /dev/null
+++ b/fpga/usrp3/top/n3xx/dboards/common/sync/TdcWrapper.vhd
@@ -0,0 +1,397 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright 2018 Ettus Research, a National Instruments Company
+--
+-- SPDX-License-Identifier: LGPL-3.0-or-later
+--
+--
+-- Purpose:
+--
+-- Wrapper for the TDC and register control modules.
+--
+-- vreview_group Tdc
+-- vreview_reviewers dabaker sgupta jmarsar
+-------------------------------------------------------------------------------
+
+library ieee;
+ use ieee.std_logic_1164.all;
+ use ieee.numeric_std.all;
+
+library work;
+ use work.PkgRegs.all;
+
+entity TdcWrapper is
+ port (
+ -- Clocks and Resets : --------------------------------------------------------------
+ -- Bus Clock and synchronous bus reset.
+ BusClk : in std_logic;
+ bBusReset : in std_logic;
+ -- Reference Clock
+ RefClk : in std_logic;
+ -- Sample Clock
+ SampleClk : in std_logic;
+ -- Measurement Clock must run at a very specific frequency, determined by the
+ -- SampleClk, RefClk, and Sync Pulse rates... oh and a lot of math.
+ MeasClk : in std_logic;
+
+
+ -- Register Port: -------------------------------------------------------------------
+ bSyncRegPortOut : out RegPortOut_t;
+ bSyncRegPortIn : in RegPortIn_t;
+
+
+ -- PPS In and Out : -----------------------------------------------------------------
+ -- Only required to pulse 1 RefClk cycle.
+ rPpsPulse : in std_logic;
+ -- PPS pulse output on the SampleClk domain.
+ sPpsPulse : out std_logic;
+
+
+ -- Sync Pulse Outputs : -------------------------------------------------------------
+ -- The repeating pulses can be useful for many things, including passing triggers.
+ rRpTransfer : out std_logic;
+ sSpTransfer : out std_logic;
+
+ -- Pin bouncers out and in. Must go to unused and unconnected pins on the FPGA!
+ rGatedPulseToPin : inout std_logic;
+ sGatedPulseToPin : inout std_logic
+ );
+end TdcWrapper;
+
+
+architecture struct of TdcWrapper is
+
+ component SyncRegsIfc
+ port (
+ aBusReset : in std_logic;
+ bBusReset : in std_logic;
+ BusClk : in std_logic;
+ aTdcReset : out std_logic;
+ bRegPortInFlat : in std_logic_vector(49 downto 0);
+ bRegPortOutFlat : out std_logic_vector(33 downto 0);
+ RefClk : in std_logic;
+ rResetTdc : out std_logic;
+ rResetTdcDone : in std_logic;
+ rEnableTdc : out std_logic;
+ rReRunEnable : out std_logic;
+ rEnablePpsCrossing : out std_logic;
+ rPpsPulseCaptured : in std_logic;
+ rPulserEnableDelayVal : out std_logic_vector(3 downto 0);
+ SampleClk : in std_logic;
+ sPpsClkCrossDelayVal : out std_logic_vector(3 downto 0);
+ MeasClk : in std_logic;
+ mRpOffset : in std_logic_vector(39 downto 0);
+ mSpOffset : in std_logic_vector(39 downto 0);
+ mOffsetsDone : in std_logic;
+ mOffsetsValid : in std_logic;
+ rLoadRePulseCounts : out std_logic;
+ rRePulsePeriodInRClks : out std_logic_vector(23 downto 0);
+ rRePulseHighTimeInRClks : out std_logic_vector(23 downto 0);
+ rLoadRpCounts : out std_logic;
+ rRpPeriodInRClks : out std_logic_vector(15 downto 0);
+ rRpHighTimeInRClks : out std_logic_vector(15 downto 0);
+ rLoadRptCounts : out std_logic;
+ rRptPeriodInRClks : out std_logic_vector(15 downto 0);
+ rRptHighTimeInRClks : out std_logic_vector(15 downto 0);
+ sLoadSpCounts : out std_logic;
+ sSpPeriodInSClks : out std_logic_vector(15 downto 0);
+ sSpHighTimeInSClks : out std_logic_vector(15 downto 0);
+ sLoadSptCounts : out std_logic;
+ sSptPeriodInSClks : out std_logic_vector(15 downto 0);
+ sSptHighTimeInSClks : out std_logic_vector(15 downto 0));
+ end component;
+
+ -- Generic values for the TdcTop instantiation below. These generics are the maximum
+ -- of possible values for all combinations of Sample and Reference clocks for the N3xx
+ -- family of devices.
+ constant kRClksPerRePulsePeriodBitsMax : integer := 24;
+ constant kRClksPerRpPeriodBitsMax : integer := 16;
+ constant kSClksPerSpPeriodBitsMax : integer := 16;
+ constant kPulsePeriodCntSize : integer := 13;
+ -- The following are ideal values for balancing measurement time and accuracy, based
+ -- on calcs given in the spec doc.
+ constant kFreqRefPeriodsToCheckSize : integer := 17;
+ constant kSyncPeriodsToStampSize : integer := 10;
+
+ --vhook_sigstart
+ signal aTdcReset: std_logic;
+ signal bSyncRegPortInFlat: std_logic_vector(49 downto 0);
+ signal bSyncRegPortOutFlat: std_logic_vector(33 downto 0);
+ signal mOffsetsDone: boolean;
+ signal mOffsetsValid: boolean;
+ signal mRpOffset: unsigned(kPulsePeriodCntSize+kSyncPeriodsToStampSize+kFreqRefPeriodsToCheckSize-1 downto 0);
+ signal mSpOffset: unsigned(kPulsePeriodCntSize+kSyncPeriodsToStampSize+kFreqRefPeriodsToCheckSize-1 downto 0);
+ signal rEnablePpsCrossing: std_logic;
+ signal rEnableTdc: std_logic;
+ signal rLoadRePulseCounts: std_logic;
+ signal rLoadRpCounts: std_logic;
+ signal rLoadRptCounts: std_logic;
+ signal rPpsPulseCaptured: boolean;
+ signal rPulserEnableDelayVal: std_logic_vector(3 downto 0);
+ signal rRePulseHighTimeInRClks: std_logic_vector(kRClksPerRePulsePeriodBitsMax-1 downto 0);
+ signal rRePulsePeriodInRClks: std_logic_vector(kRClksPerRePulsePeriodBitsMax-1 downto 0);
+ signal rReRunEnable: std_logic;
+ signal rResetTdc: std_logic;
+ signal rResetTdcDone: boolean;
+ signal rRpHighTimeInRClks: std_logic_vector(kRClksPerRpPeriodBitsMax-1 downto 0);
+ signal rRpPeriodInRClks: std_logic_vector(kRClksPerRpPeriodBitsMax-1 downto 0);
+ signal rRptHighTimeInRClks: std_logic_vector(kRClksPerRpPeriodBitsMax-1 downto 0);
+ signal rRptPeriodInRClks: std_logic_vector(kRClksPerRpPeriodBitsMax-1 downto 0);
+ signal rRpTransferBool: boolean;
+ signal sLoadSpCounts: std_logic;
+ signal sLoadSptCounts: std_logic;
+ signal sPpsClkCrossDelayVal: std_logic_vector(3 downto 0);
+ signal sPpsPulseAsyncReset: boolean;
+ signal sSpHighTimeInSClks: std_logic_vector(kSClksPerSpPeriodBitsMax-1 downto 0);
+ signal sSpPeriodInSClks: std_logic_vector(kSClksPerSpPeriodBitsMax-1 downto 0);
+ signal sSptHighTimeInSClks: std_logic_vector(kSClksPerSpPeriodBitsMax-1 downto 0);
+ signal sSptPeriodInSClks: std_logic_vector(kSClksPerSpPeriodBitsMax-1 downto 0);
+ signal sSpTransferBool: boolean;
+ --vhook_sigend
+
+ signal rPpsPulseAsyncReset_ms, rPpsPulseAsyncReset,
+ sPpsPulseOut_ms, sPpsPulseOut : std_logic := '0';
+
+ function to_StdLogic(b : boolean) return std_ulogic is
+ begin
+ if b then
+ return '1';
+ else
+ return '0';
+ end if;
+ end to_StdLogic;
+
+ function to_Boolean (s : std_ulogic) return boolean is
+ begin
+ return (To_X01(s)='1');
+ end to_Boolean;
+
+ attribute ASYNC_REG : string;
+ attribute ASYNC_REG of rPpsPulseAsyncReset_ms : signal is "true";
+ attribute ASYNC_REG of rPpsPulseAsyncReset : signal is "true";
+ attribute ASYNC_REG of sPpsPulseOut_ms : signal is "true";
+ attribute ASYNC_REG of sPpsPulseOut : signal is "true";
+
+begin
+
+ -- Cross the PPS from the no-reset domain into the aTdcReset domain since there is a
+ -- reset crossing going into the TdcWrapper (reset by aTdcReset)! No clock domain
+ -- crossing here, so crossing a single-cycle pulse is safe.
+ DoubleSyncToAsyncReset : process (aTdcReset, RefClk)
+ begin
+ if to_boolean(aTdcReset) then
+ rPpsPulseAsyncReset_ms <= '0';
+ rPpsPulseAsyncReset <= '0';
+ elsif rising_edge(RefClk) then
+ rPpsPulseAsyncReset_ms <= rPpsPulse;
+ rPpsPulseAsyncReset <= rPpsPulseAsyncReset_ms;
+ end if;
+ end process;
+
+ -- In a similar fashion, cross the output PPS trigger from the async aTdcReset domain
+ -- to the no-reset of the rest of the design. The odds of this signal triggering a
+ -- failure are astronomically low (since it only pulses one clock cycle per second),
+ -- but two flops is worth the assurance it won't mess something else up downstream.
+ -- Note this double-sync mainly protects against the reset assertion case, since in the
+ -- de-assertion case sPpsPulseAsyncReset should be zero and not transition for a long
+ -- time afterwards. Again no clock crossing here, so crossing a single-cycle pulse
+ -- is safe.
+ DoubleSyncToNoReset : process (SampleClk)
+ begin
+ if rising_edge(SampleClk) then
+ sPpsPulseOut_ms <= to_stdlogic(sPpsPulseAsyncReset);
+ sPpsPulseOut <= sPpsPulseOut_ms;
+ end if;
+ end process;
+
+ sPpsPulse <= sPpsPulseOut;
+
+
+ rRpTransfer <= to_stdlogic(rRpTransferBool);
+ sSpTransfer <= to_stdlogic(sSpTransferBool);
+
+ --vhook_e TdcTop
+ --vhook_a aReset to_boolean(aTdcReset)
+ --vhook_a rResetTdc to_boolean(rResetTdc)
+ --vhook_a rEnableTdc to_boolean(rEnableTdc)
+ --vhook_a rReRunEnable to_boolean(rReRunEnable)
+ --vhook_a rPpsPulse to_boolean(rPpsPulseAsyncReset)
+ --vhook_a rLoadRePulseCounts to_boolean(rLoadRePulseCounts)
+ --vhook_a rLoadRpCounts to_boolean(rLoadRpCounts)
+ --vhook_a rLoadRptCounts to_boolean(rLoadRptCounts)
+ --vhook_a sLoadSpCounts to_boolean(sLoadSpCounts)
+ --vhook_a sLoadSptCounts to_boolean(sLoadSptCounts)
+ --vhook_a rEnablePpsCrossing to_boolean(rEnablePpsCrossing)
+ --vhook_a rPulserEnableDelayVal unsigned(rPulserEnableDelayVal)
+ --vhook_a sPpsClkCrossDelayVal unsigned(sPpsClkCrossDelayVal)
+ --vhook_a rRpTransfer rRpTransferBool
+ --vhook_a sSpTransfer sSpTransferBool
+ --vhook_a sPpsPulse sPpsPulseAsyncReset
+ --vhook_p {^rR(.*)In(.*)Clks} unsigned(rR$1In$2Clks)
+ --vhook_p {^sS(.*)In(.*)Clks} unsigned(sS$1In$2Clks)
+ TdcTopx: entity work.TdcTop (struct)
+ generic map (
+ kRClksPerRePulsePeriodBitsMax => kRClksPerRePulsePeriodBitsMax, --integer range 3:32 :=24
+ kRClksPerRpPeriodBitsMax => kRClksPerRpPeriodBitsMax, --integer range 3:16 :=16
+ kSClksPerSpPeriodBitsMax => kSClksPerSpPeriodBitsMax, --integer range 3:16 :=16
+ kPulsePeriodCntSize => kPulsePeriodCntSize, --integer:=13
+ kFreqRefPeriodsToCheckSize => kFreqRefPeriodsToCheckSize, --integer:=17
+ kSyncPeriodsToStampSize => kSyncPeriodsToStampSize) --integer:=10
+ port map (
+ aReset => to_boolean(aTdcReset), --in boolean
+ RefClk => RefClk, --in std_logic
+ SampleClk => SampleClk, --in std_logic
+ MeasClk => MeasClk, --in std_logic
+ rResetTdc => to_boolean(rResetTdc), --in boolean
+ rResetTdcDone => rResetTdcDone, --out boolean
+ rEnableTdc => to_boolean(rEnableTdc), --in boolean
+ rReRunEnable => to_boolean(rReRunEnable), --in boolean
+ rPpsPulse => to_boolean(rPpsPulseAsyncReset), --in boolean
+ rPpsPulseCaptured => rPpsPulseCaptured, --out boolean
+ rPulserEnableDelayVal => unsigned(rPulserEnableDelayVal), --in unsigned(3:0)
+ rEnablePpsCrossing => to_boolean(rEnablePpsCrossing), --in boolean
+ sPpsClkCrossDelayVal => unsigned(sPpsClkCrossDelayVal), --in unsigned(3:0)
+ sPpsPulse => sPpsPulseAsyncReset, --out boolean
+ mRpOffset => mRpOffset, --out unsigned(kPulsePeriodCntSize+ kSyncPeriodsToStampSize+ kFreqRefPeriodsToCheckSize-1:0)
+ mSpOffset => mSpOffset, --out unsigned(kPulsePeriodCntSize+ kSyncPeriodsToStampSize+ kFreqRefPeriodsToCheckSize-1:0)
+ mOffsetsDone => mOffsetsDone, --out boolean
+ mOffsetsValid => mOffsetsValid, --out boolean
+ rLoadRePulseCounts => to_boolean(rLoadRePulseCounts), --in boolean
+ rRePulsePeriodInRClks => unsigned(rRePulsePeriodInRClks), --in unsigned(kRClksPerRePulsePeriodBitsMax-1:0)
+ rRePulseHighTimeInRClks => unsigned(rRePulseHighTimeInRClks), --in unsigned(kRClksPerRePulsePeriodBitsMax-1:0)
+ rLoadRpCounts => to_boolean(rLoadRpCounts), --in boolean
+ rRpPeriodInRClks => unsigned(rRpPeriodInRClks), --in unsigned(kRClksPerRpPeriodBitsMax-1:0)
+ rRpHighTimeInRClks => unsigned(rRpHighTimeInRClks), --in unsigned(kRClksPerRpPeriodBitsMax-1:0)
+ rLoadRptCounts => to_boolean(rLoadRptCounts), --in boolean
+ rRptPeriodInRClks => unsigned(rRptPeriodInRClks), --in unsigned(kRClksPerRpPeriodBitsMax-1:0)
+ rRptHighTimeInRClks => unsigned(rRptHighTimeInRClks), --in unsigned(kRClksPerRpPeriodBitsMax-1:0)
+ sLoadSpCounts => to_boolean(sLoadSpCounts), --in boolean
+ sSpPeriodInSClks => unsigned(sSpPeriodInSClks), --in unsigned(kSClksPerSpPeriodBitsMax-1:0)
+ sSpHighTimeInSClks => unsigned(sSpHighTimeInSClks), --in unsigned(kSClksPerSpPeriodBitsMax-1:0)
+ sLoadSptCounts => to_boolean(sLoadSptCounts), --in boolean
+ sSptPeriodInSClks => unsigned(sSptPeriodInSClks), --in unsigned(kSClksPerSpPeriodBitsMax-1:0)
+ sSptHighTimeInSClks => unsigned(sSptHighTimeInSClks), --in unsigned(kSClksPerSpPeriodBitsMax-1:0)
+ rRpTransfer => rRpTransferBool, --out boolean
+ sSpTransfer => sSpTransferBool, --out boolean
+ rGatedPulseToPin => rGatedPulseToPin, --inout std_logic
+ sGatedPulseToPin => sGatedPulseToPin); --inout std_logic
+
+ -- Expand/compress the RegPort for moving through the netlist boundary.
+ bSyncRegPortOut <= Unflatten(bSyncRegPortOutFlat);
+ bSyncRegPortInFlat <= Flatten(bSyncRegPortIn);
+
+ --vhook SyncRegsIfc
+ --vhook_# Tying this low is safe because the sync reset is used inside SyncRegsIfc.
+ --vhook_a aBusReset '0'
+ --vhook_a bRegPortInFlat bSyncRegPortInFlat
+ --vhook_a bRegPortOutFlat bSyncRegPortOutFlat
+ --vhook_a rResetTdcDone to_stdlogic(rResetTdcDone)
+ --vhook_a rPpsPulseCaptured to_stdlogic(rPpsPulseCaptured)
+ --vhook_a mOffsetsDone to_stdlogic(mOffsetsDone)
+ --vhook_a mOffsetsValid to_stdlogic(mOffsetsValid)
+ --vhook_a mRpOffset std_logic_vector(mRpOffset)
+ --vhook_a mSpOffset std_logic_vector(mSpOffset)
+ SyncRegsIfcx: SyncRegsIfc
+ port map (
+ aBusReset => '0', --in std_logic
+ bBusReset => bBusReset, --in std_logic
+ BusClk => BusClk, --in std_logic
+ aTdcReset => aTdcReset, --out std_logic
+ bRegPortInFlat => bSyncRegPortInFlat, --in std_logic_vector(49:0)
+ bRegPortOutFlat => bSyncRegPortOutFlat, --out std_logic_vector(33:0)
+ RefClk => RefClk, --in std_logic
+ rResetTdc => rResetTdc, --out std_logic
+ rResetTdcDone => to_stdlogic(rResetTdcDone), --in std_logic
+ rEnableTdc => rEnableTdc, --out std_logic
+ rReRunEnable => rReRunEnable, --out std_logic
+ rEnablePpsCrossing => rEnablePpsCrossing, --out std_logic
+ rPpsPulseCaptured => to_stdlogic(rPpsPulseCaptured), --in std_logic
+ rPulserEnableDelayVal => rPulserEnableDelayVal, --out std_logic_vector(3:0)
+ SampleClk => SampleClk, --in std_logic
+ sPpsClkCrossDelayVal => sPpsClkCrossDelayVal, --out std_logic_vector(3:0)
+ MeasClk => MeasClk, --in std_logic
+ mRpOffset => std_logic_vector(mRpOffset), --in std_logic_vector(39:0)
+ mSpOffset => std_logic_vector(mSpOffset), --in std_logic_vector(39:0)
+ mOffsetsDone => to_stdlogic(mOffsetsDone), --in std_logic
+ mOffsetsValid => to_stdlogic(mOffsetsValid), --in std_logic
+ rLoadRePulseCounts => rLoadRePulseCounts, --out std_logic
+ rRePulsePeriodInRClks => rRePulsePeriodInRClks, --out std_logic_vector(23:0)
+ rRePulseHighTimeInRClks => rRePulseHighTimeInRClks, --out std_logic_vector(23:0)
+ rLoadRpCounts => rLoadRpCounts, --out std_logic
+ rRpPeriodInRClks => rRpPeriodInRClks, --out std_logic_vector(15:0)
+ rRpHighTimeInRClks => rRpHighTimeInRClks, --out std_logic_vector(15:0)
+ rLoadRptCounts => rLoadRptCounts, --out std_logic
+ rRptPeriodInRClks => rRptPeriodInRClks, --out std_logic_vector(15:0)
+ rRptHighTimeInRClks => rRptHighTimeInRClks, --out std_logic_vector(15:0)
+ sLoadSpCounts => sLoadSpCounts, --out std_logic
+ sSpPeriodInSClks => sSpPeriodInSClks, --out std_logic_vector(15:0)
+ sSpHighTimeInSClks => sSpHighTimeInSClks, --out std_logic_vector(15:0)
+ sLoadSptCounts => sLoadSptCounts, --out std_logic
+ sSptPeriodInSClks => sSptPeriodInSClks, --out std_logic_vector(15:0)
+ sSptHighTimeInSClks => sSptHighTimeInSClks); --out std_logic_vector(15:0)
+
+
+end struct;
+
+
+--------------------------------------------------------------------------------
+-- Testbench for TdcWrapper
+--------------------------------------------------------------------------------
+
+--synopsys translate_off
+library ieee;
+ use ieee.std_logic_1164.all;
+ use ieee.numeric_std.all;
+
+library work;
+ use work.PkgRegs.all;
+
+entity tb_TdcWrapper is end tb_TdcWrapper;
+
+architecture test of tb_TdcWrapper is
+
+ --vhook_sigstart
+ signal bBusReset: std_logic;
+ signal bSyncRegPortIn: RegPortIn_t;
+ signal bSyncRegPortOut: RegPortOut_t;
+ signal BusClk: std_logic := '0';
+ signal MeasClk: std_logic := '0';
+ signal RefClk: std_logic := '0';
+ signal rGatedPulseToPin: std_logic;
+ signal rPpsPulse: std_logic;
+ signal rRpTransfer: std_logic;
+ signal SampleClk: std_logic := '0';
+ signal sGatedPulseToPin: std_logic;
+ signal sPpsPulse: std_logic;
+ signal sSpTransfer: std_logic;
+ --vhook_sigend
+
+begin
+
+ --vhook_e TdcWrapper dutx
+ dutx: entity work.TdcWrapper (struct)
+ port map (
+ BusClk => BusClk, --in std_logic
+ bBusReset => bBusReset, --in std_logic
+ RefClk => RefClk, --in std_logic
+ SampleClk => SampleClk, --in std_logic
+ MeasClk => MeasClk, --in std_logic
+ bSyncRegPortOut => bSyncRegPortOut, --out RegPortOut_t
+ bSyncRegPortIn => bSyncRegPortIn, --in RegPortIn_t
+ rPpsPulse => rPpsPulse, --in std_logic
+ sPpsPulse => sPpsPulse, --out std_logic
+ rRpTransfer => rRpTransfer, --out std_logic
+ sSpTransfer => sSpTransfer, --out std_logic
+ rGatedPulseToPin => rGatedPulseToPin, --inout std_logic
+ sGatedPulseToPin => sGatedPulseToPin); --inout std_logic
+
+ main: process
+
+ begin
+ report "TdcWrapper Test is EMPTY! (but that's ok in this case)" severity note;
+ --vhook_nowarn tb_TdcWrapper.test.*
+ wait;
+ end process;
+
+end test;
+--synopsys translate_on