pyibis-ami 7.1.0__tar.gz → 7.2.0__tar.gz
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.1.0/src/PyIBIS_AMI.egg-info → pyibis_ami-7.2.0}/PKG-INFO +1 -1
- {pyibis_ami-7.1.0 → pyibis_ami-7.2.0}/docs/source/conf.py +4 -2
- {pyibis_ami-7.1.0 → pyibis_ami-7.2.0}/pyproject.toml +1 -1
- {pyibis_ami-7.1.0 → pyibis_ami-7.2.0/src/PyIBIS_AMI.egg-info}/PKG-INFO +1 -1
- {pyibis_ami-7.1.0 → pyibis_ami-7.2.0}/src/PyIBIS_AMI.egg-info/SOURCES.txt +1 -0
- {pyibis_ami-7.1.0 → pyibis_ami-7.2.0}/src/pyibisami/ami/model.py +1 -1
- {pyibis_ami-7.1.0 → pyibis_ami-7.2.0}/src/pyibisami/ami/parameter.py +0 -59
- {pyibis_ami-7.1.0 → pyibis_ami-7.2.0}/src/pyibisami/ami/parser.py +123 -84
- pyibis_ami-7.2.0/src/pyibisami/ami/reserved_parameter_names.py +84 -0
- {pyibis_ami-7.1.0 → pyibis_ami-7.2.0}/src/pyibisami/common.py +4 -2
- {pyibis_ami-7.1.0 → pyibis_ami-7.2.0}/LICENSE +0 -0
- {pyibis_ami-7.1.0 → pyibis_ami-7.2.0}/MANIFEST.in +0 -0
- {pyibis_ami-7.1.0 → pyibis_ami-7.2.0}/README.md +0 -0
- {pyibis_ami-7.1.0 → pyibis_ami-7.2.0}/docs/source/ami.rst +0 -0
- {pyibis_ami-7.1.0 → pyibis_ami-7.2.0}/docs/source/ibis.rst +0 -0
- {pyibis_ami-7.1.0 → pyibis_ami-7.2.0}/docs/source/index.rst +0 -0
- {pyibis_ami-7.1.0 → pyibis_ami-7.2.0}/docs/source/install.rst +0 -0
- {pyibis_ami-7.1.0 → pyibis_ami-7.2.0}/docs/source/modules.rst +0 -0
- {pyibis_ami-7.1.0 → pyibis_ami-7.2.0}/docs/source/tools.rst +0 -0
- {pyibis_ami-7.1.0 → pyibis_ami-7.2.0}/examples/all_taps.run +0 -0
- {pyibis_ami-7.1.0 → pyibis_ami-7.2.0}/examples/bandwidth.run +0 -0
- {pyibis_ami-7.1.0 → pyibis_ami-7.2.0}/examples/dummy.em +0 -0
- {pyibis_ami-7.1.0 → pyibis_ami-7.2.0}/examples/examples.md +0 -0
- {pyibis_ami-7.1.0 → pyibis_ami-7.2.0}/examples/freq_resp.em +0 -0
- {pyibis_ami-7.1.0 → pyibis_ami-7.2.0}/examples/impulse.em +0 -0
- {pyibis_ami-7.1.0 → pyibis_ami-7.2.0}/examples/impulse_response_8ma.txt +0 -0
- {pyibis_ami-7.1.0 → pyibis_ami-7.2.0}/examples/mode.run +0 -0
- {pyibis_ami-7.1.0 → pyibis_ami-7.2.0}/examples/stratix4_ami_tx_runs/all_taps.run +0 -0
- {pyibis_ami-7.1.0 → pyibis_ami-7.2.0}/examples/stratix4_ami_tx_runs/test_results.xml +0 -0
- {pyibis_ami-7.1.0 → pyibis_ami-7.2.0}/examples/test_results/test_results.xsl +0 -0
- {pyibis_ami-7.1.0 → pyibis_ami-7.2.0}/setup.cfg +0 -0
- {pyibis_ami-7.1.0 → pyibis_ami-7.2.0}/src/PyIBIS_AMI.egg-info/dependency_links.txt +0 -0
- {pyibis_ami-7.1.0 → pyibis_ami-7.2.0}/src/PyIBIS_AMI.egg-info/entry_points.txt +0 -0
- {pyibis_ami-7.1.0 → pyibis_ami-7.2.0}/src/PyIBIS_AMI.egg-info/requires.txt +0 -0
- {pyibis_ami-7.1.0 → pyibis_ami-7.2.0}/src/PyIBIS_AMI.egg-info/top_level.txt +0 -0
- {pyibis_ami-7.1.0 → pyibis_ami-7.2.0}/src/pyibisami/IBIS_AMI_Checker.ipynb +0 -0
- {pyibis_ami-7.1.0 → pyibis_ami-7.2.0}/src/pyibisami/IBIS_AMI_Tester.ipynb +0 -0
- {pyibis_ami-7.1.0 → pyibis_ami-7.2.0}/src/pyibisami/__init__.py +0 -0
- {pyibis_ami-7.1.0 → pyibis_ami-7.2.0}/src/pyibisami/__main__.py +0 -0
- {pyibis_ami-7.1.0 → pyibis_ami-7.2.0}/src/pyibisami/ami/__init__.py +0 -0
- {pyibis_ami-7.1.0 → pyibis_ami-7.2.0}/src/pyibisami/ami/config.py +0 -0
- {pyibis_ami-7.1.0 → pyibis_ami-7.2.0}/src/pyibisami/ami/generic.ami.em +0 -0
- {pyibis_ami-7.1.0 → pyibis_ami-7.2.0}/src/pyibisami/ami/generic.ibs.em +0 -0
- {pyibis_ami-7.1.0 → pyibis_ami-7.2.0}/src/pyibisami/ibis/__init__.py +0 -0
- {pyibis_ami-7.1.0 → pyibis_ami-7.2.0}/src/pyibisami/ibis/file.py +0 -0
- {pyibis_ami-7.1.0 → pyibis_ami-7.2.0}/src/pyibisami/ibis/model.py +0 -0
- {pyibis_ami-7.1.0 → pyibis_ami-7.2.0}/src/pyibisami/ibis/parser.py +0 -0
- {pyibis_ami-7.1.0 → pyibis_ami-7.2.0}/src/pyibisami/tools/__init__.py +0 -0
- {pyibis_ami-7.1.0 → pyibis_ami-7.2.0}/src/pyibisami/tools/run_notebook.py +0 -0
- {pyibis_ami-7.1.0 → pyibis_ami-7.2.0}/src/pyibisami/tools/run_tests.py +0 -0
- {pyibis_ami-7.1.0 → pyibis_ami-7.2.0}/src/pyibisami/tools/test_results.xsl +0 -0
- {pyibis_ami-7.1.0 → pyibis_ami-7.2.0}/tests/test_run_tests.py +0 -0
@@ -84,9 +84,11 @@ author = "David Banas"
|
|
84
84
|
# built documents.
|
85
85
|
#
|
86
86
|
# The short X.Y version.
|
87
|
-
|
87
|
+
_ver = os.environ['PROJ_VER']
|
88
|
+
# The short X.Y version.
|
89
|
+
version = '.'.join(_ver.split('.')[0:2])
|
88
90
|
# The full version, including alpha/beta/rc tags.
|
89
|
-
release =
|
91
|
+
release = _ver
|
90
92
|
|
91
93
|
# The language for content autogenerated by Sphinx. Refer to documentation
|
92
94
|
# for a list of supported languages.
|
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
|
|
5
5
|
[project]
|
6
6
|
name = "pyibis-ami"
|
7
7
|
description = "Facilitates working directly with IBIS-AMI DLLs from the Python command prompt."
|
8
|
-
version = "7.
|
8
|
+
version = "7.2.0"
|
9
9
|
authors = [ {name = "David Banas", email = "capn.freako@gmail.com"}
|
10
10
|
]
|
11
11
|
readme = "README.md"
|
@@ -44,6 +44,7 @@ src/pyibisami/ami/generic.ibs.em
|
|
44
44
|
src/pyibisami/ami/model.py
|
45
45
|
src/pyibisami/ami/parameter.py
|
46
46
|
src/pyibisami/ami/parser.py
|
47
|
+
src/pyibisami/ami/reserved_parameter_names.py
|
47
48
|
src/pyibisami/ibis/__init__.py
|
48
49
|
src/pyibisami/ibis/file.py
|
49
50
|
src/pyibisami/ibis/model.py
|
@@ -481,7 +481,7 @@ class AMIModel: # pylint: disable=too-many-instance-attributes
|
|
481
481
|
ui = self.bit_time
|
482
482
|
ts = self.sample_interval
|
483
483
|
info_params = self.info_params
|
484
|
-
ignore_bits = info_params["Ignore_Bits"] if "Ignore_Bits" in info_params else 0
|
484
|
+
ignore_bits = info_params["Ignore_Bits"].pvalue if "Ignore_Bits" in info_params else 0
|
485
485
|
|
486
486
|
# Capture/convert instance variables.
|
487
487
|
chnl_imp = np.array(self.channel_response) * ts # input (a.k.a. - "channel") impulse response (V/sample)
|
@@ -23,65 +23,6 @@ class AMIParameter: # pylint: disable=too-many-instance-attributes,too-few-publ
|
|
23
23
|
parameter.
|
24
24
|
"""
|
25
25
|
|
26
|
-
RESERVED_PARAM_NAMES = [
|
27
|
-
"AMI_Version",
|
28
|
-
"Init_Returns_Impulse",
|
29
|
-
"GetWave_Exists",
|
30
|
-
"Use_Init_Output",
|
31
|
-
"Max_Init_Aggressors",
|
32
|
-
"Ignore_Bits",
|
33
|
-
"Resolve_Exists",
|
34
|
-
"Model_Name",
|
35
|
-
"Special_Param_Names",
|
36
|
-
"Component_Name",
|
37
|
-
"Signal_Name",
|
38
|
-
"Rx_Decision_Time",
|
39
|
-
"DC_Offset",
|
40
|
-
"Rx_Use_Clock_Input",
|
41
|
-
"Supporting_Files",
|
42
|
-
"DLL_Path",
|
43
|
-
"DLL_ID",
|
44
|
-
"Tx_Jitter",
|
45
|
-
"Tx_DCD",
|
46
|
-
"Tx_Rj",
|
47
|
-
"Tx_Dj",
|
48
|
-
"Tx_Sj",
|
49
|
-
"Tx_Sj_Frequency",
|
50
|
-
"Rx_DCD",
|
51
|
-
"Rx_Rj",
|
52
|
-
"Rx_Dj",
|
53
|
-
"Rx_Sj",
|
54
|
-
"Rx_Clock_PDF",
|
55
|
-
"Rx_Clock_Recovery_Mean",
|
56
|
-
"Rx_Clock_Recovery_Rj",
|
57
|
-
"Rx_Clock_Recovery_Dj",
|
58
|
-
"Rx_Clock_Recovery_Sj",
|
59
|
-
"Rx_Clock_Recovery_DCD",
|
60
|
-
"Rx_Receiver_Sensitivity",
|
61
|
-
"Rx_Noise",
|
62
|
-
"Rx_GaussianNoise",
|
63
|
-
"Rx_UniformNoise",
|
64
|
-
"Modulation",
|
65
|
-
"PAM4_Mapping",
|
66
|
-
"PAM4_UpperThreshold",
|
67
|
-
"PAM4_CenterThreshold",
|
68
|
-
"PAM4_LowerThreshold",
|
69
|
-
"PAM4_UpperEyeOffset",
|
70
|
-
"PAM4_CenterEyeOffset",
|
71
|
-
"PAM4_LowerEyeOffset",
|
72
|
-
"Repeater_Type",
|
73
|
-
"BCI_Protocol",
|
74
|
-
"BCI_ID",
|
75
|
-
"BCI_State",
|
76
|
-
"BCI_Message_Interval_UI",
|
77
|
-
"BCI_Training_UI",
|
78
|
-
"BCI_Training_Mode",
|
79
|
-
"Ts4file",
|
80
|
-
"Tx_V",
|
81
|
-
"Tx_R",
|
82
|
-
"Rx_R",
|
83
|
-
]
|
84
|
-
|
85
26
|
# Properties.
|
86
27
|
|
87
28
|
# Note: They are read-only, despite the presence of apparent setters.
|
@@ -9,16 +9,18 @@ Copyright (c) 2019 David Banas; all rights reserved World wide.
|
|
9
9
|
|
10
10
|
from ctypes import c_double
|
11
11
|
import re
|
12
|
-
from typing import Any, NewType, Optional, TypeAlias
|
12
|
+
from typing import Any, Callable, NewType, Optional, TypeAlias
|
13
13
|
|
14
|
+
import numpy as np
|
14
15
|
from numpy.typing import NDArray
|
15
16
|
from parsec import ParseError, generate, many, regex, string
|
16
17
|
from traits.api import Bool, Enum, HasTraits, Range, Trait, TraitType
|
17
18
|
from traitsui.api import Group, HGroup, Item, VGroup, View
|
18
19
|
from traitsui.menu import ModalButtons
|
19
20
|
|
20
|
-
from
|
21
|
-
from
|
21
|
+
from .model import AMIModelInitializer
|
22
|
+
from .parameter import AMIParamError, AMIParameter
|
23
|
+
from .reserved_parameter_names import AmiReservedParameterName, RESERVED_PARAM_NAMES
|
22
24
|
|
23
25
|
# New types and aliases.
|
24
26
|
# Parameters = NewType('Parameters', dict[str, AMIParameter] | dict[str, 'Parameters'])
|
@@ -26,8 +28,25 @@ from pyibisami.ami.parameter import AMIParamError, AMIParameter
|
|
26
28
|
# See: https://stackoverflow.com/questions/70894567/using-mypy-newtype-with-type-aliases-or-protocols
|
27
29
|
ParamName = NewType("ParamName", str)
|
28
30
|
ParamValue: TypeAlias = int | float | str | list["ParamValue"]
|
29
|
-
Parameters: TypeAlias = dict[ParamName, AMIParameter
|
30
|
-
ParamValues: TypeAlias = dict[ParamName, ParamValue
|
31
|
+
Parameters: TypeAlias = dict[ParamName, "AMIParameter | 'Parameters'"]
|
32
|
+
ParamValues: TypeAlias = dict[ParamName, "ParamValue | 'ParamValues'"]
|
33
|
+
|
34
|
+
AmiName = NewType("AmiName", str)
|
35
|
+
AmiAtom: TypeAlias = bool | int | float | str
|
36
|
+
AmiExpr: TypeAlias = "AmiAtom | 'AmiNode'"
|
37
|
+
AmiNode: TypeAlias = tuple[AmiName, list[AmiExpr]]
|
38
|
+
AmiNodeParser: TypeAlias = Callable[[str], AmiNode]
|
39
|
+
AmiParser: TypeAlias = Callable[[str], tuple[AmiName, list[AmiNode]]] # Atoms may not exist at the root level.
|
40
|
+
|
41
|
+
ParseErrMsg = NewType("ParseErrMsg", str)
|
42
|
+
AmiRootName = NewType("AmiRootName", str)
|
43
|
+
ReservedParamDict: TypeAlias = dict[AmiReservedParameterName, AMIParameter]
|
44
|
+
ModelSpecificDict: TypeAlias = dict[ParamName, "AMIParameter | 'ModelSpecificDict'"]
|
45
|
+
|
46
|
+
__all__ = [
|
47
|
+
"ParamName", "ParamValue", "Parameters", "ParamValues",
|
48
|
+
"AmiName", "AmiAtom", "AmiExpr", "AmiNode", "AmiNodeParser", "AmiParser",
|
49
|
+
"ami_parse", "AMIParamConfigurator"]
|
31
50
|
|
32
51
|
#####
|
33
52
|
# AMI parameter configurator.
|
@@ -77,25 +96,19 @@ class AMIParamConfigurator(HasTraits):
|
|
77
96
|
# to get all the Traits/UI machinery setup correctly.
|
78
97
|
super().__init__()
|
79
98
|
|
80
|
-
# Parse the AMI file contents, storing any errors or warnings,
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
if "Model_Specific" not in param_dict:
|
94
|
-
print(f"Error: {err_str}\nParameters: {param_dict}")
|
95
|
-
raise KeyError("Unable to get 'Model_Specific' from the parameter set.")
|
96
|
-
pdict = param_dict["Reserved_Parameters"].copy()
|
97
|
-
pdict.update(param_dict["Model_Specific"])
|
98
|
-
gui_items, new_traits = make_gui(pdict)
|
99
|
+
# Parse the AMI file contents, storing any errors or warnings, and customize the view accordingly.
|
100
|
+
err_str, root_name, description, reserved_param_dict, model_specific_dict = parse_ami_file_contents(ami_file_contents_str)
|
101
|
+
assert reserved_param_dict, ValueError(
|
102
|
+
"\n".join([
|
103
|
+
"No 'Reserved_Parameters' section found!",
|
104
|
+
err_str
|
105
|
+
]))
|
106
|
+
assert model_specific_dict, ValueError(
|
107
|
+
"\n".join([
|
108
|
+
"No 'Model_Specific' section found!",
|
109
|
+
err_str
|
110
|
+
]))
|
111
|
+
gui_items, new_traits = make_gui(model_specific_dict)
|
99
112
|
trait_names = []
|
100
113
|
for trait in new_traits:
|
101
114
|
self.add_trait(trait[0], trait[1])
|
@@ -104,8 +117,9 @@ class AMIParamConfigurator(HasTraits):
|
|
104
117
|
self._root_name = root_name
|
105
118
|
self._ami_parsing_errors = err_str
|
106
119
|
self._content = gui_items
|
107
|
-
self.
|
108
|
-
self.
|
120
|
+
self._reserved_param_dict = reserved_param_dict
|
121
|
+
self._model_specific_dict = model_specific_dict
|
122
|
+
self._description = description
|
109
123
|
|
110
124
|
def __call__(self):
|
111
125
|
self.open_gui()
|
@@ -187,12 +201,13 @@ class AMIParamConfigurator(HasTraits):
|
|
187
201
|
return self._ami_parsing_errors
|
188
202
|
|
189
203
|
@property
|
190
|
-
def ami_param_defs(self) -> dict[
|
204
|
+
def ami_param_defs(self) -> dict[str, ReservedParamDict | ModelSpecificDict]:
|
191
205
|
"""The entire AMI parameter definition dictionary.
|
192
206
|
|
193
207
|
Should *not* be passed to ``AMIModelInitializer`` constructor!
|
194
208
|
"""
|
195
|
-
return self.
|
209
|
+
return {"Reserved_Parameters": self._reserved_param_dict,
|
210
|
+
"Model_Specific": self._model_specific_dict}
|
196
211
|
|
197
212
|
@property
|
198
213
|
def input_ami_params(self) -> ParamValues:
|
@@ -203,9 +218,9 @@ class AMIParamConfigurator(HasTraits):
|
|
203
218
|
Should be passed to ``AMIModelInitializer`` constructor.
|
204
219
|
"""
|
205
220
|
|
206
|
-
res = {}
|
207
|
-
res[ParamName("root_name")] = self._root_name
|
208
|
-
params = self.
|
221
|
+
res: ParamValues = {}
|
222
|
+
res[ParamName("root_name")] = str(self._root_name)
|
223
|
+
params = self._model_specific_dict
|
209
224
|
for pname in params:
|
210
225
|
res.update(self.input_ami_param(params, pname))
|
211
226
|
return res
|
@@ -260,13 +275,13 @@ class AMIParamConfigurator(HasTraits):
|
|
260
275
|
@property
|
261
276
|
def info_ami_params(self):
|
262
277
|
"Dictionary of *Reserved* AMI parameter values."
|
263
|
-
return self.
|
278
|
+
return self._reserved_param_dict
|
264
279
|
|
265
280
|
def get_init(
|
266
281
|
self,
|
267
282
|
bit_time: float,
|
268
283
|
sample_interval: float,
|
269
|
-
channel_response: NDArray[
|
284
|
+
channel_response: NDArray[np.longdouble],
|
270
285
|
ami_params: Optional[dict[str, Any]] = None
|
271
286
|
) -> AMIModelInitializer:
|
272
287
|
"""
|
@@ -343,14 +358,25 @@ node_name = tap_ix ^ symbol # `tap_ix` is new and gives the tap position; negat
|
|
343
358
|
def node():
|
344
359
|
"Parse AMI node."
|
345
360
|
yield lparen
|
346
|
-
label
|
361
|
+
label = yield node_name
|
347
362
|
values = yield many(expr)
|
348
363
|
yield rparen
|
349
364
|
return (label, values)
|
350
365
|
|
351
366
|
|
367
|
+
@generate("AMI file")
|
368
|
+
def root():
|
369
|
+
"Parse AMI file."
|
370
|
+
yield lparen
|
371
|
+
label = yield node_name
|
372
|
+
values = yield many(node)
|
373
|
+
yield rparen
|
374
|
+
return (label, values)
|
375
|
+
|
376
|
+
|
352
377
|
expr = atom | node
|
353
|
-
|
378
|
+
ami = ignore >> root
|
379
|
+
ami_parse: AmiParser = ami.parse
|
354
380
|
|
355
381
|
|
356
382
|
def proc_branch(branch):
|
@@ -428,102 +454,115 @@ def proc_branch(branch):
|
|
428
454
|
return results
|
429
455
|
|
430
456
|
|
431
|
-
def
|
432
|
-
|
457
|
+
def parse_ami_file_contents( # pylint: disable=too-many-locals,too-many-branches
|
458
|
+
file_contents: str
|
459
|
+
) -> tuple[ParseErrMsg, AmiRootName, str, ReservedParamDict, ModelSpecificDict]:
|
460
|
+
"""
|
461
|
+
Parse the contents of an IBIS-AMI *parameter definition* (i.e. - `*.ami`) file.
|
433
462
|
|
434
463
|
Args:
|
435
|
-
|
464
|
+
file_contents: The contents of the file, as a single string.
|
436
465
|
|
437
466
|
Example:
|
438
467
|
::
|
439
468
|
|
440
469
|
with open(<ami_file_name>) as ami_file:
|
441
|
-
|
442
|
-
(err_str,
|
470
|
+
file_contents = ami_file.read()
|
471
|
+
(err_str, root_name, reserved_param_dict, model_specific_param_dict) = parse_ami_file_contents(file_contents)
|
443
472
|
|
444
473
|
Returns:
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
The keys of the 'Model_Specific' dictionary can be
|
467
|
-
anything.
|
468
|
-
|
469
|
-
The values of both are either:
|
470
|
-
- instances of class *AMIParameter*, or
|
471
|
-
- sub-dictionaries following the same pattern.
|
474
|
+
A tuple containing
|
475
|
+
|
476
|
+
1. Any error message generated by the parser. (empty on success)
|
477
|
+
|
478
|
+
2. AMI file "root" name.
|
479
|
+
|
480
|
+
3. *Reserved Parameters* dictionary. (empty on failure)
|
481
|
+
|
482
|
+
- The keys of the *Reserved Parameters* dictionary are
|
483
|
+
limited to those called out in the IBIS-AMI specification.
|
484
|
+
|
485
|
+
- The values of the *Reserved Parameters* dictionary
|
486
|
+
must be instances of class ``AMIParameter``.
|
487
|
+
|
488
|
+
4. *Model Specific Parameters* dictionary. (empty on failure)
|
489
|
+
|
490
|
+
- The keys of the *Model Specific Parameters* dictionary can be anything.
|
491
|
+
|
492
|
+
- The values of the *Model Specific Parameters* dictionary
|
493
|
+
may be either: an instance of class ``AMIParameter``, or a nested sub-dictionary.
|
472
494
|
"""
|
473
495
|
try:
|
474
|
-
res =
|
496
|
+
res = ami_parse(file_contents)
|
475
497
|
except ParseError as pe:
|
476
|
-
err_str = f"Expected {pe.expected} at {pe.loc()} in:\n{pe.text[pe.index:]}"
|
477
|
-
return err_str, {}
|
498
|
+
err_str = ParseErrMsg(f"Expected {pe.expected} at {pe.loc()} in:\n{pe.text[pe.index:]}")
|
499
|
+
return err_str, AmiRootName(""), "", {}, {}
|
478
500
|
|
479
501
|
err_str, param_dict = proc_branch(res)
|
480
502
|
if err_str:
|
481
|
-
return (err_str,
|
503
|
+
return (err_str, AmiRootName(""), "", {}, {})
|
504
|
+
assert len(param_dict.keys()) == 1, ValueError(
|
505
|
+
f"Malformed AMI parameter S-exp has top-level keys: {param_dict.keys()}!")
|
482
506
|
|
483
507
|
reserved_found = False
|
484
508
|
init_returns_impulse_found = False
|
485
509
|
getwave_exists_found = False
|
486
510
|
model_spec_found = False
|
487
|
-
params = list(param_dict.items())[0]
|
511
|
+
root_name, params = list(param_dict.items())[0]
|
512
|
+
description = ""
|
513
|
+
reserved_params_dict = {}
|
514
|
+
model_specific_dict = {}
|
515
|
+
_err_str = ""
|
488
516
|
for label in list(params.keys()):
|
517
|
+
tmp_params = params[label]
|
489
518
|
if label == "Reserved_Parameters":
|
490
519
|
reserved_found = True
|
491
|
-
tmp_params = params[label]
|
492
520
|
for param_name in list(tmp_params.keys()):
|
493
|
-
if param_name not in
|
494
|
-
|
521
|
+
if param_name not in RESERVED_PARAM_NAMES:
|
522
|
+
_err_str += f"WARNING: Unrecognized reserved parameter name, '{param_name}', found in parameter definition string!\n"
|
495
523
|
continue
|
496
524
|
param = tmp_params[param_name]
|
497
525
|
if param.pname == "AMI_Version":
|
498
526
|
if param.pusage != "Info" or param.ptype != "String":
|
499
|
-
|
527
|
+
_err_str += "WARNING: Malformed 'AMI_Version' parameter.\n"
|
500
528
|
elif param.pname == "Init_Returns_Impulse":
|
501
529
|
init_returns_impulse_found = True
|
502
530
|
elif param.pname == "GetWave_Exists":
|
503
531
|
getwave_exists_found = True
|
532
|
+
reserved_params_dict = tmp_params
|
504
533
|
elif label == "Model_Specific":
|
505
534
|
model_spec_found = True
|
535
|
+
model_specific_dict = tmp_params
|
506
536
|
elif label == "description":
|
507
|
-
|
537
|
+
description = str(tmp_params)
|
508
538
|
else:
|
509
|
-
|
539
|
+
_err_str += f"WARNING: Unrecognized group with label, '{label}', found in parameter definition string!\n"
|
510
540
|
|
511
541
|
if not reserved_found:
|
512
|
-
|
542
|
+
_err_str += "ERROR: Reserved parameters section not found! It is required."
|
513
543
|
|
514
544
|
if not init_returns_impulse_found:
|
515
|
-
|
545
|
+
_err_str += "ERROR: Reserved parameter, 'Init_Returns_Impulse', not found! It is required."
|
516
546
|
|
517
547
|
if not getwave_exists_found:
|
518
|
-
|
548
|
+
_err_str += "ERROR: Reserved parameter, 'GetWave_Exists', not found! It is required."
|
519
549
|
|
520
550
|
if not model_spec_found:
|
521
|
-
|
551
|
+
_err_str += "WARNING: Model specific parameters section not found!"
|
552
|
+
|
553
|
+
return (ParseErrMsg(_err_str), root_name, description, reserved_params_dict, model_specific_dict)
|
554
|
+
|
522
555
|
|
523
|
-
|
556
|
+
# Legacy client code support:
|
557
|
+
def parse_ami_param_defs(file_contents: str) -> tuple[ParseErrMsg, dict[str, Any]]:
|
558
|
+
"The legacy version of ``parse_ami_file_contents()``."
|
559
|
+
err_msg, root_name, description, reserved_params_dict, model_specific_dict = parse_ami_file_contents(file_contents)
|
560
|
+
return (err_msg, {root_name: {"description": description,
|
561
|
+
"Reserved_Parameters": reserved_params_dict,
|
562
|
+
"Model_Specific": model_specific_dict}})
|
524
563
|
|
525
564
|
|
526
|
-
def make_gui(params:
|
565
|
+
def make_gui(params: ModelSpecificDict) -> tuple[Group, list[TraitType]]:
|
527
566
|
"""
|
528
567
|
Builds top-level ``Group`` and list of ``Trait`` s from AMI parameter dictionary.
|
529
568
|
|
@@ -0,0 +1,84 @@
|
|
1
|
+
"""
|
2
|
+
IBIS-AMI reserved parameter names, as a Python ``dataclass``.
|
3
|
+
|
4
|
+
Original author: David Banas <capn.freako@gmail.com>
|
5
|
+
|
6
|
+
Original date: March 17, 2025
|
7
|
+
|
8
|
+
Copyright (c) 2025 David Banas; all rights reserved World wide.
|
9
|
+
"""
|
10
|
+
|
11
|
+
from dataclasses import dataclass
|
12
|
+
|
13
|
+
|
14
|
+
@dataclass
|
15
|
+
class AmiReservedParameterName():
|
16
|
+
"IBIS-AMI Reserved Parameter Name"
|
17
|
+
|
18
|
+
pname: str
|
19
|
+
|
20
|
+
def __post_init__(self):
|
21
|
+
"Validate parameter name."
|
22
|
+
|
23
|
+
assert self.pname in RESERVED_PARAM_NAMES, ValueError(
|
24
|
+
f"Parameter name: {self.pname}, is not an IBIS-AMI reserved parameter name!")
|
25
|
+
|
26
|
+
|
27
|
+
RESERVED_PARAM_NAMES = [
|
28
|
+
"AMI_Version",
|
29
|
+
"Init_Returns_Impulse",
|
30
|
+
"GetWave_Exists",
|
31
|
+
"Use_Init_Output",
|
32
|
+
"Max_Init_Aggressors",
|
33
|
+
"Ignore_Bits",
|
34
|
+
"Resolve_Exists",
|
35
|
+
"Model_Name",
|
36
|
+
"Special_Param_Names",
|
37
|
+
"Component_Name",
|
38
|
+
"Signal_Name",
|
39
|
+
"Rx_Decision_Time",
|
40
|
+
"DC_Offset",
|
41
|
+
"Rx_Use_Clock_Input",
|
42
|
+
"Supporting_Files",
|
43
|
+
"DLL_Path",
|
44
|
+
"DLL_ID",
|
45
|
+
"Tx_Jitter",
|
46
|
+
"Tx_DCD",
|
47
|
+
"Tx_Rj",
|
48
|
+
"Tx_Dj",
|
49
|
+
"Tx_Sj",
|
50
|
+
"Tx_Sj_Frequency",
|
51
|
+
"Rx_DCD",
|
52
|
+
"Rx_Rj",
|
53
|
+
"Rx_Dj",
|
54
|
+
"Rx_Sj",
|
55
|
+
"Rx_Clock_PDF",
|
56
|
+
"Rx_Clock_Recovery_Mean",
|
57
|
+
"Rx_Clock_Recovery_Rj",
|
58
|
+
"Rx_Clock_Recovery_Dj",
|
59
|
+
"Rx_Clock_Recovery_Sj",
|
60
|
+
"Rx_Clock_Recovery_DCD",
|
61
|
+
"Rx_Receiver_Sensitivity",
|
62
|
+
"Rx_Noise",
|
63
|
+
"Rx_GaussianNoise",
|
64
|
+
"Rx_UniformNoise",
|
65
|
+
"Modulation",
|
66
|
+
"PAM4_Mapping",
|
67
|
+
"PAM4_UpperThreshold",
|
68
|
+
"PAM4_CenterThreshold",
|
69
|
+
"PAM4_LowerThreshold",
|
70
|
+
"PAM4_UpperEyeOffset",
|
71
|
+
"PAM4_CenterEyeOffset",
|
72
|
+
"PAM4_LowerEyeOffset",
|
73
|
+
"Repeater_Type",
|
74
|
+
"BCI_Protocol",
|
75
|
+
"BCI_ID",
|
76
|
+
"BCI_State",
|
77
|
+
"BCI_Message_Interval_UI",
|
78
|
+
"BCI_Training_UI",
|
79
|
+
"BCI_Training_Mode",
|
80
|
+
"Ts4file",
|
81
|
+
"Tx_V",
|
82
|
+
"Tx_R",
|
83
|
+
"Rx_R",
|
84
|
+
]
|
@@ -20,8 +20,10 @@ Cvec: TypeAlias = npt.NDArray[Comp]
|
|
20
20
|
PI: float = 3.141592653589793238462643383279502884
|
21
21
|
TWOPI: float = 2.0 * PI
|
22
22
|
|
23
|
-
TestConfig: TypeAlias = tuple[str, tuple[dict[str, Any], dict[str, Any]]]
|
24
|
-
TestSweep: TypeAlias = tuple[str, str, list[TestConfig]]
|
23
|
+
# TestConfig: TypeAlias = tuple[str, tuple[dict[str, Any], dict[str, Any]]]
|
24
|
+
# TestSweep: TypeAlias = tuple[str, str, list[TestConfig]]
|
25
|
+
TestConfig = tuple[str, tuple[dict[str, Any], dict[str, Any]]]
|
26
|
+
TestSweep = tuple[str, str, list[TestConfig]]
|
25
27
|
|
26
28
|
|
27
29
|
def deconv_same(y: Rvec, x: Rvec) -> Rvec:
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|