pyedb 0.50.1__py3-none-any.whl → 0.52.0__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.
Potentially problematic release.
This version of pyedb might be problematic. Click here for more details.
- pyedb/__init__.py +1 -1
- pyedb/configuration/cfg_ports_sources.py +79 -239
- pyedb/configuration/configuration.py +213 -340
- pyedb/dotnet/clr_module.py +9 -3
- pyedb/dotnet/database/cell/layout.py +10 -1
- pyedb/dotnet/database/dotnet/database.py +0 -2
- pyedb/dotnet/database/edb_data/padstacks_data.py +8 -2
- pyedb/dotnet/database/layout_validation.py +20 -26
- pyedb/dotnet/database/modeler.py +0 -1
- pyedb/dotnet/database/stackup.py +4 -3
- pyedb/dotnet/edb.py +42 -2
- pyedb/generic/design_types.py +183 -62
- pyedb/grpc/database/__init__.py +0 -1
- pyedb/grpc/database/components.py +110 -0
- pyedb/grpc/database/control_file.py +150 -17
- pyedb/grpc/database/definition/materials.py +7 -7
- pyedb/grpc/database/definitions.py +36 -2
- pyedb/grpc/database/hfss.py +15 -0
- pyedb/grpc/database/hierarchy/component.py +10 -2
- pyedb/grpc/database/hierarchy/pin_pair_model.py +1 -1
- pyedb/grpc/database/layout_validation.py +58 -7
- pyedb/grpc/database/net/differential_pair.py +2 -1
- pyedb/grpc/database/nets.py +233 -4
- pyedb/grpc/database/padstacks.py +97 -0
- pyedb/grpc/database/primitive/padstack_instance.py +1 -1
- pyedb/grpc/database/primitive/polygon.py +1 -1
- pyedb/grpc/database/siwave.py +63 -3
- pyedb/grpc/database/source_excitations.py +317 -50
- pyedb/grpc/database/stackup.py +107 -2
- pyedb/grpc/database/terminal/point_terminal.py +2 -2
- pyedb/grpc/database/terminal/terminal.py +1 -1
- pyedb/grpc/edb.py +190 -224
- pyedb/grpc/edb_init.py +54 -5
- {pyedb-0.50.1.dist-info → pyedb-0.52.0.dist-info}/METADATA +4 -4
- {pyedb-0.50.1.dist-info → pyedb-0.52.0.dist-info}/RECORD +37 -37
- {pyedb-0.50.1.dist-info → pyedb-0.52.0.dist-info}/LICENSE +0 -0
- {pyedb-0.50.1.dist-info → pyedb-0.52.0.dist-info}/WHEEL +0 -0
|
@@ -19,10 +19,11 @@
|
|
|
19
19
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
20
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
21
|
# SOFTWARE.
|
|
22
|
-
|
|
22
|
+
from datetime import datetime
|
|
23
23
|
import json
|
|
24
24
|
import os
|
|
25
25
|
from pathlib import Path
|
|
26
|
+
import warnings
|
|
26
27
|
|
|
27
28
|
import toml
|
|
28
29
|
|
|
@@ -33,341 +34,9 @@ from pyedb.dotnet.database.definition.package_def import PackageDef
|
|
|
33
34
|
class Configuration:
|
|
34
35
|
"""Enables export and import of a JSON configuration file that can be applied to a new or existing design."""
|
|
35
36
|
|
|
36
|
-
class Grpc:
|
|
37
|
-
def __init__(self, parent):
|
|
38
|
-
self.parent = parent
|
|
39
|
-
self._pedb = parent._pedb
|
|
40
|
-
|
|
41
|
-
def configuration_stackup(self, kwargs):
|
|
42
|
-
if kwargs.get("fix_padstack_def"):
|
|
43
|
-
from pyedb.configuration.cfg_padstacks import CfgPadstackDefinition
|
|
44
|
-
|
|
45
|
-
pedb_defs = self._pedb.padstacks.definitions
|
|
46
|
-
temp = []
|
|
47
|
-
for _, pdef in pedb_defs.items():
|
|
48
|
-
cfg_def = CfgPadstackDefinition(self._pedb, pdef)
|
|
49
|
-
cfg_def.api.retrieve_parameters_from_edb()
|
|
50
|
-
temp.append(cfg_def)
|
|
51
|
-
self.parent.cfg_data.stackup.apply()
|
|
52
|
-
for cfg_pdef in temp:
|
|
53
|
-
cfg_pdef.api.set_parameters_to_edb()
|
|
54
|
-
else:
|
|
55
|
-
temp_pdef_data = {}
|
|
56
|
-
from ansys.edb.core.definition.padstack_def_data import (
|
|
57
|
-
PadType as GrpcPadType,
|
|
58
|
-
)
|
|
59
|
-
|
|
60
|
-
for pdef_name, pdef in self._pedb.padstacks.definitions.items():
|
|
61
|
-
for layer in pdef.data.layer_names:
|
|
62
|
-
result = pdef.data.get_pad_parameters(layer, GrpcPadType.REGULAR_PAD)
|
|
63
|
-
if len(result) == 4:
|
|
64
|
-
# polygon based
|
|
65
|
-
temp_pdef_data[pdef_name] = pdef.data
|
|
66
|
-
break
|
|
67
|
-
self.parent.cfg_data.stackup.apply()
|
|
68
|
-
for pdef_name, pdef_data in temp_pdef_data.items():
|
|
69
|
-
pdef = self._pedb.padstacks.definitions[pdef_name]
|
|
70
|
-
pdef._padstack_def_data = pdef_data
|
|
71
|
-
|
|
72
|
-
def _load_stackup(self):
|
|
73
|
-
"""Imports stackup information from json."""
|
|
74
|
-
data = self.data["stackup"]
|
|
75
|
-
materials = data.get("materials")
|
|
76
|
-
|
|
77
|
-
if materials:
|
|
78
|
-
edb_materials = {i.lower(): i for i, _ in self._pedb.materials.materials.items()}
|
|
79
|
-
for mat in materials:
|
|
80
|
-
name = mat["name"].lower()
|
|
81
|
-
if name in edb_materials:
|
|
82
|
-
self._pedb.materials.delete_material(edb_materials[name])
|
|
83
|
-
for mat in materials:
|
|
84
|
-
self._pedb.materials.add_material(**mat)
|
|
85
|
-
|
|
86
|
-
layers = data.get("layers")
|
|
87
|
-
|
|
88
|
-
if layers:
|
|
89
|
-
input_signal_layers = [i for i in layers if i["type"].lower() == "signal"]
|
|
90
|
-
if not len(input_signal_layers) == len(self._pedb.stackup.signal_layers):
|
|
91
|
-
self._pedb.logger.error("Input signal layer count do not match.")
|
|
92
|
-
return False
|
|
93
|
-
|
|
94
|
-
removal_list = []
|
|
95
|
-
lc_signal_layers = []
|
|
96
|
-
for name, obj in self._pedb.stackup.all_layers.items():
|
|
97
|
-
if obj.type == "dielectric":
|
|
98
|
-
removal_list.append(name)
|
|
99
|
-
elif obj.type == "signal":
|
|
100
|
-
lc_signal_layers.append(obj.id)
|
|
101
|
-
for l in removal_list:
|
|
102
|
-
self._pedb.stackup.remove_layer(l)
|
|
103
|
-
|
|
104
|
-
# update all signal layers
|
|
105
|
-
id_name = {i[0]: i[1] for i in self._pedb.stackup.layers_by_id}
|
|
106
|
-
signal_idx = 0
|
|
107
|
-
for l in layers:
|
|
108
|
-
if l["type"] == "signal":
|
|
109
|
-
layer_id = lc_signal_layers[signal_idx]
|
|
110
|
-
layer_name = id_name[layer_id]
|
|
111
|
-
self._pedb.stackup.layers[layer_name].update(**l)
|
|
112
|
-
signal_idx = signal_idx + 1
|
|
113
|
-
|
|
114
|
-
# add all dielectric layers. Dielectric layers must be added last. Otherwise,
|
|
115
|
-
# dielectric layer will occupy signal and document layer id.
|
|
116
|
-
prev_layer_clone = None
|
|
117
|
-
l = layers.pop(0)
|
|
118
|
-
if l["type"] == "signal":
|
|
119
|
-
prev_layer_clone = self._pedb.stackup.layers[l["name"]]
|
|
120
|
-
else:
|
|
121
|
-
prev_layer_clone = self._pedb.stackup.add_layer_top(**l)
|
|
122
|
-
for idx, l in enumerate(layers):
|
|
123
|
-
if l["type"] == "dielectric":
|
|
124
|
-
prev_layer_clone = self._pedb.stackup.add_layer_below(
|
|
125
|
-
base_layer_name=prev_layer_clone.name, **l
|
|
126
|
-
)
|
|
127
|
-
elif l["type"] == "signal":
|
|
128
|
-
prev_layer_clone = self._pedb.stackup.layers[l["name"]]
|
|
129
|
-
|
|
130
|
-
def _load_package_def(self):
|
|
131
|
-
"""Imports package definition information from JSON."""
|
|
132
|
-
comps = self._pedb.components.instances
|
|
133
|
-
for pkgd in self.parent.data["package_definitions"]:
|
|
134
|
-
name = pkgd["name"]
|
|
135
|
-
if name in self._pedb.definitions.package:
|
|
136
|
-
self._pedb.definitions.package[name].delete()
|
|
137
|
-
extent_bounding_box = pkgd.get("extent_bounding_box", None)
|
|
138
|
-
if extent_bounding_box:
|
|
139
|
-
package_def = PackageDef(self._pedb, name=name, extent_bounding_box=extent_bounding_box)
|
|
140
|
-
else:
|
|
141
|
-
package_def = PackageDef(self._pedb, name=name, component_part_name=pkgd["component_definition"])
|
|
142
|
-
package_def.maximum_power = pkgd["maximum_power"]
|
|
143
|
-
package_def.therm_cond = pkgd["therm_cond"]
|
|
144
|
-
package_def.theta_jb = pkgd["theta_jb"]
|
|
145
|
-
package_def.theta_jc = pkgd["theta_jc"]
|
|
146
|
-
package_def.height = pkgd["height"]
|
|
147
|
-
|
|
148
|
-
heatsink = pkgd.get("heatsink", None)
|
|
149
|
-
if heatsink:
|
|
150
|
-
package_def.set_heatsink(
|
|
151
|
-
heatsink["fin_base_height"],
|
|
152
|
-
heatsink["fin_height"],
|
|
153
|
-
heatsink["fin_orientation"],
|
|
154
|
-
heatsink["fin_spacing"],
|
|
155
|
-
heatsink["fin_thickness"],
|
|
156
|
-
)
|
|
157
|
-
|
|
158
|
-
comp_def_name = pkgd["component_definition"]
|
|
159
|
-
comp_def = self._pedb.definitions.component[comp_def_name]
|
|
160
|
-
|
|
161
|
-
comp_list = dict()
|
|
162
|
-
if pkgd["apply_to_all"]:
|
|
163
|
-
comp_list.update(
|
|
164
|
-
{
|
|
165
|
-
refdes: comp
|
|
166
|
-
for refdes, comp in comp_def.components.items()
|
|
167
|
-
if refdes not in pkgd["components"]
|
|
168
|
-
}
|
|
169
|
-
)
|
|
170
|
-
else:
|
|
171
|
-
comp_list.update(
|
|
172
|
-
{refdes: comp for refdes, comp in comp_def.components.items() if refdes in pkgd["components"]}
|
|
173
|
-
)
|
|
174
|
-
for _, i in comp_list.items():
|
|
175
|
-
i.package_def = name
|
|
176
|
-
|
|
177
|
-
def get_data_from_db(self, **kwargs):
|
|
178
|
-
"""Get configuration data from layout.
|
|
179
|
-
|
|
180
|
-
Parameters
|
|
181
|
-
----------
|
|
182
|
-
stackup
|
|
183
|
-
|
|
184
|
-
Returns
|
|
185
|
-
-------
|
|
186
|
-
|
|
187
|
-
"""
|
|
188
|
-
self._pedb.logger.info("Getting data from layout database.")
|
|
189
|
-
data = {}
|
|
190
|
-
if kwargs.get("general", False):
|
|
191
|
-
data["general"] = self.parent.cfg_data.general.get_data_from_db()
|
|
192
|
-
if kwargs.get("stackup", False):
|
|
193
|
-
data["stackup"] = self.parent.cfg_data.stackup.get_data_from_db()
|
|
194
|
-
if kwargs.get("package_definitions", False):
|
|
195
|
-
data["package_definitions"] = self.parent.cfg_data.package_definitions.get_data_from_db()
|
|
196
|
-
if kwargs.get("setups", False):
|
|
197
|
-
setups = self.parent.cfg_data.setups
|
|
198
|
-
setups.retrieve_parameters_from_edb()
|
|
199
|
-
data["setups"] = setups.to_dict()
|
|
200
|
-
if kwargs.get("sources", False):
|
|
201
|
-
data["sources"] = self.parent.cfg_data.sources.get_data_from_db()
|
|
202
|
-
if kwargs.get("ports", False):
|
|
203
|
-
data["ports"] = self.parent.cfg_data.ports.get_data_from_db()
|
|
204
|
-
if kwargs.get("components", False) or kwargs.get("s_parameters", False):
|
|
205
|
-
self.parent.cfg_data.components.retrieve_parameters_from_edb()
|
|
206
|
-
components = []
|
|
207
|
-
for i in self.parent.cfg_data.components.components:
|
|
208
|
-
if i.type == "io":
|
|
209
|
-
components.append(i.get_attributes())
|
|
210
|
-
components.append(i.get_attributes())
|
|
211
|
-
|
|
212
|
-
if kwargs.get("components", False):
|
|
213
|
-
data["components"] = components
|
|
214
|
-
elif kwargs.get("s_parameters", False):
|
|
215
|
-
data["s_parameters"] = self.parent.cfg_data.s_parameters.get_data_from_db(components)
|
|
216
|
-
if kwargs.get("nets", False):
|
|
217
|
-
data["nets"] = self.parent.cfg_data.nets.get_data_from_db()
|
|
218
|
-
if kwargs.get("pin_groups", False):
|
|
219
|
-
data["pin_groups"] = self.parent.cfg_data.pin_groups.get_data_from_db()
|
|
220
|
-
if kwargs.get("operations", False):
|
|
221
|
-
data["operations"] = self.parent.cfg_data.operations.get_data_from_db()
|
|
222
|
-
if kwargs.get("padstacks", False):
|
|
223
|
-
self.parent.cfg_data.padstacks.retrieve_parameters_from_edb()
|
|
224
|
-
definitions = []
|
|
225
|
-
for i in self.parent.cfg_data.padstacks.definitions:
|
|
226
|
-
definitions.append(i.get_attributes())
|
|
227
|
-
instances = []
|
|
228
|
-
for i in self.parent.cfg_data.padstacks.instances:
|
|
229
|
-
instances.append(i.get_attributes())
|
|
230
|
-
data["padstacks"] = dict()
|
|
231
|
-
data["padstacks"]["definitions"] = definitions
|
|
232
|
-
data["padstacks"]["instances"] = instances
|
|
233
|
-
|
|
234
|
-
if kwargs.get("boundaries", False):
|
|
235
|
-
data["boundaries"] = self.parent.cfg_data.boundaries.get_data_from_db()
|
|
236
|
-
|
|
237
|
-
return data
|
|
238
|
-
|
|
239
|
-
def export(
|
|
240
|
-
self,
|
|
241
|
-
file_path,
|
|
242
|
-
stackup=True,
|
|
243
|
-
package_definitions=False,
|
|
244
|
-
setups=True,
|
|
245
|
-
sources=True,
|
|
246
|
-
ports=True,
|
|
247
|
-
nets=True,
|
|
248
|
-
pin_groups=True,
|
|
249
|
-
operations=True,
|
|
250
|
-
components=True,
|
|
251
|
-
boundaries=True,
|
|
252
|
-
s_parameters=True,
|
|
253
|
-
padstacks=True,
|
|
254
|
-
general=True,
|
|
255
|
-
):
|
|
256
|
-
"""Export the configuration data from layout to a file.
|
|
257
|
-
|
|
258
|
-
Parameters
|
|
259
|
-
----------
|
|
260
|
-
file_path : str, Path
|
|
261
|
-
File path to export the configuration data.
|
|
262
|
-
stackup : bool
|
|
263
|
-
Whether to export stackup or not.
|
|
264
|
-
package_definitions : bool
|
|
265
|
-
Whether to export package definitions or not.
|
|
266
|
-
setups : bool
|
|
267
|
-
Whether to export setups or not.
|
|
268
|
-
sources : bool
|
|
269
|
-
Whether to export sources or not.
|
|
270
|
-
ports : bool
|
|
271
|
-
Whether to export ports or not.
|
|
272
|
-
nets : bool
|
|
273
|
-
Whether to export nets.
|
|
274
|
-
pin_groups : bool
|
|
275
|
-
Whether to export pin groups.
|
|
276
|
-
operations : bool
|
|
277
|
-
Whether to export operations.
|
|
278
|
-
components : bool
|
|
279
|
-
Whether to export component.
|
|
280
|
-
boundaries : bool
|
|
281
|
-
Whether to export boundaries.
|
|
282
|
-
s_parameters : bool
|
|
283
|
-
Whether to export s_parameters.
|
|
284
|
-
padstacks : bool
|
|
285
|
-
Whether to export padstacks.
|
|
286
|
-
general : bool
|
|
287
|
-
Whether to export general information.
|
|
288
|
-
Returns
|
|
289
|
-
-------
|
|
290
|
-
bool
|
|
291
|
-
"""
|
|
292
|
-
data = self.get_data_from_db(
|
|
293
|
-
stackup=stackup,
|
|
294
|
-
package_definitions=package_definitions,
|
|
295
|
-
setups=setups,
|
|
296
|
-
sources=sources,
|
|
297
|
-
ports=ports,
|
|
298
|
-
nets=nets,
|
|
299
|
-
pin_groups=pin_groups,
|
|
300
|
-
operations=operations,
|
|
301
|
-
components=components,
|
|
302
|
-
boundaries=boundaries,
|
|
303
|
-
s_parameters=s_parameters,
|
|
304
|
-
padstacks=padstacks,
|
|
305
|
-
general=general,
|
|
306
|
-
)
|
|
307
|
-
|
|
308
|
-
file_path = file_path if isinstance(file_path, Path) else Path(file_path)
|
|
309
|
-
file_path = file_path.with_suffix(".json") if file_path.suffix == "" else file_path
|
|
310
|
-
|
|
311
|
-
for comp in data["components"]:
|
|
312
|
-
for key, value in comp.items():
|
|
313
|
-
try:
|
|
314
|
-
json.dumps(value)
|
|
315
|
-
print(f"Key '{key}' is serializable.")
|
|
316
|
-
except TypeError as e:
|
|
317
|
-
print(f"Key '{key}' failed: {e}")
|
|
318
|
-
|
|
319
|
-
with open(file_path, "w") as f:
|
|
320
|
-
if file_path.suffix == ".json":
|
|
321
|
-
json.dump(data, f, ensure_ascii=False, indent=4)
|
|
322
|
-
else:
|
|
323
|
-
toml.dump(data, f)
|
|
324
|
-
return True if os.path.isfile(file_path) else False
|
|
325
|
-
|
|
326
|
-
class DotNet(Grpc):
|
|
327
|
-
def __init__(self, parent):
|
|
328
|
-
super().__init__(parent)
|
|
329
|
-
|
|
330
|
-
def configuration_stackup(self, kwargs):
|
|
331
|
-
if kwargs.get("fix_padstack_def"):
|
|
332
|
-
from pyedb.configuration.cfg_padstacks import CfgPadstackDefinition
|
|
333
|
-
|
|
334
|
-
pedb_defs = self._pedb.padstacks.definitions
|
|
335
|
-
temp = []
|
|
336
|
-
for _, pdef in pedb_defs.items():
|
|
337
|
-
cfg_def = CfgPadstackDefinition(self._pedb, pdef)
|
|
338
|
-
cfg_def.api.retrieve_parameters_from_edb()
|
|
339
|
-
temp.append(cfg_def)
|
|
340
|
-
self.parent.cfg_data.stackup.apply()
|
|
341
|
-
for cfg_pdef in temp:
|
|
342
|
-
cfg_pdef.api.set_parameters_to_edb()
|
|
343
|
-
else:
|
|
344
|
-
temp_pdef_data = {}
|
|
345
|
-
for pdef_name, pdef in self._pedb.padstacks.definitions.items():
|
|
346
|
-
pdef_data = pdef._padstack_def_data
|
|
347
|
-
for lyr_name in list(pdef_data.GetLayerNames()):
|
|
348
|
-
result = pdef_data.GetPadParametersValue(
|
|
349
|
-
lyr_name, self._pedb._edb.Definition.PadType.RegularPad
|
|
350
|
-
)
|
|
351
|
-
flag, pad_shape, params, offset_x, offset_y, rotation = result
|
|
352
|
-
if flag is False:
|
|
353
|
-
result = pdef_data.GetPolygonalPadParameters(
|
|
354
|
-
lyr_name, self._pedb._edb.Definition.PadType.RegularPad
|
|
355
|
-
)
|
|
356
|
-
flag, polygon_data, offset_x, offset_y, rotation = result
|
|
357
|
-
if flag:
|
|
358
|
-
temp_pdef_data[pdef_name] = pdef_data
|
|
359
|
-
break
|
|
360
|
-
self.parent.cfg_data.stackup.apply()
|
|
361
|
-
for pdef_name, pdef_data in temp_pdef_data.items():
|
|
362
|
-
pdef = self._pedb.padstacks.definitions[pdef_name]
|
|
363
|
-
pdef._padstack_def_data = pdef_data
|
|
364
|
-
|
|
365
37
|
def __init__(self, pedb):
|
|
366
38
|
self._pedb = pedb
|
|
367
|
-
|
|
368
|
-
self.api = self.Grpc(self)
|
|
369
|
-
else:
|
|
370
|
-
self.api = self.DotNet(self)
|
|
39
|
+
|
|
371
40
|
self._components = self._pedb.components.instances
|
|
372
41
|
self.data = {}
|
|
373
42
|
self._s_parameter_library = ""
|
|
@@ -438,6 +107,8 @@ class Configuration:
|
|
|
438
107
|
|
|
439
108
|
def run(self, **kwargs):
|
|
440
109
|
"""Apply configuration settings to the current design"""
|
|
110
|
+
if kwargs.get("fix_padstack_def"):
|
|
111
|
+
warnings.warn("fix_padstack_def is deprecated.", DeprecationWarning)
|
|
441
112
|
|
|
442
113
|
if self.cfg_data.variables:
|
|
443
114
|
self.cfg_data.variables.apply()
|
|
@@ -446,63 +117,199 @@ class Configuration:
|
|
|
446
117
|
self.cfg_data.general.apply()
|
|
447
118
|
|
|
448
119
|
# Configure boundary settings
|
|
120
|
+
now = datetime.now()
|
|
449
121
|
if self.cfg_data.boundaries:
|
|
450
122
|
self.cfg_data.boundaries.apply()
|
|
123
|
+
self._pedb.logger.info(f"Updating boundaries finished. Time lapse {datetime.now() - now}")
|
|
124
|
+
now = datetime.now()
|
|
451
125
|
|
|
452
126
|
# Configure nets
|
|
453
127
|
if self.cfg_data.nets:
|
|
454
128
|
self.cfg_data.nets.apply()
|
|
129
|
+
self._pedb.logger.info(f"Updating nets finished. Time lapse {datetime.now() - now}")
|
|
130
|
+
now = datetime.now()
|
|
455
131
|
|
|
456
132
|
# Configure components
|
|
457
133
|
self.cfg_data.components.apply()
|
|
134
|
+
self._pedb.logger.info(f"Updating components finished. Time lapse {datetime.now() - now}")
|
|
135
|
+
now = datetime.now()
|
|
458
136
|
|
|
459
137
|
# Configure pin groups
|
|
460
138
|
self.cfg_data.pin_groups.apply()
|
|
139
|
+
self._pedb.logger.info(f"Creating pin groups finished. Time lapse {datetime.now() - now}")
|
|
140
|
+
now = datetime.now()
|
|
461
141
|
|
|
462
142
|
# Configure sources
|
|
463
143
|
self.cfg_data.sources.apply()
|
|
144
|
+
self._pedb.logger.info(f"Placing sources finished. Time lapse {datetime.now() - now}")
|
|
145
|
+
now = datetime.now()
|
|
464
146
|
|
|
465
147
|
# Configure setup
|
|
466
148
|
self.cfg_data.setups.apply()
|
|
149
|
+
self._pedb.logger.info(f"Creating setups finished. Time lapse {datetime.now() - now}")
|
|
150
|
+
now = datetime.now()
|
|
467
151
|
|
|
468
152
|
# Configure stackup
|
|
469
|
-
self.
|
|
153
|
+
self.configuration_stackup()
|
|
154
|
+
self._pedb.logger.info(f"Updating stackup finished. Time lapse {datetime.now() - now}")
|
|
155
|
+
now = datetime.now()
|
|
470
156
|
|
|
471
157
|
# Configure padstacks
|
|
472
158
|
if self.cfg_data.padstacks:
|
|
473
159
|
self.cfg_data.padstacks.apply()
|
|
160
|
+
self._pedb.logger.info(f"Applying padstacks finished. Time lapse {datetime.now() - now}")
|
|
161
|
+
now = datetime.now()
|
|
474
162
|
|
|
475
163
|
# Configure S-parameter
|
|
476
164
|
self.cfg_data.s_parameters.apply()
|
|
165
|
+
self._pedb.logger.info(f"Applying S-parameters finished. Time lapse {datetime.now() - now}")
|
|
166
|
+
now = datetime.now()
|
|
477
167
|
|
|
478
168
|
# Configure SPICE models
|
|
479
169
|
for spice_model in self.cfg_data.spice_models:
|
|
480
170
|
spice_model.apply()
|
|
171
|
+
self._pedb.logger.info(f"Assigning Spice models finished. Time lapse {datetime.now() - now}")
|
|
172
|
+
now = datetime.now()
|
|
481
173
|
|
|
482
174
|
# Configure package definitions
|
|
483
175
|
self.cfg_data.package_definitions.apply()
|
|
176
|
+
self._pedb.logger.info(f"Applying package definitions finished. Time lapse {datetime.now() - now}")
|
|
177
|
+
now = datetime.now()
|
|
484
178
|
|
|
485
179
|
# Modeler
|
|
486
180
|
self.cfg_data.modeler.apply()
|
|
487
181
|
|
|
488
182
|
# Configure ports
|
|
489
183
|
self.cfg_data.ports.apply()
|
|
184
|
+
self._pedb.logger.info(f"Placing ports finished. Time lapse {datetime.now() - now}")
|
|
185
|
+
now = datetime.now()
|
|
490
186
|
|
|
491
187
|
# Configure probes
|
|
492
188
|
self.cfg_data.probes.apply()
|
|
189
|
+
self._pedb.logger.info(f"Placing probes finished. Time lapse {datetime.now() - now}")
|
|
493
190
|
|
|
494
191
|
# Configure operations
|
|
495
192
|
self.cfg_data.operations.apply()
|
|
496
193
|
|
|
497
194
|
return True
|
|
498
195
|
|
|
196
|
+
def configuration_stackup(self):
|
|
197
|
+
temp_pdef_data = {}
|
|
198
|
+
for pdef_name, pdef in self._pedb.padstacks.definitions.items():
|
|
199
|
+
pdef_edb_object = pdef._padstack_def_data
|
|
200
|
+
temp_pdef_data[pdef_name] = pdef_edb_object
|
|
201
|
+
|
|
202
|
+
temp_p_inst_layer_map = {}
|
|
203
|
+
for p_inst in self._pedb.layout.padstack_instances:
|
|
204
|
+
temp_p_inst_layer_map[p_inst.id] = p_inst._edb_object.GetLayerMap()
|
|
205
|
+
|
|
206
|
+
self.cfg_data.stackup.apply()
|
|
207
|
+
|
|
208
|
+
for pdef_name, pdef_data in temp_pdef_data.items():
|
|
209
|
+
pdef = self._pedb.padstacks.definitions[pdef_name]
|
|
210
|
+
pdef._padstack_def_data = pdef_data
|
|
211
|
+
|
|
212
|
+
for p_inst in self._pedb.layout.padstack_instances:
|
|
213
|
+
p_inst._edb_object.SetLayerMap(temp_p_inst_layer_map[p_inst.id])
|
|
214
|
+
|
|
499
215
|
def _load_stackup(self):
|
|
500
216
|
"""Imports stackup information from json."""
|
|
501
|
-
self.
|
|
217
|
+
data = self.data["stackup"]
|
|
218
|
+
materials = data.get("materials")
|
|
219
|
+
|
|
220
|
+
if materials:
|
|
221
|
+
edb_materials = {i.lower(): i for i, _ in self._pedb.materials.materials.items()}
|
|
222
|
+
for mat in materials:
|
|
223
|
+
name = mat["name"].lower()
|
|
224
|
+
if name in edb_materials:
|
|
225
|
+
self._pedb.materials.delete_material(edb_materials[name])
|
|
226
|
+
for mat in materials:
|
|
227
|
+
self._pedb.materials.add_material(**mat)
|
|
228
|
+
|
|
229
|
+
layers = data.get("layers")
|
|
230
|
+
|
|
231
|
+
if layers:
|
|
232
|
+
input_signal_layers = [i for i in layers if i["type"].lower() == "signal"]
|
|
233
|
+
if not len(input_signal_layers) == len(self._pedb.stackup.signal_layers):
|
|
234
|
+
self._pedb.logger.error("Input signal layer count do not match.")
|
|
235
|
+
return False
|
|
236
|
+
|
|
237
|
+
removal_list = []
|
|
238
|
+
lc_signal_layers = []
|
|
239
|
+
for name, obj in self._pedb.stackup.all_layers.items():
|
|
240
|
+
if obj.type == "dielectric":
|
|
241
|
+
removal_list.append(name)
|
|
242
|
+
elif obj.type == "signal":
|
|
243
|
+
lc_signal_layers.append(obj.id)
|
|
244
|
+
for l in removal_list:
|
|
245
|
+
self._pedb.stackup.remove_layer(l)
|
|
246
|
+
|
|
247
|
+
# update all signal layers
|
|
248
|
+
id_name = {i[0]: i[1] for i in self._pedb.stackup.layers_by_id}
|
|
249
|
+
signal_idx = 0
|
|
250
|
+
for l in layers:
|
|
251
|
+
if l["type"] == "signal":
|
|
252
|
+
layer_id = lc_signal_layers[signal_idx]
|
|
253
|
+
layer_name = id_name[layer_id]
|
|
254
|
+
self._pedb.stackup.layers[layer_name].update(**l)
|
|
255
|
+
signal_idx = signal_idx + 1
|
|
256
|
+
|
|
257
|
+
# add all dielectric layers. Dielectric layers must be added last. Otherwise,
|
|
258
|
+
# dielectric layer will occupy signal and document layer id.
|
|
259
|
+
prev_layer_clone = None
|
|
260
|
+
l = layers.pop(0)
|
|
261
|
+
if l["type"] == "signal":
|
|
262
|
+
prev_layer_clone = self._pedb.stackup.layers[l["name"]]
|
|
263
|
+
else:
|
|
264
|
+
prev_layer_clone = self._pedb.stackup.add_layer_top(**l)
|
|
265
|
+
for idx, l in enumerate(layers):
|
|
266
|
+
if l["type"] == "dielectric":
|
|
267
|
+
prev_layer_clone = self._pedb.stackup.add_layer_below(base_layer_name=prev_layer_clone.name, **l)
|
|
268
|
+
elif l["type"] == "signal":
|
|
269
|
+
prev_layer_clone = self._pedb.stackup.layers[l["name"]]
|
|
502
270
|
|
|
503
271
|
def _load_package_def(self):
|
|
504
272
|
"""Imports package definition information from JSON."""
|
|
505
|
-
self.
|
|
273
|
+
comps = self._pedb.components.instances
|
|
274
|
+
for pkgd in self.data["package_definitions"]:
|
|
275
|
+
name = pkgd["name"]
|
|
276
|
+
if name in self._pedb.definitions.package:
|
|
277
|
+
self._pedb.definitions.package[name].delete()
|
|
278
|
+
extent_bounding_box = pkgd.get("extent_bounding_box", None)
|
|
279
|
+
if extent_bounding_box:
|
|
280
|
+
package_def = PackageDef(self._pedb, name=name, extent_bounding_box=extent_bounding_box)
|
|
281
|
+
else:
|
|
282
|
+
package_def = PackageDef(self._pedb, name=name, component_part_name=pkgd["component_definition"])
|
|
283
|
+
package_def.maximum_power = pkgd["maximum_power"]
|
|
284
|
+
package_def.therm_cond = pkgd["therm_cond"]
|
|
285
|
+
package_def.theta_jb = pkgd["theta_jb"]
|
|
286
|
+
package_def.theta_jc = pkgd["theta_jc"]
|
|
287
|
+
package_def.height = pkgd["height"]
|
|
288
|
+
|
|
289
|
+
heatsink = pkgd.get("heatsink", None)
|
|
290
|
+
if heatsink:
|
|
291
|
+
package_def.set_heatsink(
|
|
292
|
+
heatsink["fin_base_height"],
|
|
293
|
+
heatsink["fin_height"],
|
|
294
|
+
heatsink["fin_orientation"],
|
|
295
|
+
heatsink["fin_spacing"],
|
|
296
|
+
heatsink["fin_thickness"],
|
|
297
|
+
)
|
|
298
|
+
|
|
299
|
+
comp_def_name = pkgd["component_definition"]
|
|
300
|
+
comp_def = self._pedb.definitions.component[comp_def_name]
|
|
301
|
+
|
|
302
|
+
comp_list = dict()
|
|
303
|
+
if pkgd["apply_to_all"]:
|
|
304
|
+
comp_list.update(
|
|
305
|
+
{refdes: comp for refdes, comp in comp_def.components.items() if refdes not in pkgd["components"]}
|
|
306
|
+
)
|
|
307
|
+
else:
|
|
308
|
+
comp_list.update(
|
|
309
|
+
{refdes: comp for refdes, comp in comp_def.components.items() if refdes in pkgd["components"]}
|
|
310
|
+
)
|
|
311
|
+
for _, i in comp_list.items():
|
|
312
|
+
i.package_def = name
|
|
506
313
|
|
|
507
314
|
def get_data_from_db(self, **kwargs):
|
|
508
315
|
"""Get configuration data from layout.
|
|
@@ -515,7 +322,56 @@ class Configuration:
|
|
|
515
322
|
-------
|
|
516
323
|
|
|
517
324
|
"""
|
|
518
|
-
|
|
325
|
+
self._pedb.logger.info("Getting data from layout database.")
|
|
326
|
+
data = {}
|
|
327
|
+
if kwargs.get("general", False):
|
|
328
|
+
data["general"] = self.cfg_data.general.get_data_from_db()
|
|
329
|
+
if kwargs.get("stackup", False):
|
|
330
|
+
data["stackup"] = self.cfg_data.stackup.get_data_from_db()
|
|
331
|
+
if kwargs.get("package_definitions", False):
|
|
332
|
+
data["package_definitions"] = self.cfg_data.package_definitions.get_data_from_db()
|
|
333
|
+
if kwargs.get("setups", False):
|
|
334
|
+
setups = self.cfg_data.setups
|
|
335
|
+
setups.retrieve_parameters_from_edb()
|
|
336
|
+
data["setups"] = setups.to_dict()
|
|
337
|
+
if kwargs.get("sources", False):
|
|
338
|
+
data["sources"] = self.cfg_data.sources.get_data_from_db()
|
|
339
|
+
if kwargs.get("ports", False):
|
|
340
|
+
data["ports"] = self.cfg_data.ports.get_data_from_db()
|
|
341
|
+
if kwargs.get("components", False) or kwargs.get("s_parameters", False):
|
|
342
|
+
self.cfg_data.components.retrieve_parameters_from_edb()
|
|
343
|
+
components = []
|
|
344
|
+
for i in self.cfg_data.components.components:
|
|
345
|
+
if i.type == "io":
|
|
346
|
+
components.append(i.get_attributes())
|
|
347
|
+
components.append(i.get_attributes())
|
|
348
|
+
|
|
349
|
+
if kwargs.get("components", False):
|
|
350
|
+
data["components"] = components
|
|
351
|
+
elif kwargs.get("s_parameters", False):
|
|
352
|
+
data["s_parameters"] = self.cfg_data.s_parameters.get_data_from_db(components)
|
|
353
|
+
if kwargs.get("nets", False):
|
|
354
|
+
data["nets"] = self.cfg_data.nets.get_data_from_db()
|
|
355
|
+
if kwargs.get("pin_groups", False):
|
|
356
|
+
data["pin_groups"] = self.cfg_data.pin_groups.get_data_from_db()
|
|
357
|
+
if kwargs.get("operations", False):
|
|
358
|
+
data["operations"] = self.cfg_data.operations.get_data_from_db()
|
|
359
|
+
if kwargs.get("padstacks", False):
|
|
360
|
+
self.cfg_data.padstacks.retrieve_parameters_from_edb()
|
|
361
|
+
definitions = []
|
|
362
|
+
for i in self.cfg_data.padstacks.definitions:
|
|
363
|
+
definitions.append(i.get_attributes())
|
|
364
|
+
instances = []
|
|
365
|
+
for i in self.cfg_data.padstacks.instances:
|
|
366
|
+
instances.append(i.get_attributes())
|
|
367
|
+
data["padstacks"] = dict()
|
|
368
|
+
data["padstacks"]["definitions"] = definitions
|
|
369
|
+
data["padstacks"]["instances"] = instances
|
|
370
|
+
|
|
371
|
+
if kwargs.get("boundaries", False):
|
|
372
|
+
data["boundaries"] = self.cfg_data.boundaries.get_data_from_db()
|
|
373
|
+
|
|
374
|
+
return data
|
|
519
375
|
|
|
520
376
|
def export(
|
|
521
377
|
self,
|
|
@@ -570,8 +426,7 @@ class Configuration:
|
|
|
570
426
|
-------
|
|
571
427
|
bool
|
|
572
428
|
"""
|
|
573
|
-
|
|
574
|
-
file_path,
|
|
429
|
+
data = self.get_data_from_db(
|
|
575
430
|
stackup=stackup,
|
|
576
431
|
package_definitions=package_definitions,
|
|
577
432
|
setups=setups,
|
|
@@ -586,3 +441,21 @@ class Configuration:
|
|
|
586
441
|
padstacks=padstacks,
|
|
587
442
|
general=general,
|
|
588
443
|
)
|
|
444
|
+
|
|
445
|
+
file_path = file_path if isinstance(file_path, Path) else Path(file_path)
|
|
446
|
+
file_path = file_path.with_suffix(".json") if file_path.suffix == "" else file_path
|
|
447
|
+
|
|
448
|
+
for comp in data["components"]:
|
|
449
|
+
for key, value in comp.items():
|
|
450
|
+
try:
|
|
451
|
+
json.dumps(value)
|
|
452
|
+
print(f"Key '{key}' is serializable.")
|
|
453
|
+
except TypeError as e:
|
|
454
|
+
print(f"Key '{key}' failed: {e}")
|
|
455
|
+
|
|
456
|
+
with open(file_path, "w") as f:
|
|
457
|
+
if file_path.suffix == ".json":
|
|
458
|
+
json.dump(data, f, ensure_ascii=False, indent=4)
|
|
459
|
+
else:
|
|
460
|
+
toml.dump(data, f)
|
|
461
|
+
return True if os.path.isfile(file_path) else False
|
pyedb/dotnet/clr_module.py
CHANGED
|
@@ -38,6 +38,7 @@ if is_linux: # pragma: no cover
|
|
|
38
38
|
|
|
39
39
|
dotnet_root = None
|
|
40
40
|
runtime_config = None
|
|
41
|
+
runtime_spec = None
|
|
41
42
|
# Use system .NET core runtime or fall back to dotnetcore2
|
|
42
43
|
if os.environ.get("DOTNET_ROOT") is None:
|
|
43
44
|
try:
|
|
@@ -78,11 +79,16 @@ if is_linux: # pragma: no cover
|
|
|
78
79
|
"Please ensure that .NET SDK is correctly installed or "
|
|
79
80
|
"that DOTNET_ROOT is correctly set."
|
|
80
81
|
)
|
|
81
|
-
|
|
82
|
+
runtime_spec = candidates[0]
|
|
82
83
|
# Use specific .NET core runtime
|
|
83
|
-
if dotnet_root is not None and runtime_config is not None:
|
|
84
|
+
if dotnet_root is not None and (runtime_config is not None or runtime_spec is not None):
|
|
84
85
|
try:
|
|
85
|
-
load(
|
|
86
|
+
load(
|
|
87
|
+
"coreclr",
|
|
88
|
+
runtime_config=str(runtime_config) if runtime_config else None,
|
|
89
|
+
runtime_spec=runtime_spec,
|
|
90
|
+
dotnet_root=str(dotnet_root),
|
|
91
|
+
)
|
|
86
92
|
os.environ["DOTNET_ROOT"] = dotnet_root.as_posix()
|
|
87
93
|
if "mono" not in os.getenv("LD_LIBRARY_PATH", ""):
|
|
88
94
|
warnings.warn("LD_LIBRARY_PATH needs to be setup to use pyedb.")
|