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.
Files changed (73) hide show
  1. adijif/__init__.py +32 -0
  2. adijif/adijif.py +1 -0
  3. adijif/cli.py +21 -0
  4. adijif/clocks/__init__.py +10 -0
  5. adijif/clocks/ad9523.py +321 -0
  6. adijif/clocks/ad9523_1_bf.py +91 -0
  7. adijif/clocks/ad9528.py +444 -0
  8. adijif/clocks/ad9528_bf.py +70 -0
  9. adijif/clocks/ad9545.py +553 -0
  10. adijif/clocks/clock.py +153 -0
  11. adijif/clocks/hmc7044.py +558 -0
  12. adijif/clocks/hmc7044_bf.py +68 -0
  13. adijif/clocks/ltc6952.py +624 -0
  14. adijif/clocks/ltc6952_bf.py +67 -0
  15. adijif/clocks/ltc6953.py +509 -0
  16. adijif/common.py +70 -0
  17. adijif/converters/__init__.py +3 -0
  18. adijif/converters/ad9081.py +679 -0
  19. adijif/converters/ad9081_dp.py +206 -0
  20. adijif/converters/ad9081_util.py +124 -0
  21. adijif/converters/ad9084.py +588 -0
  22. adijif/converters/ad9084_dp.py +111 -0
  23. adijif/converters/ad9084_draw.py +203 -0
  24. adijif/converters/ad9084_util.py +365 -0
  25. adijif/converters/ad9144.py +316 -0
  26. adijif/converters/ad9144_bf.py +44 -0
  27. adijif/converters/ad9680.py +201 -0
  28. adijif/converters/ad9680_bf.py +43 -0
  29. adijif/converters/ad9680_draw.py +184 -0
  30. adijif/converters/adc.py +83 -0
  31. adijif/converters/adrv9009.py +426 -0
  32. adijif/converters/adrv9009_bf.py +43 -0
  33. adijif/converters/adrv9009_util.py +89 -0
  34. adijif/converters/converter.py +399 -0
  35. adijif/converters/dac.py +85 -0
  36. adijif/converters/resources/AD9084_JTX_JRX.xlsx +0 -0
  37. adijif/converters/resources/ad9081_JRx_204B.csv +180 -0
  38. adijif/converters/resources/ad9081_JRx_204C.csv +411 -0
  39. adijif/converters/resources/ad9081_JTx_204B.csv +1488 -0
  40. adijif/converters/resources/ad9081_JTx_204C.csv +1064 -0
  41. adijif/converters/resources/full_rx_mode_table_ad9081.csv +1904 -0
  42. adijif/converters/resources/full_tx_mode_table_ad9081.csv +994 -0
  43. adijif/d2/__init__.py +26 -0
  44. adijif/d2/d2lib.h +81 -0
  45. adijif/draw.py +498 -0
  46. adijif/fpgas/__init__.py +1 -0
  47. adijif/fpgas/fpga.py +64 -0
  48. adijif/fpgas/xilinx/__init__.py +1143 -0
  49. adijif/fpgas/xilinx/bf.py +101 -0
  50. adijif/fpgas/xilinx/pll.py +232 -0
  51. adijif/fpgas/xilinx/sevenseries.py +531 -0
  52. adijif/fpgas/xilinx/ultrascaleplus.py +485 -0
  53. adijif/fpgas/xilinx/xilinx_draw.py +516 -0
  54. adijif/gekko_trans.py +295 -0
  55. adijif/jesd.py +760 -0
  56. adijif/plls/__init__.py +3 -0
  57. adijif/plls/adf4030.py +259 -0
  58. adijif/plls/adf4371.py +419 -0
  59. adijif/plls/adf4382.py +581 -0
  60. adijif/plls/pll.py +103 -0
  61. adijif/solvers.py +54 -0
  62. adijif/sys/__init__.py +1 -0
  63. adijif/sys/s_plls.py +185 -0
  64. adijif/system.py +567 -0
  65. adijif/system_draw.py +65 -0
  66. adijif/types.py +151 -0
  67. adijif/utils.py +191 -0
  68. pyadi_jif-0.1.0.dist-info/METADATA +62 -0
  69. pyadi_jif-0.1.0.dist-info/RECORD +73 -0
  70. pyadi_jif-0.1.0.dist-info/WHEEL +6 -0
  71. pyadi_jif-0.1.0.dist-info/licenses/AUTHORS.rst +13 -0
  72. pyadi_jif-0.1.0.dist-info/licenses/LICENSE +277 -0
  73. pyadi_jif-0.1.0.dist-info/top_level.txt +1 -0
adijif/d2/__init__.py ADDED
@@ -0,0 +1,26 @@
1
+ # flake8: noqa
2
+ """Bindings for the D2 Compiler"""
3
+
4
+ import ctypes
5
+ import os
6
+
7
+ loc = os.path.dirname(os.path.abspath(__file__))
8
+ lib_path = os.path.join(loc, "d2lib.so")
9
+
10
+ if not os.path.exists(lib_path):
11
+ raise FileNotFoundError(f"Could not find {lib_path}")
12
+
13
+ library = ctypes.cdll.LoadLibrary(lib_path)
14
+
15
+ runme = library.runme
16
+ runme.argtypes = [ctypes.c_char_p]
17
+ runme.restype = ctypes.c_char_p
18
+
19
+
20
+ def compile(code: str) -> str:
21
+ try:
22
+ graph_bytes = runme(code.encode("utf-8"))
23
+ return graph_bytes.decode("utf-8")
24
+ except Exception as e:
25
+ print(e)
26
+ return None
adijif/d2/d2lib.h ADDED
@@ -0,0 +1,81 @@
1
+ /* Code generated by cmd/cgo; DO NOT EDIT. */
2
+
3
+ /* package command-line-arguments */
4
+
5
+
6
+ #line 1 "cgo-builtin-export-prolog"
7
+
8
+ #include <stddef.h>
9
+
10
+ #ifndef GO_CGO_EXPORT_PROLOGUE_H
11
+ #define GO_CGO_EXPORT_PROLOGUE_H
12
+
13
+ #ifndef GO_CGO_GOSTRING_TYPEDEF
14
+ typedef struct { const char *p; ptrdiff_t n; } _GoString_;
15
+ #endif
16
+
17
+ #endif
18
+
19
+ /* Start of preamble from import "C" comments. */
20
+
21
+
22
+
23
+
24
+ /* End of preamble from import "C" comments. */
25
+
26
+
27
+ /* Start of boilerplate cgo prologue. */
28
+ #line 1 "cgo-gcc-export-header-prolog"
29
+
30
+ #ifndef GO_CGO_PROLOGUE_H
31
+ #define GO_CGO_PROLOGUE_H
32
+
33
+ typedef signed char GoInt8;
34
+ typedef unsigned char GoUint8;
35
+ typedef short GoInt16;
36
+ typedef unsigned short GoUint16;
37
+ typedef int GoInt32;
38
+ typedef unsigned int GoUint32;
39
+ typedef long long GoInt64;
40
+ typedef unsigned long long GoUint64;
41
+ typedef GoInt64 GoInt;
42
+ typedef GoUint64 GoUint;
43
+ typedef size_t GoUintptr;
44
+ typedef float GoFloat32;
45
+ typedef double GoFloat64;
46
+ #ifdef _MSC_VER
47
+ #include <complex.h>
48
+ typedef _Fcomplex GoComplex64;
49
+ typedef _Dcomplex GoComplex128;
50
+ #else
51
+ typedef float _Complex GoComplex64;
52
+ typedef double _Complex GoComplex128;
53
+ #endif
54
+
55
+ /*
56
+ static assertion to make sure the file is being used on architecture
57
+ at least with matching size of GoInt.
58
+ */
59
+ typedef char _check_for_64_bit_pointer_matching_GoInt[sizeof(void*)==64/8 ? 1:-1];
60
+
61
+ #ifndef GO_CGO_GOSTRING_TYPEDEF
62
+ typedef _GoString_ GoString;
63
+ #endif
64
+ typedef void *GoMap;
65
+ typedef void *GoChan;
66
+ typedef struct { void *t; void *v; } GoInterface;
67
+ typedef struct { void *data; GoInt len; GoInt cap; } GoSlice;
68
+
69
+ #endif
70
+
71
+ /* End of boilerplate cgo prologue. */
72
+
73
+ #ifdef __cplusplus
74
+ extern "C" {
75
+ #endif
76
+
77
+ extern char* runme(char* namePtr);
78
+
79
+ #ifdef __cplusplus
80
+ }
81
+ #endif
adijif/draw.py ADDED
@@ -0,0 +1,498 @@
1
+ """Diagraming functions for different components."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import os
6
+ from typing import Union
7
+
8
+ connection_style_types = {
9
+ "data": {"stroke": "blue", "stroke-width": 2},
10
+ }
11
+
12
+
13
+ class Node:
14
+ """Node model for diagraming which can have children and connections."""
15
+
16
+ def __init__(self, name: str, ntype: str = None, parent: Node = None) -> None:
17
+ """Initialize node with name, type and parent node.
18
+
19
+ Args:
20
+ name (str): Name of the node.
21
+ ntype (str): Type of the node.
22
+ parent (Node): Parent node of the node.
23
+ """
24
+ self.name = name
25
+ self.parent = parent
26
+ self.ntype = ntype
27
+ self.children = []
28
+ self.connections = []
29
+ self.shape = "rectangle"
30
+ self.use_unit_conversion_for_rate = True
31
+ self._value = None
32
+
33
+ def __repr__(self) -> str:
34
+ """Get string representation of the node.
35
+
36
+ Returns:
37
+ str: String representation of the node.
38
+ """
39
+ return f"Node({self.name})"
40
+
41
+ @property
42
+ def value(self) -> str:
43
+ """Get value of the node.
44
+
45
+ Returns:
46
+ str: Value of the node.
47
+ """
48
+ return f"{self.name} = {self._value}" if self._value else None
49
+
50
+ @value.setter
51
+ def value(self, value: Union(int, float, str)) -> None:
52
+ """Set value of the node."""
53
+ self._value = value
54
+
55
+ def add_connection(self, connection: dict) -> None:
56
+ """Add connection between this node and another node.
57
+
58
+ Args:
59
+ connection (dict): Connection dictionary with keys "from", "to",
60
+ optionally "rate" and "style".
61
+ """
62
+ if "rate" in connection and self.use_unit_conversion_for_rate:
63
+ units = ["Hz", "kHz", "MHz", "GHz"]
64
+ rate = connection["rate"]
65
+ # Convert to unit based on rate scale
66
+ for unit in units:
67
+ if rate < 1000:
68
+ connection["rate"] = f"{rate:.2f} {unit}"
69
+ break
70
+ rate /= 1000
71
+
72
+ self.connections.append(connection)
73
+
74
+ def get_connection(self, from_s: str, to: str) -> dict:
75
+ """Get connection between this node and another node.
76
+
77
+ Args:
78
+ from_s (str): Name of the node from which connection originates.
79
+ to (str): Name of the node to which connection goes.
80
+
81
+ Returns:
82
+ dict: Connection dictionary with keys "from", "to" and optionally "rate".
83
+
84
+ Raises:
85
+ ValueError: If connection not found.
86
+ """
87
+ for conn in self.connections:
88
+ if conn["from"].name == from_s and conn["to"].name == to:
89
+ return conn
90
+ raise ValueError(f"Connection from {from_s} to {to} not found.")
91
+
92
+ def remove_connection(self, from_s: str, to: str) -> None:
93
+ """Remove connection between this node and another node.
94
+
95
+ Args:
96
+ from_s (str): Name of the node from which connection originates.
97
+ to (str): Name of the node to which connection goes.
98
+
99
+ Raises:
100
+ ValueError: If connection not found.
101
+ """
102
+ conn_to_remove = None
103
+ for conn in self.connections:
104
+ if conn["from"].name == from_s and conn["to"].name == to:
105
+ conn_to_remove = conn
106
+ break
107
+ if conn_to_remove:
108
+ self.connections.remove(conn_to_remove)
109
+ return
110
+ raise ValueError(f"Connection from {from_s} to {to} not found.")
111
+
112
+ def update_connection(self, from_s: str, to: str, rate: Union(int, float)) -> None:
113
+ """Update connection rate between this node and another node.
114
+
115
+ Args:
116
+ from_s (str): Name of the node from which connection originates.
117
+ to (str): Name of the node to which connection goes.
118
+ rate (float): Rate of the connection.
119
+
120
+ Raises:
121
+ ValueError: If connection not found.
122
+ """
123
+ for conn in self.connections:
124
+ if conn["from"].name == from_s and conn["to"].name == to:
125
+ units = ["Hz", "kHz", "MHz", "GHz"]
126
+ # Convert to unit based on rate scale
127
+ for unit in units:
128
+ if rate < 1000:
129
+ conn["rate"] = f"{rate:.2f} {unit}"
130
+ return
131
+ rate /= 1000
132
+
133
+ raise ValueError(f"Connection from {from_s} to {to} not found.")
134
+
135
+ def add_child(self, child: Node) -> None:
136
+ """Add child node to this node.
137
+
138
+ Args:
139
+ child (Node): Child node to add.
140
+ """
141
+ if not isinstance(child, list):
142
+ child = [child]
143
+ for c in child:
144
+ c.parent = self
145
+ self.children.append(c)
146
+
147
+ def get_child(self, name: str) -> Node:
148
+ """Get child node by name.
149
+
150
+ Args:
151
+ name (str): Name of the child node.
152
+
153
+ Returns:
154
+ Node: Child node with the given name.
155
+
156
+ Raises:
157
+ ValueError: If child node not found.
158
+ """
159
+ for child in self.children:
160
+ if child.name == name:
161
+ return child
162
+ raise ValueError(f"Child with name {name} not found.")
163
+
164
+ def remove_child(self, name: str) -> None:
165
+ """Remove child node by name.
166
+
167
+ Args:
168
+ name (str): Name of the child node to remove.
169
+ """
170
+ # Remove connections with the child first
171
+ connections_to_keep = []
172
+ for conn in self.connections:
173
+ if conn["to"].name != name:
174
+ connections_to_keep.append(conn)
175
+ self.connections = connections_to_keep
176
+ connections_to_keep = []
177
+ for conn in self.connections:
178
+ if conn["from"].name != name:
179
+ connections_to_keep.append(conn)
180
+ self.connections = connections_to_keep
181
+
182
+ children_to_keep = []
183
+ for child in self.children:
184
+ if child.name != name:
185
+ children_to_keep.append(child)
186
+ self.children = children_to_keep
187
+
188
+
189
+ class Layout:
190
+ """Layout model for diagraming which contains nodes and connections."""
191
+
192
+ si = " "
193
+ use_d2_cli = False
194
+ _write_out_d2_file = True
195
+
196
+ def __init__(self, name: str) -> None:
197
+ """Initialize layout with name.
198
+
199
+ Args:
200
+ name (str): Name of the layout.
201
+ """
202
+ self.name = name
203
+ self.nodes = []
204
+ self.connections = []
205
+ self.use_unit_conversion_for_rate = True
206
+ self.output_filename = "clocks.d2"
207
+ self.output_image_filename = "clocks.svg"
208
+ self.layout_engine = "elk"
209
+ self.show_rates = True
210
+
211
+ def add_node(self, node: Node) -> None:
212
+ """Add node to the layout.
213
+
214
+ Args:
215
+ node (Node): Node to add to the layout.
216
+ """
217
+ self.nodes.append(node)
218
+
219
+ def remove_node(self, name: str) -> None:
220
+ """Remove node by name.
221
+
222
+ Args:
223
+ name (str): Name of the node to remove.
224
+ """
225
+ # Remove connections with the node first
226
+ connections_to_keep = []
227
+ for conn in self.connections:
228
+ if conn["to"].name != name:
229
+ connections_to_keep.append(conn)
230
+ self.connections = connections_to_keep
231
+ connections_to_keep = []
232
+ for conn in self.connections:
233
+ if conn["from"].name != name:
234
+ connections_to_keep.append(conn)
235
+ self.connections = connections_to_keep
236
+
237
+ nodes_to_keep = []
238
+ for node in self.nodes:
239
+ if node.name != name:
240
+ nodes_to_keep.append(node)
241
+ self.nodes = nodes_to_keep
242
+
243
+ def add_connection(self, connection: dict) -> None:
244
+ """Add connection between two nodes.
245
+
246
+ Args:
247
+ connection (dict): Connection dictionary with keys "from", "to"
248
+ and optionally "rate".
249
+ """
250
+ if "rate" in connection and self.use_unit_conversion_for_rate:
251
+ units = ["Hz", "kHz", "MHz", "GHz"]
252
+ rate = connection["rate"]
253
+ # Convert to unit based on rate scale
254
+ for unit in units:
255
+ if rate < 1000:
256
+ connection["rate"] = f"{rate:.2f} {unit}"
257
+ break
258
+ rate /= 1000
259
+ self.connections.append(connection)
260
+
261
+ def get_connection(
262
+ self, from_s: str = None, to: str = None
263
+ ) -> Union[dict, list[dict]]:
264
+ """Get connection between two nodes.
265
+
266
+ Args:
267
+ from_s (str): Name of the node from which connection originates.
268
+ to (str): Name of the node to which connection goes.
269
+
270
+ Returns:
271
+ List[dict] or dict: List of or single Connection dictionary with
272
+ keys "from", "to" and optionally "rate".
273
+
274
+ Raises:
275
+ ValueError: If connection not found.
276
+ """
277
+ if from_s is None and to is None:
278
+ raise ValueError("Both from and to cannot be None.")
279
+ found = []
280
+ if from_s is None:
281
+ for conn in self.connections:
282
+ if conn["to"].name == to:
283
+ found.append(conn)
284
+ return found
285
+ if to is None:
286
+ for conn in self.connections:
287
+ if conn["from"].name == from_s:
288
+ found.append(conn)
289
+ return found
290
+ for conn in self.connections:
291
+ if conn["from"].name == from_s and conn["to"].name == to:
292
+ return conn
293
+
294
+ def get_node(self, name: str) -> Node:
295
+ """Get node by name.
296
+
297
+ Args:
298
+ name (str): Name of the node.
299
+
300
+ Returns:
301
+ Node: Node with the given name.
302
+
303
+ Raises:
304
+ ValueError: If node not found.
305
+ """
306
+ for node in self.nodes:
307
+ if node.name == name:
308
+ return node
309
+ raise ValueError(f"Node with name {name} not found.")
310
+
311
+ def draw(self) -> str:
312
+ """Draw diagram in d2 language.
313
+
314
+ Returns:
315
+ str: Path to the output image file.
316
+ """
317
+ diag = "direction: right\n\n"
318
+
319
+ def apply_connection_style(diag: str, connection: dict) -> str:
320
+ """Apply style to the connection in the diagram.
321
+
322
+ Args:
323
+ diag (str): Current diagram string.
324
+ connection (dict): Connection dictionary with keys "from", "to",
325
+ and optionally "style".
326
+
327
+ Returns:
328
+ str: Updated diagram string with applied style.
329
+ """
330
+ from_p_name = get_parents_names(connection["from"])
331
+ to_p_name = get_parents_names(connection["to"])
332
+
333
+ if "type" in connection and connection["type"] in connection_style_types:
334
+ style = connection_style_types[connection["type"]]
335
+ index = 0 # Default index but make sure its not in the diag
336
+ for key in style:
337
+ while True:
338
+ con_str = f"({from_p_name}{connection['from'].name} -> "
339
+ con_str += f"{to_p_name}{connection['to'].name})[{index}]"
340
+ con_str += f".style.{key}: {style[key]}\n"
341
+ if con_str not in diag:
342
+ diag += con_str
343
+ break
344
+ index += 1 # Increment index to avoid duplicates
345
+ # Duplicates can happen if multiple connections
346
+ # between the same nodes
347
+
348
+ index = 0
349
+ if "index" in connection:
350
+ index = connection["index"]
351
+ if "style" in connection:
352
+ for key in connection["style"]:
353
+ diag += f"({from_p_name}{connection['from'].name} -> "
354
+ diag += f"{to_p_name}{connection['to'].name})[{index}]"
355
+ diag += f".style.{key}: {connection['style'][key]}\n"
356
+ return diag
357
+
358
+ def get_parents_names(node: Node) -> str:
359
+ """Get names of all parent nodes of the given node.
360
+
361
+ Args:
362
+ node (Node): Node for which to get parent names.
363
+
364
+ Returns:
365
+ str: Names of all parent nodes of the given node.
366
+ """
367
+ parents = []
368
+ while node.parent:
369
+ parents.append(node.parent.name)
370
+ node = node.parent
371
+ if not parents:
372
+ return ""
373
+ return ".".join(parents[::-1]) + "."
374
+
375
+ def draw_subnodes(node: Node, spacing: str = " ") -> str:
376
+ """Draw subnodes of the given node.
377
+
378
+ Args:
379
+ node (Node): Node for which to draw subnodes.
380
+ spacing (str): Spacing for indentation.
381
+
382
+ Returns:
383
+ str: Subnodes of the given node.
384
+ """
385
+ diag = " {\n"
386
+ for child in node.children:
387
+ if child.value:
388
+ diag += spacing + child.name + f": {{tooltip: {child.value} }}"
389
+ else:
390
+ diag += spacing + child.name
391
+ if child.children:
392
+ diag += draw_subnodes(child, spacing + " ")
393
+ else:
394
+ diag += "\n"
395
+ diag += spacing + child.name + ".shape: " + child.shape + "\n"
396
+ lr = len(" ")
397
+ diag += spacing[:-lr] + "}\n"
398
+ return diag
399
+
400
+ # Add all nodes
401
+ for node in self.nodes:
402
+ diag += f"{node.name}"
403
+ if node.children:
404
+ diag += draw_subnodes(node)
405
+ diag += "\n"
406
+
407
+ diag += "\n"
408
+
409
+ # # Set shapes
410
+ # for node in self.nodes:
411
+ # parents_string = get_parents_names(node)
412
+ # diag += f"{parents_string}{node.name}.shape = {node.shape}\n"
413
+
414
+ # diag += "\n"
415
+
416
+ # Add all connections
417
+ for connection in self.connections:
418
+ from_p_name = get_parents_names(connection["from"])
419
+ to_p_name = get_parents_names(connection["to"])
420
+ if self.show_rates:
421
+ label = f"{connection['rate']}" if "rate" in connection else None
422
+ else:
423
+ label = None
424
+ diag += f"{from_p_name}{connection['from'].name} ->"
425
+ diag += f" {to_p_name}{connection['to'].name}"
426
+ diag += ": " + label if label else ""
427
+ diag += "\n"
428
+ diag = apply_connection_style(diag, connection)
429
+
430
+ def draw_nodes_connections(nodes: list[Node], show_rates: bool) -> str:
431
+ """Draw connections between nodes.
432
+
433
+ Args:
434
+ nodes (list[Node]): List of nodes to draw connections between.
435
+ show_rates (bool): Whether to show rates in the diagram.
436
+
437
+ Returns:
438
+ str: Connections between nodes.
439
+ """
440
+ diag = ""
441
+ for node in nodes:
442
+ for connection in node.connections:
443
+ from_p_name = get_parents_names(connection["from"])
444
+ to_p_name = get_parents_names(connection["to"])
445
+ if show_rates:
446
+ label = f"{connection['rate']}" if "rate" in connection else ""
447
+ else:
448
+ label = ""
449
+ diag += f"{from_p_name}{connection['from'].name} -> "
450
+ diag += f"{to_p_name}{connection['to'].name}"
451
+ diag += ": " + label if label else ""
452
+ diag += "\n"
453
+ diag = apply_connection_style(diag, connection)
454
+
455
+ if node.children:
456
+ diag += draw_nodes_connections(node.children, show_rates)
457
+
458
+ return diag
459
+
460
+ # for node in self.nodes:
461
+ diag += draw_nodes_connections(self.nodes, show_rates=self.show_rates)
462
+
463
+ # for node in self.nodes:
464
+ # for connection in node.connections:
465
+ # from_p_name = get_parents_names(connection["from"])
466
+ # to_p_name = get_parents_names(connection["to"])
467
+ # label = f"{connection['rate']}" if "rate" in connection else ""
468
+ # diag += f"{from_p_name}{connection['from'].name} -> "
469
+ # diag += f"{to_p_name}{connection['to'].name}"
470
+ # diag += ": " + label if label else ""
471
+ # diag += "\n"
472
+
473
+ if self.use_d2_cli:
474
+ with open(self.output_filename, "w") as f:
475
+ f.write(diag)
476
+
477
+ cmd = (
478
+ f"d2 --theme=0 --dark-theme=200 -l {self.layout_engine} "
479
+ + f"{self.output_filename} "
480
+ )
481
+ cmd += f"{self.output_image_filename}"
482
+ os.system(cmd) # noqa: S605
483
+ return self.output_image_filename
484
+ else:
485
+ if self._write_out_d2_file:
486
+ with open(self.output_filename, "w") as f:
487
+ f.write(diag)
488
+ print(f"Saved to {self.output_filename}")
489
+
490
+ # Use bindings
491
+ from .d2 import compile
492
+
493
+ out = compile(diag)
494
+ # with open(self.output_image_filename, "w") as f:
495
+ # f.write(out)
496
+
497
+ # return self.output_image_filename
498
+ return out
@@ -0,0 +1 @@
1
+ """ADI JIF FPGA Models and Utilities."""
adijif/fpgas/fpga.py ADDED
@@ -0,0 +1,64 @@
1
+ """FPGA parent metaclass to maintain consistency for all FPGA classes."""
2
+
3
+ from abc import ABCMeta, abstractmethod
4
+ from typing import Dict, List, Optional, Union
5
+
6
+ from adijif.common import core
7
+ from adijif.converters.converter import converter as conv
8
+ from adijif.gekko_trans import gekko_translation
9
+ from adijif.solvers import CpoSolveResult
10
+
11
+
12
+ class fpga(core, gekko_translation, metaclass=ABCMeta):
13
+ """Parent metaclass for all FPGA classes."""
14
+
15
+ """Generate another clock for link layer output.
16
+ This is used when the GEARBOX is enabled in HDL within link layer core.
17
+ """
18
+ requires_separate_link_layer_out_clock: bool = False
19
+
20
+ @property
21
+ @abstractmethod
22
+ def determine_cpll(self) -> None:
23
+ """Try to use CPLL for clocking.
24
+
25
+ This method is only used in brute-force classes
26
+
27
+ Raises:
28
+ NotImplementedError: Method not implemented
29
+ """
30
+ raise NotImplementedError # pragma: no cover
31
+
32
+ @property
33
+ @abstractmethod
34
+ def determine_qpll(self) -> None:
35
+ """Try to use QPLL for clocking.
36
+
37
+ This method is only used in brute-force classes
38
+
39
+ Raises:
40
+ NotImplementedError: Method not implemented
41
+ """
42
+ raise NotImplementedError # pragma: no cover
43
+
44
+ @property
45
+ @abstractmethod
46
+ def get_config( # type: ignore
47
+ self,
48
+ converter: conv,
49
+ fpga_ref: Union[float, int],
50
+ solution: Optional[CpoSolveResult] = None,
51
+ ) -> Union[List[Dict], Dict]:
52
+ """Extract clocking configuration from solutions.
53
+
54
+ Args:
55
+ converter (conv): Converter object connected to FPGA who config is
56
+ collected
57
+ fpga_ref (int or float): Reference clock generated for FPGA for specific
58
+ converter
59
+ solution (CpoSolveResult): CPlex solution. Only needed for CPlex solver
60
+
61
+ Raises:
62
+ NotImplementedError: Method not implemented
63
+ """
64
+ raise NotImplementedError # pragma: no cover