siliconcompiler 0.36.1__py3-none-any.whl → 0.36.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.
- siliconcompiler/_metadata.py +1 -1
- siliconcompiler/asic.py +4 -4
- siliconcompiler/design.py +6 -1
- siliconcompiler/package/__init__.py +3 -2
- siliconcompiler/project.py +36 -18
- siliconcompiler/schema/baseschema.py +7 -4
- siliconcompiler/schema/docschema.py +3 -3
- siliconcompiler/schema/editableschema.py +1 -1
- siliconcompiler/schema/namedschema.py +6 -6
- siliconcompiler/schema_support/cmdlineschema.py +5 -3
- siliconcompiler/schema_support/filesetschema.py +9 -1
- siliconcompiler/schema_support/pathschema.py +16 -10
- siliconcompiler/tool.py +7 -3
- siliconcompiler/tools/builtin/wait.py +16 -0
- siliconcompiler/tools/keplerformal/lec.py +2 -2
- siliconcompiler/tools/klayout/export.py +1 -3
- siliconcompiler/tools/klayout/merge.py +95 -0
- siliconcompiler/tools/klayout/scripts/klayout_merge.py +79 -0
- siliconcompiler/tools/openroad/_apr.py +69 -11
- siliconcompiler/tools/openroad/power_grid.py +1 -1
- siliconcompiler/tools/openroad/scripts/common/read_timing_constraints.tcl +17 -15
- siliconcompiler/tools/openroad/scripts/common/write_data_timing.tcl +3 -1
- siliconcompiler/tools/vpr/__init__.py +9 -9
- siliconcompiler/tools/vpr/place.py +1 -2
- siliconcompiler/tools/yosys/syn_asic.py +4 -4
- siliconcompiler/tools/yosys/syn_fpga.py +7 -8
- siliconcompiler/toolscripts/_tools.json +6 -6
- siliconcompiler/utils/logging.py +6 -0
- {siliconcompiler-0.36.1.dist-info → siliconcompiler-0.36.3.dist-info}/METADATA +3 -3
- {siliconcompiler-0.36.1.dist-info → siliconcompiler-0.36.3.dist-info}/RECORD +34 -31
- {siliconcompiler-0.36.1.dist-info → siliconcompiler-0.36.3.dist-info}/WHEEL +1 -1
- {siliconcompiler-0.36.1.dist-info → siliconcompiler-0.36.3.dist-info}/entry_points.txt +0 -0
- {siliconcompiler-0.36.1.dist-info → siliconcompiler-0.36.3.dist-info}/licenses/LICENSE +0 -0
- {siliconcompiler-0.36.1.dist-info → siliconcompiler-0.36.3.dist-info}/top_level.txt +0 -0
siliconcompiler/_metadata.py
CHANGED
siliconcompiler/asic.py
CHANGED
|
@@ -244,7 +244,7 @@ class ASIC(Project):
|
|
|
244
244
|
if pdk not in self.getkeys("library"):
|
|
245
245
|
error = True
|
|
246
246
|
self.logger.error(f"{pdk} library has not been loaded")
|
|
247
|
-
elif not isinstance(self.
|
|
247
|
+
elif not isinstance(self.get_library(pdk), PDK):
|
|
248
248
|
error = True
|
|
249
249
|
self.logger.error(f"{pdk} must be a PDK")
|
|
250
250
|
|
|
@@ -432,7 +432,7 @@ class ASIC(Project):
|
|
|
432
432
|
if not self.get("asic", "pdk") and self.get("asic", "mainlib"):
|
|
433
433
|
mainlib = None
|
|
434
434
|
if self._has_library(self.get("asic", "mainlib")):
|
|
435
|
-
mainlib = self.
|
|
435
|
+
mainlib = self.get_library(self.get("asic", "mainlib"))
|
|
436
436
|
if mainlib:
|
|
437
437
|
mainlib_pdk = mainlib.get("asic", "pdk")
|
|
438
438
|
if mainlib_pdk:
|
|
@@ -530,7 +530,7 @@ class ASICTask(Task):
|
|
|
530
530
|
raise ValueError("mainlib has not been defined in [asic,mainlib]")
|
|
531
531
|
if mainlib not in self.project.getkeys("library"):
|
|
532
532
|
raise LookupError(f"{mainlib} has not been loaded")
|
|
533
|
-
return self.project.
|
|
533
|
+
return self.project.get_library(mainlib)
|
|
534
534
|
|
|
535
535
|
@property
|
|
536
536
|
def pdk(self) -> PDK:
|
|
@@ -540,7 +540,7 @@ class ASICTask(Task):
|
|
|
540
540
|
raise ValueError("pdk has not been defined in [asic,pdk]")
|
|
541
541
|
if pdk not in self.project.getkeys("library"):
|
|
542
542
|
raise LookupError(f"{pdk} has not been loaded")
|
|
543
|
-
return self.project.
|
|
543
|
+
return self.project.get_library(pdk)
|
|
544
544
|
|
|
545
545
|
def set_asic_var(self,
|
|
546
546
|
key: str,
|
siliconcompiler/design.py
CHANGED
|
@@ -694,7 +694,12 @@ class Design(DependencySchema, LibrarySchema):
|
|
|
694
694
|
if dataroot is ...:
|
|
695
695
|
dataroot = None
|
|
696
696
|
else:
|
|
697
|
-
|
|
697
|
+
if option in ['idir', 'libdir']:
|
|
698
|
+
try:
|
|
699
|
+
dataroot = self._get_active_dataroot(dataroot)
|
|
700
|
+
except ValueError as e:
|
|
701
|
+
if any(not os.path.isabs(v) for v in value):
|
|
702
|
+
raise e
|
|
698
703
|
|
|
699
704
|
with self.active_dataroot(dataroot):
|
|
700
705
|
if list in typelist and not clobber:
|
|
@@ -72,9 +72,10 @@ class Resolver:
|
|
|
72
72
|
self.__cacheid = None
|
|
73
73
|
|
|
74
74
|
if self.__root and hasattr(self.__root, "logger"):
|
|
75
|
-
|
|
75
|
+
rootlogger = self.__root.logger
|
|
76
76
|
else:
|
|
77
|
-
|
|
77
|
+
rootlogger = MPManager.logger()
|
|
78
|
+
self.__logger = rootlogger.getChild(f"resolver-{self.name}")
|
|
78
79
|
|
|
79
80
|
@staticmethod
|
|
80
81
|
def populate_resolvers() -> None:
|
siliconcompiler/project.py
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
import os
|
|
3
|
-
import sys
|
|
4
3
|
import uuid
|
|
5
4
|
|
|
6
5
|
import os.path
|
|
7
6
|
|
|
8
|
-
from typing import Union, List, Tuple, TextIO, Optional, Dict, Set
|
|
7
|
+
from typing import Type, Union, List, Tuple, TextIO, Optional, Dict, Set, TypeVar
|
|
9
8
|
|
|
10
9
|
from siliconcompiler.schema import BaseSchema, NamedSchema, EditableSchema, Parameter, Scope, \
|
|
11
10
|
__version__ as schema_version, \
|
|
@@ -28,12 +27,14 @@ from siliconcompiler.schema_support.pathschema import PathSchemaBase
|
|
|
28
27
|
|
|
29
28
|
from siliconcompiler.report.dashboard.cli import CliDashboard
|
|
30
29
|
from siliconcompiler.scheduler import Scheduler, SCRuntimeError
|
|
31
|
-
from siliconcompiler.utils.logging import
|
|
30
|
+
from siliconcompiler.utils.logging import get_stream_handler
|
|
32
31
|
from siliconcompiler.utils import get_file_ext
|
|
33
32
|
from siliconcompiler.utils.multiprocessing import MPManager
|
|
34
33
|
from siliconcompiler.utils.paths import jobdir, workdir
|
|
35
34
|
from siliconcompiler.flows.showflow import ShowFlow
|
|
36
35
|
|
|
36
|
+
TProject = TypeVar("TProject", bound="Project")
|
|
37
|
+
|
|
37
38
|
|
|
38
39
|
class Project(PathSchemaBase, CommandLineSchema, BaseSchema):
|
|
39
40
|
"""
|
|
@@ -143,12 +144,7 @@ class Project(PathSchemaBase, CommandLineSchema, BaseSchema):
|
|
|
143
144
|
self.__logger = MPManager.logger().getChild(f"project_{uuid.uuid4().hex}")
|
|
144
145
|
self.__logger.setLevel(logging.INFO)
|
|
145
146
|
|
|
146
|
-
self._logger_console =
|
|
147
|
-
if SCColorLoggerFormatter.supports_color(sys.stdout):
|
|
148
|
-
self._logger_console.setFormatter(SCColorLoggerFormatter(SCLoggerFormatter()))
|
|
149
|
-
else:
|
|
150
|
-
self._logger_console.setFormatter(SCLoggerFormatter())
|
|
151
|
-
|
|
147
|
+
self._logger_console = get_stream_handler(self, in_run=False, step=None, index=None)
|
|
152
148
|
self.__logger.addHandler(self._logger_console)
|
|
153
149
|
|
|
154
150
|
def __init_dashboard(self):
|
|
@@ -225,7 +221,7 @@ class Project(PathSchemaBase, CommandLineSchema, BaseSchema):
|
|
|
225
221
|
if not self.valid("library", design_name):
|
|
226
222
|
raise KeyError(f"{design_name} design has not been loaded")
|
|
227
223
|
|
|
228
|
-
return self.
|
|
224
|
+
return self.get_library(design_name)
|
|
229
225
|
|
|
230
226
|
@property
|
|
231
227
|
def option(self) -> OptionSchema:
|
|
@@ -242,7 +238,7 @@ class Project(PathSchemaBase, CommandLineSchema, BaseSchema):
|
|
|
242
238
|
return self.get("option", field="schema")
|
|
243
239
|
|
|
244
240
|
@classmethod
|
|
245
|
-
def convert(cls, obj: "Project") ->
|
|
241
|
+
def convert(cls: Type[TProject], obj: "Project") -> TProject:
|
|
246
242
|
"""
|
|
247
243
|
Converts a project from one type to another (e.g., Project to Sim).
|
|
248
244
|
|
|
@@ -482,7 +478,7 @@ class Project(PathSchemaBase, CommandLineSchema, BaseSchema):
|
|
|
482
478
|
if not self._has_library(src_lib):
|
|
483
479
|
continue
|
|
484
480
|
|
|
485
|
-
if not self.
|
|
481
|
+
if not self.get_library(src_lib).has_fileset(src_fileset):
|
|
486
482
|
self.logger.error(f"{src_fileset} is not a valid fileset in {src_lib}")
|
|
487
483
|
error = True
|
|
488
484
|
continue
|
|
@@ -496,7 +492,7 @@ class Project(PathSchemaBase, CommandLineSchema, BaseSchema):
|
|
|
496
492
|
continue
|
|
497
493
|
|
|
498
494
|
if dst_fileset and \
|
|
499
|
-
not self.
|
|
495
|
+
not self.get_library(dst_lib).has_fileset(dst_fileset):
|
|
500
496
|
self.logger.error(f"{dst_fileset} is not a valid fileset in {dst_lib}")
|
|
501
497
|
error = True
|
|
502
498
|
continue
|
|
@@ -532,7 +528,7 @@ class Project(PathSchemaBase, CommandLineSchema, BaseSchema):
|
|
|
532
528
|
f"{', '.join([f'{step}/{index}' for step, index in breakpoints])}")
|
|
533
529
|
self.__dashboard.stop()
|
|
534
530
|
|
|
535
|
-
def run(self) ->
|
|
531
|
+
def run(self) -> TProject:
|
|
536
532
|
'''
|
|
537
533
|
Executes the compilation flow defined in the project's flowgraph.
|
|
538
534
|
|
|
@@ -715,7 +711,7 @@ class Project(PathSchemaBase, CommandLineSchema, BaseSchema):
|
|
|
715
711
|
if dst_lib:
|
|
716
712
|
if not self._has_library(dst_lib):
|
|
717
713
|
raise KeyError(f"{dst_lib} is not a loaded library")
|
|
718
|
-
dst_obj = self.
|
|
714
|
+
dst_obj = self.get_library(dst_lib)
|
|
719
715
|
else:
|
|
720
716
|
dst_obj = None
|
|
721
717
|
if not dst_fileset:
|
|
@@ -844,7 +840,7 @@ class Project(PathSchemaBase, CommandLineSchema, BaseSchema):
|
|
|
844
840
|
|
|
845
841
|
if isinstance(src_dep, str):
|
|
846
842
|
if self._has_library(src_dep):
|
|
847
|
-
src_dep = self.
|
|
843
|
+
src_dep = self.get_library(src_dep)
|
|
848
844
|
else:
|
|
849
845
|
src_dep_name = src_dep
|
|
850
846
|
src_dep = None
|
|
@@ -875,7 +871,7 @@ class Project(PathSchemaBase, CommandLineSchema, BaseSchema):
|
|
|
875
871
|
if not self._has_library(alias_dep):
|
|
876
872
|
raise KeyError(f"{alias_dep} has not been loaded")
|
|
877
873
|
|
|
878
|
-
alias_dep = self.
|
|
874
|
+
alias_dep = self.get_library(alias_dep)
|
|
879
875
|
|
|
880
876
|
if alias_dep is not None:
|
|
881
877
|
if isinstance(alias_dep, Design):
|
|
@@ -894,6 +890,28 @@ class Project(PathSchemaBase, CommandLineSchema, BaseSchema):
|
|
|
894
890
|
else:
|
|
895
891
|
return self.add("option", "alias", alias)
|
|
896
892
|
|
|
893
|
+
def get_library(self, library: str) -> NamedSchema:
|
|
894
|
+
"""
|
|
895
|
+
Retrieves a library by name from the project.
|
|
896
|
+
|
|
897
|
+
Args:
|
|
898
|
+
library (str): The name of the library to retrieve.
|
|
899
|
+
|
|
900
|
+
Returns:
|
|
901
|
+
NamedSchema: The `NamedSchema` object representing the library.
|
|
902
|
+
|
|
903
|
+
Raises:
|
|
904
|
+
KeyError: If the specified library is not found in the project.
|
|
905
|
+
TypeError: If the provided `library` is not a string.
|
|
906
|
+
"""
|
|
907
|
+
if not isinstance(library, str):
|
|
908
|
+
raise TypeError("library must be a string")
|
|
909
|
+
|
|
910
|
+
if not self._has_library(library):
|
|
911
|
+
raise KeyError(f"{library} is not a valid library")
|
|
912
|
+
|
|
913
|
+
return self.get("library", library, field="schema")
|
|
914
|
+
|
|
897
915
|
def _has_library(self, library: Union[str, NamedSchema]) -> bool:
|
|
898
916
|
"""
|
|
899
917
|
Checks if a library with the given name exists and is loaded in the project.
|
|
@@ -1222,7 +1240,7 @@ class Project(PathSchemaBase, CommandLineSchema, BaseSchema):
|
|
|
1222
1240
|
return None
|
|
1223
1241
|
|
|
1224
1242
|
# Create copy of project to avoid changing user project
|
|
1225
|
-
proj
|
|
1243
|
+
proj = self.copy()
|
|
1226
1244
|
proj.set_flow(ShowFlow(task))
|
|
1227
1245
|
|
|
1228
1246
|
# Setup options:
|
|
@@ -26,12 +26,15 @@ import os.path
|
|
|
26
26
|
|
|
27
27
|
from enum import Enum, auto
|
|
28
28
|
from functools import cache
|
|
29
|
-
from typing import Dict, Type, Tuple, Union, Set, Callable, List, Optional,
|
|
29
|
+
from typing import Dict, Type, Tuple, TypeVar, Union, Set, Callable, List, Optional, \
|
|
30
|
+
TextIO, Iterable, Any
|
|
30
31
|
|
|
31
32
|
from .parameter import Parameter, NodeValue
|
|
32
33
|
from .journal import Journal
|
|
33
34
|
from ._metadata import version
|
|
34
35
|
|
|
36
|
+
TSchema = TypeVar('TSchema', bound='BaseSchema')
|
|
37
|
+
|
|
35
38
|
|
|
36
39
|
class LazyLoad(Enum):
|
|
37
40
|
"""
|
|
@@ -286,10 +289,10 @@ class BaseSchema:
|
|
|
286
289
|
|
|
287
290
|
# Manifest methods
|
|
288
291
|
@classmethod
|
|
289
|
-
def from_manifest(cls,
|
|
292
|
+
def from_manifest(cls: Type[TSchema],
|
|
290
293
|
filepath: Union[None, str] = None,
|
|
291
294
|
cfg: Union[None, Dict] = None,
|
|
292
|
-
lazyload: bool = True) ->
|
|
295
|
+
lazyload: bool = True) -> TSchema:
|
|
293
296
|
'''
|
|
294
297
|
Create a new schema based on the provided source files.
|
|
295
298
|
|
|
@@ -849,7 +852,7 @@ class BaseSchema:
|
|
|
849
852
|
return manifest
|
|
850
853
|
|
|
851
854
|
# Utility functions
|
|
852
|
-
def copy(self, key: Optional[Tuple[str, ...]] = None) ->
|
|
855
|
+
def copy(self: TSchema, key: Optional[Tuple[str, ...]] = None) -> TSchema:
|
|
853
856
|
"""
|
|
854
857
|
Returns a copy of this schema.
|
|
855
858
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
from typing import Union, List
|
|
1
|
+
from typing import Type, Union, List
|
|
2
2
|
|
|
3
|
-
from .baseschema import BaseSchema
|
|
3
|
+
from .baseschema import BaseSchema, TSchema
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
class DocsSchema(BaseSchema):
|
|
@@ -11,7 +11,7 @@ class DocsSchema(BaseSchema):
|
|
|
11
11
|
"""
|
|
12
12
|
|
|
13
13
|
@classmethod
|
|
14
|
-
def make_docs(cls) -> Union[
|
|
14
|
+
def make_docs(cls: Type[TSchema]) -> Union[TSchema, List[TSchema]]:
|
|
15
15
|
"""Generate the documentation representation for this schema.
|
|
16
16
|
|
|
17
17
|
By default, this method returns a standard instance of the class itself.
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
# SC dependencies outside of its directory, since it may be used by tool drivers
|
|
5
5
|
# that have isolated Python environments.
|
|
6
6
|
|
|
7
|
-
from typing import Dict, Tuple, Optional, Set, Union, List
|
|
7
|
+
from typing import Dict, Tuple, Optional, Set, Type, Union, List
|
|
8
8
|
|
|
9
|
-
from .baseschema import BaseSchema, LazyLoad
|
|
9
|
+
from .baseschema import BaseSchema, LazyLoad, TSchema
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
class NamedSchema(BaseSchema):
|
|
@@ -76,11 +76,11 @@ class NamedSchema(BaseSchema):
|
|
|
76
76
|
return cfg.get("__meta__", {}).get("name", None)
|
|
77
77
|
|
|
78
78
|
@classmethod
|
|
79
|
-
def from_manifest(cls,
|
|
79
|
+
def from_manifest(cls: Type[TSchema],
|
|
80
80
|
filepath: Union[None, str] = None,
|
|
81
81
|
cfg: Union[None, Dict] = None,
|
|
82
82
|
lazyload: bool = True,
|
|
83
|
-
name: Optional[str] = None):
|
|
83
|
+
name: Optional[str] = None) -> TSchema:
|
|
84
84
|
'''
|
|
85
85
|
Create a new schema based on the provided source files.
|
|
86
86
|
|
|
@@ -115,8 +115,8 @@ class NamedSchema(BaseSchema):
|
|
|
115
115
|
|
|
116
116
|
return super()._from_dict(manifest, keypath, version=version, lazyload=lazyload)
|
|
117
117
|
|
|
118
|
-
def copy(self, key: Optional[Tuple[str, ...]] = None) ->
|
|
119
|
-
copy
|
|
118
|
+
def copy(self: TSchema, key: Optional[Tuple[str, ...]] = None) -> TSchema:
|
|
119
|
+
copy = super().copy(key=key)
|
|
120
120
|
|
|
121
121
|
if key and key[-1] != "default":
|
|
122
122
|
copy.__name = key[-1]
|
|
@@ -4,12 +4,14 @@ import sys
|
|
|
4
4
|
|
|
5
5
|
import os.path
|
|
6
6
|
|
|
7
|
-
from typing import Set, List, Optional, Union
|
|
7
|
+
from typing import Set, List, Optional, Type, Union, TypeVar
|
|
8
8
|
|
|
9
9
|
from siliconcompiler.schema import BaseSchema, EditableSchema, Parameter, Scope, PerNode
|
|
10
10
|
from siliconcompiler.schema.utils import trim
|
|
11
11
|
from siliconcompiler import _metadata
|
|
12
12
|
|
|
13
|
+
TCmdSchema = TypeVar("TCmdSchema", bound="CommandLineSchema")
|
|
14
|
+
|
|
13
15
|
|
|
14
16
|
class CommandLineSchema(BaseSchema):
|
|
15
17
|
'''
|
|
@@ -68,14 +70,14 @@ class CommandLineSchema(BaseSchema):
|
|
|
68
70
|
EditableSchema(self).insert("cmdarg", name, Parameter(type, **kwargs))
|
|
69
71
|
|
|
70
72
|
@classmethod
|
|
71
|
-
def create_cmdline(cls,
|
|
73
|
+
def create_cmdline(cls: Type[TCmdSchema],
|
|
72
74
|
progname: Optional[str] = None,
|
|
73
75
|
description: Optional[str] = None,
|
|
74
76
|
switchlist: Optional[Union[List[str], Set[str]]] = None,
|
|
75
77
|
version: Optional[str] = None,
|
|
76
78
|
print_banner: bool = True,
|
|
77
79
|
use_cfg: bool = False,
|
|
78
|
-
use_sources: bool = True) ->
|
|
80
|
+
use_sources: bool = True) -> TCmdSchema:
|
|
79
81
|
"""
|
|
80
82
|
Creates an SC command line interface.
|
|
81
83
|
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import contextlib
|
|
2
2
|
|
|
3
|
+
import os.path
|
|
4
|
+
|
|
3
5
|
from pathlib import Path
|
|
4
6
|
|
|
5
7
|
from typing import List, Tuple, Optional, Union, Iterable, Set
|
|
@@ -118,8 +120,14 @@ class FileSetSchema(PathSchema):
|
|
|
118
120
|
ext = utils.get_file_ext(filename)
|
|
119
121
|
filetype = utils.get_default_iomap().get(ext, ext)
|
|
120
122
|
|
|
123
|
+
try:
|
|
124
|
+
dataroot = self._get_active_dataroot(dataroot)
|
|
125
|
+
except ValueError as e:
|
|
126
|
+
if not os.path.isabs(filename):
|
|
127
|
+
raise e
|
|
128
|
+
|
|
121
129
|
# adding files to dictionary
|
|
122
|
-
with self.active_dataroot(
|
|
130
|
+
with self.active_dataroot(dataroot):
|
|
123
131
|
if clobber:
|
|
124
132
|
return self.set('fileset', fileset, 'file', filetype, filename)
|
|
125
133
|
else:
|
|
@@ -11,7 +11,9 @@ from siliconcompiler.schema.parameter import Parameter, Scope
|
|
|
11
11
|
from siliconcompiler.schema.utils import trim
|
|
12
12
|
|
|
13
13
|
from siliconcompiler.package import Resolver
|
|
14
|
+
from siliconcompiler.utils.logging import get_stream_handler
|
|
14
15
|
from siliconcompiler.utils.paths import collectiondir, cwdirsafe
|
|
16
|
+
from siliconcompiler.utils.multiprocessing import MPManager
|
|
15
17
|
|
|
16
18
|
|
|
17
19
|
class PathSchemaBase(BaseSchema):
|
|
@@ -19,6 +21,15 @@ class PathSchemaBase(BaseSchema):
|
|
|
19
21
|
Schema extension to add simpler find_files and check_filepaths
|
|
20
22
|
'''
|
|
21
23
|
|
|
24
|
+
def __getlogger(self, logger_name: str) -> logging.Logger:
|
|
25
|
+
schema_root = self._parent(root=True)
|
|
26
|
+
root_logger = getattr(schema_root, "logger", MPManager.logger())
|
|
27
|
+
logger = root_logger.getChild(logger_name)
|
|
28
|
+
if not logger.handlers:
|
|
29
|
+
logger.addHandler(get_stream_handler(schema_root, in_run=False, step=None, index=None))
|
|
30
|
+
logger.setLevel(logging.INFO)
|
|
31
|
+
return logger
|
|
32
|
+
|
|
22
33
|
def find_files(self, *keypath: str,
|
|
23
34
|
missing_ok: bool = False,
|
|
24
35
|
step: Optional[str] = None, index: Optional[Union[int, str]] = None) \
|
|
@@ -69,13 +80,10 @@ class PathSchemaBase(BaseSchema):
|
|
|
69
80
|
True if all file paths are valid, otherwise False.
|
|
70
81
|
'''
|
|
71
82
|
schema_root = self._parent(root=True)
|
|
72
|
-
logger = getattr(schema_root,
|
|
73
|
-
"logger",
|
|
74
|
-
logging.getLogger("siliconcompiler.check_filepaths"))
|
|
75
83
|
|
|
76
84
|
return super()._check_filepaths(
|
|
77
85
|
ignore_keys=ignore_keys,
|
|
78
|
-
logger=
|
|
86
|
+
logger=self.__getlogger("check_filepaths"),
|
|
79
87
|
collection_dir=collectiondir(schema_root),
|
|
80
88
|
cwd=cwdirsafe(schema_root))
|
|
81
89
|
|
|
@@ -121,13 +129,11 @@ class PathSchemaBase(BaseSchema):
|
|
|
121
129
|
>>> hashlist = hash_files('input', 'rtl', 'verilog')
|
|
122
130
|
Computes, stores, and returns hashes of files in :keypath:`input, rtl, verilog`.
|
|
123
131
|
'''
|
|
124
|
-
schema_root = self._parent(root=True)
|
|
125
|
-
logger = getattr(schema_root,
|
|
126
|
-
"logger",
|
|
127
|
-
logging.getLogger("siliconcompiler.hash_files"))
|
|
128
|
-
|
|
129
132
|
if verbose:
|
|
130
|
-
|
|
133
|
+
self.__getlogger("hash_files").info(
|
|
134
|
+
f"Computing hash value for [{','.join([*self._keypath, *keypath])}]")
|
|
135
|
+
|
|
136
|
+
schema_root = self._parent(root=True)
|
|
131
137
|
|
|
132
138
|
hashes = super()._hash_files(*keypath,
|
|
133
139
|
missing_ok=missing_ok,
|
siliconcompiler/tool.py
CHANGED
|
@@ -53,7 +53,8 @@ if TYPE_CHECKING:
|
|
|
53
53
|
from siliconcompiler.scheduler import SchedulerNode
|
|
54
54
|
from siliconcompiler import Project
|
|
55
55
|
|
|
56
|
-
TTask = TypeVar('TTask')
|
|
56
|
+
TTask = TypeVar('TTask', bound='Task')
|
|
57
|
+
TShowTask = TypeVar('TShowTask', bound='ShowTask')
|
|
57
58
|
|
|
58
59
|
|
|
59
60
|
class TaskError(Exception):
|
|
@@ -997,7 +998,7 @@ class Task(NamedSchema, PathSchema, DocsSchema):
|
|
|
997
998
|
open(stderr_file, 'w') as stderr_writer:
|
|
998
999
|
if stderr_file == stdout_file:
|
|
999
1000
|
stderr_writer.close()
|
|
1000
|
-
stderr_writer =
|
|
1001
|
+
stderr_writer = stdout_writer
|
|
1001
1002
|
|
|
1002
1003
|
with contextlib.redirect_stderr(stderr_writer), \
|
|
1003
1004
|
contextlib.redirect_stdout(stdout_writer):
|
|
@@ -1009,6 +1010,8 @@ class Task(NamedSchema, PathSchema, DocsSchema):
|
|
|
1009
1010
|
finally:
|
|
1010
1011
|
with sc_open(stdout_file) as stdout_reader, \
|
|
1011
1012
|
sc_open(stderr_file) as stderr_reader:
|
|
1013
|
+
if stdout_file == stderr_file:
|
|
1014
|
+
stderr_reader = None
|
|
1012
1015
|
read_stdio(stdout_reader, stderr_reader)
|
|
1013
1016
|
|
|
1014
1017
|
if resource:
|
|
@@ -2175,7 +2178,8 @@ class ShowTask(Task):
|
|
|
2175
2178
|
cls.register_task(c)
|
|
2176
2179
|
|
|
2177
2180
|
@classmethod
|
|
2178
|
-
def get_task(cls, ext: Optional[str]) ->
|
|
2181
|
+
def get_task(cls: Type[TShowTask], ext: Optional[str]) -> \
|
|
2182
|
+
Union[Optional[TShowTask], Set[Type[TShowTask]]]:
|
|
2179
2183
|
"""
|
|
2180
2184
|
Retrieves a suitable show task instance for a given file extension.
|
|
2181
2185
|
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from siliconcompiler.tools.builtin import BuiltinTask
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class Wait(BuiltinTask):
|
|
5
|
+
'''
|
|
6
|
+
A wait task that stalls the flow until all inputs are available.
|
|
7
|
+
'''
|
|
8
|
+
def __init__(self):
|
|
9
|
+
super().__init__()
|
|
10
|
+
|
|
11
|
+
def _set_io_files(self):
|
|
12
|
+
# No file IO needed for wait task
|
|
13
|
+
return
|
|
14
|
+
|
|
15
|
+
def task(self):
|
|
16
|
+
return "wait"
|
|
@@ -37,7 +37,7 @@ class LECTask(Task):
|
|
|
37
37
|
libcorners = scenario.get_libcorner(self.step, self.index)
|
|
38
38
|
delay_model = self.project.get("asic", "delaymodel")
|
|
39
39
|
for asiclib in self.project.get("asic", "asiclib"):
|
|
40
|
-
lib = self.project.
|
|
40
|
+
lib = self.project.get_library(asiclib)
|
|
41
41
|
for corner in libcorners:
|
|
42
42
|
if not lib.valid("asic", "libcornerfileset", corner, delay_model):
|
|
43
43
|
continue
|
|
@@ -64,7 +64,7 @@ class LECTask(Task):
|
|
|
64
64
|
libcorners = scenario.get_libcorner(self.step, self.index)
|
|
65
65
|
delay_model = self.project.get("asic", "delaymodel")
|
|
66
66
|
for asiclib in self.project.get("asic", "asiclib"):
|
|
67
|
-
lib = self.project.
|
|
67
|
+
lib = self.project.get_library(asiclib)
|
|
68
68
|
for corner in libcorners:
|
|
69
69
|
if not lib.valid("asic", "libcornerfileset", corner, delay_model):
|
|
70
70
|
continue
|
|
@@ -79,8 +79,6 @@ class ExportTask(KLayoutTask, ScreenshotParams):
|
|
|
79
79
|
self.add_output_file(ext="lyt")
|
|
80
80
|
self.add_output_file(ext="lyp")
|
|
81
81
|
|
|
82
|
-
self.add_required_key("var", "stream")
|
|
83
|
-
|
|
84
82
|
sc_stream_order = [default_stream, *[s for s in ("gds", "oas") if s != default_stream]]
|
|
85
83
|
req_set = False
|
|
86
84
|
for s in sc_stream_order:
|
|
@@ -98,7 +96,7 @@ class ExportTask(KLayoutTask, ScreenshotParams):
|
|
|
98
96
|
lib_requires_stream = False
|
|
99
97
|
|
|
100
98
|
req_set = False
|
|
101
|
-
libobj = self.project.
|
|
99
|
+
libobj = self.project.get_library(lib)
|
|
102
100
|
for s in sc_stream_order:
|
|
103
101
|
for fileset in libobj.get("asic", "aprfileset"):
|
|
104
102
|
if libobj.valid("fileset", fileset, "file", s):
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
from typing import Optional, Union
|
|
2
|
+
|
|
3
|
+
from siliconcompiler.tools.klayout import KLayoutTask
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Merge(KLayoutTask):
|
|
7
|
+
"""
|
|
8
|
+
Klayout task to merge multiple GDS files and provide prefixing for cell names.
|
|
9
|
+
"""
|
|
10
|
+
def __init__(self):
|
|
11
|
+
super().__init__()
|
|
12
|
+
|
|
13
|
+
self.add_parameter("reference", "(<fs,input>,str,str)",
|
|
14
|
+
"Reference fileset or input node for merge operation, structured as "
|
|
15
|
+
"(fs, library name, fileset) or (input, step, index)")
|
|
16
|
+
self.add_parameter("merge", "[(<fs,input>,str,str,str)]",
|
|
17
|
+
"Fileset or input node to be merge with prefix, structured as "
|
|
18
|
+
"(fs, library name, fileset) or (input, step, index) along with prefix "
|
|
19
|
+
"string")
|
|
20
|
+
|
|
21
|
+
def __fix_type(self, type: str) -> str:
|
|
22
|
+
if type == "fileset":
|
|
23
|
+
return "fs"
|
|
24
|
+
return type
|
|
25
|
+
|
|
26
|
+
def set_klayout_reference(self, type: str, source0: str, source1: str,
|
|
27
|
+
step: Optional[str] = None,
|
|
28
|
+
index: Optional[Union[str, int]] = None):
|
|
29
|
+
"""
|
|
30
|
+
Sets the reference file for the merge operation.
|
|
31
|
+
Args:
|
|
32
|
+
type (str): The reference fileset or input node.
|
|
33
|
+
source0 (str): The first part of the source (library name or step).
|
|
34
|
+
source1 (str): The second part of the source (fileset name or index).
|
|
35
|
+
step (Optional[str]): The specific step to apply this configuration to.
|
|
36
|
+
index (Optional[Union[str, int]]): The specific index to apply this configuration to.
|
|
37
|
+
"""
|
|
38
|
+
self.set("var", "reference", (self.__fix_type(type), source0, source1),
|
|
39
|
+
step=step, index=index)
|
|
40
|
+
|
|
41
|
+
def add_klayout_merge(self, type: str, source0: str, source1: str, prefix: str,
|
|
42
|
+
step: Optional[str] = None,
|
|
43
|
+
index: Optional[Union[str, int]] = None, clobber: bool = False):
|
|
44
|
+
"""
|
|
45
|
+
Adds a file to be merged with the reference file.
|
|
46
|
+
Args:
|
|
47
|
+
type (str): The fileset or input node to be merged.
|
|
48
|
+
prefix (str): The prefix to apply during the merge.
|
|
49
|
+
source0 (str): The first part of the source (library name or step).
|
|
50
|
+
source1 (str): The second part of the source (fileset name or index).
|
|
51
|
+
step (Optional[str]): The specific step to apply this configuration to.
|
|
52
|
+
index (Optional[Union[str, int]]): The specific index to apply this configuration to.
|
|
53
|
+
clobber (bool, optional): If True, overwrites the existing list of merge files.
|
|
54
|
+
If False, appends to the list. Defaults to False.
|
|
55
|
+
"""
|
|
56
|
+
if clobber:
|
|
57
|
+
self.set("var", "merge", (self.__fix_type(type), source0, source1, prefix),
|
|
58
|
+
step=step, index=index)
|
|
59
|
+
else:
|
|
60
|
+
self.add("var", "merge", (self.__fix_type(type), source0, source1, prefix),
|
|
61
|
+
step=step, index=index)
|
|
62
|
+
|
|
63
|
+
def task(self) -> str:
|
|
64
|
+
return 'merge'
|
|
65
|
+
|
|
66
|
+
def setup(self) -> None:
|
|
67
|
+
super().setup()
|
|
68
|
+
|
|
69
|
+
self.set_script("klayout_merge.py")
|
|
70
|
+
|
|
71
|
+
self.add_required_key("var", "reference")
|
|
72
|
+
self.add_required_key("var", "merge")
|
|
73
|
+
|
|
74
|
+
if self.get("var", "reference"):
|
|
75
|
+
ref_type, ref_source0, ref_source1 = self.get("var", "reference")
|
|
76
|
+
if ref_type == 'input':
|
|
77
|
+
step, index = ref_source0, ref_source1
|
|
78
|
+
self.add_input_file(
|
|
79
|
+
self.compute_input_file_node_name(f"{self.design_topmodule}.gds",
|
|
80
|
+
step, index))
|
|
81
|
+
else:
|
|
82
|
+
lib_name, fileset = ref_source0, ref_source1
|
|
83
|
+
self.add_required_key("library", lib_name, "fileset", fileset, "file", "gds")
|
|
84
|
+
for merge_entry in self.get("var", "merge"):
|
|
85
|
+
merge_type, merge_source0, merge_source1, _ = merge_entry
|
|
86
|
+
if merge_type == 'input':
|
|
87
|
+
step, index = merge_source0, merge_source1
|
|
88
|
+
self.add_input_file(
|
|
89
|
+
self.compute_input_file_node_name(f"{self.design_topmodule}.gds",
|
|
90
|
+
step, index))
|
|
91
|
+
else:
|
|
92
|
+
lib_name, fileset = merge_source0, merge_source1
|
|
93
|
+
self.add_required_key("library", lib_name, "fileset", fileset, "file", "gds")
|
|
94
|
+
|
|
95
|
+
self.add_output_file(ext="gds")
|