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
@@ -3,16 +3,21 @@ from siliconcompiler._common import NodeStatus, SiliconCompilerError
3
3
  from siliconcompiler.utils import sc_open
4
4
  from siliconcompiler.schema_obj import SchemaTmp as Schema
5
5
 
6
+ from siliconcompiler.packageschema import PackageSchema
7
+
6
8
  from siliconcompiler.design import DesignSchema
7
9
  from siliconcompiler.record import RecordSchema
8
10
  from siliconcompiler.metric import MetricSchema
9
11
  from siliconcompiler.pdk import PDKSchema
10
12
  from siliconcompiler.flowgraph import FlowgraphSchema
11
- from siliconcompiler.tool import ToolSchema
13
+ from siliconcompiler.tool import ToolSchema, TaskSchema
12
14
  from siliconcompiler.checklist import ChecklistSchema
13
15
  from siliconcompiler.asic import ASICSchema
14
16
  from siliconcompiler.fpga import FPGASchema
15
17
 
18
+ from siliconcompiler.project import Project
19
+ from siliconcompiler.library import LibrarySchema, StdCellLibrarySchema
20
+
16
21
  from siliconcompiler.core import Chip
17
22
 
18
23
  from siliconcompiler._metadata import version as __version__
@@ -31,13 +36,20 @@ __all__ = [
31
36
  "Checklist",
32
37
  "Schema",
33
38
  "sc_open",
39
+
34
40
  "DesignSchema",
41
+ "LibrarySchema",
35
42
  "RecordSchema",
36
43
  "MetricSchema",
37
44
  "PDKSchema",
38
45
  "FlowgraphSchema",
39
46
  "ToolSchema",
47
+ "TaskSchema",
40
48
  "ChecklistSchema",
41
49
  "ASICSchema",
42
- "FPGASchema"
50
+ "FPGASchema",
51
+ "PackageSchema",
52
+
53
+ "Project",
54
+ "StdCellLibrarySchema"
43
55
  ]
@@ -1,5 +1,5 @@
1
1
  # Version number following semver standard.
2
- version = '0.34.1'
2
+ version = '0.34.2'
3
3
 
4
4
  # Default server address for remote runs, if unspecified.
5
5
  default_server = 'https://server.siliconcompiler.com'
@@ -85,7 +85,7 @@ def main():
85
85
  for fileset in chip.getkeys('input'):
86
86
  for mode in chip.getkeys('input', fileset):
87
87
  if chip.get('input', fileset, mode, field=None).getvalues():
88
- input_mode = [('input', fileset, mode)]
88
+ input_mode.append(('input', fileset, mode))
89
89
 
90
90
  filename = None
91
91
  if input_mode:
@@ -0,0 +1,17 @@
1
+ from siliconcompiler.constraints.asic_timing import \
2
+ ASICTimingConstraintSchema, ASICTimingScenarioSchema
3
+ from siliconcompiler.constraints.asic_floorplan import ASICAreaConstraint
4
+ from siliconcompiler.constraints.asic_pins import \
5
+ ASICPinConstraint, ASICPinConstraints
6
+ from siliconcompiler.constraints.asic_component import \
7
+ ASICComponentConstraint, ASICComponentConstraints
8
+
9
+ __all__ = [
10
+ "ASICTimingConstraintSchema",
11
+ "ASICTimingScenarioSchema",
12
+ "ASICAreaConstraint",
13
+ "ASICPinConstraint",
14
+ "ASICPinConstraints",
15
+ "ASICComponentConstraint",
16
+ "ASICComponentConstraints"
17
+ ]
@@ -0,0 +1,378 @@
1
+ from typing import Tuple, Union
2
+
3
+ from siliconcompiler.schema import BaseSchema, NamedSchema, EditableSchema, Parameter, \
4
+ PerNode, Scope
5
+
6
+
7
+ class ASICComponentConstraint(NamedSchema):
8
+ """
9
+ Represents a single ASIC component constraint within the design configuration.
10
+
11
+ This class defines various constraints that can be applied to an individual
12
+ ASIC component instance, such as its placement, part name (cell name),
13
+ keepout halo, and rotation.
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: component placement",
30
+ example=["api: chip.set('constraint', 'component', 'i0', 'placement', (2.0, 3.0))"],
31
+ schelp="""
32
+ Placement location of a named instance, specified as a (x, y) tuple of
33
+ floats. The location refers to the distance from the substrate origin to
34
+ the anchor point of the placed component, defined by
35
+ the :keypath:`datasheet,package,<name>,anchor` parameter."""))
36
+
37
+ schema.insert(
38
+ 'partname',
39
+ Parameter(
40
+ 'str',
41
+ pernode=PerNode.OPTIONAL,
42
+ scope=Scope.GLOBAL,
43
+ shorthelp="Constraint: component part name",
44
+ example=["api: chip.set('constraint', 'component', 'i0', 'partname', 'filler_x1')"],
45
+ schelp="""
46
+ Name of the model, type, or variant of the placed component. In the chip
47
+ design domain, 'partname' is synonymous to 'cellname' or 'cell'. The
48
+ 'partname' is required for instances that are not represented within
49
+ the design netlist (ie. physical only cells)."""))
50
+
51
+ schema.insert(
52
+ 'halo',
53
+ Parameter(
54
+ '(float,float)',
55
+ unit='um',
56
+ pernode=PerNode.OPTIONAL,
57
+ scope=Scope.GLOBAL,
58
+ shorthelp="Constraint: component halo",
59
+ switch="-constraint_component_halo 'inst <(float,float)>'",
60
+ example=[
61
+ "cli: -constraint_component_halo 'i0 (1,1)'",
62
+ "api: chip.set('constraint', 'component', 'i0', 'halo', (1, 1))"],
63
+ schelp="""
64
+ Placement keepout halo around the named component, specified as a
65
+ (horizontal, vertical) tuple."""))
66
+
67
+ rotations = ['R0', 'R90', 'R180', 'R270',
68
+ 'MX', 'MX_R90', 'MX_R180', 'MX_R270',
69
+ 'MY', 'MY_R90', 'MY_R180', 'MY_R270',
70
+ 'MZ', 'MZ_R90', 'MZ_R180', 'MZ_R270',
71
+ 'MZ_MX', 'MZ_MX_R90', 'MZ_MX_R180', 'MZ_MX_R270',
72
+ 'MZ_MY', 'MZ_MY_R90', 'MZ_MY_R180', 'MZ_MY_R270']
73
+ schema.insert(
74
+ 'rotation',
75
+ Parameter(
76
+ f'<{",".join(rotations)}>',
77
+ pernode=PerNode.OPTIONAL,
78
+ scope=Scope.GLOBAL,
79
+ defvalue='R0',
80
+ shorthelp="Constraint: component rotation",
81
+ switch="-constraint_component_rotation 'inst <str>'",
82
+ example=[
83
+ "cli: -constraint_component_rotation 'i0 R90'",
84
+ "api: chip.set('constraint', 'component', 'i0', 'rotation', 'R90')"],
85
+ schelp="""
86
+ Placement rotation of the component. Components are always placed
87
+ such that the lower left corner of the cell is at the anchor point
88
+ (0,0) after any orientation. The MZ type rotations are for 3D design and
89
+ typically not supported by 2D layout systems like traditional
90
+ ASIC tools. For graphical illustrations of the rotation types, see
91
+ the SiliconCompiler documentation.
92
+
93
+ * ``R0``: North orientation (no rotation)
94
+ * ``R90``: West orientation, rotate 90 deg counter clockwise (ccw)
95
+ * ``R180``: South orientation, rotate 180 deg counter ccw
96
+ * ``R270``: East orientation, rotate 180 deg counter ccw
97
+
98
+ * ``MX``, ``MY_R180``: Flip on x-axis
99
+ * ``MX_R90``, ``MY_R270``: Flip on x-axis and rotate 90 deg ccw
100
+ * ``MX_R180``, ``MY``: Flip on x-axis and rotate 180 deg ccw
101
+ * ``MX_R270``, ``MY_R90``: Flip on x-axis and rotate 270 deg ccw
102
+
103
+ * ``MZ``: Reverse component metal stack
104
+ * ``MZ_R90``: Reverse metal stack and rotate 90 deg ccw
105
+ * ``MZ_R180``: Reverse metal stack and rotate 180 deg ccw
106
+ * ``MZ_R270``: Reverse metal stack and rotate 270 deg ccw
107
+ * ``MZ_MX``, ``MZ_MY_R180``: Reverse metal stack and flip on x-axis
108
+ * ``MZ_MX_R90``, ``MZ_MY_R270``: Reverse metal stack, flip on x-axis, and
109
+ rotate 90 deg ccw
110
+ * ``MZ_MX_R180``, ``MZ_MY``: Reverse metal stack, flip on x-axis, and rotate
111
+ 180 deg ccw
112
+ * ``MZ_MX_R270``, ``MZ_MY_R90``: Reverse metal stack, flip on x-axis and rotate
113
+ 270 deg ccw
114
+ """))
115
+
116
+ def set_placement(self, x: float, y: float, step: str = None, index: Union[str, int] = None):
117
+ """
118
+ Sets the placement constraint for the component.
119
+
120
+ Args:
121
+ x (float): The X-coordinate for the component's anchor point in
122
+ micrometers (um) relative to the substrate origin.
123
+ y (float): The Y-coordinate for the component's anchor point in
124
+ micrometers (um) relative to the substrate origin.
125
+ step (str, optional): step name.
126
+ index (str, optional): index name.
127
+
128
+ Raises:
129
+ TypeError: If `x` or `y` is not an int or float.
130
+ """
131
+ if not isinstance(x, (int, float)):
132
+ raise TypeError("x must be a number")
133
+ if not isinstance(y, (int, float)):
134
+ raise TypeError("y must be a number")
135
+ return self.set("placement", (x, y), step=step, index=index)
136
+
137
+ def get_placement(self, step: str = None, index: Union[str, int] = None) -> Tuple[float, float]:
138
+ """
139
+ Retrieves the current placement constraint of the component.
140
+
141
+ Args:
142
+ step (str, optional): step name.
143
+ index (str, optional): index name.
144
+
145
+ Returns:
146
+ Tuple[float, float]: A tuple (x, y) representing the component's
147
+ anchor point coordinates in micrometers (um).
148
+ """
149
+ return self.get("placement", step=step, index=index)
150
+
151
+ def set_partname(self, name: str, step: str = None, index: Union[str, int] = None):
152
+ """
153
+ Sets the part name (cell name) constraint for the component.
154
+
155
+ Args:
156
+ name (str): The name of the model, type, or variant of the placed component.
157
+ This is required for instances not in the design netlist.
158
+ step (str, optional): step name.
159
+ index (str, optional): index name.
160
+
161
+ Raises:
162
+ ValueError: If `name` is an empty string or None.
163
+ """
164
+ if not name:
165
+ raise ValueError("a partname is required")
166
+ return self.set("partname", name, step=step, index=index)
167
+
168
+ def get_partname(self, step: str = None, index: Union[str, int] = None) -> str:
169
+ """
170
+ Retrieves the current part name (cell name) constraint of the component.
171
+
172
+ Args:
173
+ step (str, optional): step name.
174
+ index (str, optional): index name.
175
+
176
+ Returns:
177
+ str: The part name of the component.
178
+ """
179
+ return self.get("partname", step=step, index=index)
180
+
181
+ def set_halo(self, x: float, y: float, step: str = None, index: Union[str, int] = None):
182
+ """
183
+ Sets the placement keepout halo constraint around the component.
184
+
185
+ Args:
186
+ x (float): The horizontal extent of the halo in micrometers (um).
187
+ Must be a non-negative numeric value.
188
+ y (float): The vertical extent of the halo in micrometers (um).
189
+ Must be a non-negative numeric value.
190
+ step (str, optional): step name.
191
+ index (str, optional): index name.
192
+
193
+ Raises:
194
+ TypeError: If `x` or `y` is not an int or float.
195
+ ValueError: If `x` or `y` is a negative value.
196
+ """
197
+ if not isinstance(x, (int, float)):
198
+ raise TypeError("x must be a number")
199
+ if not isinstance(y, (int, float)):
200
+ raise TypeError("y must be a number")
201
+ if x < 0:
202
+ raise ValueError("x must be a positive number")
203
+ if y < 0:
204
+ raise ValueError("y must be a positive number")
205
+ return self.set("halo", (x, y), step=step, index=index)
206
+
207
+ def get_halo(self, step: str = None, index: Union[str, int] = None) -> Tuple[float, float]:
208
+ """
209
+ Retrieves the current placement keepout halo constraint of the component.
210
+
211
+ Args:
212
+ step (str, optional): step name.
213
+ index (str, optional): index name.
214
+
215
+ Returns:
216
+ Tuple[float, float]: A tuple (horizontal, vertical) representing the
217
+ halo extents in micrometers (um).
218
+ """
219
+ return self.get("halo", step=step, index=index)
220
+
221
+ def set_rotation(self, rotation: str, step: str = None, index: Union[str, int] = None):
222
+ """
223
+ Sets the rotation constraint for the component.
224
+
225
+ Args:
226
+ rotation (str): The desired rotation of the component. Valid values
227
+ are defined by the `rotations` list schema help
228
+ (e.g., 'R0', 'R90', 'MX', 'MZ_R90').
229
+ step (str, optional): step name.
230
+ index (str, optional): index name.
231
+ """
232
+ return self.set("rotation", rotation, step=step, index=index)
233
+
234
+ def get_rotation(self, step: str = None, index: Union[str, int] = None) -> str:
235
+ """
236
+ Retrieves the current rotation constraint of the component.
237
+
238
+ Args:
239
+ step (str, optional): step name.
240
+ index (str, optional): index name.
241
+
242
+ Returns:
243
+ str: The rotation of the component.
244
+ """
245
+ return self.get("rotation", step=step, index=index)
246
+
247
+
248
+ class ASICComponentConstraints(BaseSchema):
249
+ """
250
+ Manages a collection of ASIC component constraints.
251
+
252
+ This class provides methods to add, retrieve, create, and remove
253
+ individual :class:`ASICComponentConstraint` objects, allowing for organized
254
+ management of component-level placement and property constraints.
255
+ """
256
+ def __init__(self):
257
+ super().__init__()
258
+
259
+ schema = EditableSchema(self)
260
+ schema.insert("default", ASICComponentConstraint())
261
+
262
+ def add_component(self, component: ASICComponentConstraint):
263
+ """
264
+ Adds a component constraint to the design configuration.
265
+
266
+ This method incorporates a new or updated component constraint into the system's
267
+ configuration. If a constraint with the same name already exists, it will
268
+ be overwritten (`clobber=True`).
269
+
270
+ Args:
271
+ component: The :class:`ASICComponentConstraint` object representing the component
272
+ constraint to add. This object must have a valid name defined
273
+ via its `name()` method.
274
+
275
+ Raises:
276
+ TypeError: If the provided `component` argument is not an instance of
277
+ `ASICComponentConstraint`.
278
+ ValueError: If the `component` object's `name()` method returns None,
279
+ indicating that the component constraint does not have a defined name.
280
+ """
281
+ if not isinstance(component, ASICComponentConstraint):
282
+ raise TypeError("component must be a component constraint object")
283
+
284
+ if component.name() is None:
285
+ raise ValueError("component constraint must have a name")
286
+
287
+ EditableSchema(self).insert(component.name(), component, clobber=True)
288
+
289
+ def get_component(self, component: str = None):
290
+ """
291
+ Retrieves one or all component constraints from the configuration.
292
+
293
+ This method provides flexibility to fetch either a specific component constraint
294
+ by its name or a collection of all currently defined constraints.
295
+
296
+ Args:
297
+ component (str, optional): The name (string) of the specific component
298
+ constraint to retrieve. If this argument is
299
+ omitted or set to None, the method will return
300
+ a dictionary containing all available component constraints.
301
+
302
+ Returns:
303
+ - If `component` is provided: The :class:`ASICComponentConstraint` object
304
+ corresponding to the specified component name.
305
+ - If `component` is None: A dictionary where keys are component names (str) and
306
+ values are their respective :class:`ASICComponentConstraint` objects.
307
+
308
+ Raises:
309
+ LookupError: If a specific `component` name is provided but no component
310
+ constraint with that name is found in the configuration.
311
+ """
312
+ if component is None:
313
+ components = {}
314
+ for component in self.getkeys():
315
+ components[component] = self.get(component, field="schema")
316
+ return components
317
+
318
+ if not self.valid(component):
319
+ raise LookupError(f"{component} is not defined")
320
+ return self.get(component, field="schema")
321
+
322
+ def make_component(self, component: str) -> ASICComponentConstraint:
323
+ """
324
+ Creates and adds a new component constraint with the specified name.
325
+
326
+ This method initializes a new :class:`ASICComponentConstraint` object with the given
327
+ name and immediately adds it to the design configuration. It ensures that
328
+ a constraint with the same name does not already exist, preventing accidental
329
+ overwrites.
330
+
331
+ Args:
332
+ component (str): The name for the new component constraint. This name must be
333
+ a non-empty string and unique within the current configuration.
334
+
335
+ Returns:
336
+ ASICComponentConstraint: The newly created :class:`ASICComponentConstraint` object.
337
+
338
+ Raises:
339
+ ValueError: If the provided `component` name is empty or None.
340
+ LookupError: If a component constraint with the specified `component` name
341
+ already exists in the configuration.
342
+ """
343
+ if not component:
344
+ raise ValueError("component name is required")
345
+
346
+ if self.valid(component):
347
+ raise LookupError(f"{component} constraint already exists")
348
+
349
+ constraint = ASICComponentConstraint(component)
350
+ self.add_component(constraint)
351
+ return constraint
352
+
353
+ def remove_component(self, component: str) -> bool:
354
+ """
355
+ Removes a component constraint from the design configuration.
356
+
357
+ This method deletes the specified component constraint from the system's
358
+ configuration.
359
+
360
+ Args:
361
+ component (str): The name of the component constraint to remove.
362
+ This name must be a non-empty string.
363
+
364
+ Returns:
365
+ bool: True if the component constraint was successfully removed, False if no
366
+ component constraint with the given name was found.
367
+
368
+ Raises:
369
+ ValueError: If the provided `component` name is empty or None.
370
+ """
371
+ if not component:
372
+ raise ValueError("component name is required")
373
+
374
+ if not self.valid(component):
375
+ return False
376
+
377
+ EditableSchema(self).remove(component)
378
+ return True