pyibis-ami 7.2.3__py3-none-any.whl → 7.2.4__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.
- {pyibis_ami-7.2.3.dist-info → pyibis_ami-7.2.4.dist-info}/METADATA +133 -134
- pyibis_ami-7.2.4.dist-info/RECORD +27 -0
- {pyibis_ami-7.2.3.dist-info → pyibis_ami-7.2.4.dist-info}/WHEEL +1 -1
- {pyibis_ami-7.2.3.dist-info → pyibis_ami-7.2.4.dist-info}/licenses/LICENSE +8 -8
- pyibisami/IBIS_AMI_Checker.ipynb +1693 -1693
- pyibisami/IBIS_AMI_Tester.ipynb +1457 -1457
- pyibisami/__init__.py +22 -22
- pyibisami/__main__.py +7 -7
- pyibisami/ami/config.py +297 -297
- pyibisami/ami/generic.ami.em +20 -20
- pyibisami/ami/generic.ibs.em +176 -139
- pyibisami/ami/model.py +631 -631
- pyibisami/ami/parameter.py +325 -324
- pyibisami/ami/parser.py +680 -680
- pyibisami/ami/reserved_parameter_names.py +84 -84
- pyibisami/common.py +42 -42
- pyibisami/ibis/file.py +325 -325
- pyibisami/ibis/model.py +399 -399
- pyibisami/ibis/parser.py +525 -525
- pyibisami/tools/run_notebook.py +144 -144
- pyibisami/tools/run_tests.py +273 -273
- pyibisami/tools/test_results.xsl +42 -42
- pyibis_ami-7.2.3.dist-info/RECORD +0 -27
- {pyibis_ami-7.2.3.dist-info → pyibis_ami-7.2.4.dist-info}/entry_points.txt +0 -0
- {pyibis_ami-7.2.3.dist-info → pyibis_ami-7.2.4.dist-info}/top_level.txt +0 -0
pyibisami/ibis/file.py
CHANGED
@@ -1,325 +1,325 @@
|
|
1
|
-
"""A class for encapsulating IBIS model files.
|
2
|
-
|
3
|
-
Original Author: David Banas <capn.freako@gmail.com>
|
4
|
-
|
5
|
-
Original Date: November 1, 2019
|
6
|
-
|
7
|
-
For information regarding the IBIS modeling standard, visit:
|
8
|
-
https://ibis.org/
|
9
|
-
|
10
|
-
**Note:** The ``IBISModel`` class, defined here, needs to be kept separate from the
|
11
|
-
other IBIS-related classes, defined in the ``model`` module, in order to
|
12
|
-
avoid circular imports.
|
13
|
-
|
14
|
-
Copyright (c) 2019 by David Banas; All rights reserved World wide.
|
15
|
-
"""
|
16
|
-
|
17
|
-
import platform
|
18
|
-
from datetime import datetime
|
19
|
-
|
20
|
-
from traits.api import (
|
21
|
-
Any,
|
22
|
-
Dict,
|
23
|
-
Enum,
|
24
|
-
Float,
|
25
|
-
HasTraits,
|
26
|
-
List,
|
27
|
-
Property,
|
28
|
-
String,
|
29
|
-
Trait,
|
30
|
-
cached_property,
|
31
|
-
)
|
32
|
-
from traitsui.api import HGroup, Item, ModalButtons, VGroup, View, spring
|
33
|
-
from traitsui.message import message
|
34
|
-
|
35
|
-
from pyibisami.ibis.parser import parse_ibis_file
|
36
|
-
|
37
|
-
|
38
|
-
class IBISModel(HasTraits): # pylint: disable=too-many-instance-attributes
|
39
|
-
"""HasTraits subclass for wrapping and interacting with an IBIS model.
|
40
|
-
|
41
|
-
This class can be configured to present a customized GUI to the user
|
42
|
-
for interacting with a particular IBIS model (i.e. - selecting components,
|
43
|
-
pins, and models).
|
44
|
-
|
45
|
-
The intended use model is as follows:
|
46
|
-
|
47
|
-
1. Instantiate this class only once per IBIS model file.
|
48
|
-
When instantiating, provide the unprocessed contents of the IBIS
|
49
|
-
file, as a single string. This class will take care of getting
|
50
|
-
that string parsed properly, and report any errors or warnings
|
51
|
-
it encounters, in its ``ibis_parsing_errors`` property.
|
52
|
-
|
53
|
-
2. When you want to let the user select a particular component/pin/model,
|
54
|
-
call the newly created instance, as if it were a function, passing
|
55
|
-
no arguments.
|
56
|
-
The instance will then present a GUI to the user,
|
57
|
-
allowing him to select a particular component/pin/model, which may then
|
58
|
-
be retrieved, via the ``model`` property.
|
59
|
-
The latest user selections will be remembered,
|
60
|
-
as long as the instance remains in scope.
|
61
|
-
|
62
|
-
Any errors or warnings encountered while parsing are available, in
|
63
|
-
the ``ibis_parsing_errors`` property.
|
64
|
-
|
65
|
-
The complete dictionary containing all parsed models may be retrieved,
|
66
|
-
via the ``model_dict`` property.
|
67
|
-
"""
|
68
|
-
|
69
|
-
_log = ""
|
70
|
-
|
71
|
-
pin_ = Property(Any, depends_on=["pin"])
|
72
|
-
pin_rlcs = Property(Dict, depends_on=["pin"])
|
73
|
-
model = Property(Any, depends_on=["mod"])
|
74
|
-
pins = List # Always holds the list of valid pin selections, given a component selection.
|
75
|
-
models = List # Always holds the list of valid model selections, given a pin selection.
|
76
|
-
|
77
|
-
def get_models(self, mname):
|
78
|
-
"""Return the list of models associated with a particular name."""
|
79
|
-
model_dict = self._model_dict
|
80
|
-
if "model_selectors" in model_dict and mname in model_dict["model_selectors"]:
|
81
|
-
return list(map(lambda pr: pr[0], model_dict["model_selectors"][mname]))
|
82
|
-
return [mname]
|
83
|
-
|
84
|
-
def get_pins(self):
|
85
|
-
"""Get the list of appropriate pins, given our type (i.e. - Tx or Rx)."""
|
86
|
-
pins = self.comp_.pins
|
87
|
-
|
88
|
-
def pin_ok(pname):
|
89
|
-
(mname, _) = pins[pname]
|
90
|
-
mods = self.get_models(mname)
|
91
|
-
mod = self._models[mods[0]]
|
92
|
-
mod_type = mod.mtype.lower()
|
93
|
-
tx_ok = mod_type in ("output", "i/o")
|
94
|
-
if self._is_tx:
|
95
|
-
return tx_ok
|
96
|
-
return not tx_ok
|
97
|
-
|
98
|
-
return list(filter(pin_ok, list(pins)))
|
99
|
-
|
100
|
-
def __init__(self, ibis_file_name, is_tx, debug=False, gui=True):
|
101
|
-
"""
|
102
|
-
Args:
|
103
|
-
ibis_file_name (str): The name of the IBIS file.
|
104
|
-
is_tx (bool): True if this is a Tx model.
|
105
|
-
|
106
|
-
Keyword Args:
|
107
|
-
debug (bool): Output debugging info to console when true.
|
108
|
-
Default = False
|
109
|
-
gui (bool): Set to `False` for command line and/or script usage.
|
110
|
-
Default = True.
|
111
|
-
"""
|
112
|
-
|
113
|
-
# Super-class initialization is ABSOLUTELY NECESSARY, in order
|
114
|
-
# to get all the Traits/UI machinery setup correctly.
|
115
|
-
super().__init__()
|
116
|
-
|
117
|
-
self.debug = debug
|
118
|
-
self.GUI = gui
|
119
|
-
if debug:
|
120
|
-
self.log("pyibisami.ibis_file.IBISModel initializing in debug mode...")
|
121
|
-
else:
|
122
|
-
self.log("pyibisami.ibis_file.IBISModel initializing in non-debug mode...")
|
123
|
-
|
124
|
-
# Parse the IBIS file contents, storing any errors or warnings, and validate it.
|
125
|
-
with open(ibis_file_name, "r", encoding="utf-8") as file:
|
126
|
-
ibis_file_contents_str = file.read()
|
127
|
-
err_str, model_dict = parse_ibis_file(ibis_file_contents_str, debug=debug)
|
128
|
-
self.log("IBIS parsing errors/warnings:\n" + err_str)
|
129
|
-
if "components" not in model_dict or not model_dict["components"]:
|
130
|
-
print(f":\n{model_dict}", flush=True)
|
131
|
-
raise ValueError("This IBIS model has no components!")
|
132
|
-
components = model_dict["components"]
|
133
|
-
if "models" not in model_dict or not model_dict["models"]:
|
134
|
-
raise ValueError("This IBIS model has no models!")
|
135
|
-
models = model_dict["models"]
|
136
|
-
self._model_dict = model_dict
|
137
|
-
self._models = models
|
138
|
-
self._is_tx = is_tx
|
139
|
-
|
140
|
-
# Add Traits for various attributes found in the IBIS file.
|
141
|
-
self.add_trait("comp", Trait(list(components)[0], components)) # Doesn't need a custom mapper, because
|
142
|
-
self.pins = self.get_pins() # the thing above it (file) can't change.
|
143
|
-
self.add_trait("pin", Enum(self.pins[0], values="pins"))
|
144
|
-
(mname, _) = self.pin_
|
145
|
-
self.models = self.get_models(mname)
|
146
|
-
self.add_trait("mod", Enum(self.models[0], values="models"))
|
147
|
-
self.add_trait("ibis_ver", Float(model_dict["ibis_ver"]))
|
148
|
-
self.add_trait("file_name", String(model_dict["file_name"]))
|
149
|
-
self.add_trait("file_rev", String(model_dict["file_rev"]))
|
150
|
-
if "date" in model_dict:
|
151
|
-
self.add_trait("date", String(model_dict["date"]))
|
152
|
-
else:
|
153
|
-
self.add_trait("date", String("(n/a)"))
|
154
|
-
|
155
|
-
self._ibis_parsing_errors = err_str
|
156
|
-
self._os_type = platform.system() # These 2 are used, to choose
|
157
|
-
self._os_bits = platform.architecture()[0] # the correct AMI executable.
|
158
|
-
|
159
|
-
self._comp_changed(list(components)[0]) # Wasn't being called automatically.
|
160
|
-
self._pin_changed(self.pins[0]) # Wasn't being called automatically.
|
161
|
-
|
162
|
-
self.log("Done.")
|
163
|
-
|
164
|
-
def __str__(self):
|
165
|
-
return f"IBIS Model '{self._model_dict['file_name']}'"
|
166
|
-
|
167
|
-
def info(self):
|
168
|
-
"""Basic information about the IBIS model."""
|
169
|
-
res = ""
|
170
|
-
try:
|
171
|
-
for k in ["ibis_ver", "file_name", "file_rev"]:
|
172
|
-
res += k + ":\t" + str(self._model_dict[k]) + "\n"
|
173
|
-
except Exception as err:
|
174
|
-
print(f"{err}")
|
175
|
-
print(self._model_dict)
|
176
|
-
raise
|
177
|
-
res += "date" + ":\t\t" + str(self._model_dict["date"]) + "\n"
|
178
|
-
res += "\nComponents:"
|
179
|
-
res += "\n=========="
|
180
|
-
for c in list(self._model_dict["components"]):
|
181
|
-
res += "\n" + c + ":\n" + "---\n" + str(self._model_dict["components"][c]) + "\n"
|
182
|
-
res += "\nModel Selectors:"
|
183
|
-
res += "\n===============\n"
|
184
|
-
for s in list(self._model_dict["model_selectors"]):
|
185
|
-
res += f"{s}\n"
|
186
|
-
res += "\nModels:"
|
187
|
-
res += "\n======"
|
188
|
-
for m in list(self._model_dict["models"]):
|
189
|
-
res += "\n" + m + ":\n" + "---\n" + str(self._model_dict["models"][m])
|
190
|
-
return res
|
191
|
-
|
192
|
-
def __call__(self):
|
193
|
-
"""Present a customized GUI to the user, for model selection, etc."""
|
194
|
-
self.edit_traits(kind="livemodal")
|
195
|
-
|
196
|
-
# Logger & Pop-up
|
197
|
-
def log(self, msg, alert=False):
|
198
|
-
"""Log a message to the console and, optionally, to terminal and/or
|
199
|
-
pop-up dialog."""
|
200
|
-
_msg = msg.strip()
|
201
|
-
txt = f"\n[{datetime.now()}]: IBISModel: {_msg}\n"
|
202
|
-
self._log += txt
|
203
|
-
if self.debug:
|
204
|
-
print(txt, flush=True)
|
205
|
-
if alert and self.GUI:
|
206
|
-
message(_msg, "PyAMI Alert")
|
207
|
-
|
208
|
-
def default_traits_view(self):
|
209
|
-
"Default Traits/UI view definition."
|
210
|
-
view = View(
|
211
|
-
VGroup(
|
212
|
-
HGroup(
|
213
|
-
Item("file_name", label="File name", style="readonly"),
|
214
|
-
spring,
|
215
|
-
Item("file_rev", label="rev", style="readonly"),
|
216
|
-
),
|
217
|
-
HGroup(
|
218
|
-
Item("ibis_ver", label="IBIS ver", style="readonly"),
|
219
|
-
spring,
|
220
|
-
Item("date", label="Date", style="readonly"),
|
221
|
-
),
|
222
|
-
HGroup(
|
223
|
-
Item("comp", label="Component"),
|
224
|
-
Item("pin", label="Pin"),
|
225
|
-
Item("mod", label="Model"),
|
226
|
-
),
|
227
|
-
),
|
228
|
-
resizable=False,
|
229
|
-
buttons=ModalButtons,
|
230
|
-
title="PyBERT IBIS Model Selector",
|
231
|
-
id="pybert.pybert_ami.model_selector",
|
232
|
-
)
|
233
|
-
return view
|
234
|
-
|
235
|
-
@cached_property
|
236
|
-
def _get_pin_(self):
|
237
|
-
return self.comp_.pins[self.pin]
|
238
|
-
|
239
|
-
@cached_property
|
240
|
-
def _get_pin_rlcs(self):
|
241
|
-
(_, pin_rlcs) = self.pin_
|
242
|
-
return pin_rlcs
|
243
|
-
|
244
|
-
@cached_property
|
245
|
-
def _get_model(self):
|
246
|
-
return self._models[self.mod]
|
247
|
-
|
248
|
-
@property
|
249
|
-
def ibis_parsing_errors(self):
|
250
|
-
"""Any errors or warnings encountered, while parsing the IBIS file
|
251
|
-
contents."""
|
252
|
-
return self._ibis_parsing_errors
|
253
|
-
|
254
|
-
@property
|
255
|
-
def log_txt(self):
|
256
|
-
"""The complete log since instantiation."""
|
257
|
-
return self._log
|
258
|
-
|
259
|
-
@property
|
260
|
-
def model_dict(self):
|
261
|
-
"Dictionary of all model keywords."
|
262
|
-
return self._model_dict
|
263
|
-
|
264
|
-
@property
|
265
|
-
def dll_file(self):
|
266
|
-
"Shared object file."
|
267
|
-
return self._dll_file
|
268
|
-
|
269
|
-
@property
|
270
|
-
def ami_file(self):
|
271
|
-
"AMI file."
|
272
|
-
return self._ami_file
|
273
|
-
|
274
|
-
def _comp_changed(self, new_value):
|
275
|
-
del new_value
|
276
|
-
self.pins = self.get_pins()
|
277
|
-
self.pin = self.pins[0]
|
278
|
-
|
279
|
-
def _pin_changed(self, new_value):
|
280
|
-
# (mname, rlc_dict) = self.pin_ # Doesn't work. Because ``pin_`` is a cached property and hasn't yet been marked "dirty"?
|
281
|
-
(mname, _) = self.comp_.pins[new_value]
|
282
|
-
self.models = self.get_models(mname)
|
283
|
-
self.mod = self.models[0]
|
284
|
-
|
285
|
-
def _mod_changed(self, new_value):
|
286
|
-
model = self._models[new_value]
|
287
|
-
os_type = self._os_type
|
288
|
-
os_bits = self._os_bits
|
289
|
-
fnames = []
|
290
|
-
dll_file = ""
|
291
|
-
ami_file = ""
|
292
|
-
if os_type.lower() == "windows":
|
293
|
-
if os_bits == "64bit":
|
294
|
-
fnames = model._exec64Wins # pylint: disable=protected-access
|
295
|
-
else:
|
296
|
-
fnames = model._exec32Wins # pylint: disable=protected-access
|
297
|
-
else:
|
298
|
-
if os_bits == "64bit":
|
299
|
-
fnames = model._exec64Lins # pylint: disable=protected-access
|
300
|
-
else:
|
301
|
-
fnames = model._exec32Lins # pylint: disable=protected-access
|
302
|
-
if fnames:
|
303
|
-
dll_file = fnames[0]
|
304
|
-
ami_file = fnames[1]
|
305
|
-
self.log(
|
306
|
-
"There was an [Algorithmic Model] keyword in this model.\n \
|
307
|
-
If you wish to use the AMI model associated with this IBIS model,\n \
|
308
|
-
please, go the 'Equalization' tab and enable it now.",
|
309
|
-
alert=True,
|
310
|
-
)
|
311
|
-
elif "algorithmic_model" in model._subDict: # pylint: disable=protected-access
|
312
|
-
self.log(
|
313
|
-
f"There was an [Algorithmic Model] keyword for this model,\n \
|
314
|
-
but no executable for your platform: {os_type}-{os_bits};\n \
|
315
|
-
PyBERT native equalization modeling being used instead.",
|
316
|
-
alert=True,
|
317
|
-
)
|
318
|
-
else:
|
319
|
-
self.log(
|
320
|
-
"There was no [Algorithmic Model] keyword for this model;\n \
|
321
|
-
PyBERT native equalization modeling being used instead.",
|
322
|
-
alert=True,
|
323
|
-
)
|
324
|
-
self._dll_file = dll_file # pylint: disable=attribute-defined-outside-init
|
325
|
-
self._ami_file = ami_file # pylint: disable=attribute-defined-outside-init
|
1
|
+
"""A class for encapsulating IBIS model files.
|
2
|
+
|
3
|
+
Original Author: David Banas <capn.freako@gmail.com>
|
4
|
+
|
5
|
+
Original Date: November 1, 2019
|
6
|
+
|
7
|
+
For information regarding the IBIS modeling standard, visit:
|
8
|
+
https://ibis.org/
|
9
|
+
|
10
|
+
**Note:** The ``IBISModel`` class, defined here, needs to be kept separate from the
|
11
|
+
other IBIS-related classes, defined in the ``model`` module, in order to
|
12
|
+
avoid circular imports.
|
13
|
+
|
14
|
+
Copyright (c) 2019 by David Banas; All rights reserved World wide.
|
15
|
+
"""
|
16
|
+
|
17
|
+
import platform
|
18
|
+
from datetime import datetime
|
19
|
+
|
20
|
+
from traits.api import (
|
21
|
+
Any,
|
22
|
+
Dict,
|
23
|
+
Enum,
|
24
|
+
Float,
|
25
|
+
HasTraits,
|
26
|
+
List,
|
27
|
+
Property,
|
28
|
+
String,
|
29
|
+
Trait,
|
30
|
+
cached_property,
|
31
|
+
)
|
32
|
+
from traitsui.api import HGroup, Item, ModalButtons, VGroup, View, spring
|
33
|
+
from traitsui.message import message
|
34
|
+
|
35
|
+
from pyibisami.ibis.parser import parse_ibis_file
|
36
|
+
|
37
|
+
|
38
|
+
class IBISModel(HasTraits): # pylint: disable=too-many-instance-attributes
|
39
|
+
"""HasTraits subclass for wrapping and interacting with an IBIS model.
|
40
|
+
|
41
|
+
This class can be configured to present a customized GUI to the user
|
42
|
+
for interacting with a particular IBIS model (i.e. - selecting components,
|
43
|
+
pins, and models).
|
44
|
+
|
45
|
+
The intended use model is as follows:
|
46
|
+
|
47
|
+
1. Instantiate this class only once per IBIS model file.
|
48
|
+
When instantiating, provide the unprocessed contents of the IBIS
|
49
|
+
file, as a single string. This class will take care of getting
|
50
|
+
that string parsed properly, and report any errors or warnings
|
51
|
+
it encounters, in its ``ibis_parsing_errors`` property.
|
52
|
+
|
53
|
+
2. When you want to let the user select a particular component/pin/model,
|
54
|
+
call the newly created instance, as if it were a function, passing
|
55
|
+
no arguments.
|
56
|
+
The instance will then present a GUI to the user,
|
57
|
+
allowing him to select a particular component/pin/model, which may then
|
58
|
+
be retrieved, via the ``model`` property.
|
59
|
+
The latest user selections will be remembered,
|
60
|
+
as long as the instance remains in scope.
|
61
|
+
|
62
|
+
Any errors or warnings encountered while parsing are available, in
|
63
|
+
the ``ibis_parsing_errors`` property.
|
64
|
+
|
65
|
+
The complete dictionary containing all parsed models may be retrieved,
|
66
|
+
via the ``model_dict`` property.
|
67
|
+
"""
|
68
|
+
|
69
|
+
_log = ""
|
70
|
+
|
71
|
+
pin_ = Property(Any, depends_on=["pin"])
|
72
|
+
pin_rlcs = Property(Dict, depends_on=["pin"])
|
73
|
+
model = Property(Any, depends_on=["mod"])
|
74
|
+
pins = List # Always holds the list of valid pin selections, given a component selection.
|
75
|
+
models = List # Always holds the list of valid model selections, given a pin selection.
|
76
|
+
|
77
|
+
def get_models(self, mname):
|
78
|
+
"""Return the list of models associated with a particular name."""
|
79
|
+
model_dict = self._model_dict
|
80
|
+
if "model_selectors" in model_dict and mname in model_dict["model_selectors"]:
|
81
|
+
return list(map(lambda pr: pr[0], model_dict["model_selectors"][mname]))
|
82
|
+
return [mname]
|
83
|
+
|
84
|
+
def get_pins(self):
|
85
|
+
"""Get the list of appropriate pins, given our type (i.e. - Tx or Rx)."""
|
86
|
+
pins = self.comp_.pins
|
87
|
+
|
88
|
+
def pin_ok(pname):
|
89
|
+
(mname, _) = pins[pname]
|
90
|
+
mods = self.get_models(mname)
|
91
|
+
mod = self._models[mods[0]]
|
92
|
+
mod_type = mod.mtype.lower()
|
93
|
+
tx_ok = mod_type in ("output", "i/o")
|
94
|
+
if self._is_tx:
|
95
|
+
return tx_ok
|
96
|
+
return not tx_ok
|
97
|
+
|
98
|
+
return list(filter(pin_ok, list(pins)))
|
99
|
+
|
100
|
+
def __init__(self, ibis_file_name, is_tx, debug=False, gui=True):
|
101
|
+
"""
|
102
|
+
Args:
|
103
|
+
ibis_file_name (str): The name of the IBIS file.
|
104
|
+
is_tx (bool): True if this is a Tx model.
|
105
|
+
|
106
|
+
Keyword Args:
|
107
|
+
debug (bool): Output debugging info to console when true.
|
108
|
+
Default = False
|
109
|
+
gui (bool): Set to `False` for command line and/or script usage.
|
110
|
+
Default = True.
|
111
|
+
"""
|
112
|
+
|
113
|
+
# Super-class initialization is ABSOLUTELY NECESSARY, in order
|
114
|
+
# to get all the Traits/UI machinery setup correctly.
|
115
|
+
super().__init__()
|
116
|
+
|
117
|
+
self.debug = debug
|
118
|
+
self.GUI = gui
|
119
|
+
if debug:
|
120
|
+
self.log("pyibisami.ibis_file.IBISModel initializing in debug mode...")
|
121
|
+
else:
|
122
|
+
self.log("pyibisami.ibis_file.IBISModel initializing in non-debug mode...")
|
123
|
+
|
124
|
+
# Parse the IBIS file contents, storing any errors or warnings, and validate it.
|
125
|
+
with open(ibis_file_name, "r", encoding="utf-8") as file:
|
126
|
+
ibis_file_contents_str = file.read()
|
127
|
+
err_str, model_dict = parse_ibis_file(ibis_file_contents_str, debug=debug)
|
128
|
+
self.log("IBIS parsing errors/warnings:\n" + err_str)
|
129
|
+
if "components" not in model_dict or not model_dict["components"]:
|
130
|
+
print(f":\n{model_dict}", flush=True)
|
131
|
+
raise ValueError("This IBIS model has no components!")
|
132
|
+
components = model_dict["components"]
|
133
|
+
if "models" not in model_dict or not model_dict["models"]:
|
134
|
+
raise ValueError("This IBIS model has no models!")
|
135
|
+
models = model_dict["models"]
|
136
|
+
self._model_dict = model_dict
|
137
|
+
self._models = models
|
138
|
+
self._is_tx = is_tx
|
139
|
+
|
140
|
+
# Add Traits for various attributes found in the IBIS file.
|
141
|
+
self.add_trait("comp", Trait(list(components)[0], components)) # Doesn't need a custom mapper, because
|
142
|
+
self.pins = self.get_pins() # the thing above it (file) can't change.
|
143
|
+
self.add_trait("pin", Enum(self.pins[0], values="pins"))
|
144
|
+
(mname, _) = self.pin_
|
145
|
+
self.models = self.get_models(mname)
|
146
|
+
self.add_trait("mod", Enum(self.models[0], values="models"))
|
147
|
+
self.add_trait("ibis_ver", Float(model_dict["ibis_ver"]))
|
148
|
+
self.add_trait("file_name", String(model_dict["file_name"]))
|
149
|
+
self.add_trait("file_rev", String(model_dict["file_rev"]))
|
150
|
+
if "date" in model_dict:
|
151
|
+
self.add_trait("date", String(model_dict["date"]))
|
152
|
+
else:
|
153
|
+
self.add_trait("date", String("(n/a)"))
|
154
|
+
|
155
|
+
self._ibis_parsing_errors = err_str
|
156
|
+
self._os_type = platform.system() # These 2 are used, to choose
|
157
|
+
self._os_bits = platform.architecture()[0] # the correct AMI executable.
|
158
|
+
|
159
|
+
self._comp_changed(list(components)[0]) # Wasn't being called automatically.
|
160
|
+
self._pin_changed(self.pins[0]) # Wasn't being called automatically.
|
161
|
+
|
162
|
+
self.log("Done.")
|
163
|
+
|
164
|
+
def __str__(self):
|
165
|
+
return f"IBIS Model '{self._model_dict['file_name']}'"
|
166
|
+
|
167
|
+
def info(self):
|
168
|
+
"""Basic information about the IBIS model."""
|
169
|
+
res = ""
|
170
|
+
try:
|
171
|
+
for k in ["ibis_ver", "file_name", "file_rev"]:
|
172
|
+
res += k + ":\t" + str(self._model_dict[k]) + "\n"
|
173
|
+
except Exception as err:
|
174
|
+
print(f"{err}")
|
175
|
+
print(self._model_dict)
|
176
|
+
raise
|
177
|
+
res += "date" + ":\t\t" + str(self._model_dict["date"]) + "\n"
|
178
|
+
res += "\nComponents:"
|
179
|
+
res += "\n=========="
|
180
|
+
for c in list(self._model_dict["components"]):
|
181
|
+
res += "\n" + c + ":\n" + "---\n" + str(self._model_dict["components"][c]) + "\n"
|
182
|
+
res += "\nModel Selectors:"
|
183
|
+
res += "\n===============\n"
|
184
|
+
for s in list(self._model_dict["model_selectors"]):
|
185
|
+
res += f"{s}\n"
|
186
|
+
res += "\nModels:"
|
187
|
+
res += "\n======"
|
188
|
+
for m in list(self._model_dict["models"]):
|
189
|
+
res += "\n" + m + ":\n" + "---\n" + str(self._model_dict["models"][m])
|
190
|
+
return res
|
191
|
+
|
192
|
+
def __call__(self):
|
193
|
+
"""Present a customized GUI to the user, for model selection, etc."""
|
194
|
+
self.edit_traits(kind="livemodal")
|
195
|
+
|
196
|
+
# Logger & Pop-up
|
197
|
+
def log(self, msg, alert=False):
|
198
|
+
"""Log a message to the console and, optionally, to terminal and/or
|
199
|
+
pop-up dialog."""
|
200
|
+
_msg = msg.strip()
|
201
|
+
txt = f"\n[{datetime.now()}]: IBISModel: {_msg}\n"
|
202
|
+
self._log += txt
|
203
|
+
if self.debug:
|
204
|
+
print(txt, flush=True)
|
205
|
+
if alert and self.GUI:
|
206
|
+
message(_msg, "PyAMI Alert")
|
207
|
+
|
208
|
+
def default_traits_view(self):
|
209
|
+
"Default Traits/UI view definition."
|
210
|
+
view = View(
|
211
|
+
VGroup(
|
212
|
+
HGroup(
|
213
|
+
Item("file_name", label="File name", style="readonly"),
|
214
|
+
spring,
|
215
|
+
Item("file_rev", label="rev", style="readonly"),
|
216
|
+
),
|
217
|
+
HGroup(
|
218
|
+
Item("ibis_ver", label="IBIS ver", style="readonly"),
|
219
|
+
spring,
|
220
|
+
Item("date", label="Date", style="readonly"),
|
221
|
+
),
|
222
|
+
HGroup(
|
223
|
+
Item("comp", label="Component"),
|
224
|
+
Item("pin", label="Pin"),
|
225
|
+
Item("mod", label="Model"),
|
226
|
+
),
|
227
|
+
),
|
228
|
+
resizable=False,
|
229
|
+
buttons=ModalButtons,
|
230
|
+
title="PyBERT IBIS Model Selector",
|
231
|
+
id="pybert.pybert_ami.model_selector",
|
232
|
+
)
|
233
|
+
return view
|
234
|
+
|
235
|
+
@cached_property
|
236
|
+
def _get_pin_(self):
|
237
|
+
return self.comp_.pins[self.pin]
|
238
|
+
|
239
|
+
@cached_property
|
240
|
+
def _get_pin_rlcs(self):
|
241
|
+
(_, pin_rlcs) = self.pin_
|
242
|
+
return pin_rlcs
|
243
|
+
|
244
|
+
@cached_property
|
245
|
+
def _get_model(self):
|
246
|
+
return self._models[self.mod]
|
247
|
+
|
248
|
+
@property
|
249
|
+
def ibis_parsing_errors(self):
|
250
|
+
"""Any errors or warnings encountered, while parsing the IBIS file
|
251
|
+
contents."""
|
252
|
+
return self._ibis_parsing_errors
|
253
|
+
|
254
|
+
@property
|
255
|
+
def log_txt(self):
|
256
|
+
"""The complete log since instantiation."""
|
257
|
+
return self._log
|
258
|
+
|
259
|
+
@property
|
260
|
+
def model_dict(self):
|
261
|
+
"Dictionary of all model keywords."
|
262
|
+
return self._model_dict
|
263
|
+
|
264
|
+
@property
|
265
|
+
def dll_file(self):
|
266
|
+
"Shared object file."
|
267
|
+
return self._dll_file
|
268
|
+
|
269
|
+
@property
|
270
|
+
def ami_file(self):
|
271
|
+
"AMI file."
|
272
|
+
return self._ami_file
|
273
|
+
|
274
|
+
def _comp_changed(self, new_value):
|
275
|
+
del new_value
|
276
|
+
self.pins = self.get_pins()
|
277
|
+
self.pin = self.pins[0]
|
278
|
+
|
279
|
+
def _pin_changed(self, new_value):
|
280
|
+
# (mname, rlc_dict) = self.pin_ # Doesn't work. Because ``pin_`` is a cached property and hasn't yet been marked "dirty"?
|
281
|
+
(mname, _) = self.comp_.pins[new_value]
|
282
|
+
self.models = self.get_models(mname)
|
283
|
+
self.mod = self.models[0]
|
284
|
+
|
285
|
+
def _mod_changed(self, new_value):
|
286
|
+
model = self._models[new_value]
|
287
|
+
os_type = self._os_type
|
288
|
+
os_bits = self._os_bits
|
289
|
+
fnames = []
|
290
|
+
dll_file = ""
|
291
|
+
ami_file = ""
|
292
|
+
if os_type.lower() == "windows":
|
293
|
+
if os_bits == "64bit":
|
294
|
+
fnames = model._exec64Wins # pylint: disable=protected-access
|
295
|
+
else:
|
296
|
+
fnames = model._exec32Wins # pylint: disable=protected-access
|
297
|
+
else:
|
298
|
+
if os_bits == "64bit":
|
299
|
+
fnames = model._exec64Lins # pylint: disable=protected-access
|
300
|
+
else:
|
301
|
+
fnames = model._exec32Lins # pylint: disable=protected-access
|
302
|
+
if fnames:
|
303
|
+
dll_file = fnames[0]
|
304
|
+
ami_file = fnames[1]
|
305
|
+
self.log(
|
306
|
+
"There was an [Algorithmic Model] keyword in this model.\n \
|
307
|
+
If you wish to use the AMI model associated with this IBIS model,\n \
|
308
|
+
please, go the 'Equalization' tab and enable it now.",
|
309
|
+
alert=True,
|
310
|
+
)
|
311
|
+
elif "algorithmic_model" in model._subDict: # pylint: disable=protected-access
|
312
|
+
self.log(
|
313
|
+
f"There was an [Algorithmic Model] keyword for this model,\n \
|
314
|
+
but no executable for your platform: {os_type}-{os_bits};\n \
|
315
|
+
PyBERT native equalization modeling being used instead.",
|
316
|
+
alert=True,
|
317
|
+
)
|
318
|
+
else:
|
319
|
+
self.log(
|
320
|
+
"There was no [Algorithmic Model] keyword for this model;\n \
|
321
|
+
PyBERT native equalization modeling being used instead.",
|
322
|
+
alert=True,
|
323
|
+
)
|
324
|
+
self._dll_file = dll_file # pylint: disable=attribute-defined-outside-init
|
325
|
+
self._ami_file = ami_file # pylint: disable=attribute-defined-outside-init
|