diff options
Diffstat (limited to 'fpga/usrp3/top/n3xx/dboards/common/sync/TdcWrapper.vhd')
-rw-r--r-- | fpga/usrp3/top/n3xx/dboards/common/sync/TdcWrapper.vhd | 397 |
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 |