siliconcompiler 0.34.1__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 (46) hide show
  1. siliconcompiler/__init__.py +14 -2
  2. siliconcompiler/_metadata.py +1 -1
  3. siliconcompiler/apps/sc_show.py +1 -1
  4. siliconcompiler/constraints/__init__.py +17 -0
  5. siliconcompiler/constraints/asic_component.py +378 -0
  6. siliconcompiler/constraints/asic_floorplan.py +449 -0
  7. siliconcompiler/constraints/asic_pins.py +489 -0
  8. siliconcompiler/constraints/asic_timing.py +517 -0
  9. siliconcompiler/core.py +3 -3
  10. siliconcompiler/dependencyschema.py +10 -174
  11. siliconcompiler/design.py +235 -118
  12. siliconcompiler/flowgraph.py +27 -14
  13. siliconcompiler/library.py +133 -0
  14. siliconcompiler/metric.py +94 -72
  15. siliconcompiler/metrics/__init__.py +7 -0
  16. siliconcompiler/metrics/asic.py +245 -0
  17. siliconcompiler/metrics/fpga.py +220 -0
  18. siliconcompiler/package/__init__.py +138 -35
  19. siliconcompiler/package/github.py +6 -10
  20. siliconcompiler/packageschema.py +256 -12
  21. siliconcompiler/pathschema.py +226 -0
  22. siliconcompiler/project.py +459 -0
  23. siliconcompiler/scheduler/docker.py +2 -3
  24. siliconcompiler/scheduler/run_node.py +2 -1
  25. siliconcompiler/scheduler/scheduler.py +4 -13
  26. siliconcompiler/scheduler/schedulernode.py +25 -17
  27. siliconcompiler/scheduler/taskscheduler.py +2 -1
  28. siliconcompiler/schema/__init__.py +0 -2
  29. siliconcompiler/schema/baseschema.py +147 -24
  30. siliconcompiler/schema/editableschema.py +14 -6
  31. siliconcompiler/schema/journal.py +23 -15
  32. siliconcompiler/schema/namedschema.py +6 -4
  33. siliconcompiler/schema/parameter.py +34 -19
  34. siliconcompiler/schema/parametertype.py +2 -0
  35. siliconcompiler/schema/parametervalue.py +198 -15
  36. siliconcompiler/schema/schema_cfg.py +18 -14
  37. siliconcompiler/schema_obj.py +5 -3
  38. siliconcompiler/tool.py +199 -10
  39. siliconcompiler/toolscripts/_tools.json +4 -4
  40. {siliconcompiler-0.34.1.dist-info → siliconcompiler-0.34.2.dist-info}/METADATA +3 -3
  41. {siliconcompiler-0.34.1.dist-info → siliconcompiler-0.34.2.dist-info}/RECORD +45 -35
  42. siliconcompiler/schema/packageschema.py +0 -101
  43. {siliconcompiler-0.34.1.dist-info → siliconcompiler-0.34.2.dist-info}/WHEEL +0 -0
  44. {siliconcompiler-0.34.1.dist-info → siliconcompiler-0.34.2.dist-info}/entry_points.txt +0 -0
  45. {siliconcompiler-0.34.1.dist-info → siliconcompiler-0.34.2.dist-info}/licenses/LICENSE +0 -0
  46. {siliconcompiler-0.34.1.dist-info → siliconcompiler-0.34.2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,449 @@
1
+ from typing import Union, List, Tuple
2
+
3
+ from siliconcompiler.schema import BaseSchema, EditableSchema, Parameter, PerNode, Scope
4
+
5
+
6
+ class ASICAreaConstraint(BaseSchema):
7
+ """
8
+ Manages various area-related constraints for an ASIC design.
9
+
10
+ This class provides a structured way to define and retrieve constraints
11
+ related to the die area, core area, core margin, target density, and
12
+ aspect ratio of the physical layout.
13
+ """
14
+
15
+ def __init__(self):
16
+ super().__init__()
17
+
18
+ schema = EditableSchema(self)
19
+
20
+ schema.insert(
21
+ 'diearea',
22
+ Parameter(
23
+ '[(float,float)]',
24
+ pernode=PerNode.OPTIONAL,
25
+ scope=Scope.GLOBAL,
26
+ unit='um',
27
+ shorthelp="Constraint: die area outline",
28
+ switch="-constraint_diearea <(float,float)>",
29
+ example=["api: chip.set('constraint', 'diearea', (0, 0))"],
30
+ schelp="""
31
+ List of (x, y) points that define the outline physical layout
32
+ physical design. Simple rectangle areas can be defined with two points,
33
+ one for the lower left corner and one for the upper right corner."""))
34
+
35
+ schema.insert(
36
+ 'corearea',
37
+ Parameter(
38
+ '[(float,float)]',
39
+ pernode=PerNode.OPTIONAL,
40
+ scope=Scope.GLOBAL,
41
+ unit='um',
42
+ shorthelp="Constraint: layout core area",
43
+ switch="-constraint_corearea <(float,float)>",
44
+ example=["api: chip.set('constraint', 'corearea', (0, 0))"],
45
+ schelp="""
46
+ List of (x, y) points that define the outline of the core area for the
47
+ physical design. Simple rectangle areas can be defined with two points,
48
+ one for the lower left corner and one for the upper right corner."""))
49
+
50
+ schema.insert(
51
+ 'coremargin',
52
+ Parameter(
53
+ 'float',
54
+ pernode=PerNode.OPTIONAL,
55
+ scope=Scope.GLOBAL,
56
+ unit='um',
57
+ shorthelp="Constraint: layout core margin",
58
+ switch="-constraint_coremargin <float>",
59
+ example=["api: chip.set('constraint', 'coremargin', 1)"],
60
+ schelp="""
61
+ Halo/margin between the outline and core area for fully
62
+ automated layout sizing and floorplanning."""))
63
+
64
+ schema.insert(
65
+ 'density', Parameter(
66
+ 'float',
67
+ pernode=PerNode.OPTIONAL,
68
+ scope=Scope.GLOBAL,
69
+ shorthelp="Constraint: layout density",
70
+ switch="-constraint_density <float>",
71
+ example=["api: chip.set('constraint', 'density', 30)"],
72
+ schelp="""
73
+ Target density based on the total design cells area reported
74
+ after synthesis/elaboration. This number is used when no outline
75
+ or floorplan is supplied. Any number between 1 and 100 is legal,
76
+ but values above 50 may fail due to area/congestion issues during
77
+ automated place and route."""))
78
+
79
+ schema.insert(
80
+ 'aspectratio', Parameter(
81
+ 'float',
82
+ pernode=PerNode.OPTIONAL,
83
+ defvalue=1.0,
84
+ scope=Scope.GLOBAL,
85
+ shorthelp="Constraint: layout aspect ratio",
86
+ switch="-constraint_aspectratio <float>",
87
+ example=["api: chip.set('constraint', 'aspectratio', 2.0)"],
88
+ schelp="""
89
+ Height to width ratio of the block for automated floorplanning.
90
+ Values below 0.1 and above 10 should be avoided as they will likely fail
91
+ to converge during placement and routing. The ideal aspect ratio for
92
+ most designs is 1. This value is only used when no diearea or floorplan
93
+ is supplied."""))
94
+
95
+ def set_density(self,
96
+ density: float,
97
+ aspectratio: float = None,
98
+ coremargin: float = None,
99
+ step: str = None, index: Union[str, int] = None):
100
+ """
101
+ Sets the density value.
102
+
103
+ This method validates the `density` input to ensure it's a number
104
+ between 0 (exclusive) and 100 (inclusive). Optionally, it can also
105
+ set the aspect ratio and core margin if provided.
106
+
107
+ Args:
108
+ density (float): The density value to set. Must be a number
109
+ between 0.0 and 100.0 (exclusive of 0.0).
110
+ aspectratio (float, optional): The aspect ratio to set. If provided,
111
+ `set_aspectratio` will be called.
112
+ Defaults to None.
113
+ coremargin (float, optional): The core margin to set. If provided,
114
+ `set_coremargin` will be called.
115
+ Defaults to None.
116
+ step (str, optional): An identifier for the step in a workflow.
117
+ Defaults to None.
118
+ index (Union[str, int], optional): An index or identifier within a step.
119
+ Defaults to None.
120
+
121
+ Raises:
122
+ TypeError: If `density` is not a number.
123
+ ValueError: If `density` is not within the valid range (0, 100].
124
+
125
+ Returns:
126
+ list: A list of return values from the `set` and any optional
127
+ `set_aspectratio` or `set_coremargin` calls.
128
+ """
129
+ if not isinstance(density, (int, float)):
130
+ raise TypeError("density must be a number")
131
+
132
+ if density <= 0.0 or density > 100.0:
133
+ raise ValueError("density must be between (0, 100]")
134
+
135
+ params = [
136
+ self.set("density", density, step=step, index=index)
137
+ ]
138
+ if aspectratio is not None:
139
+ params.append(self.set_aspectratio(aspectratio, step=step, index=index))
140
+ if coremargin is not None:
141
+ params.append(self.set_coremargin(coremargin, step=step, index=index))
142
+ return params
143
+
144
+ def get_density(self, step: str = None, index: Union[str, int] = None) -> float:
145
+ """
146
+ Retrieves the current density value.
147
+
148
+ Args:
149
+ step (str, optional): An identifier for the step in a workflow.
150
+ Defaults to None.
151
+ index (Union[str, int], optional): An index or identifier within a step.
152
+ Defaults to None.
153
+
154
+ Returns:
155
+ float: The current density value.
156
+ """
157
+ return self.get("density", step=step, index=index)
158
+
159
+ def set_aspectratio(self,
160
+ aspectratio: float,
161
+ step: str = None, index: Union[str, int] = None):
162
+ """
163
+ Sets the aspect ratio.
164
+
165
+ This method validates the `aspectratio` input to ensure it's a positive number.
166
+
167
+ Args:
168
+ aspectratio (float): The aspect ratio value to set. Must be a
169
+ number greater than 0.0.
170
+ step (str, optional): An identifier for the step in a workflow.
171
+ Defaults to None.
172
+ index (Union[str, int], optional): An index or identifier within a step.
173
+ Defaults to None.
174
+
175
+ Raises:
176
+ TypeError: If `aspectratio` is not a number.
177
+ ValueError: If `aspectratio` is zero or negative.
178
+
179
+ Returns:
180
+ Any: The return value from the internal `set` method call.
181
+ """
182
+ if not isinstance(aspectratio, (int, float)):
183
+ raise TypeError("aspectratio must be a number")
184
+
185
+ if aspectratio <= 0.0:
186
+ raise ValueError("aspectratio cannot be zero or negative")
187
+
188
+ return self.set("aspectratio", aspectratio, step=step, index=index)
189
+
190
+ def get_aspectratio(self,
191
+ step: str = None, index: Union[str, int] = None) -> float:
192
+ """
193
+ Retrieves the current aspect ratio.
194
+
195
+ Args:
196
+ step (str, optional): An identifier for the step in a workflow.
197
+ Defaults to None.
198
+ index (Union[str, int], optional): An index or identifier within a step.
199
+ Defaults to None.
200
+
201
+ Returns:
202
+ float: The current aspect ratio value.
203
+ """
204
+ return self.get("aspectratio", step=step, index=index)
205
+
206
+ def set_coremargin(self,
207
+ coremargin: float,
208
+ step: str = None, index: Union[str, int] = None):
209
+ """
210
+ Sets the core margin.
211
+
212
+ This method validates the `coremargin` input to ensure it's a non-negative number.
213
+
214
+ Args:
215
+ coremargin (float): The core margin value to set. Must be a
216
+ number greater than or equal to 0.0.
217
+ step (str, optional): An identifier for the step in a workflow.
218
+ Defaults to None.
219
+ index (Union[str, int], optional): An index or identifier within a step.
220
+ Defaults to None.
221
+
222
+ Raises:
223
+ TypeError: If `coremargin` is not a number.
224
+ ValueError: If `coremargin` is negative.
225
+
226
+ Returns:
227
+ Any: The return value from the internal `set` method call.
228
+ """
229
+ if not isinstance(coremargin, (int, float)):
230
+ raise TypeError("coremargin must be a number")
231
+
232
+ if coremargin < 0.0:
233
+ raise ValueError("coremargin cannot be negative")
234
+
235
+ return self.set("coremargin", coremargin, step=step, index=index)
236
+
237
+ def get_coremargin(self,
238
+ step: str = None, index: Union[str, int] = None) -> float:
239
+ """
240
+ Retrieves the current core margin.
241
+
242
+ Args:
243
+ step (str, optional): An identifier for the step in a workflow.
244
+ Defaults to None.
245
+ index (Union[str, int], optional): An index or identifier within a step.
246
+ Defaults to None.
247
+
248
+ Returns:
249
+ float: The current core margin value.
250
+ """
251
+ return self.get("coremargin", step=step, index=index)
252
+
253
+ def set_diearea_rectangle(self,
254
+ height: float,
255
+ width: float,
256
+ coremargin: Union[float, Tuple[float, float]] = None,
257
+ step: str = None, index: Union[str, int] = None):
258
+ """
259
+ Sets the die area as a rectangle defined by its height and width,
260
+ with its bottom-left corner at (0,0).
261
+
262
+ Optionally, it can also set the core area as a rectangle based on
263
+ the provided core margin.
264
+
265
+ Args:
266
+ height (float): The height of the rectangular die area. Must be
267
+ greater than zero.
268
+ width (float): The width of the rectangular die area. Must be
269
+ greater than zero.
270
+ coremargin (Union[float, Tuple[float, float]], optional):
271
+ The margin for the core area. Can be a single float
272
+ (uniform margin) or a tuple of two floats (x and y margins).
273
+ If provided, `set_corearea_rectangle` will be called.
274
+ Defaults to None.
275
+ step (str, optional): An identifier for the step in a workflow.
276
+ Defaults to None.
277
+ index (Union[str, int], optional): An index or identifier within a step.
278
+ Defaults to None.
279
+
280
+ Raises:
281
+ TypeError: If `height` or `width` are not numbers.
282
+ ValueError: If `height` or `width` are zero or negative.
283
+
284
+ Returns:
285
+ list: A list of return values from the `set_diearea` and any optional
286
+ `set_corearea_rectangle` calls.
287
+ """
288
+ if not isinstance(height, (int, float)):
289
+ raise TypeError("height must be a number")
290
+ if not isinstance(width, (int, float)):
291
+ raise TypeError("width must be a number")
292
+
293
+ if height <= 0.0:
294
+ raise ValueError("height must be greater than zero")
295
+
296
+ if width <= 0.0:
297
+ raise ValueError("width must be greater than zero")
298
+
299
+ params = [
300
+ self.set_diearea([(0, 0), (width, height)], step=step, index=index)
301
+ ]
302
+ if coremargin is not None:
303
+ params.append(self.set_corearea_rectangle(
304
+ height, width, coremargin, step=step, index=index))
305
+ return params
306
+
307
+ def set_corearea_rectangle(self,
308
+ dieheight: float,
309
+ diewidth: float,
310
+ coremargin: Union[float, Tuple[float, float]],
311
+ step: str = None, index: Union[str, int] = None):
312
+ """
313
+ Sets the core area as a rectangle within a larger die area,
314
+ based on specified margins.
315
+
316
+ The core area is calculated by subtracting the margins from the die dimensions.
317
+ Margins can be uniform (single float) or specified separately for x and y.
318
+
319
+ Args:
320
+ dieheight (float): The height of the die area. Must be greater than zero.
321
+ diewidth (float): The width of the die area. Must be greater than zero.
322
+ coremargin (Union[float, Tuple[float, float]]): The margin(s) to apply
323
+ to the core area.
324
+ - If a float, it's applied uniformly to all sides.
325
+ - If a tuple of two floats, it represents (x_margin, y_margin).
326
+ step (str, optional): An identifier for the step in a workflow.
327
+ Defaults to None.
328
+ index (Union[str, int], optional): An index or identifier within a step.
329
+ Defaults to None.
330
+
331
+ Raises:
332
+ TypeError: If `dieheight` or `diewidth` are not numbers, or if
333
+ `coremargin` is not a number or a tuple of two numbers.
334
+ ValueError: If `dieheight` or `diewidth` are zero or negative,
335
+ if `coremargin` is a tuple of incorrect length,
336
+ if x or y margins are negative, or if margins are
337
+ greater than or equal to the corresponding die dimensions.
338
+
339
+ Returns:
340
+ Any: The return value from the internal `set_corearea` method call.
341
+ """
342
+ if not isinstance(dieheight, (int, float)):
343
+ raise TypeError("height must be a number")
344
+ if not isinstance(diewidth, (int, float)):
345
+ raise TypeError("width must be a number")
346
+
347
+ if dieheight <= 0.0:
348
+ raise ValueError("height must be greater than zero")
349
+
350
+ if diewidth <= 0.0:
351
+ raise ValueError("width must be greater than zero")
352
+
353
+ if isinstance(coremargin, (int, float)):
354
+ coremargin = (coremargin, coremargin)
355
+ elif not isinstance(coremargin, (list, tuple)):
356
+ raise TypeError("coremargin must be a number to a tuple of two numbers")
357
+ else:
358
+ if len(coremargin) != 2:
359
+ raise ValueError("coremargin must be a number to a tuple of two numbers")
360
+
361
+ xmargin, ymargin = coremargin
362
+
363
+ if xmargin < 0:
364
+ raise ValueError("x margin canont be negative")
365
+
366
+ if ymargin < 0:
367
+ raise ValueError("y margin canont be negative")
368
+
369
+ if 2 * xmargin >= diewidth:
370
+ raise ValueError("x margin is greater than the die width")
371
+
372
+ if 2 * ymargin >= dieheight:
373
+ raise ValueError("y margin is greater than the die height")
374
+
375
+ return self.set_corearea([
376
+ (xmargin, ymargin),
377
+ (diewidth - xmargin, dieheight - ymargin)], step=step, index=index)
378
+
379
+ def set_diearea(self,
380
+ points: List[Tuple[float, float]],
381
+ step: str = None, index: Union[str, int] = None):
382
+ """
383
+ Sets the die area using a list of points defining its boundary.
384
+
385
+ Args:
386
+ points (List[Tuple[float, float]]): A list of (x, y) tuples representing
387
+ the coordinates that define the die area.
388
+ step (str, optional): An identifier for the step in a workflow.
389
+ Defaults to None.
390
+ index (Union[str, int], optional): An index or identifier within a step.
391
+ Defaults to None.
392
+
393
+ Returns:
394
+ Any: The return value from the internal `set` method call.
395
+ """
396
+ return self.set("diearea", points, step=step, index=index)
397
+
398
+ def get_diearea(self,
399
+ step: str = None, index: Union[str, int] = None) -> List[Tuple[float, float]]:
400
+ """
401
+ Retrieves the current die area definition.
402
+
403
+ Args:
404
+ step (str, optional): An identifier for the step in a workflow.
405
+ Defaults to None.
406
+ index (Union[str, int], optional): An index or identifier within a step.
407
+ Defaults to None.
408
+
409
+ Returns:
410
+ List[Tuple[float, float]]: A list of (x, y) tuples representing
411
+ the coordinates that define the die area.
412
+ """
413
+ return self.get("diearea", step=step, index=index)
414
+
415
+ def set_corearea(self,
416
+ points: List[Tuple[float, float]],
417
+ step: str = None, index: Union[str, int] = None):
418
+ """
419
+ Sets the core area using a list of points defining its boundary.
420
+
421
+ Args:
422
+ points (List[Tuple[float, float]]): A list of (x, y) tuples representing
423
+ the coordinates that define the core area.
424
+ step (str, optional): An identifier for the step in a workflow.
425
+ Defaults to None.
426
+ index (Union[str, int], int): An index or identifier within a step.
427
+ Defaults to None.
428
+
429
+ Returns:
430
+ Any: The return value from the internal `set` method call.
431
+ """
432
+ return self.set("corearea", points, step=step, index=index)
433
+
434
+ def get_corearea(self,
435
+ step: str = None, index: Union[str, int] = None) -> List[Tuple[float, float]]:
436
+ """
437
+ Retrieves the current core area definition.
438
+
439
+ Args:
440
+ step (str, optional): An identifier for the step in a workflow.
441
+ Defaults to None.
442
+ index (Union[str, int], optional): An index or identifier within a step.
443
+ Defaults to None.
444
+
445
+ Returns:
446
+ List[Tuple[float, float]]: A list of (x, y) tuples representing
447
+ the coordinates that define the core area.
448
+ """
449
+ return self.get("corearea", step=step, index=index)