pyedb 0.2.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 +17 -0
- pyedb/dotnet/__init__.py +0 -0
- pyedb/dotnet/application/Variables.py +2261 -0
- pyedb/dotnet/application/__init__.py +0 -0
- pyedb/dotnet/clr_module.py +103 -0
- pyedb/dotnet/edb.py +4237 -0
- pyedb/dotnet/edb_core/__init__.py +1 -0
- pyedb/dotnet/edb_core/cell/__init__.py +0 -0
- pyedb/dotnet/edb_core/cell/hierarchy/__init__.py +0 -0
- pyedb/dotnet/edb_core/cell/hierarchy/model.py +66 -0
- pyedb/dotnet/edb_core/components.py +2669 -0
- pyedb/dotnet/edb_core/configuration.py +423 -0
- pyedb/dotnet/edb_core/definition/__init__.py +0 -0
- pyedb/dotnet/edb_core/definition/component_def.py +166 -0
- pyedb/dotnet/edb_core/definition/component_model.py +30 -0
- pyedb/dotnet/edb_core/definition/definition_obj.py +18 -0
- pyedb/dotnet/edb_core/definition/definitions.py +12 -0
- pyedb/dotnet/edb_core/dotnet/__init__.py +0 -0
- pyedb/dotnet/edb_core/dotnet/database.py +1218 -0
- pyedb/dotnet/edb_core/dotnet/layout.py +238 -0
- pyedb/dotnet/edb_core/dotnet/primitive.py +1517 -0
- pyedb/dotnet/edb_core/edb_data/__init__.py +0 -0
- pyedb/dotnet/edb_core/edb_data/components_data.py +938 -0
- pyedb/dotnet/edb_core/edb_data/connectable.py +113 -0
- pyedb/dotnet/edb_core/edb_data/control_file.py +1268 -0
- pyedb/dotnet/edb_core/edb_data/design_options.py +35 -0
- pyedb/dotnet/edb_core/edb_data/edbvalue.py +45 -0
- pyedb/dotnet/edb_core/edb_data/hfss_extent_info.py +330 -0
- pyedb/dotnet/edb_core/edb_data/hfss_simulation_setup_data.py +1607 -0
- pyedb/dotnet/edb_core/edb_data/layer_data.py +576 -0
- pyedb/dotnet/edb_core/edb_data/nets_data.py +281 -0
- pyedb/dotnet/edb_core/edb_data/obj_base.py +19 -0
- pyedb/dotnet/edb_core/edb_data/padstacks_data.py +2080 -0
- pyedb/dotnet/edb_core/edb_data/ports.py +287 -0
- pyedb/dotnet/edb_core/edb_data/primitives_data.py +1397 -0
- pyedb/dotnet/edb_core/edb_data/simulation_configuration.py +2914 -0
- pyedb/dotnet/edb_core/edb_data/simulation_setup.py +716 -0
- pyedb/dotnet/edb_core/edb_data/siwave_simulation_setup_data.py +1205 -0
- pyedb/dotnet/edb_core/edb_data/sources.py +514 -0
- pyedb/dotnet/edb_core/edb_data/terminals.py +632 -0
- pyedb/dotnet/edb_core/edb_data/utilities.py +148 -0
- pyedb/dotnet/edb_core/edb_data/variables.py +91 -0
- pyedb/dotnet/edb_core/general.py +181 -0
- pyedb/dotnet/edb_core/hfss.py +1646 -0
- pyedb/dotnet/edb_core/layout.py +1244 -0
- pyedb/dotnet/edb_core/layout_validation.py +272 -0
- pyedb/dotnet/edb_core/materials.py +939 -0
- pyedb/dotnet/edb_core/net_class.py +335 -0
- pyedb/dotnet/edb_core/nets.py +1215 -0
- pyedb/dotnet/edb_core/padstack.py +1389 -0
- pyedb/dotnet/edb_core/siwave.py +1427 -0
- pyedb/dotnet/edb_core/stackup.py +2703 -0
- pyedb/edb_logger.py +396 -0
- pyedb/generic/__init__.py +0 -0
- pyedb/generic/constants.py +1063 -0
- pyedb/generic/data_handlers.py +320 -0
- pyedb/generic/design_types.py +104 -0
- pyedb/generic/filesystem.py +150 -0
- pyedb/generic/general_methods.py +1535 -0
- pyedb/generic/plot.py +1840 -0
- pyedb/generic/process.py +285 -0
- pyedb/generic/settings.py +224 -0
- pyedb/ipc2581/__init__.py +0 -0
- pyedb/ipc2581/bom/__init__.py +0 -0
- pyedb/ipc2581/bom/bom.py +21 -0
- pyedb/ipc2581/bom/bom_item.py +32 -0
- pyedb/ipc2581/bom/characteristics.py +37 -0
- pyedb/ipc2581/bom/refdes.py +16 -0
- pyedb/ipc2581/content/__init__.py +0 -0
- pyedb/ipc2581/content/color.py +38 -0
- pyedb/ipc2581/content/content.py +55 -0
- pyedb/ipc2581/content/dictionary_color.py +29 -0
- pyedb/ipc2581/content/dictionary_fill.py +28 -0
- pyedb/ipc2581/content/dictionary_line.py +30 -0
- pyedb/ipc2581/content/entry_color.py +13 -0
- pyedb/ipc2581/content/entry_line.py +14 -0
- pyedb/ipc2581/content/fill.py +15 -0
- pyedb/ipc2581/content/layer_ref.py +10 -0
- pyedb/ipc2581/content/standard_geometries_dictionary.py +72 -0
- pyedb/ipc2581/ecad/__init__.py +0 -0
- pyedb/ipc2581/ecad/cad_data/__init__.py +0 -0
- pyedb/ipc2581/ecad/cad_data/assembly_drawing.py +26 -0
- pyedb/ipc2581/ecad/cad_data/cad_data.py +37 -0
- pyedb/ipc2581/ecad/cad_data/component.py +41 -0
- pyedb/ipc2581/ecad/cad_data/drill.py +30 -0
- pyedb/ipc2581/ecad/cad_data/feature.py +54 -0
- pyedb/ipc2581/ecad/cad_data/layer.py +41 -0
- pyedb/ipc2581/ecad/cad_data/layer_feature.py +151 -0
- pyedb/ipc2581/ecad/cad_data/logical_net.py +32 -0
- pyedb/ipc2581/ecad/cad_data/outline.py +25 -0
- pyedb/ipc2581/ecad/cad_data/package.py +104 -0
- pyedb/ipc2581/ecad/cad_data/padstack_def.py +38 -0
- pyedb/ipc2581/ecad/cad_data/padstack_hole_def.py +24 -0
- pyedb/ipc2581/ecad/cad_data/padstack_instance.py +62 -0
- pyedb/ipc2581/ecad/cad_data/padstack_pad_def.py +26 -0
- pyedb/ipc2581/ecad/cad_data/path.py +89 -0
- pyedb/ipc2581/ecad/cad_data/phy_net.py +80 -0
- pyedb/ipc2581/ecad/cad_data/pin.py +31 -0
- pyedb/ipc2581/ecad/cad_data/polygon.py +169 -0
- pyedb/ipc2581/ecad/cad_data/profile.py +40 -0
- pyedb/ipc2581/ecad/cad_data/stackup.py +31 -0
- pyedb/ipc2581/ecad/cad_data/stackup_group.py +42 -0
- pyedb/ipc2581/ecad/cad_data/stackup_layer.py +21 -0
- pyedb/ipc2581/ecad/cad_data/step.py +275 -0
- pyedb/ipc2581/ecad/cad_header.py +33 -0
- pyedb/ipc2581/ecad/ecad.py +19 -0
- pyedb/ipc2581/ecad/spec.py +46 -0
- pyedb/ipc2581/history_record.py +37 -0
- pyedb/ipc2581/ipc2581.py +387 -0
- pyedb/ipc2581/logistic_header.py +25 -0
- pyedb/misc/__init__.py +0 -0
- pyedb/misc/aedtlib_personalib_install.py +14 -0
- pyedb/misc/downloads.py +322 -0
- pyedb/misc/misc.py +67 -0
- pyedb/misc/pyedb.runtimeconfig.json +13 -0
- pyedb/misc/siw_feature_config/__init__.py +0 -0
- pyedb/misc/siw_feature_config/emc/__init__.py +0 -0
- pyedb/misc/siw_feature_config/emc/component_tags.py +46 -0
- pyedb/misc/siw_feature_config/emc/net_tags.py +37 -0
- pyedb/misc/siw_feature_config/emc/tag_library.py +62 -0
- pyedb/misc/siw_feature_config/emc/xml_generic.py +78 -0
- pyedb/misc/siw_feature_config/emc_rule_checker_settings.py +179 -0
- pyedb/misc/utilities.py +27 -0
- pyedb/modeler/geometry_operators.py +2082 -0
- pyedb-0.2.0.dist-info/LICENSE +21 -0
- pyedb-0.2.0.dist-info/METADATA +208 -0
- pyedb-0.2.0.dist-info/RECORD +128 -0
- pyedb-0.2.0.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,1389 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This module contains the `EdbPadstacks` class.
|
|
3
|
+
"""
|
|
4
|
+
import math
|
|
5
|
+
import warnings
|
|
6
|
+
|
|
7
|
+
from pyedb.dotnet.clr_module import Array
|
|
8
|
+
from pyedb.dotnet.edb_core.edb_data.padstacks_data import (
|
|
9
|
+
EDBPadstack,
|
|
10
|
+
EDBPadstackInstance,
|
|
11
|
+
)
|
|
12
|
+
from pyedb.dotnet.edb_core.general import convert_py_list_to_net_list
|
|
13
|
+
from pyedb.generic.general_methods import generate_unique_name, pyedb_function_handler
|
|
14
|
+
from pyedb.modeler.geometry_operators import GeometryOperators
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class EdbPadstacks(object):
|
|
18
|
+
"""Manages EDB methods for nets management accessible from `Edb.padstacks` property.
|
|
19
|
+
|
|
20
|
+
Examples
|
|
21
|
+
--------
|
|
22
|
+
>>> from pyedb import Edb
|
|
23
|
+
>>> edbapp = Edb("myaedbfolder", edbversion="2021.2")
|
|
24
|
+
>>> edb_padstacks = edbapp.padstacks
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
@pyedb_function_handler()
|
|
28
|
+
def __getitem__(self, name):
|
|
29
|
+
"""Get a padstack definition or instance from the Edb project.
|
|
30
|
+
|
|
31
|
+
Parameters
|
|
32
|
+
----------
|
|
33
|
+
name : str, int
|
|
34
|
+
|
|
35
|
+
Returns
|
|
36
|
+
-------
|
|
37
|
+
:class:`pyedb.dotnet.edb_core.edb_data.components_data.EDBComponent`
|
|
38
|
+
|
|
39
|
+
"""
|
|
40
|
+
if name in self.instances:
|
|
41
|
+
return self.instances[name]
|
|
42
|
+
elif name in self.definitions:
|
|
43
|
+
return self.definitions[name]
|
|
44
|
+
else:
|
|
45
|
+
for i in list(self.instances.values()):
|
|
46
|
+
if i.name == name or i.aedt_name == name:
|
|
47
|
+
return i
|
|
48
|
+
self._pedb.logger.error("Component or definition not found.")
|
|
49
|
+
return
|
|
50
|
+
|
|
51
|
+
def __init__(self, p_edb):
|
|
52
|
+
self._pedb = p_edb
|
|
53
|
+
|
|
54
|
+
@property
|
|
55
|
+
def _edb(self):
|
|
56
|
+
""" """
|
|
57
|
+
return self._pedb.edb_api
|
|
58
|
+
|
|
59
|
+
def _get_edb_value(self, value):
|
|
60
|
+
return self._pedb.edb_value(value)
|
|
61
|
+
|
|
62
|
+
@property
|
|
63
|
+
def _active_layout(self):
|
|
64
|
+
""" """
|
|
65
|
+
return self._pedb.active_layout
|
|
66
|
+
|
|
67
|
+
@property
|
|
68
|
+
def _layout(self):
|
|
69
|
+
""" """
|
|
70
|
+
return self._pedb.layout
|
|
71
|
+
|
|
72
|
+
@property
|
|
73
|
+
def db(self):
|
|
74
|
+
"""Db object."""
|
|
75
|
+
return self._pedb.active_db
|
|
76
|
+
|
|
77
|
+
@property
|
|
78
|
+
def _logger(self):
|
|
79
|
+
""" """
|
|
80
|
+
return self._pedb.logger
|
|
81
|
+
|
|
82
|
+
@property
|
|
83
|
+
def _layers(self):
|
|
84
|
+
""" """
|
|
85
|
+
return self._pedb.stackup.stackup_layers
|
|
86
|
+
|
|
87
|
+
@pyedb_function_handler()
|
|
88
|
+
def int_to_pad_type(self, val=0):
|
|
89
|
+
"""Convert an integer to an EDB.PadGeometryType.
|
|
90
|
+
|
|
91
|
+
Parameters
|
|
92
|
+
----------
|
|
93
|
+
val : int
|
|
94
|
+
|
|
95
|
+
Returns
|
|
96
|
+
-------
|
|
97
|
+
object
|
|
98
|
+
EDB.PadType enumerator value.
|
|
99
|
+
"""
|
|
100
|
+
|
|
101
|
+
if val == 0:
|
|
102
|
+
return self._edb.definition.PadType.RegularPad
|
|
103
|
+
elif val == 1:
|
|
104
|
+
return self._edb.definition.PadType.AntiPad
|
|
105
|
+
elif val == 2:
|
|
106
|
+
return self._edb.definition.PadType.ThermalPad
|
|
107
|
+
elif val == 3:
|
|
108
|
+
return self._edb.definition.PadType.Hole
|
|
109
|
+
elif val == 4:
|
|
110
|
+
return self._edb.definition.PadType.UnknownGeomType
|
|
111
|
+
else:
|
|
112
|
+
return val
|
|
113
|
+
|
|
114
|
+
@pyedb_function_handler()
|
|
115
|
+
def int_to_geometry_type(self, val=0):
|
|
116
|
+
"""Convert an integer to an EDB.PadGeometryType.
|
|
117
|
+
|
|
118
|
+
Parameters
|
|
119
|
+
----------
|
|
120
|
+
val : int
|
|
121
|
+
|
|
122
|
+
Returns
|
|
123
|
+
-------
|
|
124
|
+
object
|
|
125
|
+
EDB.PadGeometryType enumerator value.
|
|
126
|
+
"""
|
|
127
|
+
if val == 0:
|
|
128
|
+
return self._edb.definition.PadGeometryType.NoGeometry
|
|
129
|
+
elif val == 1:
|
|
130
|
+
return self._edb.definition.PadGeometryType.Circle
|
|
131
|
+
elif val == 2:
|
|
132
|
+
return self._edb.definition.PadGeometryType.Square
|
|
133
|
+
elif val == 3:
|
|
134
|
+
return self._edb.definition.PadGeometryType.Rectangle
|
|
135
|
+
elif val == 4:
|
|
136
|
+
return self._edb.definition.PadGeometryType.Oval
|
|
137
|
+
elif val == 5:
|
|
138
|
+
return self._edb.definition.PadGeometryType.Bullet
|
|
139
|
+
elif val == 6:
|
|
140
|
+
return self._edb.definition.PadGeometryType.NSidedPolygon
|
|
141
|
+
elif val == 7:
|
|
142
|
+
return self._edb.definition.PadGeometryType.Polygon
|
|
143
|
+
elif val == 8:
|
|
144
|
+
return self._edb.definition.PadGeometryType.Round45
|
|
145
|
+
elif val == 9:
|
|
146
|
+
return self._edb.definition.PadGeometryType.Round90
|
|
147
|
+
elif val == 10:
|
|
148
|
+
return self._edb.definition.PadGeometryType.Square45
|
|
149
|
+
elif val == 11:
|
|
150
|
+
return self._edb.definition.PadGeometryType.Square90
|
|
151
|
+
else:
|
|
152
|
+
return val
|
|
153
|
+
|
|
154
|
+
@property
|
|
155
|
+
def definitions(self):
|
|
156
|
+
"""Padstack definitions.
|
|
157
|
+
|
|
158
|
+
Returns
|
|
159
|
+
-------
|
|
160
|
+
dict[str, :class:`pyedb.dotnet.edb_core.edb_data.padstacks_data.EdbPadstack`]
|
|
161
|
+
List of definitions via padstack definitions.
|
|
162
|
+
|
|
163
|
+
"""
|
|
164
|
+
_padstacks = {}
|
|
165
|
+
for padstackdef in self._pedb.padstack_defs:
|
|
166
|
+
PadStackData = padstackdef.GetData()
|
|
167
|
+
if len(PadStackData.GetLayerNames()) >= 1:
|
|
168
|
+
_padstacks[padstackdef.GetName()] = EDBPadstack(padstackdef, self)
|
|
169
|
+
return _padstacks
|
|
170
|
+
|
|
171
|
+
@property
|
|
172
|
+
def padstacks(self):
|
|
173
|
+
"""Padstacks via padstack definitions.
|
|
174
|
+
|
|
175
|
+
.. deprecated:: 0.6.58
|
|
176
|
+
Use :func:`definitions` property instead.
|
|
177
|
+
|
|
178
|
+
Returns
|
|
179
|
+
-------
|
|
180
|
+
dict[str, :class:`pyedb.dotnet.edb_core.edb_data.EdbPadstack`]
|
|
181
|
+
List of definitions via padstack definitions.
|
|
182
|
+
|
|
183
|
+
"""
|
|
184
|
+
warnings.warn("Use `definitions` property instead.", DeprecationWarning)
|
|
185
|
+
return self.definitions
|
|
186
|
+
|
|
187
|
+
@property
|
|
188
|
+
def instances(self):
|
|
189
|
+
"""Dictionary of all padstack instances (vias and pins).
|
|
190
|
+
|
|
191
|
+
Returns
|
|
192
|
+
-------
|
|
193
|
+
dict[str, :class:`dotnet.edb_core.edb_data.padstacks_data.EDBPadstackInstance`]
|
|
194
|
+
List of padstack instances.
|
|
195
|
+
|
|
196
|
+
"""
|
|
197
|
+
|
|
198
|
+
padstack_instances = {}
|
|
199
|
+
edb_padstack_inst_list = self._pedb.layout.padstack_instances
|
|
200
|
+
for edb_padstack_instance in edb_padstack_inst_list:
|
|
201
|
+
padstack_instances[edb_padstack_instance.GetId()] = EDBPadstackInstance(edb_padstack_instance, self._pedb)
|
|
202
|
+
return padstack_instances
|
|
203
|
+
|
|
204
|
+
@property
|
|
205
|
+
def pins(self):
|
|
206
|
+
"""Dictionary of all pins instances (belonging to component).
|
|
207
|
+
|
|
208
|
+
Returns
|
|
209
|
+
-------
|
|
210
|
+
dic[str, :class:`dotnet.edb_core.edb_data.definitions.EDBPadstackInstance`]
|
|
211
|
+
Dictionary of EDBPadstackInstance Components.
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
Examples
|
|
215
|
+
--------
|
|
216
|
+
>>> edbapp = dotnet.Edb("myproject.aedb")
|
|
217
|
+
>>> pin_net_name = edbapp.pins[424968329].netname
|
|
218
|
+
"""
|
|
219
|
+
pins = {}
|
|
220
|
+
for instancename, instance in self.instances.items():
|
|
221
|
+
if instance.is_pin and instance.component:
|
|
222
|
+
pins[instancename] = instance
|
|
223
|
+
return pins
|
|
224
|
+
|
|
225
|
+
@property
|
|
226
|
+
def vias(self):
|
|
227
|
+
"""Dictionary of all vias instances not belonging to component.
|
|
228
|
+
|
|
229
|
+
Returns
|
|
230
|
+
-------
|
|
231
|
+
dic[str, :class:`dotnet.edb_core.edb_data.definitions.EDBPadstackInstance`]
|
|
232
|
+
Dictionary of EDBPadstackInstance Components.
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
Examples
|
|
236
|
+
--------
|
|
237
|
+
>>> edbapp = dotnet.Edb("myproject.aedb")
|
|
238
|
+
>>> pin_net_name = edbapp.pins[424968329].netname
|
|
239
|
+
"""
|
|
240
|
+
pnames = list(self.pins.keys())
|
|
241
|
+
vias = {i: j for i, j in self.instances.items() if i not in pnames}
|
|
242
|
+
return vias
|
|
243
|
+
|
|
244
|
+
@property
|
|
245
|
+
def padstack_instances(self):
|
|
246
|
+
"""List of padstack instances.
|
|
247
|
+
|
|
248
|
+
.. deprecated:: 0.6.58
|
|
249
|
+
Use :func:`instances` property instead.
|
|
250
|
+
|
|
251
|
+
Returns
|
|
252
|
+
-------
|
|
253
|
+
dict[str, :class:`dotnet.edb_core.edb_data.padstacks_data.EDBPadstackInstance`]
|
|
254
|
+
List of padstack instances.
|
|
255
|
+
"""
|
|
256
|
+
|
|
257
|
+
warnings.warn("Use `instances` property instead.", DeprecationWarning)
|
|
258
|
+
return self.instances
|
|
259
|
+
|
|
260
|
+
@property
|
|
261
|
+
def pingroups(self):
|
|
262
|
+
"""All Layout Pin groups.
|
|
263
|
+
|
|
264
|
+
Returns
|
|
265
|
+
-------
|
|
266
|
+
list
|
|
267
|
+
List of all layout pin groups.
|
|
268
|
+
"""
|
|
269
|
+
pingroups = []
|
|
270
|
+
for el in self._layout.pin_groups:
|
|
271
|
+
pingroups.append(el)
|
|
272
|
+
return pingroups
|
|
273
|
+
|
|
274
|
+
@property
|
|
275
|
+
def pad_type(self):
|
|
276
|
+
"""Return a PadType Enumerator."""
|
|
277
|
+
|
|
278
|
+
class PadType:
|
|
279
|
+
(RegularPad, AntiPad, ThermalPad, Hole, UnknownGeomType) = (
|
|
280
|
+
self._edb.definition.PadType.RegularPad,
|
|
281
|
+
self._edb.definition.PadType.AntiPad,
|
|
282
|
+
self._edb.definition.PadType.ThermalPad,
|
|
283
|
+
self._edb.definition.PadType.Hole,
|
|
284
|
+
self._edb.definition.PadType.UnknownGeomType,
|
|
285
|
+
)
|
|
286
|
+
|
|
287
|
+
return PadType
|
|
288
|
+
|
|
289
|
+
@pyedb_function_handler()
|
|
290
|
+
def create_circular_padstack(
|
|
291
|
+
self,
|
|
292
|
+
padstackname=None,
|
|
293
|
+
holediam="300um",
|
|
294
|
+
paddiam="400um",
|
|
295
|
+
antipaddiam="600um",
|
|
296
|
+
startlayer=None,
|
|
297
|
+
endlayer=None,
|
|
298
|
+
):
|
|
299
|
+
"""Create a circular padstack.
|
|
300
|
+
|
|
301
|
+
Parameters
|
|
302
|
+
----------
|
|
303
|
+
padstackname : str, optional
|
|
304
|
+
Name of the padstack. The default is ``None``.
|
|
305
|
+
holediam : str, optional
|
|
306
|
+
Diameter of the hole with units. The default is ``"300um"``.
|
|
307
|
+
paddiam : str, optional
|
|
308
|
+
Diameter of the pad with units. The default is ``"400um"``.
|
|
309
|
+
antipaddiam : str, optional
|
|
310
|
+
Diameter of the antipad with units. The default is ``"600um"``.
|
|
311
|
+
startlayer : str, optional
|
|
312
|
+
Starting layer. The default is ``None``, in which case the top
|
|
313
|
+
is the starting layer.
|
|
314
|
+
endlayer : str, optional
|
|
315
|
+
Ending layer. The default is ``None``, in which case the bottom
|
|
316
|
+
is the ending layer.
|
|
317
|
+
|
|
318
|
+
Returns
|
|
319
|
+
-------
|
|
320
|
+
str
|
|
321
|
+
Name of the padstack if the operation is successful.
|
|
322
|
+
"""
|
|
323
|
+
|
|
324
|
+
PadStack = self._edb.definition.PadstackDef.Create(self._layout.cell.GetDatabase(), padstackname)
|
|
325
|
+
new_PadStackData = self._edb.definition.PadstackDefData.Create()
|
|
326
|
+
list_values = convert_py_list_to_net_list(
|
|
327
|
+
[self._get_edb_value(holediam), self._get_edb_value(paddiam), self._get_edb_value(antipaddiam)]
|
|
328
|
+
)
|
|
329
|
+
value0 = self._get_edb_value(0.0)
|
|
330
|
+
new_PadStackData.SetHoleParameters(
|
|
331
|
+
self._edb.definition.PadGeometryType.Circle,
|
|
332
|
+
list_values,
|
|
333
|
+
value0,
|
|
334
|
+
value0,
|
|
335
|
+
value0,
|
|
336
|
+
)
|
|
337
|
+
new_PadStackData.SetHoleRange(self._edb.definition.PadstackHoleRange.UpperPadToLowerPad)
|
|
338
|
+
layers = list(self._pedb.stackup.signal_layers.keys())
|
|
339
|
+
if not startlayer:
|
|
340
|
+
startlayer = layers[0]
|
|
341
|
+
if not endlayer:
|
|
342
|
+
endlayer = layers[len(layers) - 1]
|
|
343
|
+
|
|
344
|
+
antipad_shape = self._edb.definition.PadGeometryType.Circle
|
|
345
|
+
started = False
|
|
346
|
+
new_PadStackData.SetPadParameters(
|
|
347
|
+
"Default",
|
|
348
|
+
self._edb.definition.PadType.RegularPad,
|
|
349
|
+
self._edb.definition.PadGeometryType.Circle,
|
|
350
|
+
convert_py_list_to_net_list([self._get_edb_value(paddiam)]),
|
|
351
|
+
value0,
|
|
352
|
+
value0,
|
|
353
|
+
value0,
|
|
354
|
+
)
|
|
355
|
+
|
|
356
|
+
new_PadStackData.SetPadParameters(
|
|
357
|
+
"Default",
|
|
358
|
+
self._edb.definition.PadType.AntiPad,
|
|
359
|
+
antipad_shape,
|
|
360
|
+
convert_py_list_to_net_list([self._get_edb_value(antipaddiam)]),
|
|
361
|
+
value0,
|
|
362
|
+
value0,
|
|
363
|
+
value0,
|
|
364
|
+
)
|
|
365
|
+
for layer in layers:
|
|
366
|
+
if layer == startlayer:
|
|
367
|
+
started = True
|
|
368
|
+
if layer == endlayer:
|
|
369
|
+
started = False
|
|
370
|
+
if started:
|
|
371
|
+
new_PadStackData.SetPadParameters(
|
|
372
|
+
layer,
|
|
373
|
+
self._edb.definition.PadType.RegularPad,
|
|
374
|
+
self._edb.definition.PadGeometryType.Circle,
|
|
375
|
+
convert_py_list_to_net_list([self._get_edb_value(paddiam)]),
|
|
376
|
+
value0,
|
|
377
|
+
value0,
|
|
378
|
+
value0,
|
|
379
|
+
)
|
|
380
|
+
new_PadStackData.SetPadParameters(
|
|
381
|
+
layer,
|
|
382
|
+
self._edb.definition.PadType.AntiPad,
|
|
383
|
+
antipad_shape,
|
|
384
|
+
convert_py_list_to_net_list([self._get_edb_value(antipaddiam)]),
|
|
385
|
+
value0,
|
|
386
|
+
value0,
|
|
387
|
+
value0,
|
|
388
|
+
)
|
|
389
|
+
PadStack.SetData(new_PadStackData)
|
|
390
|
+
|
|
391
|
+
@pyedb_function_handler()
|
|
392
|
+
def delete_padstack_instances(self, net_names): # pragma: no cover
|
|
393
|
+
"""Delete padstack instances by net names.
|
|
394
|
+
|
|
395
|
+
Parameters
|
|
396
|
+
----------
|
|
397
|
+
net_names : str, list
|
|
398
|
+
Names of the nets to delete.
|
|
399
|
+
|
|
400
|
+
Returns
|
|
401
|
+
-------
|
|
402
|
+
bool
|
|
403
|
+
``True`` when successful, ``False`` when failed.
|
|
404
|
+
|
|
405
|
+
References
|
|
406
|
+
----------
|
|
407
|
+
|
|
408
|
+
>>> Edb.padstacks.delete_padstack_instances(net_names=["GND"])
|
|
409
|
+
"""
|
|
410
|
+
if not isinstance(net_names, list): # pragma: no cover
|
|
411
|
+
net_names = [net_names]
|
|
412
|
+
|
|
413
|
+
for p_id, p in self.instances.items():
|
|
414
|
+
if p.net_name in net_names:
|
|
415
|
+
if not p.delete(): # pragma: no cover
|
|
416
|
+
return False
|
|
417
|
+
return True
|
|
418
|
+
|
|
419
|
+
@pyedb_function_handler()
|
|
420
|
+
def set_solderball(self, padstackInst, sballLayer_name, isTopPlaced=True, ballDiam=100e-6):
|
|
421
|
+
"""Set solderball for the given PadstackInstance.
|
|
422
|
+
|
|
423
|
+
Parameters
|
|
424
|
+
----------
|
|
425
|
+
padstackInst : Edb.Cell.Primitive.PadstackInstance or int
|
|
426
|
+
Padstack instance id or object.
|
|
427
|
+
sballLayer_name : str,
|
|
428
|
+
Name of the layer where the solder ball is placed. No default values.
|
|
429
|
+
isTopPlaced : bool, optional.
|
|
430
|
+
Bollean triggering is the solder ball is placed on Top or Bottom of the layer stackup.
|
|
431
|
+
ballDiam : double, optional,
|
|
432
|
+
Solder ball diameter value.
|
|
433
|
+
|
|
434
|
+
Returns
|
|
435
|
+
-------
|
|
436
|
+
bool
|
|
437
|
+
|
|
438
|
+
"""
|
|
439
|
+
if isinstance(padstackInst, int):
|
|
440
|
+
psdef = self.definitions[self.instances[padstackInst].padstack_definition].edb_padstack
|
|
441
|
+
padstackInst = self.instances[padstackInst]._edb_padstackinstance
|
|
442
|
+
|
|
443
|
+
else:
|
|
444
|
+
psdef = padstackInst.GetPadstackDef()
|
|
445
|
+
newdefdata = self._edb.definition.PadstackDefData(psdef.GetData())
|
|
446
|
+
newdefdata.SetSolderBallShape(self._edb.definition.SolderballShape.Cylinder)
|
|
447
|
+
newdefdata.SetSolderBallParameter(self._get_edb_value(ballDiam), self._get_edb_value(ballDiam))
|
|
448
|
+
sball_placement = (
|
|
449
|
+
self._edb.definition.SolderballPlacement.AbovePadstack
|
|
450
|
+
if isTopPlaced
|
|
451
|
+
else self._edb.definition.SolderballPlacement.BelowPadstack
|
|
452
|
+
)
|
|
453
|
+
newdefdata.SetSolderBallPlacement(sball_placement)
|
|
454
|
+
psdef.SetData(newdefdata)
|
|
455
|
+
sball_layer = [lay._edb_layer for lay in list(self._layers.values()) if lay.name == sballLayer_name][0]
|
|
456
|
+
if sball_layer is not None:
|
|
457
|
+
padstackInst.SetSolderBallLayer(sball_layer)
|
|
458
|
+
return True
|
|
459
|
+
|
|
460
|
+
return False
|
|
461
|
+
|
|
462
|
+
@pyedb_function_handler()
|
|
463
|
+
def create_coax_port(self, padstackinstance, use_dot_separator=True, name=None):
|
|
464
|
+
"""Create HFSS 3Dlayout coaxial lumped port on a pastack
|
|
465
|
+
Requires to have solder ball defined before calling this method.
|
|
466
|
+
|
|
467
|
+
Parameters
|
|
468
|
+
----------
|
|
469
|
+
padstackinstance : `Edb.Cell.Primitive.PadstackInstance` or int
|
|
470
|
+
Padstack instance object.
|
|
471
|
+
use_dot_separator : bool, optional
|
|
472
|
+
Whether to use ``.`` as the separator for the naming convention, which
|
|
473
|
+
is ``[component][net][pin]``. The default is ``True``. If ``False``, ``_`` is
|
|
474
|
+
used as the separator instead.
|
|
475
|
+
name : str
|
|
476
|
+
Port name for overwriting the default port-naming convention,
|
|
477
|
+
which is ``[component][net][pin]``. The port name must be unique.
|
|
478
|
+
If a port with the specified name already exists, the
|
|
479
|
+
default naming convention is used so that port creation does
|
|
480
|
+
not fail.
|
|
481
|
+
|
|
482
|
+
Returns
|
|
483
|
+
-------
|
|
484
|
+
str
|
|
485
|
+
Terminal name.
|
|
486
|
+
|
|
487
|
+
"""
|
|
488
|
+
if isinstance(padstackinstance, int):
|
|
489
|
+
padstackinstance = self.instances[padstackinstance]._edb_padstackinstance
|
|
490
|
+
elif isinstance(padstackinstance, EDBPadstackInstance):
|
|
491
|
+
padstackinstance = padstackinstance._edb_padstackinstance
|
|
492
|
+
cmp_name = padstackinstance.GetComponent().GetName()
|
|
493
|
+
if cmp_name == "":
|
|
494
|
+
cmp_name = "no_comp"
|
|
495
|
+
net_name = padstackinstance.GetNet().GetName()
|
|
496
|
+
if net_name == "":
|
|
497
|
+
net_name = "no_net"
|
|
498
|
+
pin_name = padstackinstance.GetName()
|
|
499
|
+
if pin_name == "":
|
|
500
|
+
pin_name = "no_pin_name"
|
|
501
|
+
if use_dot_separator:
|
|
502
|
+
port_name = "{0}.{1}.{2}".format(cmp_name, pin_name, net_name)
|
|
503
|
+
else:
|
|
504
|
+
port_name = "{0}_{1}_{2}".format(cmp_name, pin_name, net_name)
|
|
505
|
+
if not padstackinstance.IsLayoutPin():
|
|
506
|
+
padstackinstance.SetIsLayoutPin(True)
|
|
507
|
+
res = padstackinstance.GetLayerRange()
|
|
508
|
+
if name:
|
|
509
|
+
port_name = name
|
|
510
|
+
if self._port_exist(port_name):
|
|
511
|
+
port_name = generate_unique_name(port_name, n=2)
|
|
512
|
+
self._logger.info("An existing port already has this same name. Renaming to {}.".format(port_name))
|
|
513
|
+
self._edb.cell.terminal.PadstackInstanceTerminal.Create(
|
|
514
|
+
self._active_layout,
|
|
515
|
+
padstackinstance.GetNet(),
|
|
516
|
+
port_name,
|
|
517
|
+
padstackinstance,
|
|
518
|
+
res[2],
|
|
519
|
+
)
|
|
520
|
+
if res[0]:
|
|
521
|
+
return port_name
|
|
522
|
+
return ""
|
|
523
|
+
|
|
524
|
+
@pyedb_function_handler()
|
|
525
|
+
def _port_exist(self, port_name):
|
|
526
|
+
return any(port for port in list(self._pedb.excitations.keys()) if port == port_name)
|
|
527
|
+
|
|
528
|
+
@pyedb_function_handler()
|
|
529
|
+
def get_pinlist_from_component_and_net(self, refdes=None, netname=None):
|
|
530
|
+
"""Retrieve pins given a component's reference designator and net name.
|
|
531
|
+
|
|
532
|
+
Parameters
|
|
533
|
+
----------
|
|
534
|
+
refdes : str, optional
|
|
535
|
+
Reference designator of the component. The default is ``None``.
|
|
536
|
+
netname : str optional
|
|
537
|
+
Name of the net. The default is ``None``.
|
|
538
|
+
|
|
539
|
+
Returns
|
|
540
|
+
-------
|
|
541
|
+
dict
|
|
542
|
+
Dictionary of pins if the operation is successful.
|
|
543
|
+
``False`` is returned if the net does not belong to the component.
|
|
544
|
+
|
|
545
|
+
"""
|
|
546
|
+
pinlist = []
|
|
547
|
+
if refdes:
|
|
548
|
+
if refdes in self._pedb.components.components:
|
|
549
|
+
if netname:
|
|
550
|
+
for pin, val in self._pedb.components.components[refdes].pins.items():
|
|
551
|
+
if val.net_name == netname:
|
|
552
|
+
pinlist.append(val)
|
|
553
|
+
else:
|
|
554
|
+
for pin in self._pedb.components.components[refdes].pins.values():
|
|
555
|
+
pinlist.append(pin)
|
|
556
|
+
elif netname:
|
|
557
|
+
for pin in self._pedb.pins:
|
|
558
|
+
if pin.net_name == netname:
|
|
559
|
+
pinlist.append(pin)
|
|
560
|
+
else:
|
|
561
|
+
self._logger.error("At least a component or a net name has to be provided")
|
|
562
|
+
|
|
563
|
+
return pinlist
|
|
564
|
+
|
|
565
|
+
@pyedb_function_handler()
|
|
566
|
+
def get_pad_parameters(self, pin, layername, pad_type=0):
|
|
567
|
+
"""Get Padstack Parameters from Pin or Padstack Definition.
|
|
568
|
+
|
|
569
|
+
Parameters
|
|
570
|
+
----------
|
|
571
|
+
pin : Edb.definition.PadstackDef or Edb.definition.PadstackInstance
|
|
572
|
+
Pin or PadstackDef on which get values.
|
|
573
|
+
layername : str
|
|
574
|
+
Layer on which get properties.
|
|
575
|
+
pad_type : int
|
|
576
|
+
Pad Type.
|
|
577
|
+
|
|
578
|
+
Returns
|
|
579
|
+
-------
|
|
580
|
+
tuple
|
|
581
|
+
Tuple of (GeometryType, ParameterList, OffsetX, OffsetY, Rot).
|
|
582
|
+
"""
|
|
583
|
+
|
|
584
|
+
if "PadstackDef" in str(type(pin)):
|
|
585
|
+
padparams = pin.GetData().GetPadParametersValue(layername, self.int_to_pad_type(pad_type))
|
|
586
|
+
else:
|
|
587
|
+
padparams = self._edb.definition.PadstackDefData(pin.GetPadstackDef().GetData()).GetPadParametersValue(
|
|
588
|
+
layername, self.int_to_pad_type(pad_type)
|
|
589
|
+
)
|
|
590
|
+
if padparams[2]:
|
|
591
|
+
geometry_type = int(padparams[1])
|
|
592
|
+
parameters = [i.ToString() for i in padparams[2]]
|
|
593
|
+
offset_x = padparams[3].ToDouble()
|
|
594
|
+
offset_y = padparams[4].ToDouble()
|
|
595
|
+
rotation = padparams[5].ToDouble()
|
|
596
|
+
return geometry_type, parameters, offset_x, offset_y, rotation
|
|
597
|
+
else:
|
|
598
|
+
if isinstance(pin, self._edb.definition.PadstackDef):
|
|
599
|
+
padparams = self._edb.definition.PadstackDefData(pin.GetData()).GetPolygonalPadParameters(
|
|
600
|
+
layername, self.int_to_pad_type(pad_type)
|
|
601
|
+
)
|
|
602
|
+
else:
|
|
603
|
+
padparams = self._edb.definition.PadstackDefData(
|
|
604
|
+
pin.GetPadstackDef().GetData()
|
|
605
|
+
).GetPolygonalPadParameters(layername, self.int_to_pad_type(pad_type))
|
|
606
|
+
|
|
607
|
+
if padparams[0]:
|
|
608
|
+
parameters = [
|
|
609
|
+
padparams[1].GetBBox().Item1.X.ToDouble(),
|
|
610
|
+
padparams[1].GetBBox().Item1.Y.ToDouble(),
|
|
611
|
+
padparams[1].GetBBox().Item2.X.ToDouble(),
|
|
612
|
+
padparams[1].GetBBox().Item2.Y.ToDouble(),
|
|
613
|
+
]
|
|
614
|
+
offset_x = padparams[2]
|
|
615
|
+
offset_y = padparams[3]
|
|
616
|
+
rotation = padparams[4]
|
|
617
|
+
geometry_type = 7
|
|
618
|
+
return geometry_type, parameters, offset_x, offset_y, rotation
|
|
619
|
+
return 0, [0], 0, 0, 0
|
|
620
|
+
|
|
621
|
+
@pyedb_function_handler()
|
|
622
|
+
def set_all_antipad_value(self, value):
|
|
623
|
+
"""Set all anti-pads from all pad-stack definition to the given value.
|
|
624
|
+
|
|
625
|
+
Parameters
|
|
626
|
+
----------
|
|
627
|
+
value : float, str
|
|
628
|
+
Anti-pad value.
|
|
629
|
+
|
|
630
|
+
Returns
|
|
631
|
+
-------
|
|
632
|
+
bool
|
|
633
|
+
``True`` when successful, ``False`` if an anti-pad value fails to be assigned.
|
|
634
|
+
"""
|
|
635
|
+
if self.definitions:
|
|
636
|
+
for padstack in list(self.definitions.values()):
|
|
637
|
+
cloned_padstack_data = self._edb.definition.PadstackDefData(padstack.edb_padstack.GetData())
|
|
638
|
+
layers_name = cloned_padstack_data.GetLayerNames()
|
|
639
|
+
all_succeed = True
|
|
640
|
+
for layer in layers_name:
|
|
641
|
+
geom_type, parameters, offset_x, offset_y, rot = self.get_pad_parameters(
|
|
642
|
+
padstack.edb_padstack, layer, 1
|
|
643
|
+
)
|
|
644
|
+
if geom_type == 1: # pragma no cover
|
|
645
|
+
params = convert_py_list_to_net_list(
|
|
646
|
+
[self._pedb.edb_value(value)] * len(parameters)
|
|
647
|
+
) # pragma no cover
|
|
648
|
+
geom = self._edb.definition.PadGeometryType.Circle
|
|
649
|
+
offset_x = self._pedb.edb_value(offset_x)
|
|
650
|
+
offset_y = self._pedb.edb_value(offset_y)
|
|
651
|
+
rot = self._pedb.edb_value(rot)
|
|
652
|
+
antipad = self._edb.definition.PadType.AntiPad
|
|
653
|
+
if cloned_padstack_data.SetPadParameters(
|
|
654
|
+
layer, antipad, geom, params, offset_x, offset_y, rot
|
|
655
|
+
): # pragma no cover
|
|
656
|
+
self._logger.info(
|
|
657
|
+
"Pad-stack definition {}, anti-pad on layer {}, has been set to {}".format(
|
|
658
|
+
padstack.edb_padstack.GetName(), layer, str(value)
|
|
659
|
+
)
|
|
660
|
+
)
|
|
661
|
+
else: # pragma no cover
|
|
662
|
+
self._logger.error(
|
|
663
|
+
"Failed to reassign anti-pad value {} on Pads-stack definition {},"
|
|
664
|
+
" layer{}".format(str(value), padstack.edb_padstack.GetName(), layer)
|
|
665
|
+
)
|
|
666
|
+
all_succeed = False
|
|
667
|
+
padstack.edb_padstack.SetData(cloned_padstack_data)
|
|
668
|
+
return all_succeed
|
|
669
|
+
|
|
670
|
+
@pyedb_function_handler()
|
|
671
|
+
def check_and_fix_via_plating(self, minimum_value_to_replace=0.0, default_plating_ratio=0.2):
|
|
672
|
+
"""Check for minimum via plating ration value, values found below the minimum one are replaced by default
|
|
673
|
+
plating ratio.
|
|
674
|
+
|
|
675
|
+
Parameters
|
|
676
|
+
----------
|
|
677
|
+
minimum_value_to_replace : float
|
|
678
|
+
Plating ratio that is below or equal to this value is to be replaced
|
|
679
|
+
with the value specified for the next parameter. Default value ``0.0``.
|
|
680
|
+
default_plating_ratio : float
|
|
681
|
+
Default value to use for plating ratio. The default value is ``0.2``.
|
|
682
|
+
|
|
683
|
+
Returns
|
|
684
|
+
-------
|
|
685
|
+
bool
|
|
686
|
+
``True`` when successful, ``False`` if an anti-pad value fails to be assigned.
|
|
687
|
+
"""
|
|
688
|
+
for padstack_def in list(self.definitions.values()):
|
|
689
|
+
if padstack_def.hole_plating_ratio <= minimum_value_to_replace:
|
|
690
|
+
padstack_def.hole_plating_ratio = default_plating_ratio
|
|
691
|
+
self._logger.info(
|
|
692
|
+
"Padstack definition with zero plating ratio, defaulting to 20%".format(padstack_def.name)
|
|
693
|
+
)
|
|
694
|
+
return True
|
|
695
|
+
|
|
696
|
+
@pyedb_function_handler()
|
|
697
|
+
def get_via_instance_from_net(self, net_list=None):
|
|
698
|
+
"""Get the list for EDB vias from a net name list.
|
|
699
|
+
|
|
700
|
+
Parameters
|
|
701
|
+
----------
|
|
702
|
+
net_list : str or list
|
|
703
|
+
The list of the net name to be used for filtering vias. If no net is provided the command will
|
|
704
|
+
return an all vias list.
|
|
705
|
+
|
|
706
|
+
Returns
|
|
707
|
+
-------
|
|
708
|
+
list of Edb.Cell.Primitive.PadstackInstance
|
|
709
|
+
List of EDB vias.
|
|
710
|
+
"""
|
|
711
|
+
if net_list == None:
|
|
712
|
+
net_list = []
|
|
713
|
+
|
|
714
|
+
if not isinstance(net_list, list):
|
|
715
|
+
net_list = [net_list]
|
|
716
|
+
layout_lobj_collection = self._layout.padstack_instances
|
|
717
|
+
via_list = []
|
|
718
|
+
for lobj in layout_lobj_collection:
|
|
719
|
+
pad_layers_name = lobj.GetPadstackDef().GetData().GetLayerNames()
|
|
720
|
+
if len(pad_layers_name) > 1:
|
|
721
|
+
if not net_list:
|
|
722
|
+
via_list.append(lobj)
|
|
723
|
+
elif lobj.GetNet().GetName() in net_list:
|
|
724
|
+
via_list.append(lobj)
|
|
725
|
+
return via_list
|
|
726
|
+
|
|
727
|
+
@pyedb_function_handler()
|
|
728
|
+
def create_padstack(
|
|
729
|
+
self,
|
|
730
|
+
padstackname=None,
|
|
731
|
+
holediam="300um",
|
|
732
|
+
paddiam="400um",
|
|
733
|
+
antipaddiam="600um",
|
|
734
|
+
startlayer=None,
|
|
735
|
+
endlayer=None,
|
|
736
|
+
antipad_shape="Circle",
|
|
737
|
+
x_size="600um",
|
|
738
|
+
y_size="600um",
|
|
739
|
+
corner_radius="300um",
|
|
740
|
+
offset_x="0.0",
|
|
741
|
+
offset_y="0.0",
|
|
742
|
+
rotation="0.0",
|
|
743
|
+
has_hole=True,
|
|
744
|
+
pad_offset_x="0.0",
|
|
745
|
+
pad_offset_y="0.0",
|
|
746
|
+
pad_rotation="0.0",
|
|
747
|
+
): # pragma: no cover
|
|
748
|
+
"""Create a padstack.
|
|
749
|
+
|
|
750
|
+
.. deprecated:: 0.6.62
|
|
751
|
+
Use :func:`create` method instead.
|
|
752
|
+
|
|
753
|
+
Parameters
|
|
754
|
+
----------
|
|
755
|
+
padstackname : str, optional
|
|
756
|
+
Name of the padstack. The default is ``None``.
|
|
757
|
+
holediam : str, optional
|
|
758
|
+
Diameter of the hole with units. The default is ``"300um"``.
|
|
759
|
+
paddiam : str, optional
|
|
760
|
+
Diameter of the pad with units. The default is ``"400um"``.
|
|
761
|
+
antipaddiam : str, optional
|
|
762
|
+
Diameter of the antipad with units. The default is ``"600um"``.
|
|
763
|
+
startlayer : str, optional
|
|
764
|
+
Starting layer. The default is ``None``, in which case the top
|
|
765
|
+
is the starting layer.
|
|
766
|
+
endlayer : str, optional
|
|
767
|
+
Ending layer. The default is ``None``, in which case the bottom
|
|
768
|
+
is the ending layer.
|
|
769
|
+
antipad_shape : str, optional
|
|
770
|
+
Shape of the antipad. The default is ``"Circle"``. Options are ``"Circle"`` and ``"Bullet"``.
|
|
771
|
+
x_size : str, optional
|
|
772
|
+
Only applicable to bullet shape. The default is ``"600um"``.
|
|
773
|
+
y_size : str, optional
|
|
774
|
+
Only applicable to bullet shape. The default is ``"600um"``.
|
|
775
|
+
corner_radius :
|
|
776
|
+
Only applicable to bullet shape. The default is ``"300um"``.
|
|
777
|
+
offset_x : str, optional
|
|
778
|
+
X offset of antipad. The default is ``"0.0"``.
|
|
779
|
+
offset_y : str, optional
|
|
780
|
+
Y offset of antipad. The default is ``"0.0"``.
|
|
781
|
+
rotation : str, optional
|
|
782
|
+
rotation of antipad. The default is ``"0.0"``.
|
|
783
|
+
has_hole : bool, optional
|
|
784
|
+
Whether this padstack has a hole.
|
|
785
|
+
|
|
786
|
+
Returns
|
|
787
|
+
-------
|
|
788
|
+
str
|
|
789
|
+
Name of the padstack if the operation is successful.
|
|
790
|
+
"""
|
|
791
|
+
warnings.warn("Use :func:`create` method instead.", DeprecationWarning)
|
|
792
|
+
return self.create(
|
|
793
|
+
padstackname=padstackname,
|
|
794
|
+
holediam=holediam,
|
|
795
|
+
paddiam=paddiam,
|
|
796
|
+
antipaddiam=antipaddiam,
|
|
797
|
+
antipad_shape=antipad_shape,
|
|
798
|
+
x_size=x_size,
|
|
799
|
+
y_size=y_size,
|
|
800
|
+
corner_radius=corner_radius,
|
|
801
|
+
offset_x=offset_x,
|
|
802
|
+
offset_y=offset_y,
|
|
803
|
+
rotation=rotation,
|
|
804
|
+
has_hole=has_hole,
|
|
805
|
+
pad_offset_x=pad_offset_x,
|
|
806
|
+
pad_offset_y=pad_offset_y,
|
|
807
|
+
pad_rotation=pad_rotation,
|
|
808
|
+
)
|
|
809
|
+
|
|
810
|
+
@pyedb_function_handler()
|
|
811
|
+
def create(
|
|
812
|
+
self,
|
|
813
|
+
padstackname=None,
|
|
814
|
+
holediam="300um",
|
|
815
|
+
paddiam="400um",
|
|
816
|
+
antipaddiam="600um",
|
|
817
|
+
pad_shape="Circle",
|
|
818
|
+
antipad_shape="Circle",
|
|
819
|
+
x_size="600um",
|
|
820
|
+
y_size="600um",
|
|
821
|
+
corner_radius="300um",
|
|
822
|
+
offset_x="0.0",
|
|
823
|
+
offset_y="0.0",
|
|
824
|
+
rotation="0.0",
|
|
825
|
+
has_hole=True,
|
|
826
|
+
pad_offset_x="0.0",
|
|
827
|
+
pad_offset_y="0.0",
|
|
828
|
+
pad_rotation="0.0",
|
|
829
|
+
start_layer=None,
|
|
830
|
+
stop_layer=None,
|
|
831
|
+
add_default_layer=False,
|
|
832
|
+
anti_pad_x_size="600um",
|
|
833
|
+
anti_pad_y_size="600um",
|
|
834
|
+
hole_range="upper_pad_to_lower_pad",
|
|
835
|
+
):
|
|
836
|
+
"""Create a padstack.
|
|
837
|
+
|
|
838
|
+
Parameters
|
|
839
|
+
----------
|
|
840
|
+
padstackname : str, optional
|
|
841
|
+
Name of the padstack. The default is ``None``.
|
|
842
|
+
holediam : str, optional
|
|
843
|
+
Diameter of the hole with units. The default is ``"300um"``.
|
|
844
|
+
paddiam : str, optional
|
|
845
|
+
Diameter of the pad with units, used with ``"Circle"`` shape. The default is ``"400um"``.
|
|
846
|
+
antipaddiam : str, optional
|
|
847
|
+
Diameter of the antipad with units. The default is ``"600um"``.
|
|
848
|
+
pad_shape : str, optional
|
|
849
|
+
Shape of the pad. The default is ``"Circle``. Options are ``"Circle"`` and ``"Rectangle"``.
|
|
850
|
+
antipad_shape : str, optional
|
|
851
|
+
Shape of the antipad. The default is ``"Circle"``. Options are ``"Circle"`` ``"Rectangle"`` and
|
|
852
|
+
``"Bullet"``.
|
|
853
|
+
x_size : str, optional
|
|
854
|
+
Only applicable to bullet and rectangle shape. The default is ``"600um"``.
|
|
855
|
+
y_size : str, optional
|
|
856
|
+
Only applicable to bullet and rectangle shape. The default is ``"600um"``.
|
|
857
|
+
corner_radius :
|
|
858
|
+
Only applicable to bullet shape. The default is ``"300um"``.
|
|
859
|
+
offset_x : str, optional
|
|
860
|
+
X offset of antipad. The default is ``"0.0"``.
|
|
861
|
+
offset_y : str, optional
|
|
862
|
+
Y offset of antipad. The default is ``"0.0"``.
|
|
863
|
+
rotation : str, optional
|
|
864
|
+
rotation of antipad. The default is ``"0.0"``.
|
|
865
|
+
has_hole : bool, optional
|
|
866
|
+
Whether this padstack has a hole.
|
|
867
|
+
pad_offset_x : str, optional
|
|
868
|
+
Padstack offset in X direction.
|
|
869
|
+
pad_offset_y : str, optional
|
|
870
|
+
Padstack offset in Y direction.
|
|
871
|
+
pad_rotation : str, optional
|
|
872
|
+
Padstack rotation.
|
|
873
|
+
start_layer : str, optional
|
|
874
|
+
Start layer of the padstack definition.
|
|
875
|
+
stop_layer : str, optional
|
|
876
|
+
Stop layer of the padstack definition.
|
|
877
|
+
add_default_layer : bool, optional
|
|
878
|
+
Add ``"Default"`` to padstack definition. Default is ``False``.
|
|
879
|
+
anti_pad_x_size : str, optional
|
|
880
|
+
Only applicable to bullet and rectangle shape. The default is ``"600um"``.
|
|
881
|
+
anti_pad_y_size : str, optional
|
|
882
|
+
Only applicable to bullet and rectangle shape. The default is ``"600um"``.
|
|
883
|
+
hole_range : str, optional
|
|
884
|
+
Define the padstack hole range. Arguments supported, ``"through"``, ``"begin_on_upper_pad"``,
|
|
885
|
+
``"end_on_lower_pad"``, ``"upper_pad_to_lower_pad"``.
|
|
886
|
+
|
|
887
|
+
Returns
|
|
888
|
+
-------
|
|
889
|
+
str
|
|
890
|
+
Name of the padstack if the operation is successful.
|
|
891
|
+
"""
|
|
892
|
+
holediam = self._get_edb_value(holediam)
|
|
893
|
+
paddiam = self._get_edb_value(paddiam)
|
|
894
|
+
antipaddiam = self._get_edb_value(antipaddiam)
|
|
895
|
+
|
|
896
|
+
if not padstackname:
|
|
897
|
+
padstackname = generate_unique_name("VIA")
|
|
898
|
+
# assert not self.isreadonly, "Write Functions are not available within AEDT"
|
|
899
|
+
padstackData = self._edb.definition.PadstackDefData.Create()
|
|
900
|
+
if has_hole:
|
|
901
|
+
ptype = self._edb.definition.PadGeometryType.Circle
|
|
902
|
+
else:
|
|
903
|
+
ptype = self._edb.definition.PadGeometryType.NoGeometry
|
|
904
|
+
holparam = Array[type(holediam)]([holediam])
|
|
905
|
+
value0 = self._get_edb_value("0.0")
|
|
906
|
+
x_size = self._get_edb_value(x_size)
|
|
907
|
+
y_size = self._get_edb_value(y_size)
|
|
908
|
+
corner_radius = self._get_edb_value(corner_radius)
|
|
909
|
+
offset_x = self._get_edb_value(offset_x)
|
|
910
|
+
offset_y = self._get_edb_value(offset_y)
|
|
911
|
+
rotation = self._get_edb_value(rotation)
|
|
912
|
+
|
|
913
|
+
pad_offset_x = self._get_edb_value(pad_offset_x)
|
|
914
|
+
pad_offset_y = self._get_edb_value(pad_offset_y)
|
|
915
|
+
pad_rotation = self._get_edb_value(pad_rotation)
|
|
916
|
+
anti_pad_x_size = self._get_edb_value(anti_pad_x_size)
|
|
917
|
+
anti_pad_y_size = self._get_edb_value(anti_pad_y_size)
|
|
918
|
+
padstackData.SetHoleParameters(ptype, holparam, value0, value0, value0)
|
|
919
|
+
padstackData.SetHolePlatingPercentage(self._get_edb_value(20.0))
|
|
920
|
+
if hole_range == "through": # pragma no cover
|
|
921
|
+
padstackData.SetHoleRange(self._edb.definition.PadstackHoleRange.Through)
|
|
922
|
+
elif hole_range == "begin_on_upper_pad": # pragma no cover
|
|
923
|
+
padstackData.SetHoleRange(self._edb.definition.PadstackHoleRange.BeginOnUpperPad)
|
|
924
|
+
elif hole_range == "end_on_lower_pad": # pragma no cover
|
|
925
|
+
padstackData.SetHoleRange(self._edb.definition.PadstackHoleRange.EndOnLowerPad)
|
|
926
|
+
elif hole_range == "upper_pad_to_lower_pad": # pragma no cover
|
|
927
|
+
padstackData.SetHoleRange(self._edb.definition.PadstackHoleRange.UpperPadToLowerPad)
|
|
928
|
+
else: # pragma no cover
|
|
929
|
+
self._logger.error("Unknown padstack hole range")
|
|
930
|
+
padstackData.SetMaterial("copper")
|
|
931
|
+
layers = list(self._pedb.stackup.signal_layers.keys())[:]
|
|
932
|
+
if start_layer and start_layer in layers: # pragma no cover
|
|
933
|
+
layers = layers[layers.index(start_layer) :]
|
|
934
|
+
if stop_layer and stop_layer in layers: # pragma no cover
|
|
935
|
+
layers = layers[: layers.index(stop_layer) + 1]
|
|
936
|
+
pad_array = Array[type(paddiam)]([paddiam])
|
|
937
|
+
if pad_shape == "Circle": # pragma no cover
|
|
938
|
+
pad_shape = self._edb.definition.PadGeometryType.Circle
|
|
939
|
+
elif pad_shape == "Rectangle": # pragma no cover
|
|
940
|
+
pad_array = Array[type(x_size)]([x_size, y_size])
|
|
941
|
+
pad_shape = self._edb.definition.PadGeometryType.Rectangle
|
|
942
|
+
if antipad_shape == "Bullet": # pragma no cover
|
|
943
|
+
antipad_array = Array[type(x_size)]([x_size, y_size, corner_radius])
|
|
944
|
+
antipad_shape = self._edb.definition.PadGeometryType.Bullet
|
|
945
|
+
elif antipad_shape == "Rectangle": # pragma no cover
|
|
946
|
+
antipad_array = Array[type(anti_pad_x_size)]([anti_pad_x_size, anti_pad_y_size])
|
|
947
|
+
antipad_shape = self._edb.definition.PadGeometryType.Rectangle
|
|
948
|
+
else: # pragma no cover
|
|
949
|
+
antipad_array = Array[type(antipaddiam)]([antipaddiam])
|
|
950
|
+
antipad_shape = self._edb.definition.PadGeometryType.Circle
|
|
951
|
+
if add_default_layer: # pragma no cover
|
|
952
|
+
layers = layers + ["Default"]
|
|
953
|
+
for layer in layers:
|
|
954
|
+
padstackData.SetPadParameters(
|
|
955
|
+
layer,
|
|
956
|
+
self._edb.definition.PadType.RegularPad,
|
|
957
|
+
pad_shape,
|
|
958
|
+
pad_array,
|
|
959
|
+
pad_offset_x,
|
|
960
|
+
pad_offset_y,
|
|
961
|
+
pad_rotation,
|
|
962
|
+
)
|
|
963
|
+
|
|
964
|
+
padstackData.SetPadParameters(
|
|
965
|
+
layer,
|
|
966
|
+
self._edb.definition.PadType.AntiPad,
|
|
967
|
+
antipad_shape,
|
|
968
|
+
antipad_array,
|
|
969
|
+
offset_x,
|
|
970
|
+
offset_y,
|
|
971
|
+
rotation,
|
|
972
|
+
)
|
|
973
|
+
|
|
974
|
+
padstackDefinition = self._edb.definition.PadstackDef.Create(self.db, padstackname)
|
|
975
|
+
padstackDefinition.SetData(padstackData)
|
|
976
|
+
self._logger.info("Padstack %s create correctly", padstackname)
|
|
977
|
+
return padstackname
|
|
978
|
+
|
|
979
|
+
@pyedb_function_handler()
|
|
980
|
+
def _get_pin_layer_range(self, pin):
|
|
981
|
+
res, fromlayer, tolayer = pin.GetLayerRange()
|
|
982
|
+
if res:
|
|
983
|
+
return fromlayer, tolayer
|
|
984
|
+
else:
|
|
985
|
+
return False
|
|
986
|
+
|
|
987
|
+
@pyedb_function_handler()
|
|
988
|
+
def duplicate_padstack(self, target_padstack_name, new_padstack_name=""):
|
|
989
|
+
"""Duplicate a padstack.
|
|
990
|
+
|
|
991
|
+
.. deprecated:: 0.6.62
|
|
992
|
+
Use :func:`duplicate` method instead.
|
|
993
|
+
|
|
994
|
+
Parameters
|
|
995
|
+
----------
|
|
996
|
+
target_padstack_name : str
|
|
997
|
+
Name of the padstack to be duplicated.
|
|
998
|
+
new_padstack_name : str, optional
|
|
999
|
+
Name of the new padstack.
|
|
1000
|
+
|
|
1001
|
+
Returns
|
|
1002
|
+
-------
|
|
1003
|
+
str
|
|
1004
|
+
Name of the new padstack.
|
|
1005
|
+
"""
|
|
1006
|
+
warnings.warn("Use :func:`create` method instead.", DeprecationWarning)
|
|
1007
|
+
return self.duplicate(target_padstack_name=target_padstack_name, new_padstack_name=new_padstack_name)
|
|
1008
|
+
|
|
1009
|
+
@pyedb_function_handler()
|
|
1010
|
+
def duplicate(self, target_padstack_name, new_padstack_name=""):
|
|
1011
|
+
"""Duplicate a padstack.
|
|
1012
|
+
|
|
1013
|
+
Parameters
|
|
1014
|
+
----------
|
|
1015
|
+
target_padstack_name : str
|
|
1016
|
+
Name of the padstack to be duplicated.
|
|
1017
|
+
new_padstack_name : str, optional
|
|
1018
|
+
Name of the new padstack.
|
|
1019
|
+
|
|
1020
|
+
Returns
|
|
1021
|
+
-------
|
|
1022
|
+
str
|
|
1023
|
+
Name of the new padstack.
|
|
1024
|
+
"""
|
|
1025
|
+
p1 = self.definitions[target_padstack_name].edb_padstack.GetData()
|
|
1026
|
+
new_padstack_definition_data = self._edb.definition.PadstackDefData(p1)
|
|
1027
|
+
|
|
1028
|
+
if not new_padstack_name:
|
|
1029
|
+
new_padstack_name = generate_unique_name(target_padstack_name)
|
|
1030
|
+
|
|
1031
|
+
padstack_definition = self._edb.definition.PadstackDef.Create(self.db, new_padstack_name)
|
|
1032
|
+
padstack_definition.SetData(new_padstack_definition_data)
|
|
1033
|
+
|
|
1034
|
+
return new_padstack_name
|
|
1035
|
+
|
|
1036
|
+
@pyedb_function_handler()
|
|
1037
|
+
def place(
|
|
1038
|
+
self,
|
|
1039
|
+
position,
|
|
1040
|
+
definition_name,
|
|
1041
|
+
net_name="",
|
|
1042
|
+
via_name="",
|
|
1043
|
+
rotation=0.0,
|
|
1044
|
+
fromlayer=None,
|
|
1045
|
+
tolayer=None,
|
|
1046
|
+
solderlayer=None,
|
|
1047
|
+
is_pin=False,
|
|
1048
|
+
):
|
|
1049
|
+
"""Place a via.
|
|
1050
|
+
|
|
1051
|
+
Parameters
|
|
1052
|
+
----------
|
|
1053
|
+
position : list
|
|
1054
|
+
List of float values for the [x,y] positions where the via is to be placed.
|
|
1055
|
+
definition_name : str
|
|
1056
|
+
Name of the padstack definition.
|
|
1057
|
+
net_name : str, optional
|
|
1058
|
+
Name of the net. The default is ``""``.
|
|
1059
|
+
via_name : str, optional
|
|
1060
|
+
The default is ``""``.
|
|
1061
|
+
rotation : float, optional
|
|
1062
|
+
Rotation of the padstack in degrees. The default
|
|
1063
|
+
is ``0``.
|
|
1064
|
+
fromlayer :
|
|
1065
|
+
The default is ``None``.
|
|
1066
|
+
tolayer :
|
|
1067
|
+
The default is ``None``.
|
|
1068
|
+
solderlayer :
|
|
1069
|
+
The default is ``None``.
|
|
1070
|
+
is_pin : bool, optional
|
|
1071
|
+
Whether if the padstack is a pin or not. Default is `False`.
|
|
1072
|
+
|
|
1073
|
+
Returns
|
|
1074
|
+
-------
|
|
1075
|
+
:class:`dotnet.edb_core.edb_data.padstacks_data.EDBPadstackInstance`
|
|
1076
|
+
"""
|
|
1077
|
+
padstack = None
|
|
1078
|
+
for pad in list(self.definitions.keys()):
|
|
1079
|
+
if pad == definition_name:
|
|
1080
|
+
padstack = self.definitions[pad].edb_padstack
|
|
1081
|
+
position = self._edb.geometry.point_data(position[0], position[1])
|
|
1082
|
+
net = self._pedb.nets.find_or_create_net(net_name)
|
|
1083
|
+
rotation = self._get_edb_value(rotation * math.pi / 180)
|
|
1084
|
+
sign_layers_values = {i: v for i, v in self._pedb.stackup.signal_layers.items()}
|
|
1085
|
+
sign_layers = list(sign_layers_values.keys())
|
|
1086
|
+
if not fromlayer:
|
|
1087
|
+
try:
|
|
1088
|
+
fromlayer = sign_layers_values[list(self.definitions[pad].pad_by_layer.keys())[0]]._edb_layer
|
|
1089
|
+
except KeyError:
|
|
1090
|
+
fromlayer = sign_layers_values[sign_layers[0]]._edb_layer
|
|
1091
|
+
else:
|
|
1092
|
+
fromlayer = sign_layers_values[fromlayer]._edb_layer
|
|
1093
|
+
|
|
1094
|
+
if not tolayer:
|
|
1095
|
+
try:
|
|
1096
|
+
tolayer = sign_layers_values[list(self.definitions[pad].pad_by_layer.keys())[-1]]._edb_layer
|
|
1097
|
+
except KeyError:
|
|
1098
|
+
tolayer = sign_layers_values[sign_layers[-1]]._edb_layer
|
|
1099
|
+
else:
|
|
1100
|
+
tolayer = sign_layers_values[tolayer]._edb_layer
|
|
1101
|
+
if solderlayer:
|
|
1102
|
+
solderlayer = sign_layers_values[solderlayer]._edb_layer
|
|
1103
|
+
if padstack:
|
|
1104
|
+
padstack_instance = self._edb.cell.primitive.padstack_instance.create(
|
|
1105
|
+
self._active_layout,
|
|
1106
|
+
net,
|
|
1107
|
+
via_name,
|
|
1108
|
+
padstack,
|
|
1109
|
+
position,
|
|
1110
|
+
rotation,
|
|
1111
|
+
fromlayer,
|
|
1112
|
+
tolayer,
|
|
1113
|
+
solderlayer,
|
|
1114
|
+
None,
|
|
1115
|
+
)
|
|
1116
|
+
padstack_instance.SetIsLayoutPin(is_pin)
|
|
1117
|
+
py_padstack_instance = EDBPadstackInstance(padstack_instance.api_object, self._pedb)
|
|
1118
|
+
|
|
1119
|
+
return py_padstack_instance
|
|
1120
|
+
else:
|
|
1121
|
+
return False
|
|
1122
|
+
|
|
1123
|
+
@pyedb_function_handler()
|
|
1124
|
+
def place_padstack(
|
|
1125
|
+
self,
|
|
1126
|
+
position,
|
|
1127
|
+
definition_name,
|
|
1128
|
+
net_name="",
|
|
1129
|
+
via_name="",
|
|
1130
|
+
rotation=0.0,
|
|
1131
|
+
fromlayer=None,
|
|
1132
|
+
tolayer=None,
|
|
1133
|
+
solderlayer=None,
|
|
1134
|
+
is_pin=False,
|
|
1135
|
+
):
|
|
1136
|
+
"""Place the padstack.
|
|
1137
|
+
|
|
1138
|
+
.. deprecated:: 0.6.62
|
|
1139
|
+
Use :func:`place` method instead.
|
|
1140
|
+
|
|
1141
|
+
Parameters
|
|
1142
|
+
----------
|
|
1143
|
+
position : list
|
|
1144
|
+
List of float values for the [x,y] positions where the via is to be placed.
|
|
1145
|
+
definition_name : str
|
|
1146
|
+
Name of the padstack definition.
|
|
1147
|
+
net_name : str, optional
|
|
1148
|
+
Name of the net. The default is ``""``.
|
|
1149
|
+
via_name : str, optional
|
|
1150
|
+
The default is ``""``.
|
|
1151
|
+
rotation : float, optional
|
|
1152
|
+
Rotation of the padstack in degrees. The default
|
|
1153
|
+
is ``0``.
|
|
1154
|
+
fromlayer :
|
|
1155
|
+
The default is ``None``.
|
|
1156
|
+
tolayer :
|
|
1157
|
+
The default is ``None``.
|
|
1158
|
+
solderlayer :
|
|
1159
|
+
The default is ``None``.
|
|
1160
|
+
|
|
1161
|
+
Returns
|
|
1162
|
+
-------
|
|
1163
|
+
|
|
1164
|
+
"""
|
|
1165
|
+
warnings.warn(" Use :func:`place` method instead.", DeprecationWarning)
|
|
1166
|
+
return self.place(
|
|
1167
|
+
position=position,
|
|
1168
|
+
definition_name=definition_name,
|
|
1169
|
+
net_name=net_name,
|
|
1170
|
+
via_name=via_name,
|
|
1171
|
+
rotation=rotation,
|
|
1172
|
+
fromlayer=fromlayer,
|
|
1173
|
+
tolayer=tolayer,
|
|
1174
|
+
solderlayer=solderlayer,
|
|
1175
|
+
is_pin=is_pin,
|
|
1176
|
+
)
|
|
1177
|
+
|
|
1178
|
+
@pyedb_function_handler()
|
|
1179
|
+
def remove_pads_from_padstack(self, padstack_name, layer_name=None):
|
|
1180
|
+
"""Remove the Pad from a padstack on a specific layer by setting it as a 0 thickness circle.
|
|
1181
|
+
|
|
1182
|
+
Parameters
|
|
1183
|
+
----------
|
|
1184
|
+
padstack_name : str
|
|
1185
|
+
padstack name
|
|
1186
|
+
layer_name : str, optional
|
|
1187
|
+
Layer name on which remove the PadParameters. If None, all layers will be taken.
|
|
1188
|
+
|
|
1189
|
+
Returns
|
|
1190
|
+
-------
|
|
1191
|
+
bool
|
|
1192
|
+
``True`` if successful.
|
|
1193
|
+
"""
|
|
1194
|
+
pad_type = self._edb.definition.PadType.RegularPad
|
|
1195
|
+
pad_geo = self._edb.definition.PadGeometryType.Circle
|
|
1196
|
+
vals = self._get_edb_value(0)
|
|
1197
|
+
params = convert_py_list_to_net_list([self._get_edb_value(0)])
|
|
1198
|
+
p1 = self.definitions[padstack_name].edb_padstack.GetData()
|
|
1199
|
+
newPadstackDefinitionData = self._edb.definition.PadstackDefData(p1)
|
|
1200
|
+
|
|
1201
|
+
if not layer_name:
|
|
1202
|
+
layer_name = list(self._pedb.stackup.signal_layers.keys())
|
|
1203
|
+
elif isinstance(layer_name, str):
|
|
1204
|
+
layer_name = [layer_name]
|
|
1205
|
+
for lay in layer_name:
|
|
1206
|
+
newPadstackDefinitionData.SetPadParameters(lay, pad_type, pad_geo, params, vals, vals, vals)
|
|
1207
|
+
|
|
1208
|
+
self.definitions[padstack_name].edb_padstack.SetData(newPadstackDefinitionData)
|
|
1209
|
+
return True
|
|
1210
|
+
|
|
1211
|
+
@pyedb_function_handler()
|
|
1212
|
+
def set_pad_property(
|
|
1213
|
+
self,
|
|
1214
|
+
padstack_name,
|
|
1215
|
+
layer_name=None,
|
|
1216
|
+
pad_shape="Circle",
|
|
1217
|
+
pad_params=0,
|
|
1218
|
+
pad_x_offset=0,
|
|
1219
|
+
pad_y_offset=0,
|
|
1220
|
+
pad_rotation=0,
|
|
1221
|
+
antipad_shape="Circle",
|
|
1222
|
+
antipad_params=0,
|
|
1223
|
+
antipad_x_offset=0,
|
|
1224
|
+
antipad_y_offset=0,
|
|
1225
|
+
antipad_rotation=0,
|
|
1226
|
+
):
|
|
1227
|
+
"""Set pad and antipad properties of the padstack.
|
|
1228
|
+
|
|
1229
|
+
Parameters
|
|
1230
|
+
----------
|
|
1231
|
+
padstack_name : str
|
|
1232
|
+
Name of the padstack.
|
|
1233
|
+
layer_name : str, optional
|
|
1234
|
+
Name of the layer. If None, all layers will be taken.
|
|
1235
|
+
pad_shape : str, optional
|
|
1236
|
+
Shape of the pad. The default is ``"Circle"``. Options are ``"Circle"``, ``"Square"``, ``"Rectangle"``,
|
|
1237
|
+
``"Oval"`` and ``"Bullet"``.
|
|
1238
|
+
pad_params : str, optional
|
|
1239
|
+
Dimension of the pad. The default is ``"0"``.
|
|
1240
|
+
pad_x_offset : str, optional
|
|
1241
|
+
X offset of the pad. The default is ``"0"``.
|
|
1242
|
+
pad_y_offset : str, optional
|
|
1243
|
+
Y offset of the pad. The default is ``"0"``.
|
|
1244
|
+
pad_rotation : str, optional
|
|
1245
|
+
Rotation of the pad. The default is ``"0"``.
|
|
1246
|
+
antipad_shape : str, optional
|
|
1247
|
+
Shape of the antipad. The default is ``"0"``.
|
|
1248
|
+
antipad_params : str, optional
|
|
1249
|
+
Dimension of the antipad. The default is ``"0"``.
|
|
1250
|
+
antipad_x_offset : str, optional
|
|
1251
|
+
X offset of the antipad. The default is ``"0"``.
|
|
1252
|
+
antipad_y_offset : str, optional
|
|
1253
|
+
Y offset of the antipad. The default is ``"0"``.
|
|
1254
|
+
antipad_rotation : str, optional
|
|
1255
|
+
Rotation of the antipad. The default is ``"0"``.
|
|
1256
|
+
|
|
1257
|
+
Returns
|
|
1258
|
+
-------
|
|
1259
|
+
bool
|
|
1260
|
+
``True`` if successful.
|
|
1261
|
+
"""
|
|
1262
|
+
shape_dict = {
|
|
1263
|
+
"Circle": self._edb.definition.PadGeometryType.Circle,
|
|
1264
|
+
"Square": self._edb.definition.PadGeometryType.Square,
|
|
1265
|
+
"Rectangle": self._edb.definition.PadGeometryType.Rectangle,
|
|
1266
|
+
"Oval": self._edb.definition.PadGeometryType.Oval,
|
|
1267
|
+
"Bullet": self._edb.definition.PadGeometryType.Bullet,
|
|
1268
|
+
}
|
|
1269
|
+
pad_shape = shape_dict[pad_shape]
|
|
1270
|
+
if not isinstance(pad_params, list):
|
|
1271
|
+
pad_params = [pad_params]
|
|
1272
|
+
pad_params = convert_py_list_to_net_list([self._get_edb_value(i) for i in pad_params])
|
|
1273
|
+
pad_x_offset = self._get_edb_value(pad_x_offset)
|
|
1274
|
+
pad_y_offset = self._get_edb_value(pad_y_offset)
|
|
1275
|
+
pad_rotation = self._get_edb_value(pad_rotation)
|
|
1276
|
+
|
|
1277
|
+
antipad_shape = shape_dict[antipad_shape]
|
|
1278
|
+
if not isinstance(antipad_params, list):
|
|
1279
|
+
antipad_params = [antipad_params]
|
|
1280
|
+
antipad_params = convert_py_list_to_net_list([self._get_edb_value(i) for i in antipad_params])
|
|
1281
|
+
antipad_x_offset = self._get_edb_value(antipad_x_offset)
|
|
1282
|
+
antipad_y_offset = self._get_edb_value(antipad_y_offset)
|
|
1283
|
+
antipad_rotation = self._get_edb_value(antipad_rotation)
|
|
1284
|
+
|
|
1285
|
+
p1 = self.definitions[padstack_name].edb_padstack.GetData()
|
|
1286
|
+
new_padstack_def = self._edb.definition.PadstackDefData(p1)
|
|
1287
|
+
if not layer_name:
|
|
1288
|
+
layer_name = list(self._pedb.stackup.signal_layers.keys())
|
|
1289
|
+
elif isinstance(layer_name, str):
|
|
1290
|
+
layer_name = [layer_name]
|
|
1291
|
+
for layer in layer_name:
|
|
1292
|
+
new_padstack_def.SetPadParameters(
|
|
1293
|
+
layer,
|
|
1294
|
+
self._edb.definition.PadType.RegularPad,
|
|
1295
|
+
pad_shape,
|
|
1296
|
+
pad_params,
|
|
1297
|
+
pad_x_offset,
|
|
1298
|
+
pad_y_offset,
|
|
1299
|
+
pad_rotation,
|
|
1300
|
+
)
|
|
1301
|
+
new_padstack_def.SetPadParameters(
|
|
1302
|
+
layer,
|
|
1303
|
+
self._edb.definition.PadType.AntiPad,
|
|
1304
|
+
antipad_shape,
|
|
1305
|
+
antipad_params,
|
|
1306
|
+
antipad_x_offset,
|
|
1307
|
+
antipad_y_offset,
|
|
1308
|
+
antipad_rotation,
|
|
1309
|
+
)
|
|
1310
|
+
self.definitions[padstack_name].edb_padstack.SetData(new_padstack_def)
|
|
1311
|
+
return True
|
|
1312
|
+
|
|
1313
|
+
@pyedb_function_handler()
|
|
1314
|
+
def get_padstack_instance_by_net_name(self, net_name):
|
|
1315
|
+
"""Get a list of padstack instances by net name.
|
|
1316
|
+
|
|
1317
|
+
Parameters
|
|
1318
|
+
----------
|
|
1319
|
+
net_name : str
|
|
1320
|
+
The net name to be used for filtering padstack instances.
|
|
1321
|
+
|
|
1322
|
+
Returns
|
|
1323
|
+
-------
|
|
1324
|
+
list
|
|
1325
|
+
List of :class:`dotnet.edb_core.edb_data.padstacks_data.EDBPadstackInstance`.
|
|
1326
|
+
"""
|
|
1327
|
+
padstack_instances = []
|
|
1328
|
+
for inst_id, inst in self.instances.items():
|
|
1329
|
+
if inst.net_name == net_name:
|
|
1330
|
+
padstack_instances.append(inst)
|
|
1331
|
+
return padstack_instances
|
|
1332
|
+
|
|
1333
|
+
@pyedb_function_handler()
|
|
1334
|
+
def get_reference_pins(
|
|
1335
|
+
self, positive_pin, reference_net="gnd", search_radius=5e-3, max_limit=0, component_only=True
|
|
1336
|
+
):
|
|
1337
|
+
"""Search for reference pins using given criteria.
|
|
1338
|
+
|
|
1339
|
+
Parameters
|
|
1340
|
+
----------
|
|
1341
|
+
positive_pin : EDBPadstackInstance
|
|
1342
|
+
Pin used for evaluating the distance on the reference pins found.
|
|
1343
|
+
reference_net : str, optional
|
|
1344
|
+
Reference net. The default is ``"gnd"``.
|
|
1345
|
+
search_radius : float, optional
|
|
1346
|
+
Search radius for finding padstack instances. The default is ``5e-3``.
|
|
1347
|
+
max_limit : int, optional
|
|
1348
|
+
Maximum limit for the padstack instances found. The default is ``0``, in which
|
|
1349
|
+
case no limit is applied. The maximum limit value occurs on the nearest
|
|
1350
|
+
reference pins from the positive one that is found.
|
|
1351
|
+
component_only : bool, optional
|
|
1352
|
+
Whether to limit the search to component padstack instances only. The
|
|
1353
|
+
default is ``True``. When ``False``, the search is extended to the entire layout.
|
|
1354
|
+
|
|
1355
|
+
Returns
|
|
1356
|
+
-------
|
|
1357
|
+
list
|
|
1358
|
+
List of :class:`dotnet.edb_core.edb_data.padstacks_data.EDBPadstackInstance`.
|
|
1359
|
+
|
|
1360
|
+
Examples
|
|
1361
|
+
--------
|
|
1362
|
+
>>> edbapp = Edb("target_path")
|
|
1363
|
+
>>> pin = edbapp.components.instances["J5"].pins["19"]
|
|
1364
|
+
>>> reference_pins = edbapp.padstacks.get_reference_pins(positive_pin=pin, reference_net="GND",
|
|
1365
|
+
>>> search_radius=5e-3, max_limit=0, component_only=True)
|
|
1366
|
+
"""
|
|
1367
|
+
pinlist = []
|
|
1368
|
+
if not positive_pin:
|
|
1369
|
+
search_radius = 10e-2
|
|
1370
|
+
component_only = True
|
|
1371
|
+
if component_only:
|
|
1372
|
+
references_pins = [
|
|
1373
|
+
pin for pin in list(positive_pin.component.pins.values()) if pin.net_name == reference_net
|
|
1374
|
+
]
|
|
1375
|
+
if not references_pins:
|
|
1376
|
+
return pinlist
|
|
1377
|
+
else:
|
|
1378
|
+
references_pins = self.get_padstack_instance_by_net_name(reference_net)
|
|
1379
|
+
if not references_pins:
|
|
1380
|
+
return pinlist
|
|
1381
|
+
pinlist = [
|
|
1382
|
+
p
|
|
1383
|
+
for p in references_pins
|
|
1384
|
+
if GeometryOperators.points_distance(positive_pin.position, p.position) <= search_radius
|
|
1385
|
+
]
|
|
1386
|
+
if max_limit and len(pinlist) > max_limit:
|
|
1387
|
+
pin_dict = {GeometryOperators.points_distance(positive_pin.position, p.position): p for p in pinlist}
|
|
1388
|
+
pinlist = [pin[1] for pin in sorted(pin_dict.items())[:max_limit]]
|
|
1389
|
+
return pinlist
|