aboutsummaryrefslogtreecommitdiffstats
path: root/fpga/usrp3/top/n3xx/dboards/common/sync/TdcWrapper.vhd
blob: 1ab235fe20e08a2e7903d72481809567c3cc5dbd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
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