siliconcompiler 0.34.1__py3-none-any.whl → 0.34.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. siliconcompiler/__init__.py +14 -2
  2. siliconcompiler/_metadata.py +1 -1
  3. siliconcompiler/apps/sc_show.py +1 -1
  4. siliconcompiler/constraints/__init__.py +17 -0
  5. siliconcompiler/constraints/asic_component.py +378 -0
  6. siliconcompiler/constraints/asic_floorplan.py +449 -0
  7. siliconcompiler/constraints/asic_pins.py +489 -0
  8. siliconcompiler/constraints/asic_timing.py +517 -0
  9. siliconcompiler/core.py +3 -3
  10. siliconcompiler/dependencyschema.py +10 -174
  11. siliconcompiler/design.py +235 -118
  12. siliconcompiler/flowgraph.py +27 -14
  13. siliconcompiler/library.py +133 -0
  14. siliconcompiler/metric.py +94 -72
  15. siliconcompiler/metrics/__init__.py +7 -0
  16. siliconcompiler/metrics/asic.py +245 -0
  17. siliconcompiler/metrics/fpga.py +220 -0
  18. siliconcompiler/package/__init__.py +138 -35
  19. siliconcompiler/package/github.py +6 -10
  20. siliconcompiler/packageschema.py +256 -12
  21. siliconcompiler/pathschema.py +226 -0
  22. siliconcompiler/project.py +459 -0
  23. siliconcompiler/scheduler/docker.py +2 -3
  24. siliconcompiler/scheduler/run_node.py +2 -1
  25. siliconcompiler/scheduler/scheduler.py +4 -13
  26. siliconcompiler/scheduler/schedulernode.py +25 -17
  27. siliconcompiler/scheduler/taskscheduler.py +2 -1
  28. siliconcompiler/schema/__init__.py +0 -2
  29. siliconcompiler/schema/baseschema.py +147 -24
  30. siliconcompiler/schema/editableschema.py +14 -6
  31. siliconcompiler/schema/journal.py +23 -15
  32. siliconcompiler/schema/namedschema.py +6 -4
  33. siliconcompiler/schema/parameter.py +34 -19
  34. siliconcompiler/schema/parametertype.py +2 -0
  35. siliconcompiler/schema/parametervalue.py +198 -15
  36. siliconcompiler/schema/schema_cfg.py +18 -14
  37. siliconcompiler/schema_obj.py +5 -3
  38. siliconcompiler/tool.py +199 -10
  39. siliconcompiler/toolscripts/_tools.json +4 -4
  40. {siliconcompiler-0.34.1.dist-info → siliconcompiler-0.34.2.dist-info}/METADATA +3 -3
  41. {siliconcompiler-0.34.1.dist-info → siliconcompiler-0.34.2.dist-info}/RECORD +45 -35
  42. siliconcompiler/schema/packageschema.py +0 -101
  43. {siliconcompiler-0.34.1.dist-info → siliconcompiler-0.34.2.dist-info}/WHEEL +0 -0
  44. {siliconcompiler-0.34.1.dist-info → siliconcompiler-0.34.2.dist-info}/entry_points.txt +0 -0
  45. {siliconcompiler-0.34.1.dist-info → siliconcompiler-0.34.2.dist-info}/licenses/LICENSE +0 -0
  46. {siliconcompiler-0.34.1.dist-info → siliconcompiler-0.34.2.dist-info}/top_level.txt +0 -0
@@ -2,19 +2,270 @@ import os
2
2
 
3
3
  import os.path
4
4
 
5
- from siliconcompiler.schema import BaseSchema
6
- from siliconcompiler.schema import EditableSchema, Parameter, Scope
5
+ from typing import Union, Dict, List
6
+
7
+ from siliconcompiler.pathschema import PathSchema
8
+ from siliconcompiler.schema import BaseSchema, EditableSchema, Parameter, Scope
7
9
  from siliconcompiler.schema.utils import trim
8
10
  from siliconcompiler.package import Resolver
9
11
 
10
12
 
11
- class PackageSchema(BaseSchema):
13
+ class PackageSchema(PathSchema):
12
14
  def __init__(self):
13
15
  super().__init__()
14
16
 
15
17
  schema_package(self)
16
18
 
17
- self.__cache = {}
19
+ def set_description(self, desc: str):
20
+ """
21
+ Set the description of the package.
22
+
23
+ Args:
24
+ desc (str): The description string.
25
+ """
26
+ return self.set("package", "description", trim(desc))
27
+
28
+ def get_description(self) -> str:
29
+ """Get the description of the package.
30
+
31
+ Returns:
32
+ str: The description string.
33
+ """
34
+ return self.get("package", "description")
35
+
36
+ def set_version(self, version: str):
37
+ """
38
+ Set the version of the package.
39
+
40
+ Args:
41
+ version (str): The version string.
42
+ """
43
+ return self.set("package", "version", version)
44
+
45
+ def get_version(self) -> str:
46
+ """
47
+ Get the version of the package.
48
+
49
+ Returns:
50
+ str: The version string.
51
+ """
52
+ return self.get("package", "version")
53
+
54
+ def add_license(self, name: str):
55
+ """
56
+ Add a license name to the package.
57
+
58
+ Args:
59
+ name (str): The name of the license.
60
+ """
61
+ return self.add("package", "license", name)
62
+
63
+ def add_licensefile(self, file: str, dataroot: str = None):
64
+ """
65
+ Add a license file to the package.
66
+
67
+ Args:
68
+ file (str): The path to the license file.
69
+ dataroot (str, optional): The data reference for the package. Defaults to None,
70
+ which uses the active package.
71
+ """
72
+ if not dataroot:
73
+ dataroot = self._get_active("package")
74
+ with self.active_dataroot(dataroot):
75
+ return self.add("package", "licensefile", file)
76
+
77
+ def get_license(self) -> List[str]:
78
+ """
79
+ Get a list of license names associated with the package.
80
+ """
81
+ return self.get("package", "license")
82
+
83
+ def get_licensefile(self) -> List[str]:
84
+ """
85
+ Get a list of license file paths associated with the package.
86
+ """
87
+ return self.find_files("package", "licensefile")
88
+
89
+ def add_author(self,
90
+ identifier: str,
91
+ name: str = None,
92
+ email: str = None,
93
+ organization: str = None):
94
+ """
95
+ Add or update author information for the package.
96
+
97
+ Args:
98
+ identifier (str): A unique identifier for the author.
99
+ name (str, optional): The author's name. Defaults to None.
100
+ email (str, optional): The author's email address. Defaults to None.
101
+ organization (str, optional): The author's organization. Defaults to None.
102
+ """
103
+ params = []
104
+ if name:
105
+ params.append(self.set("package", "author", identifier, "name", name))
106
+ if email:
107
+ params.append(self.set("package", "author", identifier, "email", email))
108
+ if organization:
109
+ params.append(self.set("package", "author", identifier, "organization", organization))
110
+ return [p for p in params if p]
111
+
112
+ def get_author(self, identifier: str = None):
113
+ """
114
+ Returns the author information for a specific author or all authors.
115
+
116
+ Args:
117
+ identifier (str): A unique identifier for the author, if None returns all
118
+ """
119
+ if identifier is None:
120
+ authors = []
121
+ for author in self.getkeys("package", "author"):
122
+ authors.append(self.get_author(author))
123
+ return authors
124
+ return {
125
+ "name": self.get("package", "author", identifier, "name"),
126
+ "email": self.get("package", "author", identifier, "email"),
127
+ "organization": self.get("package", "author", identifier, "organization")
128
+ }
129
+
130
+ def add_doc(self, type: str, path: str, dataroot: str = None):
131
+ """
132
+ Add documentation to the package.
133
+
134
+ Args:
135
+ type (str): The type of documentation (e.g., "manual", "api").
136
+ path (str): The path to the documentation file.
137
+ dataroot (str, optional): The data reference for the package. Defaults to None,
138
+ which uses the active package.
139
+
140
+ Returns:
141
+ The result of the `add` operation.
142
+ """
143
+ if not dataroot:
144
+ dataroot = self._get_active("package")
145
+ with self.active_dataroot(dataroot):
146
+ return self.add("package", "doc", type, path)
147
+
148
+ def get_doc(self, type: str = None) -> Union[List[str], Dict[str, List[str]]]:
149
+ """
150
+ Get documentation files for the package.
151
+
152
+ Args:
153
+ type (str, optional): The type of documentation to retrieve. If None,
154
+ returns all documentation organized by type. Defaults to None.
155
+ """
156
+ if type:
157
+ return self.find_files("package", "doc", type)
158
+
159
+ docs = {}
160
+ for type in self.getkeys("package", "doc"):
161
+ doc_files = self.find_files("package", "doc", type)
162
+ if doc_files:
163
+ docs[type] = doc_files
164
+ return docs
165
+
166
+
167
+ ############################################
168
+ # Package information
169
+ ############################################
170
+ def schema_package(schema):
171
+ schema = EditableSchema(schema)
172
+
173
+ schema.insert(
174
+ 'package', 'version',
175
+ Parameter(
176
+ 'str',
177
+ scope=Scope.GLOBAL,
178
+ shorthelp="Package: version",
179
+ switch="-package_version <str>",
180
+ example=[
181
+ "cli: -package_version 1.0",
182
+ "api: chip.set('package', 'version', '1.0')"],
183
+ help=trim("""Package version. Can be a branch, tag, commit hash,
184
+ or a semver compatible version.""")))
185
+
186
+ schema.insert(
187
+ 'package', 'description',
188
+ Parameter(
189
+ 'str',
190
+ scope=Scope.GLOBAL,
191
+ shorthelp="Package: description",
192
+ switch="-package_description <str>",
193
+ example=[
194
+ "cli: -package_description 'Yet another cpu'",
195
+ "api: chip.set('package', 'description', 'Yet another cpu')"],
196
+ help=trim("""Package short one line description for package
197
+ managers and summary reports.""")))
198
+
199
+ for item in [
200
+ 'datasheet',
201
+ 'reference',
202
+ 'userguide',
203
+ 'quickstart',
204
+ 'releasenotes',
205
+ 'testplan',
206
+ 'signoff',
207
+ 'tutorial']:
208
+ schema.insert(
209
+ 'package', 'doc', item,
210
+ Parameter(
211
+ '[file]',
212
+ scope=Scope.GLOBAL,
213
+ shorthelp=f"Package: {item} document",
214
+ switch=f"-package_doc_{item} <file>",
215
+ example=[
216
+ f"cli: -package_doc_{item} {item}.pdf",
217
+ f"api: chip.set('package', 'doc', '{item}', '{item}.pdf')"],
218
+ help=trim(f"""Package list of {item} documents.""")))
219
+
220
+ schema.insert(
221
+ 'package', 'license',
222
+ Parameter(
223
+ '[str]',
224
+ scope=Scope.GLOBAL,
225
+ shorthelp="Package: license identifiers",
226
+ switch="-package_license <str>",
227
+ example=[
228
+ "cli: -package_license 'Apache-2.0'",
229
+ "api: chip.set('package', 'license', 'Apache-2.0')"],
230
+ help=trim("""Package list of SPDX license identifiers.""")))
231
+
232
+ schema.insert(
233
+ 'package', 'licensefile',
234
+ Parameter(
235
+ '[file]',
236
+ scope=Scope.GLOBAL,
237
+ shorthelp="Package: license files",
238
+ switch="-package_licensefile <file>",
239
+ example=[
240
+ "cli: -package_licensefile './LICENSE'",
241
+ "api: chip.set('package', 'licensefile', './LICENSE')"],
242
+ help=trim("""Package list of license files for to be
243
+ applied in cases when a SPDX identifier is not available.
244
+ (eg. proprietary licenses).""")))
245
+
246
+ for item in [
247
+ 'name',
248
+ 'email',
249
+ 'organization']:
250
+ schema.insert(
251
+ 'package', 'author', 'default', item,
252
+ Parameter(
253
+ 'str',
254
+ scope=Scope.GLOBAL,
255
+ shorthelp=f"Package: author {item}",
256
+ switch=f"-package_author_{item} 'userid <str>'",
257
+ example=[
258
+ f"cli: -package_author_{item} 'wiley wiley@acme.com'",
259
+ f"api: chip.set('package', 'author', 'wiley', '{item}', 'wiley@acme.com')"],
260
+ help=trim(f"""Package author {item} provided with full name as key and
261
+ {item} as value.""")))
262
+
263
+
264
+ class PackageSchemaTmp(BaseSchema):
265
+ def __init__(self):
266
+ super().__init__()
267
+
268
+ schema_package_tmp(self)
18
269
 
19
270
  def register(self, name, path, ref=None, clobber=True):
20
271
  """
@@ -60,7 +311,6 @@ class PackageSchema(BaseSchema):
60
311
  resolver = resolver_cls(package, self._parent(root=True),
61
312
  self.get("source", package, "path"),
62
313
  self.get("source", package, "ref"))
63
- resolver.set_cache(self.__cache)
64
314
  return resolver
65
315
 
66
316
  def get_resolvers(self):
@@ -73,17 +323,11 @@ class PackageSchema(BaseSchema):
73
323
 
74
324
  return resolvers
75
325
 
76
- def _set_cache(self, package, path):
77
- self.__cache[package] = path
78
-
79
- def get_path_cache(self):
80
- return self.__cache.copy()
81
-
82
326
 
83
327
  ############################################
84
328
  # Package information
85
329
  ############################################
86
- def schema_package(schema):
330
+ def schema_package_tmp(schema):
87
331
  schema = EditableSchema(schema)
88
332
 
89
333
  schema.insert(
@@ -0,0 +1,226 @@
1
+ import contextlib
2
+ import logging
3
+
4
+ import os.path
5
+
6
+ from siliconcompiler.schema.baseschema import BaseSchema
7
+ from siliconcompiler.schema.editableschema import EditableSchema
8
+ from siliconcompiler.schema.parameter import Parameter, Scope
9
+ from siliconcompiler.schema.utils import trim
10
+
11
+ from siliconcompiler.package import Resolver
12
+
13
+
14
+ class PathSchemaBase(BaseSchema):
15
+ '''
16
+ Schema extension to add simpler find_files and check_filepaths
17
+ '''
18
+
19
+ def find_files(self, *keypath,
20
+ missing_ok=False,
21
+ step=None, index=None):
22
+ """
23
+ Returns absolute paths to files or directories based on the keypath
24
+ provided.
25
+
26
+ The keypath provided must point to a schema parameter of type file, dir,
27
+ or lists of either. Otherwise, it will trigger an error.
28
+
29
+ Args:
30
+ keypath (list of str): Variable length schema key list.
31
+ missing_ok (bool): If True, silently return None when files aren't
32
+ found. If False, print an error and set the error flag.
33
+ step (str): Step name to access for parameters that may be specified
34
+ on a per-node basis.
35
+ index (str): Index name to access for parameters that may be specified
36
+ on a per-node basis.
37
+
38
+ Returns:
39
+ If keys points to a scalar entry, returns an absolute path to that
40
+ file/directory, or None if not found. It keys points to a list
41
+ entry, returns a list of either the absolute paths or None for each
42
+ entry, depending on whether it is found.
43
+
44
+ Examples:
45
+ >>> schema.find_files('input', 'verilog')
46
+ Returns a list of absolute paths to source files, as specified in
47
+ the schema.
48
+ """
49
+ schema_root = self._parent(root=True)
50
+ cwd = getattr(schema_root, "cwd", os.getcwd())
51
+ collection_dir = getattr(schema_root, "collection_dir", None)
52
+ if collection_dir:
53
+ collection_dir = collection_dir()
54
+
55
+ return super().find_files(*keypath,
56
+ missing_ok=missing_ok,
57
+ step=step, index=index,
58
+ collection_dir=collection_dir,
59
+ cwd=cwd)
60
+
61
+ def check_filepaths(self, ignore_keys=None):
62
+ '''
63
+ Verifies that paths to all files in manifest are valid.
64
+
65
+ Args:
66
+ ignore_keys (list of keypaths): list of keypaths to ignore while checking
67
+
68
+ Returns:
69
+ True if all file paths are valid, otherwise False.
70
+ '''
71
+ schema_root = self._parent(root=True)
72
+ cwd = getattr(schema_root, "cwd", os.getcwd())
73
+ logger = getattr(schema_root,
74
+ "logger",
75
+ logging.getLogger("siliconcompiler.check_filepaths"))
76
+ collection_dir = getattr(schema_root, "collection_dir", None)
77
+ if collection_dir:
78
+ collection_dir = collection_dir()
79
+
80
+ return super().check_filepaths(
81
+ ignore_keys=ignore_keys,
82
+ logger=logger,
83
+ collection_dir=collection_dir,
84
+ cwd=cwd)
85
+
86
+
87
+ class PathSchema(PathSchemaBase):
88
+ '''
89
+ Schema extension to add support for path handling with dataroots
90
+ '''
91
+
92
+ def __init__(self):
93
+ super().__init__()
94
+
95
+ schema = EditableSchema(self)
96
+
97
+ schema.insert(
98
+ 'dataroot', 'default', 'path',
99
+ Parameter(
100
+ 'str',
101
+ scope=Scope.GLOBAL,
102
+ shorthelp="Data directory path",
103
+ example=[
104
+ "api: chip.set('dataroot', "
105
+ "'freepdk45_data', 'path', 'ssh://git@github.com/siliconcompiler/freepdk45/')"],
106
+ help=trim("""
107
+ Data directory path, this points the location where the data can be
108
+ retrieved or accessed.
109
+ Allowed roots:
110
+
111
+ * /path/on/network/drive
112
+ * file:///path/on/network/drive
113
+ * git+https://github.com/xyz/xyz
114
+ * git://github.com/xyz/xyz
115
+ * git+ssh://github.com/xyz/xyz
116
+ * ssh://github.com/xyz/xyz
117
+ * https://github.com/xyz/xyz/archive
118
+ * https://zeroasic.com/xyz.tar.gz
119
+ * github://siliconcompiler/lambdapdk/v1.0/asap7.tar.gz
120
+ * python://siliconcompiler
121
+ """)))
122
+
123
+ schema.insert(
124
+ 'dataroot', 'default', 'tag',
125
+ Parameter(
126
+ 'str',
127
+ scope=Scope.GLOBAL,
128
+ shorthelp="Data directory reference tag/version",
129
+ example=[
130
+ "api: chip.set('dataroot', 'freepdk45_data', 'tag', '07ec4aa')"],
131
+ help=trim("""
132
+ Data directory reference tag. The meaning of the this tag depends on the
133
+ context of the path.
134
+ For git, this can be a tag, branch, or commit id. For https this is the version
135
+ of the file that will be downloaded.
136
+ """)))
137
+
138
+ def set_dataroot(self, name: str, path: str, tag: str = None):
139
+ """
140
+ Registers a data directory by its name with the root and associated tag. If the path
141
+ provided is a file, the path recorded will be the directory the file is located in.
142
+
143
+ Args:
144
+ name (str): Data directory name
145
+ path (str): Path to the root of the data directory, can be directory, git url,
146
+ archive url, or path to a file
147
+ tag (str): Reference of the sources, can be commitid, branch name, tag
148
+
149
+ Examples:
150
+ >>> schema.set_dataroot('siliconcompiler_data',
151
+ 'git+https://github.com/siliconcompiler/siliconcompiler',
152
+ 'v1.0.0')
153
+ Records the data directory for siliconcompiler_data as a git clone for tag v1.0.0
154
+ >>> schema.set_dataroot('file_data', __file__)
155
+ Records the data directory for file_data as the directory that __file__ is found in.
156
+ """
157
+
158
+ if os.path.isfile(path):
159
+ path = os.path.dirname(os.path.abspath(path))
160
+
161
+ BaseSchema.set(self, "dataroot", name, "path", path)
162
+ if tag:
163
+ BaseSchema.set(self, "dataroot", name, "tag", tag)
164
+
165
+ def get_dataroot(self, name: str) -> str:
166
+ """
167
+ Returns absolute path to the data directory.
168
+
169
+ Raises:
170
+ ValueError: is data directory is not found
171
+
172
+ Args:
173
+ name (str): name of the data directory to find.
174
+
175
+ Returns:
176
+ Path to the directory root.
177
+
178
+ Examples:
179
+ >>> schema.get_dataroot('siliconcompiler')
180
+ Returns the path to the root of the siliconcompiler data directory.
181
+ """
182
+
183
+ if not BaseSchema.valid(self, "dataroot", name):
184
+ raise ValueError(f"{name} is not a recognized source")
185
+
186
+ path = BaseSchema.get(self, "dataroot", name, "path")
187
+ tag = BaseSchema.get(self, "dataroot", name, "tag")
188
+
189
+ resolver = Resolver.find_resolver(path)
190
+ return resolver(name, self._parent(root=True), path, tag).get_path()
191
+
192
+ def _find_files_dataroot_resolvers(self):
193
+ """
194
+ Returns a dictionary of path resolevrs data directory handling for find_files
195
+
196
+ Returns:
197
+ dictionary of str to resolver mapping
198
+ """
199
+ schema_root = self._parent(root=True)
200
+ resolver_map = {}
201
+ for dataroot in self.getkeys("dataroot"):
202
+ path = BaseSchema.get(self, "dataroot", dataroot, "path")
203
+ tag = BaseSchema.get(self, "dataroot", dataroot, "tag")
204
+ resolver = Resolver.find_resolver(path)
205
+ resolver_map[dataroot] = resolver(dataroot, schema_root, path, tag).get_path
206
+ return resolver_map
207
+
208
+ @contextlib.contextmanager
209
+ def active_dataroot(self, dataroot: str = None):
210
+ '''
211
+ Use this context to set the dataroot parameter on files and directory parameters.
212
+
213
+ Args:
214
+ dataroot (str): name of the dataroot
215
+
216
+ Example:
217
+ >>> with schema.active_dataroot("lambdalib"):
218
+ ... schema.set("file", "top.v")
219
+ Sets the file to top.v and associates lambdalib as the dataroot.
220
+ '''
221
+
222
+ if dataroot and dataroot not in self.getkeys("dataroot"):
223
+ raise ValueError(f"{dataroot} is not a recognized dataroot")
224
+
225
+ with self._active(package=dataroot):
226
+ yield