siliconcompiler 0.35.2__py3-none-any.whl → 0.35.4__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 (86) hide show
  1. siliconcompiler/_metadata.py +1 -1
  2. siliconcompiler/apps/sc_issue.py +18 -2
  3. siliconcompiler/apps/smake.py +106 -100
  4. siliconcompiler/checklist.py +2 -1
  5. siliconcompiler/constraints/asic_component.py +49 -11
  6. siliconcompiler/constraints/asic_floorplan.py +23 -21
  7. siliconcompiler/constraints/asic_pins.py +55 -17
  8. siliconcompiler/constraints/asic_timing.py +53 -22
  9. siliconcompiler/constraints/fpga_timing.py +5 -6
  10. siliconcompiler/data/templates/replay/replay.sh.j2 +27 -14
  11. siliconcompiler/flowgraph.py +418 -129
  12. siliconcompiler/library.py +5 -4
  13. siliconcompiler/package/__init__.py +17 -6
  14. siliconcompiler/package/https.py +10 -5
  15. siliconcompiler/project.py +92 -33
  16. siliconcompiler/remote/client.py +17 -6
  17. siliconcompiler/scheduler/docker.py +24 -25
  18. siliconcompiler/scheduler/scheduler.py +284 -121
  19. siliconcompiler/scheduler/schedulernode.py +196 -90
  20. siliconcompiler/scheduler/slurm.py +113 -29
  21. siliconcompiler/scheduler/taskscheduler.py +0 -7
  22. siliconcompiler/schema/__init__.py +3 -2
  23. siliconcompiler/schema/_metadata.py +1 -1
  24. siliconcompiler/schema/baseschema.py +205 -93
  25. siliconcompiler/schema/editableschema.py +29 -0
  26. siliconcompiler/schema/namedschema.py +21 -13
  27. siliconcompiler/schema/parametervalue.py +14 -2
  28. siliconcompiler/schema/safeschema.py +18 -7
  29. siliconcompiler/schema_support/dependencyschema.py +4 -3
  30. siliconcompiler/schema_support/option.py +82 -1
  31. siliconcompiler/schema_support/pathschema.py +14 -15
  32. siliconcompiler/schema_support/record.py +5 -4
  33. siliconcompiler/targets/asap7_demo.py +4 -1
  34. siliconcompiler/tool.py +56 -29
  35. siliconcompiler/tools/builtin/__init__.py +2 -0
  36. siliconcompiler/tools/builtin/filter.py +8 -1
  37. siliconcompiler/tools/builtin/importfiles.py +2 -0
  38. siliconcompiler/tools/klayout/__init__.py +3 -0
  39. siliconcompiler/tools/klayout/scripts/klayout_convert_drc_db.py +1 -0
  40. siliconcompiler/tools/klayout/scripts/klayout_export.py +1 -0
  41. siliconcompiler/tools/klayout/scripts/klayout_operations.py +1 -0
  42. siliconcompiler/tools/klayout/scripts/klayout_show.py +2 -1
  43. siliconcompiler/tools/klayout/scripts/klayout_utils.py +3 -4
  44. siliconcompiler/tools/klayout/show.py +17 -5
  45. siliconcompiler/tools/openroad/__init__.py +27 -1
  46. siliconcompiler/tools/openroad/_apr.py +81 -4
  47. siliconcompiler/tools/openroad/clock_tree_synthesis.py +1 -0
  48. siliconcompiler/tools/openroad/global_placement.py +1 -0
  49. siliconcompiler/tools/openroad/init_floorplan.py +116 -7
  50. siliconcompiler/tools/openroad/power_grid_analysis.py +174 -0
  51. siliconcompiler/tools/openroad/repair_design.py +1 -0
  52. siliconcompiler/tools/openroad/repair_timing.py +1 -0
  53. siliconcompiler/tools/openroad/scripts/apr/preamble.tcl +1 -1
  54. siliconcompiler/tools/openroad/scripts/apr/sc_init_floorplan.tcl +42 -4
  55. siliconcompiler/tools/openroad/scripts/apr/sc_irdrop.tcl +146 -0
  56. siliconcompiler/tools/openroad/scripts/apr/sc_repair_design.tcl +1 -1
  57. siliconcompiler/tools/openroad/scripts/apr/sc_write_data.tcl +4 -6
  58. siliconcompiler/tools/openroad/scripts/common/procs.tcl +1 -1
  59. siliconcompiler/tools/openroad/scripts/common/reports.tcl +1 -1
  60. siliconcompiler/tools/openroad/scripts/rcx/sc_rcx_bench.tcl +2 -4
  61. siliconcompiler/tools/opensta/__init__.py +1 -1
  62. siliconcompiler/tools/opensta/scripts/sc_timing.tcl +17 -12
  63. siliconcompiler/tools/vivado/scripts/sc_bitstream.tcl +11 -0
  64. siliconcompiler/tools/vivado/scripts/sc_place.tcl +11 -0
  65. siliconcompiler/tools/vivado/scripts/sc_route.tcl +11 -0
  66. siliconcompiler/tools/vivado/scripts/sc_syn_fpga.tcl +10 -0
  67. siliconcompiler/tools/vpr/__init__.py +28 -0
  68. siliconcompiler/tools/yosys/prepareLib.py +7 -2
  69. siliconcompiler/tools/yosys/scripts/sc_screenshot.tcl +1 -1
  70. siliconcompiler/tools/yosys/scripts/sc_synth_asic.tcl +40 -4
  71. siliconcompiler/tools/yosys/scripts/sc_synth_fpga.tcl +15 -5
  72. siliconcompiler/tools/yosys/syn_asic.py +62 -2
  73. siliconcompiler/tools/yosys/syn_fpga.py +8 -0
  74. siliconcompiler/toolscripts/_tools.json +6 -6
  75. siliconcompiler/utils/__init__.py +243 -51
  76. siliconcompiler/utils/curation.py +89 -56
  77. siliconcompiler/utils/issue.py +6 -1
  78. siliconcompiler/utils/multiprocessing.py +35 -2
  79. siliconcompiler/utils/paths.py +21 -0
  80. siliconcompiler/utils/settings.py +141 -0
  81. {siliconcompiler-0.35.2.dist-info → siliconcompiler-0.35.4.dist-info}/METADATA +5 -4
  82. {siliconcompiler-0.35.2.dist-info → siliconcompiler-0.35.4.dist-info}/RECORD +86 -83
  83. {siliconcompiler-0.35.2.dist-info → siliconcompiler-0.35.4.dist-info}/WHEEL +0 -0
  84. {siliconcompiler-0.35.2.dist-info → siliconcompiler-0.35.4.dist-info}/entry_points.txt +0 -0
  85. {siliconcompiler-0.35.2.dist-info → siliconcompiler-0.35.4.dist-info}/licenses/LICENSE +0 -0
  86. {siliconcompiler-0.35.2.dist-info → siliconcompiler-0.35.4.dist-info}/top_level.txt +0 -0
@@ -1,4 +1,4 @@
1
- from typing import Union, Tuple
1
+ from typing import Union, Tuple, Optional
2
2
 
3
3
  from siliconcompiler.schema import BaseSchema, NamedSchema, EditableSchema, Parameter, \
4
4
  PerNode, Scope
@@ -13,7 +13,7 @@ class ASICPinConstraint(NamedSchema):
13
13
  metal layer, and its relative position on the chip's side.
14
14
  """
15
15
 
16
- def __init__(self, name: str = None):
16
+ def __init__(self, name: Optional[str] = None):
17
17
  super().__init__()
18
18
  self.set_name(name)
19
19
 
@@ -129,7 +129,8 @@ class ASICPinConstraint(NamedSchema):
129
129
  same order number, the actual order is at the discretion of the
130
130
  tool."""))
131
131
 
132
- def set_width(self, width: float, step: str = None, index: Union[str, int] = None):
132
+ def set_width(self, width: float,
133
+ step: Optional[str] = None, index: Optional[Union[str, int]] = None):
133
134
  """
134
135
  Sets the width constraint for the pin.
135
136
 
@@ -149,7 +150,8 @@ class ASICPinConstraint(NamedSchema):
149
150
  raise ValueError("width must be a positive value")
150
151
  return self.set("width", width, step=step, index=index)
151
152
 
152
- def get_width(self, step: str = None, index: Union[str, int] = None) -> float:
153
+ def get_width(self, step: Optional[str] = None, index: Optional[Union[str, int]] = None) \
154
+ -> float:
153
155
  """
154
156
  Retrieves the current width constraint of the pin.
155
157
 
@@ -162,7 +164,8 @@ class ASICPinConstraint(NamedSchema):
162
164
  """
163
165
  return self.get("width", step=step, index=index)
164
166
 
165
- def set_length(self, length: float, step: str = None, index: Union[str, int] = None):
167
+ def set_length(self, length: float,
168
+ step: Optional[str] = None, index: Optional[Union[str, int]] = None):
166
169
  """
167
170
  Sets the length constraint for the pin.
168
171
 
@@ -182,7 +185,8 @@ class ASICPinConstraint(NamedSchema):
182
185
  raise ValueError("length must be a positive value")
183
186
  return self.set("length", length, step=step, index=index)
184
187
 
185
- def get_length(self, step: str = None, index: Union[str, int] = None) -> float:
188
+ def get_length(self, step: Optional[str] = None, index: Optional[Union[str, int]] = None) \
189
+ -> float:
186
190
  """
187
191
  Retrieves the current length constraint of the pin.
188
192
 
@@ -195,7 +199,8 @@ class ASICPinConstraint(NamedSchema):
195
199
  """
196
200
  return self.get("length", step=step, index=index)
197
201
 
198
- def set_placement(self, x: float, y: float, step: str = None, index: Union[str, int] = None):
202
+ def set_placement(self, x: float, y: float,
203
+ step: Optional[str] = None, index: Optional[Union[str, int]] = None):
199
204
  """
200
205
  Sets the placement constraint for the pin.
201
206
 
@@ -216,7 +221,8 @@ class ASICPinConstraint(NamedSchema):
216
221
  raise TypeError("y must be a number")
217
222
  return self.set("placement", (x, y), step=step, index=index)
218
223
 
219
- def get_placement(self, step: str = None, index: Union[str, int] = None) -> Tuple[float, float]:
224
+ def get_placement(self, step: Optional[str] = None, index: Optional[Union[str, int]] = None) \
225
+ -> Tuple[float, float]:
220
226
  """
221
227
  Retrieves the current placement constraint of the pin.
222
228
 
@@ -230,7 +236,8 @@ class ASICPinConstraint(NamedSchema):
230
236
  """
231
237
  return self.get("placement", step=step, index=index)
232
238
 
233
- def set_shape(self, shape: str, step: str = None, index: Union[str, int] = None):
239
+ def set_shape(self, shape: str,
240
+ step: Optional[str] = None, index: Optional[Union[str, int]] = None):
234
241
  """
235
242
  Sets the shape constraint for the pin.
236
243
 
@@ -243,7 +250,7 @@ class ASICPinConstraint(NamedSchema):
243
250
  """
244
251
  return self.set("shape", shape, step=step, index=index)
245
252
 
246
- def get_shape(self, step: str = None, index: Union[str, int] = None) -> str:
253
+ def get_shape(self, step: Optional[str] = None, index: Optional[Union[str, int]] = None) -> str:
247
254
  """
248
255
  Retrieves the current shape constraint of the pin.
249
256
 
@@ -256,7 +263,8 @@ class ASICPinConstraint(NamedSchema):
256
263
  """
257
264
  return self.get("shape", step=step, index=index)
258
265
 
259
- def set_layer(self, layer: str, step: str = None, index: Union[str, int] = None):
266
+ def set_layer(self, layer: str,
267
+ step: Optional[str] = None, index: Optional[Union[str, int]] = None):
260
268
  """
261
269
  Sets the metal layer constraint for the pin.
262
270
 
@@ -269,7 +277,7 @@ class ASICPinConstraint(NamedSchema):
269
277
  """
270
278
  return self.set("layer", layer, step=step, index=index)
271
279
 
272
- def get_layer(self, step: str = None, index: Union[str, int] = None) -> str:
280
+ def get_layer(self, step: Optional[str] = None, index: Optional[Union[str, int]] = None) -> str:
273
281
  """
274
282
  Retrieves the current metal layer constraint of the pin.
275
283
 
@@ -282,7 +290,8 @@ class ASICPinConstraint(NamedSchema):
282
290
  """
283
291
  return self.get("layer", step=step, index=index)
284
292
 
285
- def set_side(self, side: Union[int, str], step: str = None, index: Union[str, int] = None):
293
+ def set_side(self, side: Union[int, str],
294
+ step: Optional[str] = None, index: Optional[Union[str, int]] = None):
286
295
  """
287
296
  Sets the side constraint for the pin, indicating where it should be placed.
288
297
 
@@ -318,7 +327,7 @@ class ASICPinConstraint(NamedSchema):
318
327
 
319
328
  return self.set("side", side, step=step, index=index)
320
329
 
321
- def get_side(self, step: str = None, index: Union[str, int] = None) -> int:
330
+ def get_side(self, step: Optional[str] = None, index: Optional[Union[str, int]] = None) -> int:
322
331
  """
323
332
  Retrieves the current side constraint of the pin.
324
333
 
@@ -331,7 +340,8 @@ class ASICPinConstraint(NamedSchema):
331
340
  """
332
341
  return self.get("side", step=step, index=index)
333
342
 
334
- def set_order(self, order: int, step: str = None, index: Union[str, int] = None):
343
+ def set_order(self, order: int,
344
+ step: Optional[str] = None, index: Optional[Union[str, int]] = None):
335
345
  """
336
346
  Sets the relative order constraint for the pin on its assigned side.
337
347
 
@@ -343,7 +353,7 @@ class ASICPinConstraint(NamedSchema):
343
353
  """
344
354
  return self.set("order", order, step=step, index=index)
345
355
 
346
- def get_order(self, step: str = None, index: Union[str, int] = None) -> int:
356
+ def get_order(self, step: Optional[str] = None, index: Optional[Union[str, int]] = None) -> int:
347
357
  """
348
358
  Retrieves the current order constraint of the pin.
349
359
 
@@ -398,7 +408,7 @@ class ASICPinConstraints(BaseSchema):
398
408
 
399
409
  EditableSchema(self).insert(pin.name, pin, clobber=True)
400
410
 
401
- def get_pinconstraint(self, pin: str = None):
411
+ def get_pinconstraint(self, pin: Optional[str] = None):
402
412
  """
403
413
  Retrieves one or all pin constraints from the configuration.
404
414
 
@@ -461,6 +471,34 @@ class ASICPinConstraints(BaseSchema):
461
471
  self.add_pinconstraint(constraint)
462
472
  return constraint
463
473
 
474
+ def copy_pinconstraint(self, pin: str, name: str, insert: bool = True) -> ASICPinConstraint:
475
+ """
476
+ Copies an existing pin constraint, renames it, and optionally adds it to the design.
477
+
478
+ This method retrieves the pin constraint identified by ``pin``, creates a
479
+ deep copy of it, and renames the copy to ``name``. If ``insert`` is True,
480
+ the new constraint is immediately added to the configuration.
481
+
482
+ Args:
483
+ pin (str): The name of the existing pin constraint to be copied.
484
+ name (str): The name to assign to the new copied constraint.
485
+ insert (bool, optional): Whether to add the newly created constraint
486
+ to the configuration. Defaults to True.
487
+
488
+ Returns:
489
+ ASICPinConstraint: The newly created copy of the pin constraint.
490
+
491
+ Raises:
492
+ LookupError: If the source pin constraint specified by ``pin`` does not exist.
493
+ """
494
+ constraint = EditableSchema(self.get_pinconstraint(pin)).copy()
495
+ EditableSchema(constraint).rename(name)
496
+ if insert:
497
+ if self.valid(name):
498
+ raise ValueError(f"{name} already exists")
499
+ self.add_pinconstraint(constraint)
500
+ return constraint
501
+
464
502
  def remove_pinconstraint(self, pin: str) -> bool:
465
503
  """
466
504
  Removes a pin constraint from the design configuration.
@@ -1,4 +1,4 @@
1
- from typing import Union, Set, List, Tuple
1
+ from typing import Union, Set, List, Tuple, Optional
2
2
 
3
3
  from siliconcompiler.schema import BaseSchema, NamedSchema, EditableSchema, Parameter, \
4
4
  PerNode, Scope
@@ -14,7 +14,7 @@ class ASICTimingScenarioSchema(NamedSchema):
14
14
  operating mode, SDC filesets, and timing checks to be performed.
15
15
  """
16
16
 
17
- def __init__(self, name: str = None):
17
+ def __init__(self, name: Optional[str] = None):
18
18
  super().__init__()
19
19
  self.set_name(name)
20
20
 
@@ -126,7 +126,7 @@ class ASICTimingScenarioSchema(NamedSchema):
126
126
  def set_pin_voltage(self,
127
127
  pin: str,
128
128
  voltage: float,
129
- step: str = None, index: Union[str, int] = None):
129
+ step: Optional[str] = None, index: Optional[Union[str, int]] = None):
130
130
  """
131
131
  Sets the voltage for a specified pin.
132
132
 
@@ -140,7 +140,8 @@ class ASICTimingScenarioSchema(NamedSchema):
140
140
 
141
141
  def get_pin_voltage(self,
142
142
  pin: str,
143
- step: str = None, index: Union[str, int] = None) -> float:
143
+ step: Optional[str] = None, index: Optional[Union[str, int]] = None) \
144
+ -> float:
144
145
  """
145
146
  Gets the voltage of a specified pin.
146
147
 
@@ -162,7 +163,7 @@ class ASICTimingScenarioSchema(NamedSchema):
162
163
  def add_libcorner(self,
163
164
  libcorner: Union[List[str], str],
164
165
  clobber: bool = False,
165
- step: str = None, index: Union[str, int] = None):
166
+ step: Optional[str] = None, index: Optional[Union[str, int]] = None):
166
167
  """
167
168
  Adds a library corner to the design.
168
169
 
@@ -179,8 +180,8 @@ class ASICTimingScenarioSchema(NamedSchema):
179
180
  else:
180
181
  return self.add("libcorner", libcorner, step=step, index=index)
181
182
 
182
- def get_libcorner(self,
183
- step: str = None, index: Union[str, int] = None) -> Set[str]:
183
+ def get_libcorner(self, step: Optional[str] = None, index: Optional[Union[str, int]] = None) \
184
+ -> Set[str]:
184
185
  """
185
186
  Gets the set of library corners.
186
187
 
@@ -195,7 +196,7 @@ class ASICTimingScenarioSchema(NamedSchema):
195
196
 
196
197
  def set_pexcorner(self,
197
198
  pexcorner: str,
198
- step: str = None, index: Union[str, int] = None):
199
+ step: Optional[str] = None, index: Optional[Union[str, int]] = None):
199
200
  """
200
201
  Sets the parasitic extraction (PEX) corner for the design.
201
202
 
@@ -207,7 +208,7 @@ class ASICTimingScenarioSchema(NamedSchema):
207
208
  return self.set("pexcorner", pexcorner, step=step, index=index)
208
209
 
209
210
  def get_pexcorner(self,
210
- step: str = None, index: Union[str, int] = None) -> str:
211
+ step: Optional[str] = None, index: Optional[Union[str, int]] = None) -> str:
211
212
  """
212
213
  Gets the parasitic extraction (PEX) corner currently set for the design.
213
214
 
@@ -222,7 +223,7 @@ class ASICTimingScenarioSchema(NamedSchema):
222
223
 
223
224
  def set_mode(self,
224
225
  mode: str,
225
- step: str = None, index: Union[str, int] = None):
226
+ step: Optional[str] = None, index: Optional[Union[str, int]] = None):
226
227
  """
227
228
  Sets the operational mode for the design.
228
229
 
@@ -234,7 +235,7 @@ class ASICTimingScenarioSchema(NamedSchema):
234
235
  return self.set("mode", mode, step=step, index=index)
235
236
 
236
237
  def get_mode(self,
237
- step: str = None, index: Union[str, int] = None) -> str:
238
+ step: Optional[str] = None, index: Optional[Union[str, int]] = None) -> str:
238
239
  """
239
240
  Gets the operational mode currently set for the design.
240
241
 
@@ -249,7 +250,7 @@ class ASICTimingScenarioSchema(NamedSchema):
249
250
 
250
251
  def set_opcond(self,
251
252
  opcond: str,
252
- step: str = None, index: Union[str, int] = None):
253
+ step: Optional[str] = None, index: Optional[Union[str, int]] = None):
253
254
  """
254
255
  Sets the operating condition for the design.
255
256
 
@@ -261,7 +262,7 @@ class ASICTimingScenarioSchema(NamedSchema):
261
262
  return self.set("opcond", opcond, step=step, index=index)
262
263
 
263
264
  def get_opcond(self,
264
- step: str = None, index: Union[str, int] = None) -> str:
265
+ step: Optional[str] = None, index: Optional[Union[str, int]] = None) -> str:
265
266
  """
266
267
  Gets the operating condition currently set for the design.
267
268
 
@@ -276,7 +277,7 @@ class ASICTimingScenarioSchema(NamedSchema):
276
277
 
277
278
  def set_temperature(self,
278
279
  temperature: float,
279
- step: str = None, index: Union[str, int] = None):
280
+ step: Optional[str] = None, index: Optional[Union[str, int]] = None):
280
281
  """
281
282
  Sets the temperature for the design.
282
283
 
@@ -287,8 +288,8 @@ class ASICTimingScenarioSchema(NamedSchema):
287
288
  """
288
289
  return self.set("temperature", temperature, step=step, index=index)
289
290
 
290
- def get_temperature(self,
291
- step: str = None, index: Union[str, int] = None) -> float:
291
+ def get_temperature(self, step: Optional[str] = None, index: Optional[Union[str, int]] = None) \
292
+ -> float:
292
293
  """
293
294
  Gets the temperature currently set for the design.
294
295
 
@@ -305,7 +306,7 @@ class ASICTimingScenarioSchema(NamedSchema):
305
306
  design: Union[Design, str],
306
307
  fileset: str,
307
308
  clobber: bool = False,
308
- step: str = None, index: Union[str, int] = None):
309
+ step: Optional[str] = None, index: Optional[Union[str, int]] = None):
309
310
  """
310
311
  Adds an SDC fileset for a given design.
311
312
 
@@ -337,8 +338,8 @@ class ASICTimingScenarioSchema(NamedSchema):
337
338
  else:
338
339
  return self.add("sdcfileset", (design, fileset), step=step, index=index)
339
340
 
340
- def get_sdcfileset(self,
341
- step: str = None, index: Union[str, int] = None) -> List[Tuple[str, str]]:
341
+ def get_sdcfileset(self, step: Optional[str] = None, index: Optional[Union[str, int]] = None) \
342
+ -> List[Tuple[str, str]]:
342
343
  """
343
344
  Gets the list of SDC filesets.
344
345
 
@@ -354,7 +355,7 @@ class ASICTimingScenarioSchema(NamedSchema):
354
355
  def add_check(self,
355
356
  check: Union[List[str], str],
356
357
  clobber: bool = False,
357
- step: str = None, index: Union[str, int] = None):
358
+ step: Optional[str] = None, index: Optional[Union[str, int]] = None):
358
359
  """
359
360
  Adds a check to the design process.
360
361
 
@@ -371,7 +372,8 @@ class ASICTimingScenarioSchema(NamedSchema):
371
372
  else:
372
373
  return self.add("check", check, step=step, index=index)
373
374
 
374
- def get_check(self, step: str = None, index: Union[str, int] = None) -> Set[str]:
375
+ def get_check(self, step: Optional[str] = None, index: Optional[Union[str, int]] = None) \
376
+ -> Set[str]:
375
377
  """
376
378
  Gets the set of checks configured for the design process.
377
379
 
@@ -426,7 +428,7 @@ class ASICTimingConstraintSchema(BaseSchema):
426
428
 
427
429
  EditableSchema(self).insert(scenario.name, scenario, clobber=True)
428
430
 
429
- def get_scenario(self, scenario: str = None):
431
+ def get_scenario(self, scenario: Optional[str] = None):
430
432
  """
431
433
  Retrieves one or all timing scenarios from the configuration.
432
434
 
@@ -490,6 +492,35 @@ class ASICTimingConstraintSchema(BaseSchema):
490
492
  self.add_scenario(scenarioobj)
491
493
  return scenarioobj
492
494
 
495
+ def copy_scenario(self, scenario: str, name: str, insert: bool = True) \
496
+ -> ASICTimingScenarioSchema:
497
+ """
498
+ Copies an existing timing scenario, renames it, and optionally adds it to the design.
499
+
500
+ This method retrieves the scenario identified by ``scenario``, creates a
501
+ deep copy of it, and renames the copy to ``name``. If ``insert`` is True,
502
+ the new scenario is immediately added to the configuration.
503
+
504
+ Args:
505
+ scenario (str): The name of the existing scenario to be copied.
506
+ name (str): The name to assign to the new copied scenario.
507
+ insert (bool, optional): Whether to add the newly created scenario
508
+ to the configuration. Defaults to True.
509
+
510
+ Returns:
511
+ ASICTimingScenarioSchema: The newly created copy of the scenario.
512
+
513
+ Raises:
514
+ LookupError: If the source scenario specified by ``scenario`` does not exist.
515
+ """
516
+ constraint = EditableSchema(self.get_scenario(scenario)).copy()
517
+ EditableSchema(constraint).rename(name)
518
+ if insert:
519
+ if self.valid(name):
520
+ raise ValueError(f"{name} already exists")
521
+ self.add_scenario(constraint)
522
+ return constraint
523
+
493
524
  def remove_scenario(self, scenario: str) -> bool:
494
525
  """
495
526
  Removes a timing scenario from the design configuration.
@@ -1,4 +1,4 @@
1
- from typing import Union
1
+ from typing import Union, Optional
2
2
 
3
3
  from siliconcompiler.schema import BaseSchema, NamedSchema, EditableSchema, Parameter, \
4
4
  PerNode, Scope
@@ -12,7 +12,7 @@ class FPGATimingScenarioSchema(NamedSchema):
12
12
  scenario and operating mode.
13
13
  """
14
14
 
15
- def __init__(self, name: str = None):
15
+ def __init__(self, name: Optional[str] = None):
16
16
  super().__init__()
17
17
  self.set_name(name)
18
18
 
@@ -31,7 +31,7 @@ class FPGATimingScenarioSchema(NamedSchema):
31
31
 
32
32
  def set_mode(self,
33
33
  mode: str,
34
- step: str = None, index: Union[str, int] = None):
34
+ step: Optional[str] = None, index: Optional[Union[str, int]] = None):
35
35
  """
36
36
  Sets the operational mode for the design.
37
37
 
@@ -42,8 +42,7 @@ class FPGATimingScenarioSchema(NamedSchema):
42
42
  """
43
43
  return self.set("mode", mode, step=step, index=index)
44
44
 
45
- def get_mode(self,
46
- step: str = None, index: Union[str, int] = None) -> str:
45
+ def get_mode(self, step: Optional[str] = None, index: Optional[Union[str, int]] = None) -> str:
47
46
  """
48
47
  Gets the operational mode currently set for the design.
49
48
 
@@ -98,7 +97,7 @@ class FPGATimingConstraintSchema(BaseSchema):
98
97
 
99
98
  EditableSchema(self).insert(scenario.name, scenario, clobber=True)
100
99
 
101
- def get_scenario(self, scenario: str = None):
100
+ def get_scenario(self, scenario: Optional[str] = None):
102
101
  """
103
102
  Retrieves one or all timing scenarios from the configuration.
104
103
 
@@ -4,10 +4,27 @@ if [ "${BASH_SOURCE[0]}" != "$0" ]; then
4
4
  return
5
5
  fi
6
6
 
7
+ __print_help() {
8
+ # Print help information for this file
9
+ echo "Usage: $0"
10
+ echo " Options:"
11
+ echo " --which print which executable would be used"
12
+ echo " --version print the version of the executable, if supported"
13
+ echo " --directory print the execution directory"
14
+ echo " --command print the execution command"
15
+ echo " --skipcd do not change directory into replay directory"
16
+ echo " --skipexports do not export environmental variables"
17
+ echo " --cmdprefix <cmd> prefix to add to the replay command, such as gdb"
18
+ echo " --cmdarg <args> prefix to add to the replay command, such as -gui"
19
+ echo " --node execute entire node"
20
+ echo " -h,--help print this help"
21
+ }
22
+
7
23
  # Parse replay arguments
8
24
  CD_WORK="{{ work_dir }}"
9
25
  PRINT=""
10
26
  CMDPREFIX=""
27
+ CMDARGS=""
11
28
  SKIPEXPORT=0
12
29
  DONODE={{ node_only }}
13
30
  while [[ $# -gt 0 ]]; do
@@ -41,27 +58,22 @@ while [[ $# -gt 0 ]]; do
41
58
  shift
42
59
  shift
43
60
  ;;
61
+ --cmdarg)
62
+ CMDARGS="$2"
63
+ shift
64
+ shift
65
+ ;;
44
66
  --node)
45
67
  DONODE=1
46
68
  shift
47
- shift
48
69
  ;;
49
70
  -h|--help)
50
- echo "Usage: $0"
51
- echo " Options:"
52
- echo " --which print which executable would be used"
53
- echo " --version print the version of the executable, if supported"
54
- echo " --directory print the execution directory"
55
- echo " --command print the execution command"
56
- echo " --skipcd do not change directory into replay directory"
57
- echo " --skipexports do not export environmental variables"
58
- echo " --cmdprefix <cmd> prefix to add to the replay command, such as dgb"
59
- echo " --node execute entire node"
60
- echo " -h,--help print this help"
71
+ __print_help
61
72
  exit 0
62
73
  ;;
63
74
  *)
64
75
  echo "Unknown option $1"
76
+ __print_help
65
77
  exit 1
66
78
  ;;
67
79
  esac
@@ -105,5 +117,6 @@ python3 -m siliconcompiler.scheduler.run_node \
105
117
  {% if cmds|length > 0 %}else
106
118
  # Command execution
107
119
  $CMDPREFIX \{% for cmd in cmds %}
108
- {% if not loop.first %} {% endif %}{{ cmd }}{% if not loop.last %} \{% endif %}{% endfor %}
109
- {% endif %}fi
120
+ {% if not loop.first %} {% endif %}{{ cmd }} \{% endfor %}
121
+ {% endif %} ${CMDARGS}
122
+ fi