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,203 @@
|
|
|
1
|
+
"""Drawing features for AD9084."""
|
|
2
|
+
|
|
3
|
+
from typing import Dict
|
|
4
|
+
|
|
5
|
+
from adijif.draw import Layout, Node # type: ignore # isort: skip # noqa: I202
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class ad9084_draw:
|
|
9
|
+
"""AD9084 drawing features."""
|
|
10
|
+
|
|
11
|
+
_system_draw = False
|
|
12
|
+
show_rates = True
|
|
13
|
+
|
|
14
|
+
def _init_diagram(self) -> None:
|
|
15
|
+
"""Initialize diagram for AD9084 alone."""
|
|
16
|
+
self.ic_diagram_node = None
|
|
17
|
+
self._diagram_output_dividers = []
|
|
18
|
+
|
|
19
|
+
self.ic_diagram_node = Node("AD9084")
|
|
20
|
+
|
|
21
|
+
# External
|
|
22
|
+
# ref_in = Node("REF_IN", ntype="input")
|
|
23
|
+
# lo.add_node(ref_in)
|
|
24
|
+
|
|
25
|
+
crossbar = Node("MUX0", ntype="crossbar")
|
|
26
|
+
crossbar_rm = Node("Router MUX", ntype="crossbar")
|
|
27
|
+
|
|
28
|
+
self.ic_diagram_node.add_child(crossbar)
|
|
29
|
+
self.ic_diagram_node.add_child(crossbar_rm)
|
|
30
|
+
|
|
31
|
+
for adc in range(4):
|
|
32
|
+
adc_node = Node(f"ADC{adc}", ntype="adc")
|
|
33
|
+
self.ic_diagram_node.add_child(adc_node)
|
|
34
|
+
adc_node.shape = "parallelogram"
|
|
35
|
+
self.ic_diagram_node.add_connection({"from": adc_node, "to": crossbar})
|
|
36
|
+
|
|
37
|
+
for cddc in range(4):
|
|
38
|
+
cddc_node = Node(f"CDDC{cddc}", ntype="ddc")
|
|
39
|
+
self.ic_diagram_node.add_child(cddc_node)
|
|
40
|
+
self.ic_diagram_node.add_connection({"from": crossbar, "to": cddc_node})
|
|
41
|
+
self.ic_diagram_node.add_connection({"from": cddc_node, "to": crossbar_rm})
|
|
42
|
+
|
|
43
|
+
for fddc in range(8):
|
|
44
|
+
fddc_node = Node(f"FDDC{fddc}", ntype="ddc")
|
|
45
|
+
self.ic_diagram_node.add_child(fddc_node)
|
|
46
|
+
self.ic_diagram_node.add_connection({"from": crossbar_rm, "to": fddc_node})
|
|
47
|
+
|
|
48
|
+
jesd204_framer = Node("JESD204 Framer", ntype="jesd204framer")
|
|
49
|
+
self.ic_diagram_node.add_child(jesd204_framer)
|
|
50
|
+
|
|
51
|
+
for ddc in range(8):
|
|
52
|
+
fddc = self.ic_diagram_node.get_child(f"FDDC{ddc}")
|
|
53
|
+
self.ic_diagram_node.add_connection({"from": fddc, "to": jesd204_framer})
|
|
54
|
+
|
|
55
|
+
def _update_diagram(self, config: Dict) -> None:
|
|
56
|
+
"""Update diagram with configuration.
|
|
57
|
+
|
|
58
|
+
Args:
|
|
59
|
+
config (Dict): Configuration dictionary
|
|
60
|
+
|
|
61
|
+
Raises:
|
|
62
|
+
Exception: If key is not D followed by a number
|
|
63
|
+
"""
|
|
64
|
+
# Add output dividers
|
|
65
|
+
keys = config.keys()
|
|
66
|
+
output_dividers = self.ic_diagram_node.get_child("Output Dividers")
|
|
67
|
+
for key in keys:
|
|
68
|
+
if key.startswith("D"):
|
|
69
|
+
div = Node(key, ntype="divider")
|
|
70
|
+
output_dividers.add_child(div)
|
|
71
|
+
self.ic_diagram_node.add_connection(
|
|
72
|
+
{"from": output_dividers, "to": div}
|
|
73
|
+
)
|
|
74
|
+
else:
|
|
75
|
+
raise Exception(
|
|
76
|
+
f"Unknown key {key}. Must be of for DX where X is a number"
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
def draw(
|
|
80
|
+
self, clocks: Dict, lo: Layout = None, clock_chip_node: Node = None
|
|
81
|
+
) -> str:
|
|
82
|
+
"""Draw diagram in d2 language for IC alone with reference clock.
|
|
83
|
+
|
|
84
|
+
Args:
|
|
85
|
+
clocks (Dict): Dictionary of clocks
|
|
86
|
+
lo (Layout): Layout object to add to. Defaults to None.
|
|
87
|
+
clock_chip_node (Node): Node to connect to. Defaults to None.
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
str: Diagram in d2 language
|
|
91
|
+
|
|
92
|
+
Raises:
|
|
93
|
+
Exception: If no solution is saved
|
|
94
|
+
"""
|
|
95
|
+
if not self._saved_solution:
|
|
96
|
+
raise Exception("No solution to draw. Must call solve first.")
|
|
97
|
+
|
|
98
|
+
system_draw = lo is not None
|
|
99
|
+
|
|
100
|
+
if not system_draw:
|
|
101
|
+
lo = Layout("AD9084 Example")
|
|
102
|
+
lo.show_rates = self.show_rates
|
|
103
|
+
else:
|
|
104
|
+
# Verify lo is a Layout object
|
|
105
|
+
assert isinstance(lo, Layout), "lo must be a Layout object"
|
|
106
|
+
lo.add_node(self.ic_diagram_node)
|
|
107
|
+
|
|
108
|
+
if not system_draw:
|
|
109
|
+
ref_in = Node("REF_IN", ntype="input")
|
|
110
|
+
lo.add_node(ref_in)
|
|
111
|
+
else:
|
|
112
|
+
to_node = lo.get_node("AD9084_ref_clk")
|
|
113
|
+
# Locate node connected to this one
|
|
114
|
+
from_node = lo.get_connection(to=to_node.name)
|
|
115
|
+
assert from_node, "No connection found"
|
|
116
|
+
assert isinstance(from_node, list), "Connection must be a list"
|
|
117
|
+
assert len(from_node) == 1, "Only one connection allowed"
|
|
118
|
+
ref_in = from_node[0]["from"]
|
|
119
|
+
# Remove to_node since it is not needed
|
|
120
|
+
lo.remove_node(to_node.name)
|
|
121
|
+
|
|
122
|
+
for i in range(4):
|
|
123
|
+
adc = self.ic_diagram_node.get_child(f"ADC{i}")
|
|
124
|
+
lo.add_connection(
|
|
125
|
+
{"from": ref_in, "to": adc, "rate": clocks["AD9084_ref_clk"]}
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
# Update Node values
|
|
129
|
+
fddc_index = 0
|
|
130
|
+
for cddc in range(4):
|
|
131
|
+
rate = clocks["AD9084_ref_clk"]
|
|
132
|
+
self.ic_diagram_node.update_connection("MUX0", f"CDDC{cddc}", rate)
|
|
133
|
+
|
|
134
|
+
cddc_node = self.ic_diagram_node.get_child(f"CDDC{cddc}")
|
|
135
|
+
cddc_node.value = str(self.datapath.cddc_decimations[cddc])
|
|
136
|
+
drate = rate / self.datapath.cddc_decimations[cddc]
|
|
137
|
+
|
|
138
|
+
self.ic_diagram_node.update_connection(f"CDDC{cddc}", "Router MUX", drate)
|
|
139
|
+
|
|
140
|
+
self.ic_diagram_node.update_connection(
|
|
141
|
+
"Router MUX", f"FDDC{fddc_index}", drate
|
|
142
|
+
)
|
|
143
|
+
fddc_rate_out = drate / self.datapath.fddc_decimations[fddc_index]
|
|
144
|
+
self.ic_diagram_node.update_connection(
|
|
145
|
+
f"FDDC{fddc_index}", "JESD204 Framer", fddc_rate_out
|
|
146
|
+
)
|
|
147
|
+
fddc_index += 1
|
|
148
|
+
|
|
149
|
+
self.ic_diagram_node.update_connection(
|
|
150
|
+
"Router MUX", f"FDDC{fddc_index}", drate
|
|
151
|
+
)
|
|
152
|
+
fddc_rate_out = drate / self.datapath.fddc_decimations[fddc_index]
|
|
153
|
+
self.ic_diagram_node.update_connection(
|
|
154
|
+
f"FDDC{fddc_index}", "JESD204 Framer", fddc_rate_out
|
|
155
|
+
)
|
|
156
|
+
fddc_index += 1
|
|
157
|
+
|
|
158
|
+
# Connect clock to framer
|
|
159
|
+
if not system_draw:
|
|
160
|
+
sysref_in = Node("SYSREF_IN", ntype="input")
|
|
161
|
+
|
|
162
|
+
lo.add_connection(
|
|
163
|
+
{
|
|
164
|
+
"from": sysref_in,
|
|
165
|
+
"to": self.ic_diagram_node.get_child("JESD204 Framer"),
|
|
166
|
+
"rate": clocks["AD9084_sysref"],
|
|
167
|
+
}
|
|
168
|
+
)
|
|
169
|
+
else:
|
|
170
|
+
to_node = lo.get_node("AD9084_sysref")
|
|
171
|
+
# Locate node connected to this one
|
|
172
|
+
from_node = lo.get_connection(to=to_node.name)
|
|
173
|
+
assert from_node, "No connection found"
|
|
174
|
+
assert isinstance(from_node, list), "Connection must be a list"
|
|
175
|
+
assert len(from_node) == 1, "Only one connection allowed"
|
|
176
|
+
sysref_in = from_node[0]["from"]
|
|
177
|
+
# Remove to_node since it is not needed
|
|
178
|
+
lo.remove_node(to_node.name)
|
|
179
|
+
|
|
180
|
+
lo.add_connection(
|
|
181
|
+
{
|
|
182
|
+
"from": sysref_in,
|
|
183
|
+
"to": self.ic_diagram_node.get_child("JESD204 Framer"),
|
|
184
|
+
"rate": clocks["AD9084_sysref"],
|
|
185
|
+
}
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
# Connect Remote Deframer
|
|
189
|
+
remote_deframer = Node("JESD204 Deframer", ntype="deframer")
|
|
190
|
+
|
|
191
|
+
# Add connect for each lane
|
|
192
|
+
for _ in range(self.L):
|
|
193
|
+
lane_rate = self.bit_clock
|
|
194
|
+
lo.add_connection(
|
|
195
|
+
{
|
|
196
|
+
"from": self.ic_diagram_node.get_child("JESD204 Framer"),
|
|
197
|
+
"to": remote_deframer,
|
|
198
|
+
"rate": lane_rate,
|
|
199
|
+
}
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
if not system_draw:
|
|
203
|
+
return lo.draw()
|
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
"""AD9084 MxFE Utility Functions."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import os
|
|
5
|
+
from typing import Dict, Union
|
|
6
|
+
|
|
7
|
+
import pandas as pd
|
|
8
|
+
|
|
9
|
+
from ..utils import get_jesd_mode_from_params
|
|
10
|
+
from .converter import converter
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _convert_to_config(
|
|
14
|
+
mode: str,
|
|
15
|
+
L: Union[int, float],
|
|
16
|
+
M: Union[int, float],
|
|
17
|
+
F: Union[int, float],
|
|
18
|
+
S: Union[int, float],
|
|
19
|
+
HD: Union[int, float],
|
|
20
|
+
K: Union[int, float],
|
|
21
|
+
N: Union[int, float],
|
|
22
|
+
Np: Union[int, float],
|
|
23
|
+
CS: Union[int, float],
|
|
24
|
+
E: Union[int, float],
|
|
25
|
+
global_index: Union[int, float],
|
|
26
|
+
jesd_class: str,
|
|
27
|
+
) -> Dict:
|
|
28
|
+
return {
|
|
29
|
+
"L": L,
|
|
30
|
+
"M": M,
|
|
31
|
+
"F": F,
|
|
32
|
+
"S": S,
|
|
33
|
+
# "HD": 1 if F == 1 else 0,
|
|
34
|
+
"Np": Np,
|
|
35
|
+
"K": K,
|
|
36
|
+
"HD": HD,
|
|
37
|
+
"CS": CS,
|
|
38
|
+
"E": E,
|
|
39
|
+
"jesd_class": jesd_class,
|
|
40
|
+
"global_index": global_index,
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _load_rx_config_modes() -> Dict:
|
|
45
|
+
"""Load RX JESD configuration tables from file."""
|
|
46
|
+
return _read_table_xlsx("AD9084_JTX_JRX.xlsx")
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _read_table_xlsx(filename: str) -> Dict:
|
|
50
|
+
loc = os.path.dirname(__file__)
|
|
51
|
+
fn = os.path.join(loc, "resources", filename)
|
|
52
|
+
table = pd.read_excel(open(fn, "rb"), sheet_name="JTX_RxPath")
|
|
53
|
+
|
|
54
|
+
# strip out unique JESD modes
|
|
55
|
+
# table = table.drop_duplicates(subset=["JTX_MODE NUMBER"])
|
|
56
|
+
jrx_modes_204b = {}
|
|
57
|
+
jrx_modes_204c = {}
|
|
58
|
+
for prow in table.iterrows():
|
|
59
|
+
row = prow[1].to_dict()
|
|
60
|
+
# print(row)
|
|
61
|
+
jrx_modes_204c[str(row["Mode"])] = {
|
|
62
|
+
"L": row["L"],
|
|
63
|
+
"M": row["M"],
|
|
64
|
+
"F": row["F"],
|
|
65
|
+
"S": row["S"],
|
|
66
|
+
"HD": 1,
|
|
67
|
+
# 'K': row['K'],
|
|
68
|
+
"Np": row["Np"],
|
|
69
|
+
"DL": row["DL"],
|
|
70
|
+
"jesd_class": "jesd204c",
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
# Copy settings to 204b
|
|
74
|
+
for mode, config in jrx_modes_204c.items():
|
|
75
|
+
jrx_modes_204b[mode] = config.copy()
|
|
76
|
+
jrx_modes_204b[mode]["jesd_class"] = "jesd204b"
|
|
77
|
+
# jrx_modes_204b[mode]["HD"] = 0 # HD is always 0 for 204b
|
|
78
|
+
|
|
79
|
+
return {"jesd204b": jrx_modes_204b, "jesd204c": jrx_modes_204c}
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def parse_json_config(profile_json: str, bypass_version_check: bool = False) -> Dict:
|
|
83
|
+
"""Parse Apollo profiles and extract desired part information.
|
|
84
|
+
|
|
85
|
+
Args:
|
|
86
|
+
profile_json (str): Path to the profile JSON file.
|
|
87
|
+
bypass_version_check (bool): If True, bypasses the version check for
|
|
88
|
+
the profile.
|
|
89
|
+
|
|
90
|
+
Returns:
|
|
91
|
+
Dict: A dictionary containing parsed configuration data.
|
|
92
|
+
|
|
93
|
+
Raises:
|
|
94
|
+
FileNotFoundError: If the summary or profile JSON file does not exist.
|
|
95
|
+
KeyError: If required keys are missing in the JSON data.
|
|
96
|
+
Exception: If the profile is not supported or if it is a JESD204B profile.
|
|
97
|
+
"""
|
|
98
|
+
use_summary = False # cannot use summary for now as its broken in ACE
|
|
99
|
+
summary_json = None # Needed for lint
|
|
100
|
+
if use_summary:
|
|
101
|
+
if not os.path.exists(summary_json):
|
|
102
|
+
raise FileNotFoundError(f"Summary JSON file does not exist: {summary_json}")
|
|
103
|
+
if not os.path.exists(profile_json):
|
|
104
|
+
raise FileNotFoundError(f"Profile JSON file does not exist: {profile_json}")
|
|
105
|
+
full_profile_filename = os.path.abspath(profile_json)
|
|
106
|
+
|
|
107
|
+
with open(full_profile_filename, "r") as f:
|
|
108
|
+
profile_data = json.load(f)
|
|
109
|
+
|
|
110
|
+
# Check version
|
|
111
|
+
if not bypass_version_check:
|
|
112
|
+
if (
|
|
113
|
+
"profile_cfg" not in profile_data
|
|
114
|
+
or "profile_version" not in profile_data["profile_cfg"]
|
|
115
|
+
):
|
|
116
|
+
raise KeyError(
|
|
117
|
+
f"ERROR {profile_json} because 'profile_cfg' "
|
|
118
|
+
+ f"key is missing in {profile_json}"
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
profile_version = profile_data["profile_cfg"]["profile_version"]
|
|
122
|
+
if (
|
|
123
|
+
profile_version["major"] != 9
|
|
124
|
+
or profile_version["minor"] != 1
|
|
125
|
+
or profile_version["patch"] != 0
|
|
126
|
+
):
|
|
127
|
+
raise KeyError(
|
|
128
|
+
f"ERROR {profile_json} because 'profile_version' is not "
|
|
129
|
+
+ f"supported: {profile_version}"
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
if use_summary:
|
|
133
|
+
with open(summary_json, "r") as f:
|
|
134
|
+
summary_data = json.load(f)
|
|
135
|
+
|
|
136
|
+
summary_file = summary_json
|
|
137
|
+
|
|
138
|
+
iduc = os.path.basename(profile_json)
|
|
139
|
+
iduc = iduc.replace(".json", "")
|
|
140
|
+
|
|
141
|
+
df_row = {
|
|
142
|
+
"id": iduc,
|
|
143
|
+
"profile_name": None,
|
|
144
|
+
"device_clock_Hz": None,
|
|
145
|
+
"core_clock_Hz": None,
|
|
146
|
+
"common_lane_rate_Hz": None,
|
|
147
|
+
"rx_jesd_mode": None,
|
|
148
|
+
"tx_jesd_mode": None,
|
|
149
|
+
# "failed_reason": None,
|
|
150
|
+
"is_8t8r": None,
|
|
151
|
+
"jesd_settings": None,
|
|
152
|
+
"datapath": None,
|
|
153
|
+
# "jif_model": None,
|
|
154
|
+
# "dts_file": None,
|
|
155
|
+
# "bin_filename": None,
|
|
156
|
+
# "hdl_build_id": None,
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if use_summary:
|
|
160
|
+
if "is_8t8r" not in summary_data:
|
|
161
|
+
raise Exception("AD9088 is not supported")
|
|
162
|
+
|
|
163
|
+
if "is_8t8r" in summary_data and summary_data["is_8t8r"]:
|
|
164
|
+
raise Exception("AD9088 is not supported")
|
|
165
|
+
|
|
166
|
+
else:
|
|
167
|
+
df_row["is_8t8r"] = profile_data["profile_cfg"]["is_8t8r"]
|
|
168
|
+
if df_row["is_8t8r"]:
|
|
169
|
+
raise Exception("AD9088 is not supported")
|
|
170
|
+
|
|
171
|
+
if use_summary:
|
|
172
|
+
device_clock_Hz = summary_data["general_info"]["device_clock_Hz"]
|
|
173
|
+
else:
|
|
174
|
+
device_clock_Hz = profile_data["clk_cfg"]["dev_clk_freq_kHz"] * 1000
|
|
175
|
+
if device_clock_Hz is None:
|
|
176
|
+
raise KeyError(
|
|
177
|
+
f"Skipping {profile_data} because 'device_clock_Hz' key is missing"
|
|
178
|
+
)
|
|
179
|
+
df_row["device_clock_Hz"] = device_clock_Hz
|
|
180
|
+
|
|
181
|
+
if use_summary:
|
|
182
|
+
core_clock_Hz = summary_data["general_info"]["fpga_clock_Hz"]
|
|
183
|
+
if core_clock_Hz is None:
|
|
184
|
+
raise KeyError(
|
|
185
|
+
f"Skipping {profile_data} because 'core_clock_Hz' key is missing"
|
|
186
|
+
)
|
|
187
|
+
df_row["core_clock_Hz"] = core_clock_Hz
|
|
188
|
+
|
|
189
|
+
if use_summary:
|
|
190
|
+
common_lane_rate_Hz = summary_data["general_info"]["common_lane_rate_Hz"]
|
|
191
|
+
if common_lane_rate_Hz is None:
|
|
192
|
+
raise KeyError(
|
|
193
|
+
f"Skipping {profile_data} because 'common_lane_rate_Hz' key is missing"
|
|
194
|
+
)
|
|
195
|
+
else:
|
|
196
|
+
common_lane_rate_Hz = (
|
|
197
|
+
profile_data["jtx"][0]["common_link_cfg"]["lane_rate_kHz"] * 1000
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
df_row["common_lane_rate_Hz"] = common_lane_rate_Hz
|
|
201
|
+
|
|
202
|
+
# Parse datapath config
|
|
203
|
+
path = 0
|
|
204
|
+
if use_summary:
|
|
205
|
+
cddc_decimation = summary_data["rx_routes"][path]["cdrc"]
|
|
206
|
+
fddc_decimation = summary_data["rx_routes"][path]["fdrc"]
|
|
207
|
+
cduc_interpolation = summary_data["tx_routes"][path]["cdrc"]
|
|
208
|
+
fduc_interpolation = summary_data["tx_routes"][path]["fdrc"]
|
|
209
|
+
else:
|
|
210
|
+
cddc_decimation = profile_data["rx_path"][0]["rx_cddc"][0]["drc_ratio"]
|
|
211
|
+
fddc_decimation = profile_data["rx_path"][0]["rx_fddc"][0]["drc_ratio"]
|
|
212
|
+
cduc_interpolation = profile_data["tx_path"][0]["tx_cduc"][0]["drc_ratio"]
|
|
213
|
+
fduc_interpolation = profile_data["tx_path"][0]["tx_fduc"][0]["drc_ratio"]
|
|
214
|
+
|
|
215
|
+
if cddc_decimation == 0:
|
|
216
|
+
cddc_decimation = 1
|
|
217
|
+
elif cddc_decimation == 1:
|
|
218
|
+
cddc_decimation = 2
|
|
219
|
+
elif cddc_decimation == 2:
|
|
220
|
+
cddc_decimation = 3
|
|
221
|
+
elif cddc_decimation == 3:
|
|
222
|
+
cddc_decimation = 4
|
|
223
|
+
elif cddc_decimation == 4:
|
|
224
|
+
cddc_decimation = 6
|
|
225
|
+
elif cddc_decimation == 5:
|
|
226
|
+
cddc_decimation = 12
|
|
227
|
+
|
|
228
|
+
fddc_decimation = int(fddc_decimation)
|
|
229
|
+
fddc_decimation = 2**fddc_decimation
|
|
230
|
+
|
|
231
|
+
cduc_interpolation = int(cduc_interpolation)
|
|
232
|
+
|
|
233
|
+
# THIS IS REALLY BIZARRE but how the profile gen works
|
|
234
|
+
fduc_interpolation = int(fduc_interpolation)
|
|
235
|
+
|
|
236
|
+
df_row["datapath"] = {
|
|
237
|
+
"cddc_decimation": cddc_decimation,
|
|
238
|
+
"fddc_decimation": fddc_decimation,
|
|
239
|
+
"cduc_interpolation": cduc_interpolation,
|
|
240
|
+
"fduc_interpolation": fduc_interpolation,
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
# Parse JESD204 config
|
|
244
|
+
link_index = 0
|
|
245
|
+
lane_index = 0
|
|
246
|
+
rx_jesd_mode = profile_data["jtx"][link_index]["tx_link_cfg"][lane_index][
|
|
247
|
+
"quick_mode_id"
|
|
248
|
+
]
|
|
249
|
+
tx_jesd_mode = profile_data["jrx"][link_index]["rx_link_cfg"][lane_index][
|
|
250
|
+
"quick_mode_id"
|
|
251
|
+
]
|
|
252
|
+
|
|
253
|
+
if profile_data["jtx"][link_index]["common_link_cfg"]["ver"] == 0:
|
|
254
|
+
# JESD204B
|
|
255
|
+
raise Exception(f"Skipping {summary_file} because it is a JESD204B profile")
|
|
256
|
+
if profile_data["jrx"][link_index]["common_link_cfg"]["ver"] == 0:
|
|
257
|
+
# JESD204B
|
|
258
|
+
raise Exception(f"Skipping {summary_file} because it is a JESD204B profile")
|
|
259
|
+
|
|
260
|
+
df_row["jesd_settings"] = {}
|
|
261
|
+
for rtx, cfg in zip(["jtx", "jrx"], ["tx_link_cfg", "rx_link_cfg"]):
|
|
262
|
+
df_row["jesd_settings"][rtx] = {}
|
|
263
|
+
for setting, jesd_setting_key in zip(
|
|
264
|
+
["L", "F", "M", "S", "HD", "K", "N", "Np"],
|
|
265
|
+
[
|
|
266
|
+
"l_minus1",
|
|
267
|
+
"f_minus1",
|
|
268
|
+
"m_minus1",
|
|
269
|
+
"s_minus1",
|
|
270
|
+
"high_dens",
|
|
271
|
+
"k_minus1",
|
|
272
|
+
"n_minus1",
|
|
273
|
+
"np_minus1",
|
|
274
|
+
],
|
|
275
|
+
):
|
|
276
|
+
if setting in ["N", "K"]:
|
|
277
|
+
continue
|
|
278
|
+
if jesd_setting_key not in profile_data[rtx][link_index][cfg][lane_index]:
|
|
279
|
+
raise KeyError(
|
|
280
|
+
f"Skipping {summary_file} because {jesd_setting_key} "
|
|
281
|
+
+ f"key is missing in {rtx} {cfg}"
|
|
282
|
+
)
|
|
283
|
+
if setting == "HD":
|
|
284
|
+
df_row["jesd_settings"][rtx][setting] = profile_data[rtx][link_index][
|
|
285
|
+
cfg
|
|
286
|
+
][lane_index][jesd_setting_key]
|
|
287
|
+
else:
|
|
288
|
+
df_row["jesd_settings"][rtx][setting] = (
|
|
289
|
+
int(
|
|
290
|
+
profile_data[rtx][link_index][cfg][lane_index][jesd_setting_key]
|
|
291
|
+
)
|
|
292
|
+
+ 1
|
|
293
|
+
)
|
|
294
|
+
|
|
295
|
+
if rx_jesd_mode is None:
|
|
296
|
+
raise KeyError(f"Skipping {summary_file} because 'rx_jesd_mode' key is missing")
|
|
297
|
+
df_row["rx_jesd_mode"] = rx_jesd_mode
|
|
298
|
+
if tx_jesd_mode is None:
|
|
299
|
+
raise KeyError(f"Skipping {summary_file} because 'tx_jesd_mode' key is missing")
|
|
300
|
+
df_row["tx_jesd_mode"] = tx_jesd_mode
|
|
301
|
+
profile_name = os.path.basename(full_profile_filename)
|
|
302
|
+
df_row["profile_name"] = profile_name.replace(".json", "")
|
|
303
|
+
|
|
304
|
+
return df_row
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
def apply_settings(conv: converter, profile_settings: Dict) -> None:
|
|
308
|
+
"""Apply settings to the AD9084 converter.
|
|
309
|
+
|
|
310
|
+
Args:
|
|
311
|
+
conv (converter): The AD9084 converter object.
|
|
312
|
+
profile_settings (Dict): The profile settings dictionary
|
|
313
|
+
containing configuration data.
|
|
314
|
+
|
|
315
|
+
Raises:
|
|
316
|
+
ValueError: If the TX and RX JESD204C modes do not match.
|
|
317
|
+
"""
|
|
318
|
+
jesd_class = "jesd204c" # only JESD204C is supported for AD9084 right now
|
|
319
|
+
|
|
320
|
+
cddc_dec = profile_settings["datapath"]["cddc_decimation"]
|
|
321
|
+
cddc_dec = int(cddc_dec)
|
|
322
|
+
fddc_dec = profile_settings["datapath"]["fddc_decimation"]
|
|
323
|
+
fddc_dec = int(fddc_dec)
|
|
324
|
+
converter_rate = int(profile_settings["device_clock_Hz"])
|
|
325
|
+
|
|
326
|
+
conv.sample_clock = converter_rate / (cddc_dec * fddc_dec)
|
|
327
|
+
conv.datapath.cddc_decimations = [cddc_dec] * 4
|
|
328
|
+
conv.datapath.fddc_decimations = [fddc_dec] * 8
|
|
329
|
+
conv.datapath.fddc_enabled = [True] * 8
|
|
330
|
+
|
|
331
|
+
M = profile_settings["jesd_settings"]["jtx"]["M"]
|
|
332
|
+
L = profile_settings["jesd_settings"]["jtx"]["L"]
|
|
333
|
+
S = profile_settings["jesd_settings"]["jtx"]["S"]
|
|
334
|
+
Np = profile_settings["jesd_settings"]["jtx"]["Np"]
|
|
335
|
+
|
|
336
|
+
# Verify TX and RX JESD204C modes are the same
|
|
337
|
+
M_tx = profile_settings["jesd_settings"]["jrx"]["M"]
|
|
338
|
+
L_tx = profile_settings["jesd_settings"]["jrx"]["L"]
|
|
339
|
+
S_tx = profile_settings["jesd_settings"]["jrx"]["S"]
|
|
340
|
+
Np_tx = profile_settings["jesd_settings"]["jrx"]["Np"]
|
|
341
|
+
if M != M_tx or L != L_tx or S != S_tx or Np != Np_tx:
|
|
342
|
+
raise ValueError(
|
|
343
|
+
f"TX and RX JESD204C modes do not match: "
|
|
344
|
+
f"TX (M={M_tx}, L={L_tx}, S={S_tx}, Np={Np_tx}), "
|
|
345
|
+
f"RX (M={M}, L={L}, S={S}, Np={Np})"
|
|
346
|
+
)
|
|
347
|
+
|
|
348
|
+
mode_rx = get_jesd_mode_from_params(
|
|
349
|
+
conv, M=M, L=L, S=S, Np=Np, jesd_class=jesd_class
|
|
350
|
+
)
|
|
351
|
+
assert mode_rx, f"Could not find JESD204C mode for M={M}, L={L}, S={S}, Np={Np}"
|
|
352
|
+
if isinstance(mode_rx, list) and len(mode_rx) > 1:
|
|
353
|
+
print(
|
|
354
|
+
"WARNING: Multiple JESD204C modes found for "
|
|
355
|
+
+ f"M={M}, L={L}, S={S}, Np={Np}\n"
|
|
356
|
+
+ "Picking the first one."
|
|
357
|
+
)
|
|
358
|
+
mode_rx = mode_rx[0]["mode"]
|
|
359
|
+
|
|
360
|
+
conv.set_quick_configuration_mode(mode_rx, jesd_class)
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
if __name__ == "__main__":
|
|
364
|
+
data = _load_rx_config_modes()
|
|
365
|
+
# _load_tx_config_modes()
|