pyadi-jif 0.1.0__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- adijif/__init__.py +32 -0
- adijif/adijif.py +1 -0
- adijif/cli.py +21 -0
- adijif/clocks/__init__.py +10 -0
- adijif/clocks/ad9523.py +321 -0
- adijif/clocks/ad9523_1_bf.py +91 -0
- adijif/clocks/ad9528.py +444 -0
- adijif/clocks/ad9528_bf.py +70 -0
- adijif/clocks/ad9545.py +553 -0
- adijif/clocks/clock.py +153 -0
- adijif/clocks/hmc7044.py +558 -0
- adijif/clocks/hmc7044_bf.py +68 -0
- adijif/clocks/ltc6952.py +624 -0
- adijif/clocks/ltc6952_bf.py +67 -0
- adijif/clocks/ltc6953.py +509 -0
- adijif/common.py +70 -0
- adijif/converters/__init__.py +3 -0
- adijif/converters/ad9081.py +679 -0
- adijif/converters/ad9081_dp.py +206 -0
- adijif/converters/ad9081_util.py +124 -0
- adijif/converters/ad9084.py +588 -0
- adijif/converters/ad9084_dp.py +111 -0
- adijif/converters/ad9084_draw.py +203 -0
- adijif/converters/ad9084_util.py +365 -0
- adijif/converters/ad9144.py +316 -0
- adijif/converters/ad9144_bf.py +44 -0
- adijif/converters/ad9680.py +201 -0
- adijif/converters/ad9680_bf.py +43 -0
- adijif/converters/ad9680_draw.py +184 -0
- adijif/converters/adc.py +83 -0
- adijif/converters/adrv9009.py +426 -0
- adijif/converters/adrv9009_bf.py +43 -0
- adijif/converters/adrv9009_util.py +89 -0
- adijif/converters/converter.py +399 -0
- adijif/converters/dac.py +85 -0
- adijif/converters/resources/AD9084_JTX_JRX.xlsx +0 -0
- adijif/converters/resources/ad9081_JRx_204B.csv +180 -0
- adijif/converters/resources/ad9081_JRx_204C.csv +411 -0
- adijif/converters/resources/ad9081_JTx_204B.csv +1488 -0
- adijif/converters/resources/ad9081_JTx_204C.csv +1064 -0
- adijif/converters/resources/full_rx_mode_table_ad9081.csv +1904 -0
- adijif/converters/resources/full_tx_mode_table_ad9081.csv +994 -0
- adijif/d2/__init__.py +26 -0
- adijif/d2/d2lib.h +81 -0
- adijif/draw.py +498 -0
- adijif/fpgas/__init__.py +1 -0
- adijif/fpgas/fpga.py +64 -0
- adijif/fpgas/xilinx/__init__.py +1143 -0
- adijif/fpgas/xilinx/bf.py +101 -0
- adijif/fpgas/xilinx/pll.py +232 -0
- adijif/fpgas/xilinx/sevenseries.py +531 -0
- adijif/fpgas/xilinx/ultrascaleplus.py +485 -0
- adijif/fpgas/xilinx/xilinx_draw.py +516 -0
- adijif/gekko_trans.py +295 -0
- adijif/jesd.py +760 -0
- adijif/plls/__init__.py +3 -0
- adijif/plls/adf4030.py +259 -0
- adijif/plls/adf4371.py +419 -0
- adijif/plls/adf4382.py +581 -0
- adijif/plls/pll.py +103 -0
- adijif/solvers.py +54 -0
- adijif/sys/__init__.py +1 -0
- adijif/sys/s_plls.py +185 -0
- adijif/system.py +567 -0
- adijif/system_draw.py +65 -0
- adijif/types.py +151 -0
- adijif/utils.py +191 -0
- pyadi_jif-0.1.0.dist-info/METADATA +62 -0
- pyadi_jif-0.1.0.dist-info/RECORD +73 -0
- pyadi_jif-0.1.0.dist-info/WHEEL +6 -0
- pyadi_jif-0.1.0.dist-info/licenses/AUTHORS.rst +13 -0
- pyadi_jif-0.1.0.dist-info/licenses/LICENSE +277 -0
- pyadi_jif-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,516 @@
|
|
|
1
|
+
"""Drawing features for Xilinx FPGA designs."""
|
|
2
|
+
|
|
3
|
+
from typing import Dict, List
|
|
4
|
+
|
|
5
|
+
from adijif.converters.converter import converter as Converter
|
|
6
|
+
from adijif.draw import Layout, Node
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class xilinx_draw:
|
|
10
|
+
"""Xilinx drawing features."""
|
|
11
|
+
|
|
12
|
+
def _init_diagram(self) -> None:
|
|
13
|
+
"""Initialize the diagram for a Xilinx FPGA alone."""
|
|
14
|
+
self.ic_diagram_node = None
|
|
15
|
+
|
|
16
|
+
self.ic_diagram_node = Node(self.name)
|
|
17
|
+
|
|
18
|
+
# Add generic transceiver since we don't know what is used until later
|
|
19
|
+
transceiver = Node("Transceiver", ntype="transceiver")
|
|
20
|
+
self.ic_diagram_node.add_child(transceiver)
|
|
21
|
+
|
|
22
|
+
# Add Link layer JESD204 core
|
|
23
|
+
jesd204_link = Node("JESD204-Link-IP", ntype="ip")
|
|
24
|
+
self.ic_diagram_node.add_child(jesd204_link)
|
|
25
|
+
|
|
26
|
+
# Add Transport Layer JESD204 core
|
|
27
|
+
jesd204_transport = Node("JESD204-Transport-IP", ntype="ip")
|
|
28
|
+
self.ic_diagram_node.add_child(jesd204_transport)
|
|
29
|
+
|
|
30
|
+
# Add Application layer JESD204 core
|
|
31
|
+
jesd204_application = Node("JESD204-Application-IP", ntype="ip")
|
|
32
|
+
self.ic_diagram_node.add_child(jesd204_application)
|
|
33
|
+
|
|
34
|
+
# Add connections
|
|
35
|
+
self.ic_diagram_node.add_connection({"from": transceiver, "to": jesd204_link})
|
|
36
|
+
self.ic_diagram_node.add_connection(
|
|
37
|
+
{"from": jesd204_link, "to": jesd204_transport}
|
|
38
|
+
)
|
|
39
|
+
self.ic_diagram_node.add_connection(
|
|
40
|
+
{"from": jesd204_transport, "to": jesd204_application, "type": "data"}
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
def _draw_phy(self, config: Dict, converter: Converter = None) -> tuple:
|
|
44
|
+
"""Draw the PHY layer for the Xilinx FPGA.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
config (Dict): Configuration dictionary
|
|
48
|
+
converter (Converter): Converter object (optional)
|
|
49
|
+
|
|
50
|
+
Returns:
|
|
51
|
+
tuple: Tuple of in_c, out_c, connect_to_input
|
|
52
|
+
|
|
53
|
+
Raises:
|
|
54
|
+
Exception: If unknown out_clk_select
|
|
55
|
+
"""
|
|
56
|
+
# cfg = {
|
|
57
|
+
# "clocks": {"FPGA_REF": 500000000.0, "LINK_OUT_REF": 125000000.0},
|
|
58
|
+
# "fpga": {
|
|
59
|
+
# "type": "cpll",
|
|
60
|
+
# "m": 2,
|
|
61
|
+
# "d": 1,
|
|
62
|
+
# "n1": 5,
|
|
63
|
+
# "n2": 4,
|
|
64
|
+
# "vco": 5000000000.0,
|
|
65
|
+
# "sys_clk_select": "XCVR_CPLL",
|
|
66
|
+
# "progdiv": 40.0,
|
|
67
|
+
# "out_clk_select": "XCVR_PROGDIV_CLK",
|
|
68
|
+
# "separate_device_clock_required": 1,
|
|
69
|
+
# "transport_samples_per_clock": 8,
|
|
70
|
+
# },
|
|
71
|
+
# }
|
|
72
|
+
|
|
73
|
+
if converter:
|
|
74
|
+
name = f"{self.name}_{converter.name.upper()}_ref_clk"
|
|
75
|
+
ref_in_rate = config["clocks"][name]
|
|
76
|
+
else:
|
|
77
|
+
ref_in_rate = config["clocks"]["FPGA_REF"]
|
|
78
|
+
|
|
79
|
+
phy = Node("JESD204-PHY-IP", ntype="phy")
|
|
80
|
+
self.ic_diagram_node.add_child(phy)
|
|
81
|
+
|
|
82
|
+
# PLL
|
|
83
|
+
if config["fpga"]["type"] == "cpll":
|
|
84
|
+
cpll = Node("CPLL", ntype="cpll")
|
|
85
|
+
phy.add_child(cpll)
|
|
86
|
+
|
|
87
|
+
# Put stuff in CPLL
|
|
88
|
+
m = Node("M", ntype="divider")
|
|
89
|
+
cpll.add_child(m)
|
|
90
|
+
m.value = config["fpga"]["m"]
|
|
91
|
+
|
|
92
|
+
pfd = Node("PFD", ntype="phase-frequency-detector")
|
|
93
|
+
cpll.add_child(pfd)
|
|
94
|
+
cpll.add_connection({"from": m, "to": pfd, "rate": ref_in_rate})
|
|
95
|
+
|
|
96
|
+
cp = Node("CP", ntype="charge-pump")
|
|
97
|
+
cpll.add_child(cp)
|
|
98
|
+
cpll.add_connection({"from": pfd, "to": cp})
|
|
99
|
+
|
|
100
|
+
lpf = Node("LPF", ntype="loop-filter")
|
|
101
|
+
cpll.add_child(lpf)
|
|
102
|
+
cpll.add_connection({"from": cp, "to": lpf})
|
|
103
|
+
|
|
104
|
+
vco = Node("VCO", ntype="vco")
|
|
105
|
+
cpll.add_child(vco)
|
|
106
|
+
cpll.add_connection({"from": lpf, "to": vco})
|
|
107
|
+
|
|
108
|
+
d = Node("D", ntype="divider")
|
|
109
|
+
cpll.add_child(d)
|
|
110
|
+
d.value = config["fpga"]["d"]
|
|
111
|
+
cpll.add_connection({"from": vco, "to": d, "rate": config["fpga"]["vco"]})
|
|
112
|
+
|
|
113
|
+
n1 = Node("N1", ntype="divider")
|
|
114
|
+
cpll.add_child(n1)
|
|
115
|
+
n1.value = config["fpga"]["n1"]
|
|
116
|
+
cpll.add_connection({"from": vco, "to": n1})
|
|
117
|
+
|
|
118
|
+
n2 = Node("N2", ntype="divider")
|
|
119
|
+
cpll.add_child(n2)
|
|
120
|
+
n2.value = config["fpga"]["n2"]
|
|
121
|
+
cpll.add_connection({"from": n1, "to": n2})
|
|
122
|
+
cpll.add_connection({"from": n2, "to": pfd})
|
|
123
|
+
|
|
124
|
+
transceiver = Node("Transceiver", ntype="transceiver")
|
|
125
|
+
phy.add_child(transceiver)
|
|
126
|
+
phy.add_connection({"from": d, "to": transceiver})
|
|
127
|
+
|
|
128
|
+
# Define common in/out
|
|
129
|
+
in_c = m
|
|
130
|
+
xcvr_out = d
|
|
131
|
+
xcvr_out_rate = config["fpga"]["vco"] / config["fpga"]["d"]
|
|
132
|
+
|
|
133
|
+
else:
|
|
134
|
+
|
|
135
|
+
qpll = Node("QPLL", ntype="qpll")
|
|
136
|
+
phy.add_child(qpll)
|
|
137
|
+
|
|
138
|
+
# Put stuff in QPLL
|
|
139
|
+
m = Node("M", ntype="divider")
|
|
140
|
+
m.value = config["fpga"]["m"]
|
|
141
|
+
qpll.add_child(m)
|
|
142
|
+
|
|
143
|
+
pfd = Node("PFD", ntype="phase-frequency-detector")
|
|
144
|
+
qpll.add_child(pfd)
|
|
145
|
+
|
|
146
|
+
cp = Node("CP", ntype="charge-pump")
|
|
147
|
+
qpll.add_child(cp)
|
|
148
|
+
|
|
149
|
+
lpf = Node("LPF", ntype="loop-filter")
|
|
150
|
+
qpll.add_child(lpf)
|
|
151
|
+
|
|
152
|
+
vco = Node("VCO", ntype="vco")
|
|
153
|
+
qpll.add_child(vco)
|
|
154
|
+
|
|
155
|
+
n = Node("N", ntype="divider")
|
|
156
|
+
n.value = config["fpga"]["n"]
|
|
157
|
+
qpll.add_child(n)
|
|
158
|
+
|
|
159
|
+
# d2 = Node("/2", ntype="divider")
|
|
160
|
+
# qpll.add_child(d2)
|
|
161
|
+
|
|
162
|
+
d = Node("D", ntype="divider")
|
|
163
|
+
d.value = config["fpga"]["d"]
|
|
164
|
+
qpll.add_child(d)
|
|
165
|
+
|
|
166
|
+
# Connect
|
|
167
|
+
phy.add_connection({"from": m, "to": pfd})
|
|
168
|
+
phy.add_connection({"from": pfd, "to": cp})
|
|
169
|
+
phy.add_connection({"from": cp, "to": lpf})
|
|
170
|
+
phy.add_connection({"from": lpf, "to": vco})
|
|
171
|
+
phy.add_connection({"from": vco, "to": n})
|
|
172
|
+
# TRX is DDR devices so it uses both clock edges
|
|
173
|
+
# (skipping /2 and *2 dividers)
|
|
174
|
+
# phy.add_connection({"from": vco, "to": d2,
|
|
175
|
+
# "rate": config['fpga']['vco']})
|
|
176
|
+
# phy.add_connection({"from": d2, "to": d,
|
|
177
|
+
# "rate": config['fpga']['vco'] / 2})
|
|
178
|
+
phy.add_connection({"from": vco, "to": d, "rate": config["fpga"]["vco"]})
|
|
179
|
+
phy.add_connection({"from": n, "to": pfd})
|
|
180
|
+
|
|
181
|
+
xcvr_out = d
|
|
182
|
+
xcvr_out_rate = config["fpga"]["vco"] / config["fpga"]["d"]
|
|
183
|
+
|
|
184
|
+
in_c = m
|
|
185
|
+
|
|
186
|
+
# Divider complex
|
|
187
|
+
trx_dividers = Node("Transceiver Dividers", ntype="trx-dividers")
|
|
188
|
+
phy.add_child(trx_dividers)
|
|
189
|
+
|
|
190
|
+
if config["fpga"]["out_clk_select"] == "XCVR_OUTCLK_PCS":
|
|
191
|
+
raise Exception("Only XCVR_PROGDIV_CLK supported for now")
|
|
192
|
+
elif config["fpga"]["out_clk_select"] == "XCVR_OUTCLK_PMA":
|
|
193
|
+
raise Exception("Only XCVR_PROGDIV_CLK supported for now")
|
|
194
|
+
elif config["fpga"]["out_clk_select"] == "XCVR_REFCLK":
|
|
195
|
+
|
|
196
|
+
rmux = Node("REFCLKSEL-Mux", ntype="mux")
|
|
197
|
+
trx_dividers.add_child(rmux)
|
|
198
|
+
connect_to_input = [rmux]
|
|
199
|
+
|
|
200
|
+
smux = Node("SYSCLKSEL-Mux", ntype="mux")
|
|
201
|
+
trx_dividers.add_child(smux)
|
|
202
|
+
trx_dividers.add_connection({"from": rmux, "to": smux, "rate": ref_in_rate})
|
|
203
|
+
|
|
204
|
+
out_rate = ref_in_rate
|
|
205
|
+
out = smux
|
|
206
|
+
|
|
207
|
+
elif config["fpga"]["out_clk_select"] == "XCVR_REFCLK_DIV2":
|
|
208
|
+
|
|
209
|
+
rmux = Node("REFCLKSEL-Mux", ntype="mux")
|
|
210
|
+
trx_dividers.add_child(rmux)
|
|
211
|
+
# trx_dividers.add_connection(
|
|
212
|
+
# {"from": in_c, "to": rmux, "rate": ref_in_rate}
|
|
213
|
+
# )
|
|
214
|
+
connect_to_input = [rmux]
|
|
215
|
+
|
|
216
|
+
smux = Node("SYSCLKSEL-Mux", ntype="mux")
|
|
217
|
+
trx_dividers.add_child(smux)
|
|
218
|
+
trx_dividers.add_connection({"from": rmux, "to": smux, "rate": ref_in_rate})
|
|
219
|
+
|
|
220
|
+
div2 = Node("DIV2", ntype="divider")
|
|
221
|
+
trx_dividers.add_child(div2)
|
|
222
|
+
div2.value = 2
|
|
223
|
+
trx_dividers.add_connection({"from": smux, "to": div2, "rate": ref_in_rate})
|
|
224
|
+
|
|
225
|
+
out_rate = ref_in_rate / 2
|
|
226
|
+
out = div2
|
|
227
|
+
|
|
228
|
+
elif config["fpga"]["out_clk_select"] == "XCVR_PROGDIV_CLK":
|
|
229
|
+
|
|
230
|
+
mux = Node("PLLCLKSEL-Mux", ntype="mux")
|
|
231
|
+
mux.value = config["fpga"]["type"]
|
|
232
|
+
trx_dividers.add_child(mux)
|
|
233
|
+
phy.add_connection({"from": xcvr_out, "to": mux, "rate": xcvr_out_rate})
|
|
234
|
+
|
|
235
|
+
cdr = Node("CDR", ntype="cdr")
|
|
236
|
+
trx_dividers.add_child(cdr)
|
|
237
|
+
trx_dividers.add_connection({"from": mux, "to": cdr})
|
|
238
|
+
|
|
239
|
+
progdiv = Node("ProgDiv", ntype="divider")
|
|
240
|
+
trx_dividers.add_child(progdiv)
|
|
241
|
+
progdiv.value = int(config["fpga"]["progdiv"])
|
|
242
|
+
trx_dividers.add_connection({"from": cdr, "to": progdiv})
|
|
243
|
+
|
|
244
|
+
out_rate = xcvr_out_rate / config["fpga"]["progdiv"]
|
|
245
|
+
out = progdiv
|
|
246
|
+
connect_to_input = []
|
|
247
|
+
else:
|
|
248
|
+
raise Exception(
|
|
249
|
+
f"Unknown out_clk_select: {config['fpga']['out_clk_select']}"
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
out_mux = Node("OUTCLKSEL-Mux", ntype="mux")
|
|
253
|
+
trx_dividers.add_child(out_mux)
|
|
254
|
+
trx_dividers.add_connection({"from": out, "to": out_mux, "rate": out_rate})
|
|
255
|
+
|
|
256
|
+
return in_c, out_mux, connect_to_input, xcvr_out
|
|
257
|
+
|
|
258
|
+
def draw(
|
|
259
|
+
self, config: Dict, lo: Layout = None, converters: List[Converter] = None
|
|
260
|
+
) -> str:
|
|
261
|
+
"""Draw diagram in d2 language for IC alone with reference clock.
|
|
262
|
+
|
|
263
|
+
Args:
|
|
264
|
+
config (Dict): Clock settings
|
|
265
|
+
lo (Layout): Layout object to draw on (optional)
|
|
266
|
+
converters (List): List of converters to draw (optional)
|
|
267
|
+
|
|
268
|
+
Returns:
|
|
269
|
+
str: SVG data
|
|
270
|
+
|
|
271
|
+
Raises:
|
|
272
|
+
Exception: If no solution is saved
|
|
273
|
+
Exception: If no converter is found
|
|
274
|
+
"""
|
|
275
|
+
if not self._saved_solution:
|
|
276
|
+
raise Exception("No solution to draw. Must call solve first.")
|
|
277
|
+
|
|
278
|
+
system_draw = lo is not None
|
|
279
|
+
|
|
280
|
+
if not system_draw:
|
|
281
|
+
lo = Layout(f"{self.name} Example")
|
|
282
|
+
converters = []
|
|
283
|
+
else:
|
|
284
|
+
# Verify lo is a Layout object
|
|
285
|
+
assert isinstance(lo, Layout), "lo must be a Layout object"
|
|
286
|
+
assert len(converters) == 1, "Only one converter supported"
|
|
287
|
+
|
|
288
|
+
lo.add_node(self.ic_diagram_node)
|
|
289
|
+
|
|
290
|
+
clocks = config["clocks"]
|
|
291
|
+
device_clock_source = config["fpga"]["device_clock_source"]
|
|
292
|
+
|
|
293
|
+
if not system_draw:
|
|
294
|
+
ref_in = Node("REF_IN", ntype="input")
|
|
295
|
+
lo.add_node(ref_in)
|
|
296
|
+
else:
|
|
297
|
+
for converter in converters:
|
|
298
|
+
to_node = lo.get_node(f"{self.name}_{converter.name.upper()}_ref_clk")
|
|
299
|
+
# Locate node connected to this one
|
|
300
|
+
from_node = lo.get_connection(to=to_node.name)
|
|
301
|
+
assert from_node, "No connection found"
|
|
302
|
+
assert isinstance(from_node, list), "Connection must be a list"
|
|
303
|
+
ref_in = from_node[0]["from"]
|
|
304
|
+
lo.remove_node(to_node.name)
|
|
305
|
+
|
|
306
|
+
# TO DO, ADD PHY PER CONVERTER
|
|
307
|
+
if not converters:
|
|
308
|
+
converters_first = None
|
|
309
|
+
else:
|
|
310
|
+
converters_first = converters[0]
|
|
311
|
+
in_c, out_c, connect_to_input, xcvr_out = self._draw_phy(
|
|
312
|
+
config, converters_first
|
|
313
|
+
)
|
|
314
|
+
|
|
315
|
+
if not system_draw:
|
|
316
|
+
self.ic_diagram_node.add_connection(
|
|
317
|
+
{"from": ref_in, "to": in_c, "rate": clocks["FPGA_REF"]}
|
|
318
|
+
)
|
|
319
|
+
|
|
320
|
+
else:
|
|
321
|
+
for converter in converters:
|
|
322
|
+
rcn = f"{self.name}_{converter.name.upper()}_ref_clk"
|
|
323
|
+
assert rcn in clocks, f"Missing clock {rcn}"
|
|
324
|
+
self.ic_diagram_node.add_connection(
|
|
325
|
+
{"from": ref_in, "to": in_c, "rate": clocks[rcn]}
|
|
326
|
+
)
|
|
327
|
+
if connect_to_input:
|
|
328
|
+
for c in connect_to_input:
|
|
329
|
+
self.ic_diagram_node.add_connection(
|
|
330
|
+
{"from": ref_in, "to": c, "rate": clocks[rcn]}
|
|
331
|
+
)
|
|
332
|
+
|
|
333
|
+
# Delete Transceiver node
|
|
334
|
+
self.ic_diagram_node.remove_child("Transceiver")
|
|
335
|
+
|
|
336
|
+
# Connect out_c to JESD204-Link-IP
|
|
337
|
+
if not system_draw:
|
|
338
|
+
self.ic_diagram_node.add_connection(
|
|
339
|
+
{
|
|
340
|
+
"from": out_c,
|
|
341
|
+
"to": self.ic_diagram_node.get_child("JESD204-Link-IP"),
|
|
342
|
+
"rate": clocks["LINK_OUT_REF"],
|
|
343
|
+
}
|
|
344
|
+
)
|
|
345
|
+
else:
|
|
346
|
+
for converter in converters:
|
|
347
|
+
self.ic_diagram_node.add_connection(
|
|
348
|
+
{
|
|
349
|
+
"from": out_c,
|
|
350
|
+
"to": self.ic_diagram_node.get_child("JESD204-Link-IP"),
|
|
351
|
+
"rate": clocks[
|
|
352
|
+
f"{self.name}_{converter.name.upper()}_device_clk"
|
|
353
|
+
],
|
|
354
|
+
}
|
|
355
|
+
)
|
|
356
|
+
|
|
357
|
+
# Connect device clock to JESD204-Link-IP and JESD204-Transport-IP
|
|
358
|
+
if not system_draw:
|
|
359
|
+
if device_clock_source == "external":
|
|
360
|
+
device_clock = Node("Device Clock", ntype="input")
|
|
361
|
+
lo.add_node(device_clock)
|
|
362
|
+
elif device_clock_source == "link_clock":
|
|
363
|
+
device_clock = out_c
|
|
364
|
+
elif device_clock_source == "ref_clock":
|
|
365
|
+
device_clock = ref_in
|
|
366
|
+
else:
|
|
367
|
+
raise Exception(f"Unknown device clock source: {device_clock_source}")
|
|
368
|
+
self.ic_diagram_node.add_connection(
|
|
369
|
+
{
|
|
370
|
+
"from": device_clock,
|
|
371
|
+
"to": self.ic_diagram_node.get_child("JESD204-Link-IP"),
|
|
372
|
+
"rate": clocks["LINK_OUT_REF"],
|
|
373
|
+
}
|
|
374
|
+
)
|
|
375
|
+
self.ic_diagram_node.add_connection(
|
|
376
|
+
{
|
|
377
|
+
"from": device_clock,
|
|
378
|
+
"to": self.ic_diagram_node.get_child("JESD204-Transport-IP"),
|
|
379
|
+
"rate": clocks["LINK_OUT_REF"],
|
|
380
|
+
}
|
|
381
|
+
)
|
|
382
|
+
|
|
383
|
+
else:
|
|
384
|
+
for converter in converters:
|
|
385
|
+
|
|
386
|
+
c_name = f"{self.name}_{converter.name.upper()}_device_clk"
|
|
387
|
+
to_node = lo.get_node(c_name)
|
|
388
|
+
# Locate node connected to this one
|
|
389
|
+
from_node = lo.get_connection(to=to_node.name)
|
|
390
|
+
assert from_node, "No connection found"
|
|
391
|
+
assert isinstance(from_node, list), "Connection must be a list"
|
|
392
|
+
lo.remove_node(to_node.name)
|
|
393
|
+
|
|
394
|
+
if device_clock_source == "external":
|
|
395
|
+
device_clock = from_node[0]["from"]
|
|
396
|
+
elif device_clock_source == "link_clock":
|
|
397
|
+
device_clock = out_c
|
|
398
|
+
elif device_clock_source == "ref_clock":
|
|
399
|
+
device_clock = ref_in
|
|
400
|
+
else:
|
|
401
|
+
raise Exception(
|
|
402
|
+
f"Unknown device clock source: {device_clock_source}"
|
|
403
|
+
)
|
|
404
|
+
|
|
405
|
+
self.ic_diagram_node.add_connection(
|
|
406
|
+
{
|
|
407
|
+
"from": device_clock,
|
|
408
|
+
"to": self.ic_diagram_node.get_child("JESD204-Link-IP"),
|
|
409
|
+
"rate": clocks[c_name],
|
|
410
|
+
}
|
|
411
|
+
)
|
|
412
|
+
self.ic_diagram_node.add_connection(
|
|
413
|
+
{
|
|
414
|
+
"from": device_clock,
|
|
415
|
+
"to": self.ic_diagram_node.get_child("JESD204-Transport-IP"),
|
|
416
|
+
"rate": clocks[c_name],
|
|
417
|
+
}
|
|
418
|
+
)
|
|
419
|
+
|
|
420
|
+
# Connect SYSREF to JESD204-Link-IP
|
|
421
|
+
if not system_draw:
|
|
422
|
+
sysref = Node("SYSREF", ntype="input")
|
|
423
|
+
lo.add_node(sysref)
|
|
424
|
+
else:
|
|
425
|
+
for converter in converters:
|
|
426
|
+
parent = lo.get_node(converter.name.upper())
|
|
427
|
+
to_node = parent.get_child("JESD204 Framer")
|
|
428
|
+
# Locate node connected to this one
|
|
429
|
+
from_node = lo.get_connection(to=to_node.name)
|
|
430
|
+
assert from_node, "No connection found"
|
|
431
|
+
assert isinstance(from_node, list), "Connection must be a list"
|
|
432
|
+
sysref = from_node[0]["from"]
|
|
433
|
+
# lo.remove_node(to_node.name)
|
|
434
|
+
|
|
435
|
+
self.ic_diagram_node.add_connection(
|
|
436
|
+
{
|
|
437
|
+
"from": sysref,
|
|
438
|
+
"to": self.ic_diagram_node.get_child("JESD204-Link-IP"),
|
|
439
|
+
}
|
|
440
|
+
)
|
|
441
|
+
|
|
442
|
+
# Update with config settings
|
|
443
|
+
|
|
444
|
+
# Datapath
|
|
445
|
+
|
|
446
|
+
# Get deframer
|
|
447
|
+
if system_draw:
|
|
448
|
+
deframer = lo.get_node("JESD204 Deframer")
|
|
449
|
+
assert deframer, "No JESD204 Deframer found in layout"
|
|
450
|
+
parent = lo.get_node(converter.name.upper())
|
|
451
|
+
framer = parent.get_child("JESD204 Framer")
|
|
452
|
+
assert framer, "No JESD204 Framer found in layout"
|
|
453
|
+
|
|
454
|
+
# Replace deframer with a new one inside the FPGA IC diagram
|
|
455
|
+
lo.remove_node("JESD204 Deframer")
|
|
456
|
+
phy_parent = self.ic_diagram_node.get_child("JESD204-PHY-IP")
|
|
457
|
+
new_deframer = Node("DESERIALIZER", ntype="serdes")
|
|
458
|
+
phy_parent.add_child(new_deframer)
|
|
459
|
+
lo.add_connection(
|
|
460
|
+
{
|
|
461
|
+
"from": xcvr_out,
|
|
462
|
+
"to": new_deframer,
|
|
463
|
+
"rate": converter.bit_clock,
|
|
464
|
+
}
|
|
465
|
+
)
|
|
466
|
+
# Add connect for each lane
|
|
467
|
+
for _ in range(converter.L):
|
|
468
|
+
lane_rate = converter.bit_clock
|
|
469
|
+
lo.add_connection(
|
|
470
|
+
{
|
|
471
|
+
"from": framer,
|
|
472
|
+
"to": new_deframer,
|
|
473
|
+
"rate": lane_rate,
|
|
474
|
+
"type": "data",
|
|
475
|
+
}
|
|
476
|
+
)
|
|
477
|
+
if system_draw:
|
|
478
|
+
# Connect DESERIALIZER to link layer decoder
|
|
479
|
+
link_layer = self.ic_diagram_node.get_child("JESD204-Link-IP")
|
|
480
|
+
assert link_layer, "No JESD204-Link-IP found in layout"
|
|
481
|
+
decoder = Node("Link Layer Decoder", ntype="decoder")
|
|
482
|
+
link_layer.add_child(decoder)
|
|
483
|
+
div = 40 if converter.encoding == "8b10b" else 66
|
|
484
|
+
for _ in range(converter.L):
|
|
485
|
+
# Add connect for each lane
|
|
486
|
+
lo.add_connection(
|
|
487
|
+
{
|
|
488
|
+
"from": new_deframer,
|
|
489
|
+
"to": decoder,
|
|
490
|
+
"rate": converter.bit_clock / div,
|
|
491
|
+
"type": "data",
|
|
492
|
+
}
|
|
493
|
+
)
|
|
494
|
+
|
|
495
|
+
if system_draw:
|
|
496
|
+
# Add deframer in transport layer
|
|
497
|
+
transport_layer = self.ic_diagram_node.get_child("JESD204-Transport-IP")
|
|
498
|
+
assert transport_layer, "No JESD204-Transport-IP found in layout"
|
|
499
|
+
deframer = Node("JESD204 Deframer", ntype="deframer")
|
|
500
|
+
transport_layer.add_child(deframer)
|
|
501
|
+
# Connect to link layer decoder
|
|
502
|
+
lo.add_connection(
|
|
503
|
+
{
|
|
504
|
+
"from": decoder,
|
|
505
|
+
"to": deframer,
|
|
506
|
+
"rate": converter.bit_clock
|
|
507
|
+
/ (40 if converter.encoding == "8b10b" else 66),
|
|
508
|
+
"type": "data",
|
|
509
|
+
}
|
|
510
|
+
)
|
|
511
|
+
# Remove connection between link and transport layers
|
|
512
|
+
self.ic_diagram_node.remove_connection(
|
|
513
|
+
from_s=link_layer.name, to=transport_layer.name
|
|
514
|
+
)
|
|
515
|
+
|
|
516
|
+
return lo.draw()
|