siliconcompiler 0.34.0__py3-none-any.whl → 0.34.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. siliconcompiler/__init__.py +14 -2
  2. siliconcompiler/_metadata.py +1 -1
  3. siliconcompiler/apps/_common.py +1 -1
  4. siliconcompiler/apps/sc.py +1 -1
  5. siliconcompiler/apps/sc_issue.py +1 -1
  6. siliconcompiler/apps/sc_remote.py +3 -3
  7. siliconcompiler/apps/sc_show.py +3 -3
  8. siliconcompiler/apps/utils/replay.py +4 -4
  9. siliconcompiler/checklist.py +203 -2
  10. siliconcompiler/constraints/__init__.py +17 -0
  11. siliconcompiler/constraints/asic_component.py +378 -0
  12. siliconcompiler/constraints/asic_floorplan.py +449 -0
  13. siliconcompiler/constraints/asic_pins.py +489 -0
  14. siliconcompiler/constraints/asic_timing.py +517 -0
  15. siliconcompiler/core.py +31 -249
  16. siliconcompiler/data/templates/email/general.j2 +3 -3
  17. siliconcompiler/data/templates/email/summary.j2 +1 -1
  18. siliconcompiler/data/templates/issue/README.txt +1 -1
  19. siliconcompiler/data/templates/report/sc_report.j2 +7 -7
  20. siliconcompiler/dependencyschema.py +10 -174
  21. siliconcompiler/design.py +325 -114
  22. siliconcompiler/flowgraph.py +63 -15
  23. siliconcompiler/library.py +133 -0
  24. siliconcompiler/metric.py +94 -72
  25. siliconcompiler/metrics/__init__.py +7 -0
  26. siliconcompiler/metrics/asic.py +245 -0
  27. siliconcompiler/metrics/fpga.py +220 -0
  28. siliconcompiler/optimizer/vizier.py +2 -2
  29. siliconcompiler/package/__init__.py +138 -35
  30. siliconcompiler/package/github.py +6 -10
  31. siliconcompiler/packageschema.py +256 -12
  32. siliconcompiler/pathschema.py +226 -0
  33. siliconcompiler/pdk.py +5 -5
  34. siliconcompiler/project.py +459 -0
  35. siliconcompiler/remote/client.py +18 -12
  36. siliconcompiler/remote/server.py +2 -2
  37. siliconcompiler/report/dashboard/cli/__init__.py +6 -6
  38. siliconcompiler/report/dashboard/cli/board.py +3 -3
  39. siliconcompiler/report/dashboard/web/components/__init__.py +5 -5
  40. siliconcompiler/report/dashboard/web/components/flowgraph.py +4 -4
  41. siliconcompiler/report/dashboard/web/components/graph.py +2 -2
  42. siliconcompiler/report/dashboard/web/state.py +1 -1
  43. siliconcompiler/report/dashboard/web/utils/__init__.py +5 -5
  44. siliconcompiler/report/html_report.py +1 -1
  45. siliconcompiler/report/report.py +4 -4
  46. siliconcompiler/report/summary_table.py +2 -2
  47. siliconcompiler/report/utils.py +5 -5
  48. siliconcompiler/scheduler/docker.py +4 -10
  49. siliconcompiler/scheduler/run_node.py +4 -8
  50. siliconcompiler/scheduler/scheduler.py +18 -24
  51. siliconcompiler/scheduler/schedulernode.py +161 -143
  52. siliconcompiler/scheduler/send_messages.py +3 -3
  53. siliconcompiler/scheduler/slurm.py +5 -3
  54. siliconcompiler/scheduler/taskscheduler.py +10 -8
  55. siliconcompiler/schema/__init__.py +0 -2
  56. siliconcompiler/schema/baseschema.py +148 -26
  57. siliconcompiler/schema/editableschema.py +14 -6
  58. siliconcompiler/schema/journal.py +23 -15
  59. siliconcompiler/schema/namedschema.py +30 -4
  60. siliconcompiler/schema/parameter.py +34 -19
  61. siliconcompiler/schema/parametertype.py +2 -0
  62. siliconcompiler/schema/parametervalue.py +198 -15
  63. siliconcompiler/schema/schema_cfg.py +18 -14
  64. siliconcompiler/schema_obj.py +5 -3
  65. siliconcompiler/tool.py +591 -179
  66. siliconcompiler/tools/__init__.py +2 -0
  67. siliconcompiler/tools/builtin/_common.py +5 -5
  68. siliconcompiler/tools/builtin/concatenate.py +5 -5
  69. siliconcompiler/tools/builtin/minimum.py +4 -4
  70. siliconcompiler/tools/builtin/mux.py +4 -4
  71. siliconcompiler/tools/builtin/nop.py +4 -4
  72. siliconcompiler/tools/builtin/verify.py +7 -7
  73. siliconcompiler/tools/execute/exec_input.py +1 -1
  74. siliconcompiler/tools/genfasm/genfasm.py +1 -6
  75. siliconcompiler/tools/openroad/_apr.py +5 -1
  76. siliconcompiler/tools/openroad/antenna_repair.py +1 -1
  77. siliconcompiler/tools/openroad/macro_placement.py +1 -1
  78. siliconcompiler/tools/openroad/power_grid.py +1 -1
  79. siliconcompiler/tools/openroad/scripts/common/procs.tcl +5 -0
  80. siliconcompiler/tools/opensta/timing.py +26 -3
  81. siliconcompiler/tools/slang/__init__.py +2 -2
  82. siliconcompiler/tools/surfer/__init__.py +0 -0
  83. siliconcompiler/tools/surfer/show.py +53 -0
  84. siliconcompiler/tools/surfer/surfer.py +30 -0
  85. siliconcompiler/tools/vpr/route.py +27 -14
  86. siliconcompiler/tools/vpr/vpr.py +23 -6
  87. siliconcompiler/tools/yosys/__init__.py +1 -1
  88. siliconcompiler/tools/yosys/scripts/procs.tcl +143 -0
  89. siliconcompiler/tools/yosys/{sc_synth_asic.tcl → scripts/sc_synth_asic.tcl} +4 -0
  90. siliconcompiler/tools/yosys/{sc_synth_fpga.tcl → scripts/sc_synth_fpga.tcl} +24 -77
  91. siliconcompiler/tools/yosys/syn_fpga.py +14 -0
  92. siliconcompiler/toolscripts/_tools.json +9 -13
  93. siliconcompiler/toolscripts/rhel9/install-vpr.sh +0 -2
  94. siliconcompiler/toolscripts/ubuntu22/install-surfer.sh +33 -0
  95. siliconcompiler/toolscripts/ubuntu24/install-surfer.sh +33 -0
  96. siliconcompiler/utils/__init__.py +2 -1
  97. siliconcompiler/utils/flowgraph.py +24 -23
  98. siliconcompiler/utils/issue.py +23 -29
  99. siliconcompiler/utils/logging.py +35 -6
  100. siliconcompiler/utils/showtools.py +6 -1
  101. {siliconcompiler-0.34.0.dist-info → siliconcompiler-0.34.2.dist-info}/METADATA +15 -25
  102. {siliconcompiler-0.34.0.dist-info → siliconcompiler-0.34.2.dist-info}/RECORD +109 -97
  103. siliconcompiler/schema/packageschema.py +0 -101
  104. siliconcompiler/tools/yosys/procs.tcl +0 -71
  105. siliconcompiler/toolscripts/rhel9/install-yosys-parmys.sh +0 -68
  106. siliconcompiler/toolscripts/ubuntu22/install-yosys-parmys.sh +0 -68
  107. siliconcompiler/toolscripts/ubuntu24/install-yosys-parmys.sh +0 -68
  108. /siliconcompiler/tools/yosys/{sc_lec.tcl → scripts/sc_lec.tcl} +0 -0
  109. /siliconcompiler/tools/yosys/{sc_screenshot.tcl → scripts/sc_screenshot.tcl} +0 -0
  110. /siliconcompiler/tools/yosys/{syn_strategies.tcl → scripts/syn_strategies.tcl} +0 -0
  111. {siliconcompiler-0.34.0.dist-info → siliconcompiler-0.34.2.dist-info}/WHEEL +0 -0
  112. {siliconcompiler-0.34.0.dist-info → siliconcompiler-0.34.2.dist-info}/entry_points.txt +0 -0
  113. {siliconcompiler-0.34.0.dist-info → siliconcompiler-0.34.2.dist-info}/licenses/LICENSE +0 -0
  114. {siliconcompiler-0.34.0.dist-info → siliconcompiler-0.34.2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,489 @@
1
+ from typing import Union, Tuple
2
+
3
+ from siliconcompiler.schema import BaseSchema, NamedSchema, EditableSchema, Parameter, \
4
+ PerNode, Scope
5
+
6
+
7
+ class ASICPinConstraint(NamedSchema):
8
+ """
9
+ Represents a single ASIC pin constraint within the design configuration.
10
+
11
+ This class defines various constraints that can be applied to an individual
12
+ ASIC pin, such as its placement, dimensions (width, length), shape,
13
+ metal layer, and its relative position on the chip's side.
14
+ """
15
+
16
+ def __init__(self, name: str = None):
17
+ super().__init__()
18
+ self.set_name(name)
19
+
20
+ schema = EditableSchema(self)
21
+
22
+ schema.insert(
23
+ 'placement',
24
+ Parameter(
25
+ '(float,float)',
26
+ unit='um',
27
+ pernode=PerNode.OPTIONAL,
28
+ scope=Scope.GLOBAL,
29
+ shorthelp="Constraint: pin placement",
30
+ example=["api: chip.set('constraint', 'pin', 'nreset', 'placement', (2.0, 3.0))"],
31
+ help="""
32
+ Placement location of a named pin, specified as a (x,y) tuple of
33
+ floats with respect to the lower left corner of the substrate. The location
34
+ refers to the center of the pin. The 'placement' parameter
35
+ is a goal/intent, not an exact specification. The layout system
36
+ may adjust sizes to meet competing goals such as manufacturing design
37
+ rules and grid placement guidelines."""))
38
+
39
+ schema.insert(
40
+ 'width',
41
+ Parameter(
42
+ 'float',
43
+ unit='um',
44
+ pernode=PerNode.OPTIONAL,
45
+ scope=Scope.GLOBAL,
46
+ shorthelp="Constraint: pin width",
47
+ example=["api: chip.set('constraint', 'pin', 'nreset', 'width', 1.0)"],
48
+ help="""
49
+ Pin width constraint. Package pin width is the lateral
50
+ (side-to-side) thickness of a pin on a physical component.
51
+ This parameter represents goal/intent, not an exact
52
+ specification. The layout system may adjust dimensions to meet
53
+ competing goals such as manufacturing design rules and grid placement
54
+ guidelines."""))
55
+
56
+ schema.insert(
57
+ 'length',
58
+ Parameter(
59
+ 'float',
60
+ unit='um',
61
+ pernode=PerNode.OPTIONAL,
62
+ scope=Scope.GLOBAL,
63
+ shorthelp="Constraint: pin length",
64
+ example=["api: chip.set('constraint', 'pin', 'nreset', 'length', 1.0)"],
65
+ help="""
66
+ Pin length constraint. Package pin length refers to the
67
+ length of the electrical pins extending out from (or into)
68
+ a component. This parameter represents goal/intent, not an exact
69
+ specification. The layout system may adjust dimensions to meet
70
+ competing goals such as manufacturing design rules and grid placement
71
+ guidelines."""))
72
+
73
+ schema.insert(
74
+ 'shape',
75
+ Parameter(
76
+ '<circle,rectangle,square,hexagon,octagon,oval,pill,polygon>',
77
+ pernode=PerNode.OPTIONAL,
78
+ scope=Scope.GLOBAL,
79
+ shorthelp="Constraint: pin shape",
80
+ example=["api: chip.set('constraint', 'pin', 'nreset', 'shape', 'circle')"],
81
+ help="""
82
+ Pin shape constraint specified on a per pin basis. In 3D design systems,
83
+ the pin shape represents the cross section of the pin in the direction
84
+ orthogonal to the signal flow direction. The 'pill' (aka stadium) shape,
85
+ is rectangle with semicircles at a pair of opposite sides. The other
86
+ pin shapes represent common geometric shape definitions."""))
87
+
88
+ schema.insert(
89
+ 'layer',
90
+ Parameter(
91
+ 'str',
92
+ pernode=PerNode.OPTIONAL,
93
+ scope=Scope.GLOBAL,
94
+ shorthelp="Constraint: pin layer",
95
+ example=["api: chip.set('constraint', 'pin', 'nreset', 'layer', 'm4')"],
96
+ help="""
97
+ Pin metal layer constraint specified on a per pin basis.
98
+ Metal names should either be the PDK specific metal stack name or
99
+ an integer with '1' being the lowest routing layer."""))
100
+
101
+ schema.insert(
102
+ 'side',
103
+ Parameter(
104
+ 'int',
105
+ pernode=PerNode.OPTIONAL,
106
+ scope=Scope.GLOBAL,
107
+ shorthelp="Constraint: pin side",
108
+ example=["api: chip.set('constraint', 'pin', 'nreset', 'side', 1)"],
109
+ help="""
110
+ Side of block where the named pin should be placed. Sides are
111
+ enumerated as integers with '1' being the lower left side,
112
+ with the side index incremented on right turn in a clock wise
113
+ fashion. In case of conflict between 'lower' and 'left',
114
+ 'left' has precedence. The side option and order option are
115
+ orthogonal to the placement option."""))
116
+
117
+ schema.insert(
118
+ 'order',
119
+ Parameter(
120
+ 'int',
121
+ pernode=PerNode.OPTIONAL,
122
+ scope=Scope.GLOBAL,
123
+ shorthelp="Constraint: pin order",
124
+ example=["api: chip.set('constraint', 'pin', 'nreset', 'order', 1)"],
125
+ help="""
126
+ The relative position of the named pin in a vector of pins
127
+ on the side specified by the 'side' option. Pin order counting
128
+ is done clockwise. If multiple pins on the same side have the
129
+ same order number, the actual order is at the discretion of the
130
+ tool."""))
131
+
132
+ def set_width(self, width: float, step: str = None, index: Union[str, int] = None):
133
+ """
134
+ Sets the width constraint for the pin.
135
+
136
+ Args:
137
+ width (float): The desired width of the pin in micrometers (um).
138
+ Must be a positive numeric value.
139
+ step (str, optional): step name.
140
+ index (str, optional): index name.
141
+
142
+ Raises:
143
+ TypeError: If `width` is not an int or float.
144
+ ValueError: If `width` is not a positive value.
145
+ """
146
+ if not isinstance(width, (int, float)):
147
+ raise TypeError("width must be a number")
148
+ if width <= 0:
149
+ raise ValueError("width must be a positive value")
150
+ return self.set("width", width, step=step, index=index)
151
+
152
+ def get_width(self, step: str = None, index: Union[str, int] = None) -> float:
153
+ """
154
+ Retrieves the current width constraint of the pin.
155
+
156
+ Args:
157
+ step (str, optional): step name.
158
+ index (str, optional): index name.
159
+
160
+ Returns:
161
+ float: The width of the pin in micrometers (um).
162
+ """
163
+ return self.get("width", step=step, index=index)
164
+
165
+ def set_length(self, length: float, step: str = None, index: Union[str, int] = None):
166
+ """
167
+ Sets the length constraint for the pin.
168
+
169
+ Args:
170
+ length (float): The desired length of the pin in micrometers (um).
171
+ Must be a positive numeric value.
172
+ step (str, optional): step name.
173
+ index (str, optional): index name.
174
+
175
+ Raises:
176
+ TypeError: If `length` is not an int or float.
177
+ ValueError: If `length` is not a positive value.
178
+ """
179
+ if not isinstance(length, (int, float)):
180
+ raise TypeError("length must be a number")
181
+ if length <= 0:
182
+ raise ValueError("length must be a positive value")
183
+ return self.set("length", length, step=step, index=index)
184
+
185
+ def get_length(self, step: str = None, index: Union[str, int] = None) -> float:
186
+ """
187
+ Retrieves the current length constraint of the pin.
188
+
189
+ Args:
190
+ step (str, optional): step name.
191
+ index (str, optional): index name.
192
+
193
+ Returns:
194
+ float: The length of the pin in micrometers (um).
195
+ """
196
+ return self.get("length", step=step, index=index)
197
+
198
+ def set_placement(self, x: float, y: float, step: str = None, index: Union[str, int] = None):
199
+ """
200
+ Sets the placement constraint for the pin.
201
+
202
+ Args:
203
+ x (float): The X-coordinate for the pin's center in micrometers (um)
204
+ relative to the lower-left corner of the substrate.
205
+ y (float): The Y-coordinate for the pin's center in micrometers (um)
206
+ relative to the lower-left corner of the substrate.
207
+ step (str, optional): step name.
208
+ index (str, optional): index name.
209
+
210
+ Raises:
211
+ TypeError: If `x` or `y` is not an int or float.
212
+ """
213
+ if not isinstance(x, (int, float)):
214
+ raise TypeError("x must be a number")
215
+ if not isinstance(y, (int, float)):
216
+ raise TypeError("y must be a number")
217
+ return self.set("placement", (x, y), step=step, index=index)
218
+
219
+ def get_placement(self, step: str = None, index: Union[str, int] = None) -> Tuple[float, float]:
220
+ """
221
+ Retrieves the current placement constraint of the pin.
222
+
223
+ Args:
224
+ step (str, optional): step name.
225
+ index (str, optional): index name.
226
+
227
+ Returns:
228
+ Tuple[float, float]: A tuple (x, y) representing the pin's center
229
+ coordinates in micrometers (um).
230
+ """
231
+ return self.get("placement", step=step, index=index)
232
+
233
+ def set_shape(self, shape: str, step: str = None, index: Union[str, int] = None):
234
+ """
235
+ Sets the shape constraint for the pin.
236
+
237
+ Args:
238
+ shape (str): The desired shape of the pin. Valid values include
239
+ 'circle', 'rectangle', 'square', 'hexagon', 'octagon',
240
+ 'oval', 'pill', or 'polygon'.
241
+ step (str, optional): step name.
242
+ index (str, optional): index name.
243
+ """
244
+ return self.set("shape", shape, step=step, index=index)
245
+
246
+ def get_shape(self, step: str = None, index: Union[str, int] = None) -> str:
247
+ """
248
+ Retrieves the current shape constraint of the pin.
249
+
250
+ Args:
251
+ step (str, optional): step name.
252
+ index (str, optional): index name.
253
+
254
+ Returns:
255
+ str: The shape of the pin.
256
+ """
257
+ return self.get("shape", step=step, index=index)
258
+
259
+ def set_layer(self, layer: str, step: str = None, index: Union[str, int] = None):
260
+ """
261
+ Sets the metal layer constraint for the pin.
262
+
263
+ Args:
264
+ layer (str): The name of the metal layer for the pin. This can be
265
+ a PDK-specific metal stack name (e.g., 'm4') or an
266
+ integer (e.g., '1' for the lowest routing layer).
267
+ step (str, optional): step name.
268
+ index (str, optional): index name.
269
+ """
270
+ return self.set("layer", layer, step=step, index=index)
271
+
272
+ def get_layer(self, step: str = None, index: Union[str, int] = None) -> str:
273
+ """
274
+ Retrieves the current metal layer constraint of the pin.
275
+
276
+ Args:
277
+ step (str, optional): step name.
278
+ index (str, optional): index name.
279
+
280
+ Returns:
281
+ str: The metal layer of the pin.
282
+ """
283
+ return self.get("layer", step=step, index=index)
284
+
285
+ def set_side(self, side: Union[int, str], step: str = None, index: Union[str, int] = None):
286
+ """
287
+ Sets the side constraint for the pin, indicating where it should be placed.
288
+
289
+ Args:
290
+ side (Union[int, str]): The side of the block where the pin should be placed.
291
+ Can be an integer or a string ('left', 'west', 'top',
292
+ 'north', 'right', 'east', 'bottom', 'south').
293
+ step (str, optional): step name.
294
+ index (str, optional): index name.
295
+
296
+ Raises:
297
+ TypeError: If `side` is not an int or string.
298
+ ValueError: If `side` is an unrecognized string value or a non-positive integer.
299
+ """
300
+ if isinstance(side, str):
301
+ side = side.lower()
302
+ if side in ("left", "west"):
303
+ side = 1
304
+ elif side in ("top", "north"):
305
+ side = 2
306
+ elif side in ("right", "east"):
307
+ side = 3
308
+ elif side in ("bottom", "south"):
309
+ side = 4
310
+ else:
311
+ raise ValueError(f"{side} is a not a recognized side")
312
+
313
+ if not isinstance(side, int):
314
+ raise TypeError("side must be an integer")
315
+
316
+ if side <= 0:
317
+ raise ValueError("side must be a positive integer")
318
+
319
+ return self.set("side", side, step=step, index=index)
320
+
321
+ def get_side(self, step: str = None, index: Union[str, int] = None) -> int:
322
+ """
323
+ Retrieves the current side constraint of the pin.
324
+
325
+ Args:
326
+ step (str, optional): step name.
327
+ index (str, optional): index name.
328
+
329
+ Returns:
330
+ int: The integer representation of the side (1 for lower left, etc.).
331
+ """
332
+ return self.get("side", step=step, index=index)
333
+
334
+ def set_order(self, order: int, step: str = None, index: Union[str, int] = None):
335
+ """
336
+ Sets the relative order constraint for the pin on its assigned side.
337
+
338
+ Args:
339
+ order (int): The relative position of the pin in a vector of pins
340
+ on the specified side. Counting is done clockwise.
341
+ step (str, optional): step name.
342
+ index (str, optional): index name.
343
+ """
344
+ return self.set("order", order, step=step, index=index)
345
+
346
+ def get_order(self, step: str = None, index: Union[str, int] = None) -> int:
347
+ """
348
+ Retrieves the current order constraint of the pin.
349
+
350
+ Args:
351
+ step (str, optional): step name.
352
+ index (str, optional): index name.
353
+
354
+ Returns:
355
+ int: The relative order of the pin on its side.
356
+ """
357
+ return self.get("order", step=step, index=index)
358
+
359
+
360
+ class ASICPinConstraints(BaseSchema):
361
+ """
362
+ Manages a collection of ASIC pin constraints.
363
+
364
+ This class provides methods to add, retrieve, create, and remove
365
+ individual :class:`ASICPinConstraint` objects, allowing for organized
366
+ management of pin-level placement and property constraints.
367
+ """
368
+
369
+ def __init__(self):
370
+ super().__init__()
371
+
372
+ schema = EditableSchema(self)
373
+ schema.insert("default", ASICPinConstraint())
374
+
375
+ def add_pinconstraint(self, pin: ASICPinConstraint):
376
+ """
377
+ Adds a pin constraint to the design configuration.
378
+
379
+ This method incorporates a new or updated pin constraint into the system's
380
+ configuration. If a constraint with the same name already exists, it will
381
+ be overwritten (`clobber=True`).
382
+
383
+ Args:
384
+ pin: The :class:`ASICPinConstraint` object representing the pin constraint to add.
385
+ This object must have a valid name defined via its `name()` method.
386
+
387
+ Raises:
388
+ TypeError: If the provided `pin` argument is not an instance of
389
+ :class:`ASICPinConstraint`.
390
+ ValueError: If the `pin` object's `name()` method returns None, indicating
391
+ that the pin constraint does not have a defined name.
392
+ """
393
+ if not isinstance(pin, ASICPinConstraint):
394
+ raise TypeError("pin must be a pin copnstraint object")
395
+
396
+ if pin.name() is None:
397
+ raise ValueError("pin constraint must have a name")
398
+
399
+ EditableSchema(self).insert(pin.name(), pin, clobber=True)
400
+
401
+ def get_pinconstraint(self, pin: str = None):
402
+ """
403
+ Retrieves one or all pin constraints from the configuration.
404
+
405
+ This method provides flexibility to fetch either a specific pin constraint
406
+ by its name or a collection of all currently defined constraints.
407
+
408
+ Args:
409
+ pin (str, optional): The name (string) of the specific pin constraint to retrieve.
410
+ If this argument is omitted or set to None, the method will return
411
+ a dictionary containing all available pin constraints.
412
+
413
+ Returns:
414
+ - If `pin` is provided: The :class:`ASICPinConstraint` object corresponding
415
+ to the specified pin constraint name.
416
+ - If `pin` is None: A dictionary where keys are pin constraint names (str) and
417
+ values are their respective :class:`ASICPinConstraint` objects.
418
+
419
+ Raises:
420
+ LookupError: If a specific `pin` name is provided but no pin constraint with
421
+ that name is found in the configuration.
422
+ """
423
+ if pin is None:
424
+ pins = {}
425
+ for pin in self.getkeys():
426
+ pins[pin] = self.get(pin, field="schema")
427
+ return pins
428
+
429
+ if not self.valid(pin):
430
+ raise LookupError(f"{pin} is not defined")
431
+ return self.get(pin, field="schema")
432
+
433
+ def make_pinconstraint(self, pin: str) -> ASICPinConstraint:
434
+ """
435
+ Creates and adds a new pin constraint with the specified name.
436
+
437
+ This method initializes a new :class:`ASICPinConstraint` object with the given
438
+ name and immediately adds it to the design configuration. It ensures that
439
+ a constraint with the same name does not already exist, preventing accidental
440
+ overwrites.
441
+
442
+ Args:
443
+ pin (str): The name for the new pin constraint. This name must be
444
+ a non-empty string and unique within the current configuration.
445
+
446
+ Returns:
447
+ :class:ASICPinConstraint: The newly created :class:`ASICPinConstraint` object.
448
+
449
+ Raises:
450
+ ValueError: If the provided `pin` name is empty or None.
451
+ LookupError: If a pin constraint with the specified `pin` name already exists
452
+ in the configuration.
453
+ """
454
+ if not pin:
455
+ raise ValueError("pin name is required")
456
+
457
+ if self.valid(pin):
458
+ raise LookupError(f"{pin} constraint already exists")
459
+
460
+ constraint = ASICPinConstraint(pin)
461
+ self.add_pinconstraint(constraint)
462
+ return constraint
463
+
464
+ def remove_pinconstraint(self, pin: str) -> bool:
465
+ """
466
+ Removes a pin constraint from the design configuration.
467
+
468
+ This method deletes the specified pin constraint from the system's
469
+ configuration.
470
+
471
+ Args:
472
+ pin (str): The name of the pin constraint to remove.
473
+ This name must be a non-empty string.
474
+
475
+ Returns:
476
+ bool: True if the pin constraint was successfully removed, False if no
477
+ pin constraint with the given name was found.
478
+
479
+ Raises:
480
+ ValueError: If the provided `pin` name is empty or None.
481
+ """
482
+ if not pin:
483
+ raise ValueError("pin name is required")
484
+
485
+ if not self.valid(pin):
486
+ return False
487
+
488
+ EditableSchema(self).remove(pin)
489
+ return True