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
|
--
-- 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;
|