siliconcompiler 0.34.1__py3-none-any.whl → 0.34.3__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 (129) hide show
  1. siliconcompiler/__init__.py +23 -4
  2. siliconcompiler/__main__.py +1 -7
  3. siliconcompiler/_metadata.py +1 -1
  4. siliconcompiler/apps/_common.py +104 -23
  5. siliconcompiler/apps/sc.py +4 -8
  6. siliconcompiler/apps/sc_dashboard.py +6 -4
  7. siliconcompiler/apps/sc_install.py +10 -6
  8. siliconcompiler/apps/sc_issue.py +7 -5
  9. siliconcompiler/apps/sc_remote.py +1 -1
  10. siliconcompiler/apps/sc_server.py +9 -14
  11. siliconcompiler/apps/sc_show.py +7 -6
  12. siliconcompiler/apps/smake.py +130 -94
  13. siliconcompiler/apps/utils/replay.py +4 -7
  14. siliconcompiler/apps/utils/summarize.py +3 -5
  15. siliconcompiler/asic.py +420 -0
  16. siliconcompiler/checklist.py +25 -2
  17. siliconcompiler/cmdlineschema.py +534 -0
  18. siliconcompiler/constraints/__init__.py +17 -0
  19. siliconcompiler/constraints/asic_component.py +378 -0
  20. siliconcompiler/constraints/asic_floorplan.py +449 -0
  21. siliconcompiler/constraints/asic_pins.py +489 -0
  22. siliconcompiler/constraints/asic_timing.py +517 -0
  23. siliconcompiler/core.py +10 -35
  24. siliconcompiler/data/templates/tcl/manifest.tcl.j2 +8 -0
  25. siliconcompiler/dependencyschema.py +96 -202
  26. siliconcompiler/design.py +327 -241
  27. siliconcompiler/filesetschema.py +250 -0
  28. siliconcompiler/flowgraph.py +298 -106
  29. siliconcompiler/fpga.py +124 -1
  30. siliconcompiler/library.py +331 -0
  31. siliconcompiler/metric.py +327 -92
  32. siliconcompiler/metrics/__init__.py +7 -0
  33. siliconcompiler/metrics/asic.py +245 -0
  34. siliconcompiler/metrics/fpga.py +220 -0
  35. siliconcompiler/package/__init__.py +391 -67
  36. siliconcompiler/package/git.py +92 -16
  37. siliconcompiler/package/github.py +114 -22
  38. siliconcompiler/package/https.py +79 -16
  39. siliconcompiler/packageschema.py +341 -16
  40. siliconcompiler/pathschema.py +255 -0
  41. siliconcompiler/pdk.py +566 -1
  42. siliconcompiler/project.py +1460 -0
  43. siliconcompiler/record.py +38 -1
  44. siliconcompiler/remote/__init__.py +5 -2
  45. siliconcompiler/remote/client.py +11 -6
  46. siliconcompiler/remote/schema.py +5 -23
  47. siliconcompiler/remote/server.py +41 -54
  48. siliconcompiler/report/__init__.py +3 -3
  49. siliconcompiler/report/dashboard/__init__.py +48 -14
  50. siliconcompiler/report/dashboard/cli/__init__.py +99 -21
  51. siliconcompiler/report/dashboard/cli/board.py +364 -179
  52. siliconcompiler/report/dashboard/web/__init__.py +90 -12
  53. siliconcompiler/report/dashboard/web/components/__init__.py +219 -240
  54. siliconcompiler/report/dashboard/web/components/flowgraph.py +49 -26
  55. siliconcompiler/report/dashboard/web/components/graph.py +139 -100
  56. siliconcompiler/report/dashboard/web/layouts/__init__.py +29 -1
  57. siliconcompiler/report/dashboard/web/layouts/_common.py +38 -2
  58. siliconcompiler/report/dashboard/web/layouts/vertical_flowgraph.py +39 -26
  59. siliconcompiler/report/dashboard/web/layouts/vertical_flowgraph_node_tab.py +50 -50
  60. siliconcompiler/report/dashboard/web/layouts/vertical_flowgraph_sac_tabs.py +49 -46
  61. siliconcompiler/report/dashboard/web/state.py +141 -14
  62. siliconcompiler/report/dashboard/web/utils/__init__.py +79 -16
  63. siliconcompiler/report/dashboard/web/utils/file_utils.py +74 -11
  64. siliconcompiler/report/dashboard/web/viewer.py +25 -1
  65. siliconcompiler/report/report.py +5 -2
  66. siliconcompiler/report/summary_image.py +29 -11
  67. siliconcompiler/scheduler/__init__.py +9 -1
  68. siliconcompiler/scheduler/docker.py +81 -4
  69. siliconcompiler/scheduler/run_node.py +37 -20
  70. siliconcompiler/scheduler/scheduler.py +211 -36
  71. siliconcompiler/scheduler/schedulernode.py +394 -60
  72. siliconcompiler/scheduler/send_messages.py +77 -29
  73. siliconcompiler/scheduler/slurm.py +76 -12
  74. siliconcompiler/scheduler/taskscheduler.py +142 -21
  75. siliconcompiler/schema/__init__.py +0 -4
  76. siliconcompiler/schema/baseschema.py +338 -59
  77. siliconcompiler/schema/editableschema.py +14 -6
  78. siliconcompiler/schema/journal.py +28 -17
  79. siliconcompiler/schema/namedschema.py +22 -14
  80. siliconcompiler/schema/parameter.py +89 -28
  81. siliconcompiler/schema/parametertype.py +2 -0
  82. siliconcompiler/schema/parametervalue.py +258 -15
  83. siliconcompiler/schema/safeschema.py +25 -2
  84. siliconcompiler/schema/schema_cfg.py +23 -19
  85. siliconcompiler/schema/utils.py +2 -2
  86. siliconcompiler/schema_obj.py +24 -5
  87. siliconcompiler/tool.py +1131 -265
  88. siliconcompiler/tools/bambu/__init__.py +41 -0
  89. siliconcompiler/tools/builtin/concatenate.py +2 -2
  90. siliconcompiler/tools/builtin/minimum.py +2 -1
  91. siliconcompiler/tools/builtin/mux.py +2 -1
  92. siliconcompiler/tools/builtin/nop.py +2 -1
  93. siliconcompiler/tools/builtin/verify.py +2 -1
  94. siliconcompiler/tools/klayout/__init__.py +95 -0
  95. siliconcompiler/tools/openroad/__init__.py +289 -0
  96. siliconcompiler/tools/openroad/scripts/apr/preamble.tcl +3 -0
  97. siliconcompiler/tools/openroad/scripts/apr/sc_detailed_route.tcl +7 -2
  98. siliconcompiler/tools/openroad/scripts/apr/sc_global_route.tcl +8 -4
  99. siliconcompiler/tools/openroad/scripts/apr/sc_init_floorplan.tcl +9 -5
  100. siliconcompiler/tools/openroad/scripts/common/write_images.tcl +5 -1
  101. siliconcompiler/tools/slang/__init__.py +1 -1
  102. siliconcompiler/tools/slang/elaborate.py +2 -1
  103. siliconcompiler/tools/vivado/scripts/sc_run.tcl +1 -1
  104. siliconcompiler/tools/vivado/scripts/sc_syn_fpga.tcl +8 -1
  105. siliconcompiler/tools/vivado/syn_fpga.py +6 -0
  106. siliconcompiler/tools/vivado/vivado.py +35 -2
  107. siliconcompiler/tools/vpr/__init__.py +150 -0
  108. siliconcompiler/tools/yosys/__init__.py +369 -1
  109. siliconcompiler/tools/yosys/scripts/procs.tcl +0 -1
  110. siliconcompiler/toolscripts/_tools.json +5 -10
  111. siliconcompiler/utils/__init__.py +66 -0
  112. siliconcompiler/utils/flowgraph.py +2 -2
  113. siliconcompiler/utils/issue.py +2 -1
  114. siliconcompiler/utils/logging.py +14 -0
  115. siliconcompiler/utils/multiprocessing.py +256 -0
  116. siliconcompiler/utils/showtools.py +10 -0
  117. {siliconcompiler-0.34.1.dist-info → siliconcompiler-0.34.3.dist-info}/METADATA +6 -6
  118. {siliconcompiler-0.34.1.dist-info → siliconcompiler-0.34.3.dist-info}/RECORD +122 -115
  119. {siliconcompiler-0.34.1.dist-info → siliconcompiler-0.34.3.dist-info}/entry_points.txt +3 -0
  120. siliconcompiler/schema/cmdlineschema.py +0 -250
  121. siliconcompiler/schema/packageschema.py +0 -101
  122. siliconcompiler/toolscripts/rhel8/install-slang.sh +0 -40
  123. siliconcompiler/toolscripts/rhel9/install-slang.sh +0 -40
  124. siliconcompiler/toolscripts/ubuntu20/install-slang.sh +0 -47
  125. siliconcompiler/toolscripts/ubuntu22/install-slang.sh +0 -37
  126. siliconcompiler/toolscripts/ubuntu24/install-slang.sh +0 -37
  127. {siliconcompiler-0.34.1.dist-info → siliconcompiler-0.34.3.dist-info}/WHEEL +0 -0
  128. {siliconcompiler-0.34.1.dist-info → siliconcompiler-0.34.3.dist-info}/licenses/LICENSE +0 -0
  129. {siliconcompiler-0.34.1.dist-info → siliconcompiler-0.34.3.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,517 @@
1
+ from typing import Union, Set, List, Tuple
2
+
3
+ from siliconcompiler.schema import BaseSchema, NamedSchema, EditableSchema, Parameter, \
4
+ PerNode, Scope
5
+ from siliconcompiler import DesignSchema
6
+
7
+
8
+ class ASICTimingScenarioSchema(NamedSchema):
9
+ """
10
+ Represents a single timing scenario for ASIC design constraints.
11
+
12
+ This class encapsulates various parameters that define a specific timing
13
+ scenario, such as operating voltage, temperature, library corners, PEX corners,
14
+ operating mode, SDC filesets, and timing checks to be performed.
15
+ """
16
+
17
+ def __init__(self, name: str = None):
18
+ super().__init__()
19
+ self.set_name(name)
20
+
21
+ schema = EditableSchema(self)
22
+ schema.insert(
23
+ 'voltage', 'default',
24
+ Parameter(
25
+ "float",
26
+ pernode=PerNode.OPTIONAL,
27
+ unit='V',
28
+ scope=Scope.GLOBAL,
29
+ shorthelp="Constraint: pin voltage level",
30
+ switch="-constraint_timing_voltage 'scenario pin <float>'",
31
+ example=["api: chip.set('constraint', 'timing', 'worst', 'voltage', 'VDD', '0.9')"],
32
+ help="""Operating voltage applied to a specific pin in the scenario."""))
33
+
34
+ schema.insert(
35
+ 'temperature',
36
+ Parameter(
37
+ 'float',
38
+ pernode=PerNode.OPTIONAL,
39
+ unit='C',
40
+ scope=Scope.GLOBAL,
41
+ shorthelp="Constraint: temperature",
42
+ switch="-constraint_timing_temperature 'scenario <float>'",
43
+ example=["api: chip.set('constraint', 'timing', 'worst', 'temperature', '125')"],
44
+ help="""Chip temperature applied to the scenario specified in degrees C."""))
45
+
46
+ schema.insert(
47
+ 'libcorner',
48
+ Parameter(
49
+ '{str}',
50
+ pernode=PerNode.OPTIONAL,
51
+ scope=Scope.GLOBAL,
52
+ shorthelp="Constraint: library corner",
53
+ switch="-constraint_timing_libcorner 'scenario <str>'",
54
+ example=["api: chip.set('constraint', 'timing', 'worst', 'libcorner', 'ttt')"],
55
+ help="""List of characterization corners used to select
56
+ timing files for all logiclibs and macrolibs."""))
57
+
58
+ schema.insert(
59
+ 'pexcorner',
60
+ Parameter(
61
+ 'str',
62
+ pernode=PerNode.OPTIONAL,
63
+ scope=Scope.GLOBAL,
64
+ shorthelp="Constraint: pex corner",
65
+ switch="-constraint_timing_pexcorner 'scenario <str>'",
66
+ example=["api: chip.set('constraint', 'timing', 'worst', 'pexcorner', 'max')"],
67
+ help="""Parasitic corner applied to the scenario. The
68
+ 'pexcorner' string must match a corner found in :keypath:`pdk,<pdk>,pexmodel`."""))
69
+
70
+ schema.insert(
71
+ 'opcond',
72
+ Parameter(
73
+ 'str',
74
+ pernode=PerNode.OPTIONAL,
75
+ scope=Scope.GLOBAL,
76
+ shorthelp="Constraint: operating condition",
77
+ switch="-constraint_timing_opcond 'scenario <str>'",
78
+ example=["api: chip.set('constraint', 'timing', 'worst', 'opcond', 'typical_1.0')"],
79
+ help="""Operating condition applied to the scenario. The value
80
+ can be used to access specific conditions within the library
81
+ timing models from the :keypath:`asic,logiclib` timing models."""))
82
+
83
+ schema.insert(
84
+ 'mode',
85
+ Parameter(
86
+ 'str',
87
+ pernode=PerNode.OPTIONAL,
88
+ scope=Scope.GLOBAL,
89
+ shorthelp="Constraint: operating mode",
90
+ switch="-constraint_timing_mode 'scenario <str>'",
91
+ example=["api: chip.set('constraint', 'timing', 'worst', 'mode', 'test')"],
92
+ help="""Operating mode for the scenario. Operating mode strings
93
+ can be values such as test, functional, standby."""))
94
+
95
+ schema.insert(
96
+ 'sdcfileset',
97
+ Parameter(
98
+ '[(str,str)]',
99
+ pernode=PerNode.OPTIONAL,
100
+ scope=Scope.GLOBAL,
101
+ shorthelp="Constraint: SDC files",
102
+ switch="-constraint_timing_file 'scenario <file>'",
103
+ example=["api: chip.set('constraint', 'timing', 'worst', 'file', 'hello.sdc')"],
104
+ help="""List of timing constraint sets files to use for the scenario. The
105
+ values are combined with any constraints specified by the design
106
+ 'constraint' parameter. If no constraints are found, a default
107
+ constraint file is used based on the clock definitions."""))
108
+
109
+ schema.insert(
110
+ 'check',
111
+ Parameter(
112
+ '{<setup,hold,maxtran,maxcap,mincap,power,leakagepower,dynamicpower,signalem>}',
113
+ pernode=PerNode.OPTIONAL,
114
+ scope=Scope.GLOBAL,
115
+ shorthelp="Constraint: timing checks",
116
+ switch="-constraint_timing_check 'scenario <str>'",
117
+ example=["api: chip.add('constraint', 'timing', 'worst', 'check', 'setup')"],
118
+ help="""
119
+ List of checks for to perform for the scenario. The checks must
120
+ align with the capabilities of the EDA tools and flow being used.
121
+ Checks generally include objectives like meeting setup and hold goals
122
+ and minimize power. Standard check names include setup, hold, power,
123
+ noise, reliability."""))
124
+
125
+ def set_pin_voltage(self,
126
+ pin: str,
127
+ voltage: float,
128
+ step: str = None, index: Union[str, int] = None):
129
+ """
130
+ Sets the voltage for a specified pin.
131
+
132
+ Args:
133
+ pin (str): The name of the pin.
134
+ voltage (float): The voltage value to set.
135
+ step (str, optional): step name.
136
+ index (str, optional): index name.
137
+ """
138
+ return self.set("voltage", pin, voltage, step=step, index=index)
139
+
140
+ def get_pin_voltage(self,
141
+ pin: str,
142
+ step: str = None, index: Union[str, int] = None) -> float:
143
+ """
144
+ Gets the voltage of a specified pin.
145
+
146
+ Args:
147
+ pin (str): The name of the pin.
148
+ step (str, optional): step name.
149
+ index (str, optional): index name.
150
+
151
+ Returns:
152
+ The voltage of the pin.
153
+
154
+ Raises:
155
+ LookupError: If the specified pin does not have a voltage defined.
156
+ """
157
+ if not self.valid("voltage", pin):
158
+ raise LookupError(f"{pin} does not have voltage")
159
+ return self.get("voltage", pin, step=step, index=index)
160
+
161
+ def add_libcorner(self,
162
+ libcorner: str,
163
+ clobber: bool = False,
164
+ step: str = None, index: Union[str, int] = None):
165
+ """
166
+ Adds a library corner to the design.
167
+
168
+ Args:
169
+ libcorner (str): The name of the library corner to add.
170
+ clobber (bool): If True, existing library corners at the specified step/index will
171
+ be overwritten.
172
+ If False (default), the library corner will be added.
173
+ step (str, optional): step name.
174
+ index (str, optional): index name.
175
+ """
176
+ if clobber:
177
+ return self.set("libcorner", libcorner, step=step, index=index)
178
+ else:
179
+ return self.add("libcorner", libcorner, step=step, index=index)
180
+
181
+ def get_libcorner(self,
182
+ step: str = None, index: Union[str, int] = None) -> Set[str]:
183
+ """
184
+ Gets the set of library corners.
185
+
186
+ Args:
187
+ step (str, optional): step name.
188
+ index (str, optional): index name.
189
+
190
+ Returns:
191
+ A set of library corner names.
192
+ """
193
+ return self.get("libcorner", step=step, index=index)
194
+
195
+ def set_pexcorner(self,
196
+ pexcorner: str,
197
+ step: str = None, index: Union[str, int] = None):
198
+ """
199
+ Sets the parasitic extraction (PEX) corner for the design.
200
+
201
+ Args:
202
+ pexcorner (str): The name of the PEX corner to set.
203
+ step (str, optional): step name.
204
+ index (str, optional): index name.
205
+ """
206
+ return self.set("pexcorner", pexcorner, step=step, index=index)
207
+
208
+ def get_pexcorner(self,
209
+ step: str = None, index: Union[str, int] = None) -> str:
210
+ """
211
+ Gets the parasitic extraction (PEX) corner currently set for the design.
212
+
213
+ Args:
214
+ step (str, optional): step name.
215
+ index (str, optional): index name.
216
+
217
+ Returns:
218
+ The name of the PEX corner.
219
+ """
220
+ return self.get("pexcorner", step=step, index=index)
221
+
222
+ def set_mode(self,
223
+ mode: str,
224
+ step: str = None, index: Union[str, int] = None):
225
+ """
226
+ Sets the operational mode for the design.
227
+
228
+ Args:
229
+ mode (str): The operational mode to set (e.g., "func", "scan").
230
+ step (str, optional): step name.
231
+ index (str, optional): index name.
232
+ """
233
+ return self.set("mode", mode, step=step, index=index)
234
+
235
+ def get_mode(self,
236
+ step: str = None, index: Union[str, int] = None) -> str:
237
+ """
238
+ Gets the operational mode currently set for the design.
239
+
240
+ Args:
241
+ step (str, optional): step name.
242
+ index (str, optional): index name.
243
+
244
+ Returns:
245
+ The name of the operational mode.
246
+ """
247
+ return self.get("mode", step=step, index=index)
248
+
249
+ def set_opcond(self,
250
+ opcond: str,
251
+ step: str = None, index: Union[str, int] = None):
252
+ """
253
+ Sets the operating condition for the design.
254
+
255
+ Args:
256
+ opcond (str): The operating condition to set (e.g., "WC", "BC").
257
+ step (str, optional): step name.
258
+ index (str, optional): index name.
259
+ """
260
+ return self.set("opcond", opcond, step=step, index=index)
261
+
262
+ def get_opcond(self,
263
+ step: str = None, index: Union[str, int] = None) -> str:
264
+ """
265
+ Gets the operating condition currently set for the design.
266
+
267
+ Args:
268
+ step (str, optional): step name.
269
+ index (str, optional): index name.
270
+
271
+ Returns:
272
+ The name of the operating condition.
273
+ """
274
+ return self.get("opcond", step=step, index=index)
275
+
276
+ def set_temperature(self,
277
+ temperature: float,
278
+ step: str = None, index: Union[str, int] = None):
279
+ """
280
+ Sets the temperature for the design.
281
+
282
+ Args:
283
+ temperature (float): The temperature value to set in degrees Celsius.
284
+ step (str, optional): step name.
285
+ index (str, optional): index name.
286
+ """
287
+ return self.set("temperature", temperature, step=step, index=index)
288
+
289
+ def get_temperature(self,
290
+ step: str = None, index: Union[str, int] = None) -> float:
291
+ """
292
+ Gets the temperature currently set for the design.
293
+
294
+ Args:
295
+ step (str, optional): step name.
296
+ index (str, optional): index name.
297
+
298
+ Returns:
299
+ The temperature in degrees Celsius.
300
+ """
301
+ return self.get("temperature", step=step, index=index)
302
+
303
+ def add_sdcfileset(self,
304
+ design: Union[DesignSchema, str],
305
+ fileset: str,
306
+ clobber: bool = False,
307
+ step: str = None, index: Union[str, int] = None):
308
+ """
309
+ Adds an SDC fileset for a given design.
310
+
311
+ Args:
312
+ design (:class:`DesignSchema` or str): The design object or the name of the design to
313
+ associate the fileset with.
314
+ fileset (str): The name of the SDC fileset to add.
315
+ clobber (bool): If True, existing SDC filesets for the design at the specified
316
+ step/index will be overwritten.
317
+ If False (default), the SDC fileset will be added.
318
+ step (str, optional): step name.
319
+ index (str, optional): index name.
320
+
321
+ Raises:
322
+ TypeError: If `design` is not a DesignSchema object or a string, or if `fileset` is not
323
+ a string.
324
+ """
325
+ if isinstance(design, DesignSchema):
326
+ design = design.name
327
+
328
+ if not isinstance(design, str):
329
+ raise TypeError("design must be a design object or string")
330
+
331
+ if not isinstance(fileset, str):
332
+ raise TypeError("fileset must be a string")
333
+
334
+ if clobber:
335
+ return self.set("sdcfileset", (design, fileset), step=step, index=index)
336
+ else:
337
+ return self.add("sdcfileset", (design, fileset), step=step, index=index)
338
+
339
+ def get_sdcfileset(self,
340
+ step: str = None, index: Union[str, int] = None) -> List[Tuple[str, str]]:
341
+ """
342
+ Gets the list of SDC filesets.
343
+
344
+ Args:
345
+ step (str, optional): step name.
346
+ index (str, optional): index name.
347
+
348
+ Returns:
349
+ A list of tuples, where each tuple contains the design name and the SDC fileset name.
350
+ """
351
+ return self.get("sdcfileset", step=step, index=index)
352
+
353
+ def add_check(self,
354
+ check: str,
355
+ clobber: bool = False,
356
+ step: str = None, index: Union[str, int] = None):
357
+ """
358
+ Adds a check to the design process.
359
+
360
+ Args:
361
+ check (str): The name of the check to add.
362
+ clobber (bool): If True, existing checks at the specified step/index will
363
+ be overwritten.
364
+ If False (default), the check will be added.
365
+ step (str, optional): step name.
366
+ index (str, optional): index name.
367
+ """
368
+ if clobber:
369
+ return self.set("check", check, step=step, index=index)
370
+ else:
371
+ return self.add("check", check, step=step, index=index)
372
+
373
+ def get_check(self, step: str = None, index: Union[str, int] = None) -> Set[str]:
374
+ """
375
+ Gets the set of checks configured for the design process.
376
+
377
+ Args:
378
+ step (str, optional): step name.
379
+ index (str, optional): index name.
380
+
381
+ Returns:
382
+ A set of check names.
383
+ """
384
+ return self.get("check", step=step, index=index)
385
+
386
+
387
+ class ASICTimingConstraintSchema(BaseSchema):
388
+ """
389
+ Manages a collection of ASIC timing scenarios for design constraints.
390
+
391
+ This class provides methods to add, retrieve, create, and remove
392
+ individual :class:`ASICTimingScenarioSchema` objects, allowing for organized
393
+ management of various timing-related constraints for different operating
394
+ conditions or analysis modes.
395
+ """
396
+
397
+ def __init__(self):
398
+ super().__init__()
399
+
400
+ EditableSchema(self).insert("default", ASICTimingScenarioSchema())
401
+
402
+ def add_scenario(self, scenario: ASICTimingScenarioSchema):
403
+ """
404
+ Adds a timing scenario to the design configuration.
405
+
406
+ This method is responsible for incorporating a new or updated timing scenario
407
+ into the system's configuration. If a scenario with the same name already
408
+ exists, it will be overwritten (`clobber=True`).
409
+
410
+ Args:
411
+ scenario: The :class:`ASICTimingScenarioSchema` object representing the timing scenario
412
+ to add. This object must have a valid name defined via its `name()` method.
413
+
414
+ Raises:
415
+ TypeError: If the provided `scenario` argument is not an instance of
416
+ :class:`ASICTimingScenarioSchema`.
417
+ ValueError: If the `scenario` object's `name()` method returns None, indicating
418
+ that the scenario does not have a defined name.
419
+ """
420
+ if not isinstance(scenario, ASICTimingScenarioSchema):
421
+ raise TypeError("scenario must be a timing scenario object")
422
+
423
+ if scenario.name is None:
424
+ raise ValueError("scenario must have a name")
425
+
426
+ EditableSchema(self).insert(scenario.name, scenario, clobber=True)
427
+
428
+ def get_scenario(self, scenario: str = None):
429
+ """
430
+ Retrieves one or all timing scenarios from the configuration.
431
+
432
+ This method provides flexibility to fetch either a specific timing scenario
433
+ by its name or a collection of all currently defined scenarios.
434
+
435
+ Args:
436
+ scenario (str, optional): The name (string) of the specific timing scenario to retrieve.
437
+ If this argument is omitted or set to None, the method will return
438
+ a dictionary containing all available timing scenarios.
439
+
440
+ Returns:
441
+ - If `scenario` is provided: The :class:`ASICTimingScenarioSchema` object corresponding
442
+ to the specified scenario name.
443
+ - If `scenario` is None: A dictionary where keys are scenario names (str) and
444
+ values are their respective :class:`ASICTimingScenarioSchema` objects.
445
+
446
+ Raises:
447
+ LookupError: If a specific `scenario` name is provided but no scenario with
448
+ that name is found in the configuration.
449
+ """
450
+ if scenario is None:
451
+ scenarios = {}
452
+ for scenario in self.getkeys():
453
+ scenarios[scenario] = self.get(scenario, field="schema")
454
+ return scenarios
455
+
456
+ if not self.valid(scenario):
457
+ raise LookupError(f"{scenario} is not defined")
458
+ return self.get(scenario, field="schema")
459
+
460
+ def make_scenario(self, scenario: str) -> ASICTimingScenarioSchema:
461
+ """
462
+ Creates and adds a new timing scenario with the specified name.
463
+
464
+ This method initializes a new :class:`ASICTimingScenarioSchema` object with the given
465
+ name and immediately adds it to the constraint configuration. It ensures that
466
+ a scenario with the same name does not already exist, preventing accidental
467
+ overwrites.
468
+
469
+ Args:
470
+ scenario (str): The name for the new timing scenario. This name must be
471
+ a non-empty string and unique within the current configuration.
472
+
473
+ Returns:
474
+ :class:ASICTimingScenarioSchema: The newly created :class:`ASICTimingScenarioSchema`
475
+ object.
476
+
477
+ Raises:
478
+ ValueError: If the provided `scenario` name is empty or None.
479
+ LookupError: If a scenario with the specified `scenario` name already exists
480
+ in the configuration.
481
+ """
482
+ if not scenario:
483
+ raise ValueError("scenario name is required")
484
+
485
+ if self.valid(scenario):
486
+ raise LookupError(f"{scenario} scenario already exists")
487
+
488
+ scenarioobj = ASICTimingScenarioSchema(scenario)
489
+ self.add_scenario(scenarioobj)
490
+ return scenarioobj
491
+
492
+ def remove_scenario(self, scenario: str) -> bool:
493
+ """
494
+ Removes a timing scenario from the design configuration.
495
+
496
+ This method deletes the specified timing scenario from the system's
497
+ configuration.
498
+
499
+ Args:
500
+ scenario (str): The name of the timing scenario to remove.
501
+ This name must be a non-empty string.
502
+
503
+ Returns:
504
+ bool: True if the scenario was successfully removed, False if no
505
+ scenario with the given name was found.
506
+
507
+ Raises:
508
+ ValueError: If the provided `scenario` name is empty or None.
509
+ """
510
+ if not scenario:
511
+ raise ValueError("scenario name is required")
512
+
513
+ if not self.valid(scenario):
514
+ return False
515
+
516
+ EditableSchema(self).remove(scenario)
517
+ return True
siliconcompiler/core.py CHANGED
@@ -31,12 +31,12 @@ from siliconcompiler.report import _generate_summary_image, _open_summary_image
31
31
  from siliconcompiler.report.dashboard.web import WebDashboard
32
32
  from siliconcompiler.report.dashboard.cli import CliDashboard
33
33
  from siliconcompiler.report.dashboard import DashboardType
34
- import glob
35
- from siliconcompiler.scheduler.scheduler import Scheduler
34
+ from siliconcompiler.scheduler import Scheduler, SchedulerNode
36
35
  from siliconcompiler.utils.flowgraph import _check_flowgraph_io, _get_flowgraph_information
37
36
  from siliconcompiler.tools._common import get_tool_task
38
37
  from types import FunctionType, ModuleType
39
38
  from siliconcompiler.flowgraph import RuntimeFlowgraph
39
+ from siliconcompiler.package import Resolver
40
40
 
41
41
 
42
42
  class Chip:
@@ -59,6 +59,8 @@ class Chip:
59
59
  self.scversion = _metadata.version
60
60
  self.schemaversion = SCHEMA_VERSION
61
61
 
62
+ Resolver.reset_cache(self)
63
+
62
64
  # Local variables
63
65
  self.scroot = os.path.dirname(os.path.abspath(__file__))
64
66
  self._error = False
@@ -1478,12 +1480,9 @@ class Chip:
1478
1480
  if keypath[-2:] == ('option', 'builddir'):
1479
1481
  ignore_keys.append(keypath)
1480
1482
 
1481
- package_map = self.get("package", field="schema").get_resolvers()
1482
-
1483
1483
  return self.schema.check_filepaths(
1484
1484
  ignore_keys=ignore_keys,
1485
1485
  logger=self.logger,
1486
- packages=package_map,
1487
1486
  collection_dir=self._getcollectdir(),
1488
1487
  cwd=self.cwd)
1489
1488
 
@@ -1790,6 +1789,7 @@ class Chip:
1790
1789
  fout.write(template.render(manifest_dict='\n'.join(tcl_set_cmds),
1791
1790
  scroot=os.path.abspath(
1792
1791
  os.path.join(os.path.dirname(__file__))),
1792
+ toolvars={},
1793
1793
  record_access=record,
1794
1794
  record_access_id=Schema._RECORD_ACCESS_IDENTIFIER))
1795
1795
  else:
@@ -2448,34 +2448,6 @@ class Chip:
2448
2448
  else:
2449
2449
  raise SiliconCompilerError(f'Failed to copy {path}', chip=self)
2450
2450
 
2451
- ###########################################################################
2452
- def _archive_node(self, tar, step, index, include=None, verbose=True):
2453
- if verbose:
2454
- self.logger.info(f'Archiving {step}/{index}...')
2455
-
2456
- basedir = self.getworkdir(step=step, index=index)
2457
-
2458
- def arcname(path):
2459
- return os.path.relpath(path, self.cwd)
2460
-
2461
- if not os.path.isdir(basedir):
2462
- if self.get('record', 'status', step=step, index=index) != NodeStatus.SKIPPED:
2463
- self.logger.error(f'Unable to archive {step}/{index} due to missing node directory')
2464
- return
2465
-
2466
- if include:
2467
- for pattern in include:
2468
- for path in glob.iglob(os.path.join(basedir, pattern)):
2469
- tar.add(path, arcname=arcname(path))
2470
- else:
2471
- for folder in ('reports', 'outputs'):
2472
- path = os.path.join(basedir, folder)
2473
- tar.add(path, arcname=arcname(path))
2474
-
2475
- logfile = os.path.join(basedir, f'{step}.log')
2476
- if os.path.isfile(logfile):
2477
- tar.add(logfile, arcname=arcname(logfile))
2478
-
2479
2451
  ###########################################################################
2480
2452
  def __archive_job(self, tar, job, flowgraph_nodes, index=None, include=None):
2481
2453
  design = self.get('design')
@@ -2489,7 +2461,7 @@ class Chip:
2489
2461
  self.logger.warning('Archiving job with failed or incomplete run.')
2490
2462
 
2491
2463
  for (step, idx) in flowgraph_nodes:
2492
- self._archive_node(tar, step, idx, include=include)
2464
+ SchedulerNode(self, step, idx).archive(tar, include=include)
2493
2465
 
2494
2466
  ###########################################################################
2495
2467
  def archive(self, jobs=None, step=None, index=None, include=None, archive_name=None):
@@ -2961,7 +2933,7 @@ class Chip:
2961
2933
  >>> run()
2962
2934
  Runs the execution flow defined by the flowgraph dictionary.
2963
2935
  '''
2964
- from siliconcompiler.remote.client import ClientScheduler
2936
+ from siliconcompiler.remote import ClientScheduler
2965
2937
 
2966
2938
  try:
2967
2939
  if self.get('option', 'remote'):
@@ -3241,3 +3213,6 @@ class Chip:
3241
3213
 
3242
3214
  def copy(self):
3243
3215
  return copy.deepcopy(self)
3216
+
3217
+ def _init_run(self):
3218
+ pass
@@ -21,3 +21,11 @@ proc sc_root {} {
21
21
  proc _sc_cfg_get_debug { args } {
22
22
  {% if record_access %}puts "{{ record_access_id }} [join $args ,]"{% endif %}
23
23
  }
24
+
25
+
26
+ #############################################
27
+ # Tool variables
28
+ #############################################
29
+
30
+ {% for var, val in toolvars.items() %}set {{ var }} {{ val }}
31
+ {% endfor %}