siliconcompiler 0.35.4__py3-none-any.whl → 0.36.1__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.
- siliconcompiler/_metadata.py +1 -1
- siliconcompiler/constraints/__init__.py +4 -1
- siliconcompiler/constraints/asic_timing.py +230 -38
- siliconcompiler/constraints/fpga_timing.py +209 -14
- siliconcompiler/constraints/timing_mode.py +82 -0
- siliconcompiler/data/templates/tcl/manifest.tcl.j2 +0 -6
- siliconcompiler/flowgraph.py +95 -42
- siliconcompiler/flows/generate_openroad_rcx.py +2 -2
- siliconcompiler/flows/highresscreenshotflow.py +37 -0
- siliconcompiler/library.py +2 -1
- siliconcompiler/package/__init__.py +39 -45
- siliconcompiler/project.py +4 -1
- siliconcompiler/scheduler/scheduler.py +64 -35
- siliconcompiler/scheduler/schedulernode.py +5 -2
- siliconcompiler/scheduler/slurm.py +7 -6
- siliconcompiler/scheduler/taskscheduler.py +19 -16
- siliconcompiler/schema/_metadata.py +1 -1
- siliconcompiler/schema/namedschema.py +2 -4
- siliconcompiler/schema_support/cmdlineschema.py +0 -3
- siliconcompiler/schema_support/dependencyschema.py +0 -6
- siliconcompiler/schema_support/record.py +4 -3
- siliconcompiler/tool.py +58 -27
- siliconcompiler/tools/_common/tcl/sc_schema_access.tcl +0 -6
- siliconcompiler/tools/chisel/convert.py +44 -0
- siliconcompiler/tools/ghdl/convert.py +37 -2
- siliconcompiler/tools/icarus/compile.py +14 -0
- siliconcompiler/tools/keplerformal/__init__.py +7 -0
- siliconcompiler/tools/keplerformal/lec.py +112 -0
- siliconcompiler/tools/klayout/drc.py +14 -0
- siliconcompiler/tools/klayout/export.py +40 -0
- siliconcompiler/tools/klayout/operations.py +40 -0
- siliconcompiler/tools/klayout/screenshot.py +66 -1
- siliconcompiler/tools/klayout/scripts/klayout_export.py +10 -40
- siliconcompiler/tools/klayout/scripts/klayout_show.py +4 -4
- siliconcompiler/tools/klayout/scripts/klayout_utils.py +13 -1
- siliconcompiler/tools/montage/tile.py +26 -12
- siliconcompiler/tools/openroad/__init__.py +11 -0
- siliconcompiler/tools/openroad/_apr.py +780 -11
- siliconcompiler/tools/openroad/antenna_repair.py +26 -0
- siliconcompiler/tools/openroad/fillmetal_insertion.py +14 -0
- siliconcompiler/tools/openroad/global_placement.py +67 -0
- siliconcompiler/tools/openroad/global_route.py +15 -0
- siliconcompiler/tools/openroad/init_floorplan.py +19 -2
- siliconcompiler/tools/openroad/macro_placement.py +252 -0
- siliconcompiler/tools/openroad/power_grid.py +43 -0
- siliconcompiler/tools/openroad/power_grid_analysis.py +1 -1
- siliconcompiler/tools/openroad/rcx_bench.py +28 -0
- siliconcompiler/tools/openroad/rcx_extract.py +14 -0
- siliconcompiler/tools/openroad/rdlroute.py +14 -0
- siliconcompiler/tools/openroad/repair_design.py +41 -0
- siliconcompiler/tools/openroad/repair_timing.py +54 -0
- siliconcompiler/tools/openroad/screenshot.py +31 -1
- siliconcompiler/tools/openroad/scripts/apr/preamble.tcl +8 -0
- siliconcompiler/tools/openroad/scripts/apr/sc_init_floorplan.tcl +54 -15
- siliconcompiler/tools/openroad/scripts/apr/sc_irdrop.tcl +6 -4
- siliconcompiler/tools/openroad/scripts/apr/sc_write_data.tcl +4 -4
- siliconcompiler/tools/openroad/scripts/common/procs.tcl +14 -5
- siliconcompiler/tools/openroad/scripts/common/read_liberty.tcl +2 -2
- siliconcompiler/tools/openroad/scripts/common/reports.tcl +6 -3
- siliconcompiler/tools/openroad/scripts/common/screenshot.tcl +1 -1
- siliconcompiler/tools/openroad/scripts/common/write_data_physical.tcl +8 -0
- siliconcompiler/tools/openroad/scripts/common/write_images.tcl +16 -12
- siliconcompiler/tools/openroad/scripts/sc_rdlroute.tcl +3 -1
- siliconcompiler/tools/openroad/write_data.py +78 -2
- siliconcompiler/tools/opensta/scripts/sc_check_library.tcl +2 -2
- siliconcompiler/tools/opensta/scripts/sc_report_libraries.tcl +2 -2
- siliconcompiler/tools/opensta/scripts/sc_timing.tcl +12 -14
- siliconcompiler/tools/opensta/timing.py +42 -3
- siliconcompiler/tools/slang/elaborate.py +16 -1
- siliconcompiler/tools/surelog/parse.py +54 -0
- siliconcompiler/tools/verilator/compile.py +120 -0
- siliconcompiler/tools/vivado/syn_fpga.py +27 -0
- siliconcompiler/tools/vpr/route.py +40 -0
- siliconcompiler/tools/xdm/convert.py +14 -0
- siliconcompiler/tools/xyce/simulate.py +26 -0
- siliconcompiler/tools/yosys/lec_asic.py +13 -0
- siliconcompiler/tools/yosys/syn_asic.py +332 -3
- siliconcompiler/tools/yosys/syn_fpga.py +32 -0
- siliconcompiler/toolscripts/_tools.json +9 -4
- siliconcompiler/toolscripts/ubuntu22/install-keplerformal.sh +72 -0
- siliconcompiler/toolscripts/ubuntu24/install-keplerformal.sh +72 -0
- siliconcompiler/utils/multiprocessing.py +11 -0
- siliconcompiler/utils/settings.py +70 -49
- {siliconcompiler-0.35.4.dist-info → siliconcompiler-0.36.1.dist-info}/METADATA +4 -4
- {siliconcompiler-0.35.4.dist-info → siliconcompiler-0.36.1.dist-info}/RECORD +89 -83
- {siliconcompiler-0.35.4.dist-info → siliconcompiler-0.36.1.dist-info}/WHEEL +0 -0
- {siliconcompiler-0.35.4.dist-info → siliconcompiler-0.36.1.dist-info}/entry_points.txt +0 -0
- {siliconcompiler-0.35.4.dist-info → siliconcompiler-0.36.1.dist-info}/licenses/LICENSE +0 -0
- {siliconcompiler-0.35.4.dist-info → siliconcompiler-0.36.1.dist-info}/top_level.txt +0 -0
siliconcompiler/_metadata.py
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
from siliconcompiler.schema import BaseSchema
|
|
2
2
|
|
|
3
|
+
from siliconcompiler.constraints.timing_mode import TimingModeSchema
|
|
4
|
+
|
|
3
5
|
from siliconcompiler.constraints.asic_timing import \
|
|
4
6
|
ASICTimingConstraintSchema, ASICTimingScenarioSchema
|
|
5
7
|
from siliconcompiler.constraints.asic_floorplan import ASICAreaConstraint
|
|
@@ -29,5 +31,6 @@ __all__ = [
|
|
|
29
31
|
"ASICComponentConstraint",
|
|
30
32
|
"ASICComponentConstraints",
|
|
31
33
|
"FPGATimingConstraintSchema",
|
|
32
|
-
"FPGATimingScenarioSchema"
|
|
34
|
+
"FPGATimingScenarioSchema",
|
|
35
|
+
"TimingModeSchema"
|
|
33
36
|
]
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
from typing import Union, Set, List, Tuple, Optional
|
|
1
|
+
from typing import Union, Set, List, Tuple, Optional, Dict
|
|
2
2
|
|
|
3
3
|
from siliconcompiler.schema import BaseSchema, NamedSchema, EditableSchema, Parameter, \
|
|
4
4
|
PerNode, Scope
|
|
5
5
|
from siliconcompiler import Design
|
|
6
|
+
from siliconcompiler.constraints.timing_mode import TimingModeSchema
|
|
7
|
+
from siliconcompiler.schema.baseschema import LazyLoad
|
|
6
8
|
|
|
7
9
|
|
|
8
10
|
class ASICTimingScenarioSchema(NamedSchema):
|
|
@@ -93,20 +95,6 @@ class ASICTimingScenarioSchema(NamedSchema):
|
|
|
93
95
|
help="""Operating mode for the scenario. Operating mode strings
|
|
94
96
|
can be values such as test, functional, standby."""))
|
|
95
97
|
|
|
96
|
-
schema.insert(
|
|
97
|
-
'sdcfileset',
|
|
98
|
-
Parameter(
|
|
99
|
-
'[(str,str)]',
|
|
100
|
-
pernode=PerNode.OPTIONAL,
|
|
101
|
-
scope=Scope.GLOBAL,
|
|
102
|
-
shorthelp="Constraint: SDC files",
|
|
103
|
-
switch="-constraint_timing_file 'scenario <file>'",
|
|
104
|
-
example=["api: asic.set('constraint', 'timing', 'worst', 'file', 'hello.sdc')"],
|
|
105
|
-
help="""List of timing constraint sets files to use for the scenario. The
|
|
106
|
-
values are combined with any constraints specified by the design
|
|
107
|
-
'constraint' parameter. If no constraints are found, a default
|
|
108
|
-
constraint file is used based on the clock definitions."""))
|
|
109
|
-
|
|
110
98
|
schema.insert(
|
|
111
99
|
'check',
|
|
112
100
|
Parameter(
|
|
@@ -324,19 +312,22 @@ class ASICTimingScenarioSchema(NamedSchema):
|
|
|
324
312
|
TypeError: If `design` is not a Design object or a string, or if `fileset` is not
|
|
325
313
|
a string.
|
|
326
314
|
"""
|
|
327
|
-
|
|
328
|
-
|
|
315
|
+
import warnings
|
|
316
|
+
warnings.warn("This function is deprecated and will be removed in a future version, "
|
|
317
|
+
"use TimingModeSchema instead", DeprecationWarning, stacklevel=2)
|
|
329
318
|
|
|
330
|
-
|
|
331
|
-
|
|
319
|
+
mode = self.get_mode(step=step, index=index)
|
|
320
|
+
if mode is None:
|
|
321
|
+
raise ValueError("Mode not defined")
|
|
332
322
|
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
323
|
+
timing_constraints: ASICTimingConstraintSchema = self._parent()._parent()
|
|
324
|
+
try:
|
|
325
|
+
modeobj = timing_constraints.get_mode(mode)
|
|
326
|
+
except LookupError:
|
|
327
|
+
modeobj = timing_constraints.make_mode(mode)
|
|
328
|
+
return modeobj.add_sdcfileset(design=design, fileset=fileset,
|
|
329
|
+
clobber=clobber,
|
|
330
|
+
step=step, index=index)
|
|
340
331
|
|
|
341
332
|
def get_sdcfileset(self, step: Optional[str] = None, index: Optional[Union[str, int]] = None) \
|
|
342
333
|
-> List[Tuple[str, str]]:
|
|
@@ -350,7 +341,20 @@ class ASICTimingScenarioSchema(NamedSchema):
|
|
|
350
341
|
Returns:
|
|
351
342
|
A list of tuples, where each tuple contains the design name and the SDC fileset name.
|
|
352
343
|
"""
|
|
353
|
-
|
|
344
|
+
import warnings
|
|
345
|
+
warnings.warn("This function is deprecated and will be removed in a future version, "
|
|
346
|
+
"use TimingModeSchema instead", DeprecationWarning, stacklevel=2)
|
|
347
|
+
|
|
348
|
+
mode = self.get_mode(step=step, index=index)
|
|
349
|
+
if mode is None:
|
|
350
|
+
raise ValueError("Mode not defined")
|
|
351
|
+
|
|
352
|
+
timing_constraints: ASICTimingConstraintSchema = self._parent()._parent()
|
|
353
|
+
try:
|
|
354
|
+
modeobj = timing_constraints.get_mode(mode)
|
|
355
|
+
except LookupError:
|
|
356
|
+
modeobj = timing_constraints.make_mode(mode)
|
|
357
|
+
return modeobj.get_sdcfileset(step=step, index=index)
|
|
354
358
|
|
|
355
359
|
def add_check(self,
|
|
356
360
|
check: Union[List[str], str],
|
|
@@ -386,6 +390,30 @@ class ASICTimingScenarioSchema(NamedSchema):
|
|
|
386
390
|
"""
|
|
387
391
|
return self.get("check", step=step, index=index)
|
|
388
392
|
|
|
393
|
+
def _from_dict(self, manifest: Dict,
|
|
394
|
+
keypath: Union[List[str], Tuple[str, ...]],
|
|
395
|
+
version: Optional[Tuple[int, ...]] = None,
|
|
396
|
+
lazyload: LazyLoad = LazyLoad.ON) \
|
|
397
|
+
-> Tuple[Set[Tuple[str, ...]], Set[Tuple[str, ...]]]:
|
|
398
|
+
|
|
399
|
+
sdcfileset = None
|
|
400
|
+
if version and version < (0, 53, 0):
|
|
401
|
+
sdcfileset = manifest.pop("sdcfileset", None)
|
|
402
|
+
lazyload = LazyLoad.OFF
|
|
403
|
+
|
|
404
|
+
ret = super()._from_dict(manifest, keypath, version, lazyload)
|
|
405
|
+
|
|
406
|
+
if sdcfileset:
|
|
407
|
+
param = Parameter.from_dict(sdcfileset, keypath=(*keypath, "sdcfileset"),
|
|
408
|
+
version=version)
|
|
409
|
+
for value, step, index in param.getvalues():
|
|
410
|
+
if self.get_mode(step=step, index=index) is None:
|
|
411
|
+
self.set_mode("_importcreated_", step=step, index=index)
|
|
412
|
+
for design, fileset in value:
|
|
413
|
+
self.add_sdcfileset(design, fileset, step=step, index=index)
|
|
414
|
+
|
|
415
|
+
return ret
|
|
416
|
+
|
|
389
417
|
|
|
390
418
|
class ASICTimingConstraintSchema(BaseSchema):
|
|
391
419
|
"""
|
|
@@ -400,7 +428,8 @@ class ASICTimingConstraintSchema(BaseSchema):
|
|
|
400
428
|
def __init__(self):
|
|
401
429
|
super().__init__()
|
|
402
430
|
|
|
403
|
-
EditableSchema(self).insert("default", ASICTimingScenarioSchema())
|
|
431
|
+
EditableSchema(self).insert("scenario", "default", ASICTimingScenarioSchema())
|
|
432
|
+
EditableSchema(self).insert("mode", "default", TimingModeSchema())
|
|
404
433
|
|
|
405
434
|
def add_scenario(self, scenario: ASICTimingScenarioSchema):
|
|
406
435
|
"""
|
|
@@ -426,9 +455,10 @@ class ASICTimingConstraintSchema(BaseSchema):
|
|
|
426
455
|
if scenario.name is None:
|
|
427
456
|
raise ValueError("scenario must have a name")
|
|
428
457
|
|
|
429
|
-
EditableSchema(self).insert(scenario.name, scenario, clobber=True)
|
|
458
|
+
EditableSchema(self).insert("scenario", scenario.name, scenario, clobber=True)
|
|
430
459
|
|
|
431
|
-
def get_scenario(self, scenario: Optional[str] = None)
|
|
460
|
+
def get_scenario(self, scenario: Optional[str] = None) \
|
|
461
|
+
-> Union[ASICTimingScenarioSchema, Dict[str, ASICTimingScenarioSchema]]:
|
|
432
462
|
"""
|
|
433
463
|
Retrieves one or all timing scenarios from the configuration.
|
|
434
464
|
|
|
@@ -452,13 +482,13 @@ class ASICTimingConstraintSchema(BaseSchema):
|
|
|
452
482
|
"""
|
|
453
483
|
if scenario is None:
|
|
454
484
|
scenarios = {}
|
|
455
|
-
for name in self.getkeys():
|
|
456
|
-
scenarios[name] = self.get(name, field="schema")
|
|
485
|
+
for name in self.getkeys("scenario"):
|
|
486
|
+
scenarios[name] = self.get("scenario", name, field="schema")
|
|
457
487
|
return scenarios
|
|
458
488
|
|
|
459
|
-
if not self.valid(scenario):
|
|
489
|
+
if not self.valid("scenario", scenario):
|
|
460
490
|
raise LookupError(f"{scenario} is not defined")
|
|
461
|
-
return self.get(scenario, field="schema")
|
|
491
|
+
return self.get("scenario", scenario, field="schema")
|
|
462
492
|
|
|
463
493
|
def make_scenario(self, scenario: str) -> ASICTimingScenarioSchema:
|
|
464
494
|
"""
|
|
@@ -485,7 +515,7 @@ class ASICTimingConstraintSchema(BaseSchema):
|
|
|
485
515
|
if not scenario:
|
|
486
516
|
raise ValueError("scenario name is required")
|
|
487
517
|
|
|
488
|
-
if self.valid(scenario):
|
|
518
|
+
if self.valid("scenario", scenario):
|
|
489
519
|
raise LookupError(f"{scenario} scenario already exists")
|
|
490
520
|
|
|
491
521
|
scenarioobj = ASICTimingScenarioSchema(scenario)
|
|
@@ -516,7 +546,7 @@ class ASICTimingConstraintSchema(BaseSchema):
|
|
|
516
546
|
constraint = EditableSchema(self.get_scenario(scenario)).copy()
|
|
517
547
|
EditableSchema(constraint).rename(name)
|
|
518
548
|
if insert:
|
|
519
|
-
if self.valid(name):
|
|
549
|
+
if self.valid("scenario", name):
|
|
520
550
|
raise ValueError(f"{name} already exists")
|
|
521
551
|
self.add_scenario(constraint)
|
|
522
552
|
return constraint
|
|
@@ -542,8 +572,170 @@ class ASICTimingConstraintSchema(BaseSchema):
|
|
|
542
572
|
if not scenario:
|
|
543
573
|
raise ValueError("scenario name is required")
|
|
544
574
|
|
|
545
|
-
if not self.valid(scenario):
|
|
575
|
+
if not self.valid("scenario", scenario):
|
|
576
|
+
return False
|
|
577
|
+
|
|
578
|
+
EditableSchema(self).remove("scenario", scenario)
|
|
579
|
+
return True
|
|
580
|
+
|
|
581
|
+
def add_mode(self, mode: TimingModeSchema):
|
|
582
|
+
"""
|
|
583
|
+
Adds a timing mode to the design configuration.
|
|
584
|
+
|
|
585
|
+
This method is responsible for incorporating a new or updated timing mode
|
|
586
|
+
into the system's configuration. If a mode with the same name already
|
|
587
|
+
exists, it will be overwritten (`clobber=True`).
|
|
588
|
+
|
|
589
|
+
Args:
|
|
590
|
+
mode: The :class:`TimingModeSchema` object representing the timing mode
|
|
591
|
+
to add. This object must have a valid name defined via its `name()` method.
|
|
592
|
+
|
|
593
|
+
Raises:
|
|
594
|
+
TypeError: If the provided `mode` argument is not an instance of
|
|
595
|
+
:class:`TimingModeSchema`.
|
|
596
|
+
ValueError: If the `mode` object's `name()` method returns None, indicating
|
|
597
|
+
that the mode does not have a defined name.
|
|
598
|
+
"""
|
|
599
|
+
if not isinstance(mode, TimingModeSchema):
|
|
600
|
+
raise TypeError("mode must be a timing mode object")
|
|
601
|
+
|
|
602
|
+
if mode.name is None:
|
|
603
|
+
raise ValueError("mode must have a name")
|
|
604
|
+
|
|
605
|
+
EditableSchema(self).insert("mode", mode.name, mode, clobber=True)
|
|
606
|
+
|
|
607
|
+
def get_mode(self, mode: Optional[str] = None) \
|
|
608
|
+
-> Union[TimingModeSchema, Dict[str, TimingModeSchema]]:
|
|
609
|
+
"""
|
|
610
|
+
Retrieves one or all timing modes from the configuration.
|
|
611
|
+
|
|
612
|
+
This method provides flexibility to fetch either a specific timing mode
|
|
613
|
+
by its name or a collection of all currently defined modes.
|
|
614
|
+
|
|
615
|
+
Args:
|
|
616
|
+
mode (str, optional): The name (string) of the specific timing mode to retrieve.
|
|
617
|
+
If this argument is omitted or set to None, the method will
|
|
618
|
+
return a dictionary containing all available timing modes.
|
|
619
|
+
|
|
620
|
+
Returns:
|
|
621
|
+
If `mode` is provided: The :class:`TimingModeSchema` object corresponding
|
|
622
|
+
to the specified mode name.
|
|
623
|
+
If `mode` is None: A dictionary where keys are mode names (str) and
|
|
624
|
+
values are their respective :class:`TimingModeSchema` objects.
|
|
625
|
+
|
|
626
|
+
Raises:
|
|
627
|
+
LookupError: If a specific `mode` name is provided but no mode with
|
|
628
|
+
that name is found in the configuration.
|
|
629
|
+
"""
|
|
630
|
+
if mode is None:
|
|
631
|
+
modes = {}
|
|
632
|
+
for name in self.getkeys("mode"):
|
|
633
|
+
modes[name] = self.get("mode", name, field="schema")
|
|
634
|
+
return modes
|
|
635
|
+
|
|
636
|
+
if not self.valid("mode", mode):
|
|
637
|
+
raise LookupError(f"{mode} is not defined")
|
|
638
|
+
return self.get("mode", mode, field="schema")
|
|
639
|
+
|
|
640
|
+
def make_mode(self, mode: str) -> TimingModeSchema:
|
|
641
|
+
"""
|
|
642
|
+
Creates and adds a new timing mode with the specified name.
|
|
643
|
+
|
|
644
|
+
This method initializes a new :class:`TimingModeSchema` object with the given
|
|
645
|
+
name and immediately adds it to the constraint configuration. It ensures that
|
|
646
|
+
a mode with the same name does not already exist, preventing accidental
|
|
647
|
+
overwrites.
|
|
648
|
+
|
|
649
|
+
Args:
|
|
650
|
+
mode (str): The name for the new timing mode. This name must be
|
|
651
|
+
a non-empty string and unique within the current configuration.
|
|
652
|
+
|
|
653
|
+
Returns:
|
|
654
|
+
:class:`TimingModeSchema`: The newly created :class:`TimingModeSchema`
|
|
655
|
+
object.
|
|
656
|
+
|
|
657
|
+
Raises:
|
|
658
|
+
ValueError: If the provided `mode` name is empty or None.
|
|
659
|
+
LookupError: If a mode with the specified `mode` name already exists
|
|
660
|
+
in the configuration.
|
|
661
|
+
"""
|
|
662
|
+
if not mode:
|
|
663
|
+
raise ValueError("mode name is required")
|
|
664
|
+
|
|
665
|
+
if self.valid("mode", mode):
|
|
666
|
+
raise LookupError(f"{mode} mode already exists")
|
|
667
|
+
|
|
668
|
+
modeobj = TimingModeSchema(mode)
|
|
669
|
+
self.add_mode(modeobj)
|
|
670
|
+
return modeobj
|
|
671
|
+
|
|
672
|
+
def copy_mode(self, mode: str, name: str, insert: bool = True) \
|
|
673
|
+
-> TimingModeSchema:
|
|
674
|
+
"""
|
|
675
|
+
Copies an existing timing mode, renames it, and optionally adds it to the design.
|
|
676
|
+
|
|
677
|
+
This method retrieves the mode identified by ``mode``, creates a
|
|
678
|
+
deep copy of it, and renames the copy to ``name``. If ``insert`` is True,
|
|
679
|
+
the new mode is immediately added to the configuration.
|
|
680
|
+
|
|
681
|
+
Args:
|
|
682
|
+
mode (str): The name of the existing mode to be copied.
|
|
683
|
+
name (str): The name to assign to the new copied mode.
|
|
684
|
+
insert (bool, optional): Whether to add the newly created mode
|
|
685
|
+
to the configuration. Defaults to True.
|
|
686
|
+
|
|
687
|
+
Returns:
|
|
688
|
+
TimingModeSchema: The newly created copy of the mode.
|
|
689
|
+
|
|
690
|
+
Raises:
|
|
691
|
+
LookupError: If the source mode specified by ``mode`` does not exist.
|
|
692
|
+
"""
|
|
693
|
+
newmode = EditableSchema(self.get_mode(mode)).copy()
|
|
694
|
+
EditableSchema(newmode).rename(name)
|
|
695
|
+
if insert:
|
|
696
|
+
if self.valid("mode", name):
|
|
697
|
+
raise ValueError(f"{name} already exists")
|
|
698
|
+
self.add_mode(newmode)
|
|
699
|
+
return newmode
|
|
700
|
+
|
|
701
|
+
def remove_mode(self, mode: str) -> bool:
|
|
702
|
+
"""
|
|
703
|
+
Removes a timing mode from the design configuration.
|
|
704
|
+
|
|
705
|
+
This method deletes the specified timing mode from the system's
|
|
706
|
+
configuration.
|
|
707
|
+
|
|
708
|
+
Args:
|
|
709
|
+
mode (str): The name of the timing mode to remove.
|
|
710
|
+
This name must be a non-empty string.
|
|
711
|
+
|
|
712
|
+
Returns:
|
|
713
|
+
bool: True if the mode was successfully removed, False if no
|
|
714
|
+
mode with the given name was found.
|
|
715
|
+
|
|
716
|
+
Raises:
|
|
717
|
+
ValueError: If the provided `mode` name is empty or None.
|
|
718
|
+
"""
|
|
719
|
+
if not mode:
|
|
720
|
+
raise ValueError("mode name is required")
|
|
721
|
+
|
|
722
|
+
if not self.valid("mode", mode):
|
|
546
723
|
return False
|
|
547
724
|
|
|
548
|
-
EditableSchema(self).remove(
|
|
725
|
+
EditableSchema(self).remove("mode", mode)
|
|
549
726
|
return True
|
|
727
|
+
|
|
728
|
+
def _from_dict(self, manifest: Dict,
|
|
729
|
+
keypath: Union[List[str], Tuple[str, ...]],
|
|
730
|
+
version: Optional[Tuple[int, ...]] = None,
|
|
731
|
+
lazyload: LazyLoad = LazyLoad.ON) \
|
|
732
|
+
-> Tuple[Set[Tuple[str, ...]], Set[Tuple[str, ...]]]:
|
|
733
|
+
if version and version < (0, 53, 0):
|
|
734
|
+
manifest.pop("__meta__", None)
|
|
735
|
+
manifest = {
|
|
736
|
+
"scenario": manifest,
|
|
737
|
+
"mode": self.getdict("mode")
|
|
738
|
+
}
|
|
739
|
+
lazyload = LazyLoad.OFF
|
|
740
|
+
|
|
741
|
+
return super()._from_dict(manifest, keypath, version, lazyload)
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
from typing import Union, Optional
|
|
1
|
+
from typing import List, Set, Tuple, Union, Optional, Dict
|
|
2
2
|
|
|
3
3
|
from siliconcompiler.schema import BaseSchema, NamedSchema, EditableSchema, Parameter, \
|
|
4
4
|
PerNode, Scope
|
|
5
|
+
from siliconcompiler.constraints.timing_mode import TimingModeSchema
|
|
6
|
+
from siliconcompiler.schema.baseschema import LazyLoad
|
|
5
7
|
|
|
6
8
|
|
|
7
9
|
class FPGATimingScenarioSchema(NamedSchema):
|
|
@@ -69,7 +71,8 @@ class FPGATimingConstraintSchema(BaseSchema):
|
|
|
69
71
|
def __init__(self):
|
|
70
72
|
super().__init__()
|
|
71
73
|
|
|
72
|
-
EditableSchema(self).insert("default", FPGATimingScenarioSchema())
|
|
74
|
+
EditableSchema(self).insert("scenario", "default", FPGATimingScenarioSchema())
|
|
75
|
+
EditableSchema(self).insert("mode", "default", TimingModeSchema())
|
|
73
76
|
|
|
74
77
|
def add_scenario(self, scenario: FPGATimingScenarioSchema):
|
|
75
78
|
"""
|
|
@@ -95,9 +98,10 @@ class FPGATimingConstraintSchema(BaseSchema):
|
|
|
95
98
|
if scenario.name is None:
|
|
96
99
|
raise ValueError("scenario must have a name")
|
|
97
100
|
|
|
98
|
-
EditableSchema(self).insert(scenario.name, scenario, clobber=True)
|
|
101
|
+
EditableSchema(self).insert("scenario", scenario.name, scenario, clobber=True)
|
|
99
102
|
|
|
100
|
-
def get_scenario(self, scenario: Optional[str] = None)
|
|
103
|
+
def get_scenario(self, scenario: Optional[str] = None) \
|
|
104
|
+
-> Union[FPGATimingScenarioSchema, Dict[str, FPGATimingScenarioSchema]]:
|
|
101
105
|
"""
|
|
102
106
|
Retrieves one or all timing scenarios from the configuration.
|
|
103
107
|
|
|
@@ -106,8 +110,8 @@ class FPGATimingConstraintSchema(BaseSchema):
|
|
|
106
110
|
|
|
107
111
|
Args:
|
|
108
112
|
scenario (str, optional): The name (string) of the specific timing scenario to retrieve.
|
|
109
|
-
|
|
110
|
-
|
|
113
|
+
If this argument is omitted or set to None, the method will
|
|
114
|
+
return a dictionary containing all available timing scenarios.
|
|
111
115
|
|
|
112
116
|
Returns:
|
|
113
117
|
If `scenario` is provided: The :class:`FPGATimingScenarioSchema` object corresponding
|
|
@@ -121,13 +125,13 @@ class FPGATimingConstraintSchema(BaseSchema):
|
|
|
121
125
|
"""
|
|
122
126
|
if scenario is None:
|
|
123
127
|
scenarios = {}
|
|
124
|
-
for
|
|
125
|
-
scenarios[
|
|
128
|
+
for name in self.getkeys("scenario"):
|
|
129
|
+
scenarios[name] = self.get("scenario", name, field="schema")
|
|
126
130
|
return scenarios
|
|
127
131
|
|
|
128
|
-
if not self.valid(scenario):
|
|
132
|
+
if not self.valid("scenario", scenario):
|
|
129
133
|
raise LookupError(f"{scenario} is not defined")
|
|
130
|
-
return self.get(scenario, field="schema")
|
|
134
|
+
return self.get("scenario", scenario, field="schema")
|
|
131
135
|
|
|
132
136
|
def make_scenario(self, scenario: str) -> FPGATimingScenarioSchema:
|
|
133
137
|
"""
|
|
@@ -143,7 +147,7 @@ class FPGATimingConstraintSchema(BaseSchema):
|
|
|
143
147
|
a non-empty string and unique within the current configuration.
|
|
144
148
|
|
|
145
149
|
Returns:
|
|
146
|
-
:class
|
|
150
|
+
:class:`FPGATimingScenarioSchema`: The newly created :class:`FPGATimingScenarioSchema`
|
|
147
151
|
object.
|
|
148
152
|
|
|
149
153
|
Raises:
|
|
@@ -154,13 +158,42 @@ class FPGATimingConstraintSchema(BaseSchema):
|
|
|
154
158
|
if not scenario:
|
|
155
159
|
raise ValueError("scenario name is required")
|
|
156
160
|
|
|
157
|
-
if self.valid(scenario):
|
|
161
|
+
if self.valid("scenario", scenario):
|
|
158
162
|
raise LookupError(f"{scenario} scenario already exists")
|
|
159
163
|
|
|
160
164
|
scenarioobj = FPGATimingScenarioSchema(scenario)
|
|
161
165
|
self.add_scenario(scenarioobj)
|
|
162
166
|
return scenarioobj
|
|
163
167
|
|
|
168
|
+
def copy_scenario(self, scenario: str, name: str, insert: bool = True) \
|
|
169
|
+
-> FPGATimingScenarioSchema:
|
|
170
|
+
"""
|
|
171
|
+
Copies an existing timing scenario, renames it, and optionally adds it to the design.
|
|
172
|
+
|
|
173
|
+
This method retrieves the scenario identified by ``scenario``, creates a
|
|
174
|
+
deep copy of it, and renames the copy to ``name``. If ``insert`` is True,
|
|
175
|
+
the new scenario is immediately added to the configuration.
|
|
176
|
+
|
|
177
|
+
Args:
|
|
178
|
+
scenario (str): The name of the existing scenario to be copied.
|
|
179
|
+
name (str): The name to assign to the new copied scenario.
|
|
180
|
+
insert (bool, optional): Whether to add the newly created scenario
|
|
181
|
+
to the configuration. Defaults to True.
|
|
182
|
+
|
|
183
|
+
Returns:
|
|
184
|
+
FPGATimingScenarioSchema: The newly created copy of the scenario.
|
|
185
|
+
|
|
186
|
+
Raises:
|
|
187
|
+
LookupError: If the source scenario specified by ``scenario`` does not exist.
|
|
188
|
+
"""
|
|
189
|
+
constraint = EditableSchema(self.get_scenario(scenario)).copy()
|
|
190
|
+
EditableSchema(constraint).rename(name)
|
|
191
|
+
if insert:
|
|
192
|
+
if self.valid("scenario", name):
|
|
193
|
+
raise ValueError(f"{name} already exists")
|
|
194
|
+
self.add_scenario(constraint)
|
|
195
|
+
return constraint
|
|
196
|
+
|
|
164
197
|
def remove_scenario(self, scenario: str) -> bool:
|
|
165
198
|
"""
|
|
166
199
|
Removes a timing scenario from the design configuration.
|
|
@@ -182,8 +215,170 @@ class FPGATimingConstraintSchema(BaseSchema):
|
|
|
182
215
|
if not scenario:
|
|
183
216
|
raise ValueError("scenario name is required")
|
|
184
217
|
|
|
185
|
-
if not self.valid(scenario):
|
|
218
|
+
if not self.valid("scenario", scenario):
|
|
219
|
+
return False
|
|
220
|
+
|
|
221
|
+
EditableSchema(self).remove("scenario", scenario)
|
|
222
|
+
return True
|
|
223
|
+
|
|
224
|
+
def add_mode(self, mode: TimingModeSchema):
|
|
225
|
+
"""
|
|
226
|
+
Adds a timing mode to the design configuration.
|
|
227
|
+
|
|
228
|
+
This method is responsible for incorporating a new or updated timing mode
|
|
229
|
+
into the system's configuration. If a mode with the same name already
|
|
230
|
+
exists, it will be overwritten (`clobber=True`).
|
|
231
|
+
|
|
232
|
+
Args:
|
|
233
|
+
mode: The :class:`TimingModeSchema` object representing the timing mode
|
|
234
|
+
to add. This object must have a valid name defined via its `name()` method.
|
|
235
|
+
|
|
236
|
+
Raises:
|
|
237
|
+
TypeError: If the provided `mode` argument is not an instance of
|
|
238
|
+
:class:`TimingModeSchema`.
|
|
239
|
+
ValueError: If the `mode` object's `name()` method returns None, indicating
|
|
240
|
+
that the mode does not have a defined name.
|
|
241
|
+
"""
|
|
242
|
+
if not isinstance(mode, TimingModeSchema):
|
|
243
|
+
raise TypeError("mode must be a timing mode object")
|
|
244
|
+
|
|
245
|
+
if mode.name is None:
|
|
246
|
+
raise ValueError("mode must have a name")
|
|
247
|
+
|
|
248
|
+
EditableSchema(self).insert("mode", mode.name, mode, clobber=True)
|
|
249
|
+
|
|
250
|
+
def get_mode(self, mode: Optional[str] = None) \
|
|
251
|
+
-> Union[TimingModeSchema, Dict[str, TimingModeSchema]]:
|
|
252
|
+
"""
|
|
253
|
+
Retrieves one or all timing modes from the configuration.
|
|
254
|
+
|
|
255
|
+
This method provides flexibility to fetch either a specific timing mode
|
|
256
|
+
by its name or a collection of all currently defined modes.
|
|
257
|
+
|
|
258
|
+
Args:
|
|
259
|
+
mode (str, optional): The name (string) of the specific timing mode to retrieve.
|
|
260
|
+
If this argument is omitted or set to None, the method will
|
|
261
|
+
return a dictionary containing all available timing modes.
|
|
262
|
+
|
|
263
|
+
Returns:
|
|
264
|
+
If `mode` is provided: The :class:`TimingModeSchema` object corresponding
|
|
265
|
+
to the specified mode name.
|
|
266
|
+
If `mode` is None: A dictionary where keys are mode names (str) and
|
|
267
|
+
values are their respective :class:`TimingModeSchema` objects.
|
|
268
|
+
|
|
269
|
+
Raises:
|
|
270
|
+
LookupError: If a specific `mode` name is provided but no mode with
|
|
271
|
+
that name is found in the configuration.
|
|
272
|
+
"""
|
|
273
|
+
if mode is None:
|
|
274
|
+
modes = {}
|
|
275
|
+
for name in self.getkeys("mode"):
|
|
276
|
+
modes[name] = self.get("mode", name, field="schema")
|
|
277
|
+
return modes
|
|
278
|
+
|
|
279
|
+
if not self.valid("mode", mode):
|
|
280
|
+
raise LookupError(f"{mode} is not defined")
|
|
281
|
+
return self.get("mode", mode, field="schema")
|
|
282
|
+
|
|
283
|
+
def make_mode(self, mode: str) -> TimingModeSchema:
|
|
284
|
+
"""
|
|
285
|
+
Creates and adds a new timing mode with the specified name.
|
|
286
|
+
|
|
287
|
+
This method initializes a new :class:`TimingModeSchema` object with the given
|
|
288
|
+
name and immediately adds it to the constraint configuration. It ensures that
|
|
289
|
+
a mode with the same name does not already exist, preventing accidental
|
|
290
|
+
overwrites.
|
|
291
|
+
|
|
292
|
+
Args:
|
|
293
|
+
mode (str): The name for the new timing mode. This name must be
|
|
294
|
+
a non-empty string and unique within the current configuration.
|
|
295
|
+
|
|
296
|
+
Returns:
|
|
297
|
+
:class:`TimingModeSchema`: The newly created :class:`TimingModeSchema`
|
|
298
|
+
object.
|
|
299
|
+
|
|
300
|
+
Raises:
|
|
301
|
+
ValueError: If the provided `mode` name is empty or None.
|
|
302
|
+
LookupError: If a mode with the specified `mode` name already exists
|
|
303
|
+
in the configuration.
|
|
304
|
+
"""
|
|
305
|
+
if not mode:
|
|
306
|
+
raise ValueError("mode name is required")
|
|
307
|
+
|
|
308
|
+
if self.valid("mode", mode):
|
|
309
|
+
raise LookupError(f"{mode} mode already exists")
|
|
310
|
+
|
|
311
|
+
modeobj = TimingModeSchema(mode)
|
|
312
|
+
self.add_mode(modeobj)
|
|
313
|
+
return modeobj
|
|
314
|
+
|
|
315
|
+
def copy_mode(self, mode: str, name: str, insert: bool = True) \
|
|
316
|
+
-> TimingModeSchema:
|
|
317
|
+
"""
|
|
318
|
+
Copies an existing timing mode, renames it, and optionally adds it to the design.
|
|
319
|
+
|
|
320
|
+
This method retrieves the mode identified by ``mode``, creates a
|
|
321
|
+
deep copy of it, and renames the copy to ``name``. If ``insert`` is True,
|
|
322
|
+
the new mode is immediately added to the configuration.
|
|
323
|
+
|
|
324
|
+
Args:
|
|
325
|
+
mode (str): The name of the existing mode to be copied.
|
|
326
|
+
name (str): The name to assign to the new copied mode.
|
|
327
|
+
insert (bool, optional): Whether to add the newly created mode
|
|
328
|
+
to the configuration. Defaults to True.
|
|
329
|
+
|
|
330
|
+
Returns:
|
|
331
|
+
TimingModeSchema: The newly created copy of the mode.
|
|
332
|
+
|
|
333
|
+
Raises:
|
|
334
|
+
LookupError: If the source mode specified by ``mode`` does not exist.
|
|
335
|
+
"""
|
|
336
|
+
newmode = EditableSchema(self.get_mode(mode)).copy()
|
|
337
|
+
EditableSchema(newmode).rename(name)
|
|
338
|
+
if insert:
|
|
339
|
+
if self.valid("mode", name):
|
|
340
|
+
raise ValueError(f"{name} already exists")
|
|
341
|
+
self.add_mode(newmode)
|
|
342
|
+
return newmode
|
|
343
|
+
|
|
344
|
+
def remove_mode(self, mode: str) -> bool:
|
|
345
|
+
"""
|
|
346
|
+
Removes a timing mode from the design configuration.
|
|
347
|
+
|
|
348
|
+
This method deletes the specified timing mode from the system's
|
|
349
|
+
configuration.
|
|
350
|
+
|
|
351
|
+
Args:
|
|
352
|
+
mode (str): The name of the timing mode to remove.
|
|
353
|
+
This name must be a non-empty string.
|
|
354
|
+
|
|
355
|
+
Returns:
|
|
356
|
+
bool: True if the mode was successfully removed, False if no
|
|
357
|
+
mode with the given name was found.
|
|
358
|
+
|
|
359
|
+
Raises:
|
|
360
|
+
ValueError: If the provided `mode` name is empty or None.
|
|
361
|
+
"""
|
|
362
|
+
if not mode:
|
|
363
|
+
raise ValueError("mode name is required")
|
|
364
|
+
|
|
365
|
+
if not self.valid("mode", mode):
|
|
186
366
|
return False
|
|
187
367
|
|
|
188
|
-
EditableSchema(self).remove(
|
|
368
|
+
EditableSchema(self).remove("mode", mode)
|
|
189
369
|
return True
|
|
370
|
+
|
|
371
|
+
def _from_dict(self, manifest: Dict,
|
|
372
|
+
keypath: Union[List[str], Tuple[str, ...]],
|
|
373
|
+
version: Optional[Tuple[int, ...]] = None,
|
|
374
|
+
lazyload: LazyLoad = LazyLoad.ON) \
|
|
375
|
+
-> Tuple[Set[Tuple[str, ...]], Set[Tuple[str, ...]]]:
|
|
376
|
+
if version and version < (0, 53, 0):
|
|
377
|
+
manifest.pop("__meta__", None)
|
|
378
|
+
manifest = {
|
|
379
|
+
"scenario": manifest,
|
|
380
|
+
"mode": self.getdict("mode")
|
|
381
|
+
}
|
|
382
|
+
lazyload = LazyLoad.OFF
|
|
383
|
+
|
|
384
|
+
return super()._from_dict(manifest, keypath, version, lazyload)
|