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
@@ -0,0 +1,67 @@
1
+ # flake8: noqa
2
+ import numpy as np
3
+
4
+ from adijif.clocks.clock import clock
5
+
6
+
7
+ class ltc6952_bf(clock):
8
+ """Brute force methods for calculating clocks
9
+
10
+ These are currently meant for debug to compare against
11
+ the solver solutions
12
+ """
13
+
14
+ def list_available_references(self, divider_set):
15
+ """list_available_references: Based on config list possible
16
+ references that can be generated based on VCO and output
17
+ dividers
18
+ """
19
+ # Check input
20
+ ref = {
21
+ "n2": 2,
22
+ "vco": 3000000000,
23
+ "r2": 24,
24
+ "required_output_divs": np.array([1.0]),
25
+ }
26
+ for key in ref:
27
+ if key not in divider_set:
28
+ raise Exception(
29
+ "Input must be of type dict with fields: " + str(ref.keys())
30
+ )
31
+ return [divider_set["vco"] / div for div in self.d_available]
32
+
33
+ def find_dividers(self, vcxo, rates, find=3):
34
+ v = []
35
+ for mp in range(0, 32):
36
+ for nx in range(0, 8):
37
+ val = (mp + 1) * pow(2, nx)
38
+ v.append(val)
39
+
40
+ odivs = np.unique(v)
41
+
42
+ mod = np.gcd.reduce(np.array(rates, dtype=int))
43
+ vcos = []
44
+ configs = []
45
+
46
+ for n in range(self.n2_divider_min, self.n2_divider_max):
47
+ for r in range(self.r2_divider_min, self.r2_divider_max):
48
+ # Check VCO in range and output clock a multiple of required reference
49
+ f = vcxo * n / r
50
+ if f >= self.vco_min and f <= self.vco_max:
51
+ # Check if required dividers for output clocks are in set
52
+ if f % mod == 0:
53
+ d = f / rates
54
+ if np.all(np.in1d(d, odivs)) and f not in vcos:
55
+ if f not in vcos:
56
+ vcos.append(f)
57
+ config = {
58
+ "n2": n,
59
+ "r2": r,
60
+ "vco": f,
61
+ "required_output_divs": d,
62
+ }
63
+ configs.append(config)
64
+ if len(configs) >= find:
65
+ return configs
66
+
67
+ return configs
@@ -0,0 +1,509 @@
1
+ """LTC6953 clock chip model."""
2
+
3
+ from typing import Dict, List, Union
4
+
5
+ from docplex.cp.solution import CpoSolveResult # type: ignore
6
+
7
+ from adijif.clocks.clock import clock
8
+ from adijif.solvers import CpoExpr, GK_Intermediate
9
+
10
+
11
+ class ltc6953(clock):
12
+ """LTC6953 clock chip model.
13
+
14
+ This model currently supports all divider configurations
15
+ """
16
+
17
+ name = "LTC6953"
18
+
19
+ input_ref = 1000000000
20
+
21
+ # Ranges
22
+ m_divider_min = 1
23
+ m_divider_max = 1023
24
+ m_available = [
25
+ 1,
26
+ 2,
27
+ 3,
28
+ 4,
29
+ 5,
30
+ 6,
31
+ 7,
32
+ 8,
33
+ 9,
34
+ 10,
35
+ 11,
36
+ 12,
37
+ 13,
38
+ 14,
39
+ 15,
40
+ 16,
41
+ 17,
42
+ 18,
43
+ 19,
44
+ 20,
45
+ 21,
46
+ 22,
47
+ 23,
48
+ 24,
49
+ 25,
50
+ 26,
51
+ 27,
52
+ 28,
53
+ 29,
54
+ 30,
55
+ 31,
56
+ 32,
57
+ 34,
58
+ 36,
59
+ 38,
60
+ 40,
61
+ 42,
62
+ 44,
63
+ 46,
64
+ 48,
65
+ 50,
66
+ 52,
67
+ 54,
68
+ 56,
69
+ 58,
70
+ 60,
71
+ 62,
72
+ 64,
73
+ 68,
74
+ 72,
75
+ 76,
76
+ 80,
77
+ 84,
78
+ 88,
79
+ 92,
80
+ 96,
81
+ 100,
82
+ 104,
83
+ 108,
84
+ 112,
85
+ 116,
86
+ 120,
87
+ 124,
88
+ 128,
89
+ 136,
90
+ 144,
91
+ 152,
92
+ 160,
93
+ 168,
94
+ 176,
95
+ 184,
96
+ 192,
97
+ 200,
98
+ 208,
99
+ 216,
100
+ 224,
101
+ 232,
102
+ 240,
103
+ 248,
104
+ 256,
105
+ 272,
106
+ 288,
107
+ 304,
108
+ 320,
109
+ 336,
110
+ 352,
111
+ 368,
112
+ 384,
113
+ 400,
114
+ 416,
115
+ 432,
116
+ 448,
117
+ 464,
118
+ 480,
119
+ 496,
120
+ 512,
121
+ 544,
122
+ 576,
123
+ 608,
124
+ 640,
125
+ 672,
126
+ 704,
127
+ 736,
128
+ 768,
129
+ 800,
130
+ 832,
131
+ 864,
132
+ 896,
133
+ 928,
134
+ 960,
135
+ 992,
136
+ 1024,
137
+ 1088,
138
+ 1152,
139
+ 1216,
140
+ 1280,
141
+ 1344,
142
+ 1408,
143
+ 1472,
144
+ 1536,
145
+ 1600,
146
+ 1664,
147
+ 1728,
148
+ 1792,
149
+ 1856,
150
+ 1920,
151
+ 1984,
152
+ 2048,
153
+ 2176,
154
+ 2304,
155
+ 2432,
156
+ 2560,
157
+ 2688,
158
+ 2816,
159
+ 2944,
160
+ 3072,
161
+ 3200,
162
+ 3328,
163
+ 3456,
164
+ 3584,
165
+ 3712,
166
+ 3840,
167
+ 3968,
168
+ 4096,
169
+ ]
170
+
171
+ """ Output dividers """
172
+
173
+ # Defaults
174
+ _m: Union[int, List[int]] = [
175
+ 1,
176
+ 2,
177
+ 3,
178
+ 4,
179
+ 5,
180
+ 6,
181
+ 7,
182
+ 8,
183
+ 9,
184
+ 10,
185
+ 11,
186
+ 12,
187
+ 13,
188
+ 14,
189
+ 15,
190
+ 16,
191
+ 17,
192
+ 18,
193
+ 19,
194
+ 20,
195
+ 21,
196
+ 22,
197
+ 23,
198
+ 24,
199
+ 25,
200
+ 26,
201
+ 27,
202
+ 28,
203
+ 29,
204
+ 30,
205
+ 31,
206
+ 32,
207
+ 34,
208
+ 36,
209
+ 38,
210
+ 40,
211
+ 42,
212
+ 44,
213
+ 46,
214
+ 48,
215
+ 50,
216
+ 52,
217
+ 54,
218
+ 56,
219
+ 58,
220
+ 60,
221
+ 62,
222
+ 64,
223
+ 68,
224
+ 72,
225
+ 76,
226
+ 80,
227
+ 84,
228
+ 88,
229
+ 92,
230
+ 96,
231
+ 100,
232
+ 104,
233
+ 108,
234
+ 112,
235
+ 116,
236
+ 120,
237
+ 124,
238
+ 128,
239
+ 136,
240
+ 144,
241
+ 152,
242
+ 160,
243
+ 168,
244
+ 176,
245
+ 184,
246
+ 192,
247
+ 200,
248
+ 208,
249
+ 216,
250
+ 224,
251
+ 232,
252
+ 240,
253
+ 248,
254
+ 256,
255
+ 272,
256
+ 288,
257
+ 304,
258
+ 320,
259
+ 336,
260
+ 352,
261
+ 368,
262
+ 384,
263
+ 400,
264
+ 416,
265
+ 432,
266
+ 448,
267
+ 464,
268
+ 480,
269
+ 496,
270
+ 512,
271
+ 544,
272
+ 576,
273
+ 608,
274
+ 640,
275
+ 672,
276
+ 704,
277
+ 736,
278
+ 768,
279
+ 800,
280
+ 832,
281
+ 864,
282
+ 896,
283
+ 928,
284
+ 960,
285
+ 992,
286
+ 1024,
287
+ 1088,
288
+ 1152,
289
+ 1216,
290
+ 1280,
291
+ 1344,
292
+ 1408,
293
+ 1472,
294
+ 1536,
295
+ 1600,
296
+ 1664,
297
+ 1728,
298
+ 1792,
299
+ 1856,
300
+ 1920,
301
+ 1984,
302
+ 2048,
303
+ 2176,
304
+ 2304,
305
+ 2432,
306
+ 2560,
307
+ 2688,
308
+ 2816,
309
+ 2944,
310
+ 3072,
311
+ 3200,
312
+ 3328,
313
+ 3456,
314
+ 3584,
315
+ 3712,
316
+ 3840,
317
+ 3968,
318
+ 4096,
319
+ ]
320
+
321
+ # Limits
322
+ """ Internal limits """
323
+ input_freq_max = 4.5e9
324
+
325
+ # State management
326
+ _clk_names: List[str] = []
327
+
328
+ @property
329
+ def m(self) -> Union[int, List[int]]:
330
+ """Output dividers.
331
+
332
+ Valid dividers are 1,2,3,4,5,6..32->(even)->4096
333
+
334
+ Returns:
335
+ int: Current allowable dividers
336
+ """
337
+ return self._d
338
+
339
+ @m.setter
340
+ def m(self, value: Union[int, List[int]]) -> None:
341
+ """Output dividers.
342
+
343
+ Valid dividers are 1,2,3,4,5,6..32->(even)->4096
344
+
345
+ Args:
346
+ value (int, list[int]): Allowable values for divider
347
+
348
+ """
349
+ self._check_in_range(value, self.m_available, "d")
350
+ self._d = value
351
+
352
+ def find_dividers(self) -> Dict:
353
+ """Find the best dividers for the current configuration.
354
+
355
+ NOT IMPLEMENTED YET
356
+
357
+ Raises:
358
+ NotImplementedError: Not implemented yet
359
+ """
360
+ raise NotImplementedError("find_dividers not implemented")
361
+
362
+ def list_available_references(self) -> List[int]:
363
+ """List the available reference frequencies.
364
+
365
+ NOT IMPLEMENTED YET
366
+
367
+ Raises:
368
+ NotImplementedError: Not implemented yet
369
+ """
370
+ raise NotImplementedError("list_available_references not implemented")
371
+
372
+ def get_config(self, solution: CpoSolveResult = None) -> Dict:
373
+ """Extract configurations from solver results.
374
+
375
+ Collect internal clock chip configuration and output clock definitions
376
+ leading to connected devices (converters, FPGAs)
377
+
378
+ Args:
379
+ solution (CpoSolveResult): CPlex solution. Only needed for CPlex solver
380
+
381
+ Returns:
382
+ Dict: Dictionary of clocking rates and dividers for configuration
383
+
384
+ Raises:
385
+ Exception: If solver is not called first
386
+ """
387
+ if not self._clk_names:
388
+ raise Exception("set_requested_clocks must be called before get_config")
389
+
390
+ if solution:
391
+ self.solution = solution
392
+
393
+ out_dividers = [self._get_val(x) for x in self.config["out_dividers"]]
394
+
395
+ config: Dict = {
396
+ "out_dividers": out_dividers,
397
+ "output_clocks": [],
398
+ }
399
+
400
+ config["input_ref"] = self._get_val(
401
+ self.input_ref
402
+ ) # pytype: disable=attribute-error
403
+
404
+ output_cfg = {}
405
+ for i, div in enumerate(out_dividers):
406
+ rate = config["input_ref"] / div # type: ignore # noqa: B950
407
+ output_cfg[self._clk_names[i]] = {"rate": rate, "divider": div}
408
+
409
+ config["output_clocks"] = output_cfg
410
+
411
+ self._saved_solution = config
412
+
413
+ return config
414
+
415
+ def _setup_solver_constraints(self, input_ref: int) -> None:
416
+ """Apply constraints to solver model.
417
+
418
+ Args:
419
+ input_ref (int): Input reference frequency in hertz
420
+ """
421
+ self.config = {}
422
+ if not isinstance(input_ref, (int, float)):
423
+ self.config["input_ref_set"] = input_ref(self.model) # type: ignore
424
+ input_ref = self.config["input_ref_set"]["range"]
425
+ self.input_ref = input_ref
426
+
427
+ self._add_equation(
428
+ [
429
+ input_ref <= self.input_freq_max,
430
+ ]
431
+ )
432
+
433
+ def _setup(self, input_ref: int) -> None:
434
+ if isinstance(input_ref, (float, int)):
435
+ assert self.input_freq_max >= input_ref >= 0, "Input frequency out of range"
436
+
437
+ # Setup clock chip internal constraints
438
+ self._setup_solver_constraints(input_ref)
439
+
440
+ # Add requested clocks to output constraints
441
+ self.config["out_dividers"] = []
442
+
443
+ def _get_clock_constraint(
444
+ self, clk_name: List[str]
445
+ ) -> Union[int, float, CpoExpr, GK_Intermediate]:
446
+ """Get abstract clock output.
447
+
448
+ Args:
449
+ clk_name (str): String of clock name
450
+
451
+ Returns:
452
+ (int or float or CpoExpr or GK_Intermediate): Abstract
453
+ or concrete clock reference
454
+
455
+ Raises:
456
+ Exception: Invalid solver
457
+ """
458
+ if self.solver == "gekko":
459
+ __m = self._m if isinstance(self._m, list) else [self._m]
460
+ if __m.sort() != self.m_available.sort():
461
+ raise Exception("For solver gekko d is not configurable for LTC6952")
462
+ mp = self.model.Var(integer=True, lb=1, ub=32)
463
+ nx = self.model.Var(integer=True, lb=0, ub=7)
464
+ od = self.model.Intermediate(mp * pow(2, nx))
465
+ elif self.solver == "CPLEX":
466
+ od = self._convert_input(self._m, f"m_{clk_name}")
467
+ else:
468
+ raise Exception("Unknown solver {}".format(self.solver))
469
+ self.config["out_dividers"].append(od)
470
+ return self.input_ref / od
471
+
472
+ def set_requested_clocks(
473
+ self, input_ref: int, out_freqs: List, clk_names: List[str]
474
+ ) -> None:
475
+ """Define necessary clocks to be generated in model.
476
+
477
+ Args:
478
+ input_ref (int): Input reference frequency in hertz
479
+ out_freqs (List): list of required clocks to be output
480
+ clk_names (List[str]): list of strings of clock names
481
+
482
+ Raises:
483
+ Exception: If len(out_freqs) != len(clk_names)
484
+ """
485
+ if len(clk_names) != len(out_freqs):
486
+ raise Exception("clk_names is not the same size as out_freqs")
487
+ self._clk_names = clk_names
488
+
489
+ # Setup clock chip internal constraints
490
+ self._setup(input_ref)
491
+
492
+ # Add requested clocks to output constraints
493
+ for out_freq in out_freqs:
494
+ if self.solver == "gekko":
495
+ __m = self._d if isinstance(self.__m, list) else [self.__m]
496
+ if __m.sort() != self.m_available.sort():
497
+ raise Exception(
498
+ "For solver gekko m is not configurable for LTC6953"
499
+ )
500
+
501
+ mp = self.model.Var(integer=True, lb=1, ub=32)
502
+ nx = self.model.Var(integer=True, lb=0, ub=7)
503
+ od = self.model.Intermediate(mp * pow(2, nx))
504
+
505
+ elif self.solver == "CPLEX":
506
+ od = self._convert_input(self._m, "m_" + str(out_freq))
507
+
508
+ self._add_equation([self.input_ref / od == out_freq])
509
+ self.config["out_dividers"].append(od)
adijif/common.py ADDED
@@ -0,0 +1,70 @@
1
+ """Common class for all JIF components."""
2
+
3
+ from typing import List, Union
4
+
5
+ from adijif.solvers import CpoModel # noqa: BLK100
6
+ from adijif.solvers import GK_Operators # noqa: BLK100
7
+ from adijif.solvers import GEKKO, CpoExpr, GK_Intermediate, GKVariable
8
+
9
+
10
+ class core:
11
+ """Common class for all JIF components.
12
+
13
+ This is the central point for all classes in module
14
+
15
+ """
16
+
17
+ solver = "CPLEX" # "CPLEX"
18
+
19
+ _objectives = []
20
+
21
+ def _add_objective(
22
+ self,
23
+ objective: List[Union[GKVariable, GK_Intermediate, GK_Operators, CpoExpr]],
24
+ ) -> None:
25
+ if isinstance(objective, list):
26
+ self._objectives += objective
27
+ else:
28
+ self._objectives.append(objective)
29
+
30
+ def __init__(
31
+ self, model: Union[GEKKO, CpoModel] = None, solver: str = None
32
+ ) -> None:
33
+ """Initalize clocking model.
34
+
35
+ When usings the clocking models standalone, typically for
36
+ validation flows, a solver model is created internally.
37
+ For system level work, a shared model is passed.
38
+
39
+ Args:
40
+ model (GEKKO,CpoModel): Solver model
41
+ solver (str): Solver name (gekko or CPLEX)
42
+
43
+ Raises:
44
+ Exception: If solver is not valid
45
+ """
46
+ self._saved_solution = None
47
+ self._objectives = []
48
+ self._solution = None
49
+ self.configs = [] # type: List[dict]
50
+ if hasattr(self, "_init_diagram"):
51
+ self._init_diagram()
52
+ if solver:
53
+ self.solver = solver
54
+ if self.solver == "gekko":
55
+ if model:
56
+ assert isinstance(
57
+ model, GEKKO
58
+ ), "Input model must be of type gekko.GEKKO"
59
+ else:
60
+ model = GEKKO(remote=False)
61
+ elif self.solver == "CPLEX":
62
+ if model:
63
+ assert isinstance(
64
+ model, CpoModel
65
+ ), "Input model must be of type docplex.cp.model.CpoModel"
66
+ else:
67
+ model = CpoModel()
68
+ else:
69
+ raise Exception(f"Unknown solver {self.solver}")
70
+ self.model = model
@@ -0,0 +1,3 @@
1
+ """ADI JIF converter models."""
2
+
3
+ supported_parts = ["ad9680", "adrv9009_rx", "ad9081_rx", "ad9144", "ad9084_rx"]