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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (129) hide show
  1. siliconcompiler/__init__.py +23 -4
  2. siliconcompiler/__main__.py +1 -7
  3. siliconcompiler/_metadata.py +1 -1
  4. siliconcompiler/apps/_common.py +104 -23
  5. siliconcompiler/apps/sc.py +4 -8
  6. siliconcompiler/apps/sc_dashboard.py +6 -4
  7. siliconcompiler/apps/sc_install.py +10 -6
  8. siliconcompiler/apps/sc_issue.py +7 -5
  9. siliconcompiler/apps/sc_remote.py +1 -1
  10. siliconcompiler/apps/sc_server.py +9 -14
  11. siliconcompiler/apps/sc_show.py +7 -6
  12. siliconcompiler/apps/smake.py +130 -94
  13. siliconcompiler/apps/utils/replay.py +4 -7
  14. siliconcompiler/apps/utils/summarize.py +3 -5
  15. siliconcompiler/asic.py +420 -0
  16. siliconcompiler/checklist.py +25 -2
  17. siliconcompiler/cmdlineschema.py +534 -0
  18. siliconcompiler/constraints/__init__.py +17 -0
  19. siliconcompiler/constraints/asic_component.py +378 -0
  20. siliconcompiler/constraints/asic_floorplan.py +449 -0
  21. siliconcompiler/constraints/asic_pins.py +489 -0
  22. siliconcompiler/constraints/asic_timing.py +517 -0
  23. siliconcompiler/core.py +10 -35
  24. siliconcompiler/data/templates/tcl/manifest.tcl.j2 +8 -0
  25. siliconcompiler/dependencyschema.py +96 -202
  26. siliconcompiler/design.py +327 -241
  27. siliconcompiler/filesetschema.py +250 -0
  28. siliconcompiler/flowgraph.py +298 -106
  29. siliconcompiler/fpga.py +124 -1
  30. siliconcompiler/library.py +331 -0
  31. siliconcompiler/metric.py +327 -92
  32. siliconcompiler/metrics/__init__.py +7 -0
  33. siliconcompiler/metrics/asic.py +245 -0
  34. siliconcompiler/metrics/fpga.py +220 -0
  35. siliconcompiler/package/__init__.py +391 -67
  36. siliconcompiler/package/git.py +92 -16
  37. siliconcompiler/package/github.py +114 -22
  38. siliconcompiler/package/https.py +79 -16
  39. siliconcompiler/packageschema.py +341 -16
  40. siliconcompiler/pathschema.py +255 -0
  41. siliconcompiler/pdk.py +566 -1
  42. siliconcompiler/project.py +1460 -0
  43. siliconcompiler/record.py +38 -1
  44. siliconcompiler/remote/__init__.py +5 -2
  45. siliconcompiler/remote/client.py +11 -6
  46. siliconcompiler/remote/schema.py +5 -23
  47. siliconcompiler/remote/server.py +41 -54
  48. siliconcompiler/report/__init__.py +3 -3
  49. siliconcompiler/report/dashboard/__init__.py +48 -14
  50. siliconcompiler/report/dashboard/cli/__init__.py +99 -21
  51. siliconcompiler/report/dashboard/cli/board.py +364 -179
  52. siliconcompiler/report/dashboard/web/__init__.py +90 -12
  53. siliconcompiler/report/dashboard/web/components/__init__.py +219 -240
  54. siliconcompiler/report/dashboard/web/components/flowgraph.py +49 -26
  55. siliconcompiler/report/dashboard/web/components/graph.py +139 -100
  56. siliconcompiler/report/dashboard/web/layouts/__init__.py +29 -1
  57. siliconcompiler/report/dashboard/web/layouts/_common.py +38 -2
  58. siliconcompiler/report/dashboard/web/layouts/vertical_flowgraph.py +39 -26
  59. siliconcompiler/report/dashboard/web/layouts/vertical_flowgraph_node_tab.py +50 -50
  60. siliconcompiler/report/dashboard/web/layouts/vertical_flowgraph_sac_tabs.py +49 -46
  61. siliconcompiler/report/dashboard/web/state.py +141 -14
  62. siliconcompiler/report/dashboard/web/utils/__init__.py +79 -16
  63. siliconcompiler/report/dashboard/web/utils/file_utils.py +74 -11
  64. siliconcompiler/report/dashboard/web/viewer.py +25 -1
  65. siliconcompiler/report/report.py +5 -2
  66. siliconcompiler/report/summary_image.py +29 -11
  67. siliconcompiler/scheduler/__init__.py +9 -1
  68. siliconcompiler/scheduler/docker.py +81 -4
  69. siliconcompiler/scheduler/run_node.py +37 -20
  70. siliconcompiler/scheduler/scheduler.py +211 -36
  71. siliconcompiler/scheduler/schedulernode.py +394 -60
  72. siliconcompiler/scheduler/send_messages.py +77 -29
  73. siliconcompiler/scheduler/slurm.py +76 -12
  74. siliconcompiler/scheduler/taskscheduler.py +142 -21
  75. siliconcompiler/schema/__init__.py +0 -4
  76. siliconcompiler/schema/baseschema.py +338 -59
  77. siliconcompiler/schema/editableschema.py +14 -6
  78. siliconcompiler/schema/journal.py +28 -17
  79. siliconcompiler/schema/namedschema.py +22 -14
  80. siliconcompiler/schema/parameter.py +89 -28
  81. siliconcompiler/schema/parametertype.py +2 -0
  82. siliconcompiler/schema/parametervalue.py +258 -15
  83. siliconcompiler/schema/safeschema.py +25 -2
  84. siliconcompiler/schema/schema_cfg.py +23 -19
  85. siliconcompiler/schema/utils.py +2 -2
  86. siliconcompiler/schema_obj.py +24 -5
  87. siliconcompiler/tool.py +1131 -265
  88. siliconcompiler/tools/bambu/__init__.py +41 -0
  89. siliconcompiler/tools/builtin/concatenate.py +2 -2
  90. siliconcompiler/tools/builtin/minimum.py +2 -1
  91. siliconcompiler/tools/builtin/mux.py +2 -1
  92. siliconcompiler/tools/builtin/nop.py +2 -1
  93. siliconcompiler/tools/builtin/verify.py +2 -1
  94. siliconcompiler/tools/klayout/__init__.py +95 -0
  95. siliconcompiler/tools/openroad/__init__.py +289 -0
  96. siliconcompiler/tools/openroad/scripts/apr/preamble.tcl +3 -0
  97. siliconcompiler/tools/openroad/scripts/apr/sc_detailed_route.tcl +7 -2
  98. siliconcompiler/tools/openroad/scripts/apr/sc_global_route.tcl +8 -4
  99. siliconcompiler/tools/openroad/scripts/apr/sc_init_floorplan.tcl +9 -5
  100. siliconcompiler/tools/openroad/scripts/common/write_images.tcl +5 -1
  101. siliconcompiler/tools/slang/__init__.py +1 -1
  102. siliconcompiler/tools/slang/elaborate.py +2 -1
  103. siliconcompiler/tools/vivado/scripts/sc_run.tcl +1 -1
  104. siliconcompiler/tools/vivado/scripts/sc_syn_fpga.tcl +8 -1
  105. siliconcompiler/tools/vivado/syn_fpga.py +6 -0
  106. siliconcompiler/tools/vivado/vivado.py +35 -2
  107. siliconcompiler/tools/vpr/__init__.py +150 -0
  108. siliconcompiler/tools/yosys/__init__.py +369 -1
  109. siliconcompiler/tools/yosys/scripts/procs.tcl +0 -1
  110. siliconcompiler/toolscripts/_tools.json +5 -10
  111. siliconcompiler/utils/__init__.py +66 -0
  112. siliconcompiler/utils/flowgraph.py +2 -2
  113. siliconcompiler/utils/issue.py +2 -1
  114. siliconcompiler/utils/logging.py +14 -0
  115. siliconcompiler/utils/multiprocessing.py +256 -0
  116. siliconcompiler/utils/showtools.py +10 -0
  117. {siliconcompiler-0.34.1.dist-info → siliconcompiler-0.34.3.dist-info}/METADATA +6 -6
  118. {siliconcompiler-0.34.1.dist-info → siliconcompiler-0.34.3.dist-info}/RECORD +122 -115
  119. {siliconcompiler-0.34.1.dist-info → siliconcompiler-0.34.3.dist-info}/entry_points.txt +3 -0
  120. siliconcompiler/schema/cmdlineschema.py +0 -250
  121. siliconcompiler/schema/packageschema.py +0 -101
  122. siliconcompiler/toolscripts/rhel8/install-slang.sh +0 -40
  123. siliconcompiler/toolscripts/rhel9/install-slang.sh +0 -40
  124. siliconcompiler/toolscripts/ubuntu20/install-slang.sh +0 -47
  125. siliconcompiler/toolscripts/ubuntu22/install-slang.sh +0 -37
  126. siliconcompiler/toolscripts/ubuntu24/install-slang.sh +0 -37
  127. {siliconcompiler-0.34.1.dist-info → siliconcompiler-0.34.3.dist-info}/WHEEL +0 -0
  128. {siliconcompiler-0.34.1.dist-info → siliconcompiler-0.34.3.dist-info}/licenses/LICENSE +0 -0
  129. {siliconcompiler-0.34.1.dist-info → siliconcompiler-0.34.3.dist-info}/top_level.txt +0 -0
@@ -2,23 +2,338 @@ 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):
14
+ """
15
+ A class for managing package-related schema data.
16
+ """
12
17
  def __init__(self):
18
+ """
19
+ Initializes a PackageSchema object.
20
+ """
13
21
  super().__init__()
14
22
 
15
23
  schema_package(self)
16
24
 
17
- self.__cache = {}
25
+ def set_description(self, desc: str):
26
+ """
27
+ Set the description of the package.
28
+
29
+ Args:
30
+ desc (str): The description string.
31
+ """
32
+ return self.set("package", "description", trim(desc))
33
+
34
+ def get_description(self) -> str:
35
+ """
36
+ Get the description of the package.
37
+
38
+ Returns:
39
+ str: The description string.
40
+ """
41
+
42
+ return self.get("package", "description")
43
+
44
+ def set_version(self, version: str):
45
+ """
46
+ Set the version of the package.
47
+
48
+ Args:
49
+ version (str): The version string.
50
+ """
51
+ return self.set("package", "version", version)
52
+
53
+ def get_version(self) -> str:
54
+ """
55
+ Get the version of the package.
56
+
57
+ Returns:
58
+ str: The version string.
59
+ """
60
+ return self.get("package", "version")
61
+
62
+ def set_vendor(self, vendor: str):
63
+ """
64
+ Set the vendor of the package.
65
+
66
+ Args:
67
+ vendor (str): The vendor name.
68
+ """
69
+ return self.set("package", "vendor", vendor)
70
+
71
+ def get_vendor(self) -> str:
72
+ """
73
+ Get the vendor of the package.
74
+
75
+ Returns:
76
+ str: The vendor name.
77
+ """
78
+ return self.get("package", "vendor")
79
+
80
+ def add_license(self, name: str):
81
+ """
82
+ Add a license name to the package.
83
+
84
+ Args:
85
+ name (str): The name of the license.
86
+ """
87
+ return self.add("package", "license", name)
88
+
89
+ def add_licensefile(self, file: str, dataroot: str = None):
90
+ """
91
+ Add a license file to the package.
92
+
93
+ Args:
94
+ file (str): The path to the license file.
95
+ dataroot (str, optional): The data reference for the package. Defaults to None,
96
+ which uses the active package.
97
+ """
98
+ if not dataroot:
99
+ dataroot = self._get_active("package")
100
+ with self.active_dataroot(dataroot):
101
+ return self.add("package", "licensefile", file)
102
+
103
+ def get_license(self) -> List[str]:
104
+ """
105
+ Get a list of license names associated with the package.
106
+
107
+ Returns:
108
+ List[str]: A list of license names.
109
+ """
110
+ return self.get("package", "license")
111
+
112
+ def get_licensefile(self) -> List[str]:
113
+ """
114
+ Get a list of license file paths associated with the package.
115
+
116
+ Returns:
117
+ List[str]: A list of file paths.
118
+ """
119
+ return self.find_files("package", "licensefile")
120
+
121
+ def add_author(self,
122
+ identifier: str,
123
+ name: str = None,
124
+ email: str = None,
125
+ organization: str = None):
126
+ """
127
+ Add or update author information for the package.
128
+
129
+ Args:
130
+ identifier (str): A unique identifier for the author.
131
+ name (str, optional): The author's name. Defaults to None.
132
+ email (str, optional): The author's email address. Defaults to None.
133
+ organization (str, optional): The author's organization. Defaults to None.
134
+ """
135
+ params = []
136
+ if name:
137
+ params.append(self.set("package", "author", identifier, "name", name))
138
+ if email:
139
+ params.append(self.set("package", "author", identifier, "email", email))
140
+ if organization:
141
+ params.append(self.set("package", "author", identifier, "organization", organization))
142
+ return [p for p in params if p]
143
+
144
+ def get_author(self, identifier: str = None):
145
+ """
146
+ Returns the author information for a specific author or all authors.
147
+
148
+ Args:
149
+ identifier (str): A unique identifier for the author, if None returns all
150
+ """
151
+ if identifier is None:
152
+ authors = []
153
+ for author in self.getkeys("package", "author"):
154
+ authors.append(self.get_author(author))
155
+ return authors
156
+ return {
157
+ "name": self.get("package", "author", identifier, "name"),
158
+ "email": self.get("package", "author", identifier, "email"),
159
+ "organization": self.get("package", "author", identifier, "organization")
160
+ }
161
+
162
+ def add_doc(self, type: str, path: str, dataroot: str = None):
163
+ """
164
+ Add documentation to the package.
165
+
166
+ Args:
167
+ type (str): The type of documentation (e.g., "manual", "api").
168
+ path (str): The path to the documentation file.
169
+ dataroot (str, optional): The data reference for the package. Defaults to None,
170
+ which uses the active package.
171
+
172
+ Returns:
173
+ The result of the `add` operation.
174
+ """
175
+ if not dataroot:
176
+ dataroot = self._get_active("package")
177
+ with self.active_dataroot(dataroot):
178
+ return self.add("package", "doc", type, path)
179
+
180
+ def get_doc(self, type: str = None) -> Union[List[str], Dict[str, List[str]]]:
181
+ """
182
+ Get documentation files for the package.
183
+
184
+ Args:
185
+ type (str, optional): The type of documentation to retrieve. If None,
186
+ returns all documentation organized by type. Defaults to None.
187
+ """
188
+ if type:
189
+ return self.find_files("package", "doc", type)
190
+
191
+ docs = {}
192
+ for type in self.getkeys("package", "doc"):
193
+ doc_files = self.find_files("package", "doc", type)
194
+ if doc_files:
195
+ docs[type] = doc_files
196
+ return docs
197
+
198
+ @classmethod
199
+ def _getdict_type(cls) -> str:
200
+ """
201
+ Returns the meta data for getdict
202
+ """
203
+
204
+ return PackageSchema.__name__
205
+
206
+
207
+ ############################################
208
+ # Package information
209
+ ############################################
210
+ def schema_package(schema):
211
+ """
212
+ Adds package schema parameters to the given schema.
213
+
214
+ Args:
215
+ schema (EditableSchema): The schema to modify.
216
+ """
217
+ schema = EditableSchema(schema)
218
+
219
+ schema.insert(
220
+ 'package', 'version',
221
+ Parameter(
222
+ 'str',
223
+ scope=Scope.GLOBAL,
224
+ shorthelp="Package: version",
225
+ switch="-package_version <str>",
226
+ example=[
227
+ "cli: -package_version 1.0",
228
+ "api: chip.set('package', 'version', '1.0')"],
229
+ help=trim("""Package version. Can be a branch, tag, commit hash,
230
+ or a semver compatible version.""")))
231
+
232
+ schema.insert(
233
+ 'package', 'vendor',
234
+ Parameter(
235
+ 'str',
236
+ scope=Scope.GLOBAL,
237
+ shorthelp="Package: vendor",
238
+ switch="-package_vendor <str>",
239
+ example=[
240
+ "cli: -package_vendor acme",
241
+ "api: chip.set('package', 'vendor', 'acme')"],
242
+ help=trim("""Package vendor.""")))
243
+
244
+ schema.insert(
245
+ 'package', 'description',
246
+ Parameter(
247
+ 'str',
248
+ scope=Scope.GLOBAL,
249
+ shorthelp="Package: description",
250
+ switch="-package_description <str>",
251
+ example=[
252
+ "cli: -package_description 'Yet another cpu'",
253
+ "api: chip.set('package', 'description', 'Yet another cpu')"],
254
+ help=trim("""Package short one line description for package
255
+ managers and summary reports.""")))
256
+
257
+ for item in [
258
+ 'datasheet',
259
+ 'reference',
260
+ 'userguide',
261
+ 'quickstart',
262
+ 'releasenotes',
263
+ 'testplan',
264
+ 'signoff',
265
+ 'tutorial']:
266
+ schema.insert(
267
+ 'package', 'doc', item,
268
+ Parameter(
269
+ '[file]',
270
+ scope=Scope.GLOBAL,
271
+ shorthelp=f"Package: {item} document",
272
+ switch=f"-package_doc_{item} <file>",
273
+ example=[
274
+ f"cli: -package_doc_{item} {item}.pdf",
275
+ f"api: chip.set('package', 'doc', '{item}', '{item}.pdf')"],
276
+ help=trim(f"""Package list of {item} documents.""")))
277
+
278
+ schema.insert(
279
+ 'package', 'license',
280
+ Parameter(
281
+ '[str]',
282
+ scope=Scope.GLOBAL,
283
+ shorthelp="Package: license identifiers",
284
+ switch="-package_license <str>",
285
+ example=[
286
+ "cli: -package_license 'Apache-2.0'",
287
+ "api: chip.set('package', 'license', 'Apache-2.0')"],
288
+ help=trim("""Package list of SPDX license identifiers.""")))
289
+
290
+ schema.insert(
291
+ 'package', 'licensefile',
292
+ Parameter(
293
+ '[file]',
294
+ scope=Scope.GLOBAL,
295
+ shorthelp="Package: license files",
296
+ switch="-package_licensefile <file>",
297
+ example=[
298
+ "cli: -package_licensefile './LICENSE'",
299
+ "api: chip.set('package', 'licensefile', './LICENSE')"],
300
+ help=trim("""Package list of license files for to be
301
+ applied in cases when a SPDX identifier is not available.
302
+ (eg. proprietary licenses).""")))
303
+
304
+ for item in [
305
+ 'name',
306
+ 'email',
307
+ 'organization']:
308
+ schema.insert(
309
+ 'package', 'author', 'default', item,
310
+ Parameter(
311
+ 'str',
312
+ scope=Scope.GLOBAL,
313
+ shorthelp=f"Package: author {item}",
314
+ switch=f"-package_author_{item} 'userid <str>'",
315
+ example=[
316
+ f"cli: -package_author_{item} 'wiley wiley@acme.com'",
317
+ f"api: chip.set('package', 'author', 'wiley', '{item}', 'wiley@acme.com')"],
318
+ help=trim(f"""Package author {item} provided with full name as key and
319
+ {item} as value.""")))
320
+
321
+
322
+ class PackageSchemaTmp(BaseSchema):
323
+ """
324
+ A temporary package schema used for development and testing.
325
+ """
326
+ def __init__(self):
327
+ """
328
+ Initializes a temporary PackageSchemaTmp object.
329
+ """
330
+ super().__init__()
331
+
332
+ schema_package_tmp(self)
18
333
 
19
334
  def register(self, name, path, ref=None, clobber=True):
20
335
  """
21
- Registers a package by its name with the source path and reference
336
+ Registers a package by its name with the source path and reference.
22
337
 
23
338
  Registered package sources are stored in the package section of the schema.
24
339
 
@@ -50,40 +365,50 @@ class PackageSchema(BaseSchema):
50
365
  return success
51
366
 
52
367
  def get_resolver(self, package):
53
- '''
54
- Returns a specific resolver
368
+ """
369
+ Returns a specific resolver for a package.
55
370
 
56
371
  Args:
57
372
  package (str): name of package
58
- '''
373
+ """
59
374
  resolver_cls = Resolver.find_resolver(self.get("source", package, "path"))
60
375
  resolver = resolver_cls(package, self._parent(root=True),
61
376
  self.get("source", package, "path"),
62
377
  self.get("source", package, "ref"))
63
- resolver.set_cache(self.__cache)
64
378
  return resolver
65
379
 
66
380
  def get_resolvers(self):
67
- '''
381
+ """
68
382
  Returns a dictionary of packages with their resolver method.
69
- '''
383
+
384
+ Returns:
385
+ Dict[str, callable]: A dictionary of package names mapped to their resolver methods.
386
+ """
70
387
  resolvers = {}
71
388
  for package in self.getkeys("source"):
72
389
  resolvers[package] = self.get_resolver(package).get_path
73
390
 
74
391
  return resolvers
75
392
 
76
- def _set_cache(self, package, path):
77
- self.__cache[package] = path
393
+ @classmethod
394
+ def _getdict_type(cls) -> str:
395
+ """
396
+ Returns the meta data for getdict
397
+ """
78
398
 
79
- def get_path_cache(self):
80
- return self.__cache.copy()
399
+ return PackageSchemaTmp.__name__
81
400
 
82
401
 
83
402
  ############################################
84
403
  # Package information
85
404
  ############################################
86
- def schema_package(schema):
405
+ def schema_package_tmp(schema):
406
+ """
407
+ Adds temporary package schema parameters to the given schema.
408
+
409
+ Args:
410
+ schema (EditableSchema): The schema to modify.
411
+ """
87
412
  schema = EditableSchema(schema)
88
413
 
89
414
  schema.insert(
@@ -0,0 +1,255 @@
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",
52
+ getattr(schema_root, "getcollectiondir", None))
53
+ if collection_dir:
54
+ collection_dir = collection_dir()
55
+
56
+ return super().find_files(*keypath,
57
+ missing_ok=missing_ok,
58
+ step=step, index=index,
59
+ collection_dir=collection_dir,
60
+ cwd=cwd)
61
+
62
+ def check_filepaths(self, ignore_keys=None):
63
+ '''
64
+ Verifies that paths to all files in manifest are valid.
65
+
66
+ Args:
67
+ ignore_keys (list of keypaths): list of keypaths to ignore while checking
68
+
69
+ Returns:
70
+ True if all file paths are valid, otherwise False.
71
+ '''
72
+ schema_root = self._parent(root=True)
73
+ cwd = getattr(schema_root, "cwd", os.getcwd())
74
+ logger = getattr(schema_root,
75
+ "logger",
76
+ logging.getLogger("siliconcompiler.check_filepaths"))
77
+ collection_dir = getattr(schema_root, "collection_dir",
78
+ getattr(schema_root, "getcollectiondir",
79
+ None))
80
+ if collection_dir:
81
+ collection_dir = collection_dir()
82
+
83
+ return super().check_filepaths(
84
+ ignore_keys=ignore_keys,
85
+ logger=logger,
86
+ collection_dir=collection_dir,
87
+ cwd=cwd)
88
+
89
+
90
+ class PathSchemaSimpleBase(PathSchemaBase):
91
+ def find_files(self, *keypath, missing_ok=False):
92
+ """
93
+ Returns absolute paths to files or directories based on the keypath
94
+ provided.
95
+ The keypath provided must point to a schema parameter of type file, dir,
96
+ or lists of either. Otherwise, it will trigger an error.
97
+ Args:
98
+ keypath (list of str): Variable length schema key list.
99
+ missing_ok (bool): If True, silently return None when files aren't
100
+ found. If False, print an error and set the error flag.
101
+ Returns:
102
+ If keys points to a scalar entry, returns an absolute path to that
103
+ file/directory, or None if not found. It keys points to a list
104
+ entry, returns a list of either the absolute paths or None for each
105
+ entry, depending on whether it is found.
106
+ Examples:
107
+ >>> schema.find_files('input', 'verilog')
108
+ Returns a list of absolute paths to source files, as specified in
109
+ the schema.
110
+ """
111
+ return super().find_files(*keypath,
112
+ missing_ok=missing_ok,
113
+ step=None, index=None)
114
+
115
+
116
+ class PathSchema(PathSchemaBase):
117
+ '''
118
+ Schema extension to add support for path handling with dataroots
119
+ '''
120
+
121
+ def __init__(self):
122
+ super().__init__()
123
+
124
+ schema = EditableSchema(self)
125
+
126
+ schema.insert(
127
+ 'dataroot', 'default', 'path',
128
+ Parameter(
129
+ 'str',
130
+ scope=Scope.GLOBAL,
131
+ shorthelp="Data directory path",
132
+ example=[
133
+ "api: chip.set('dataroot', "
134
+ "'freepdk45_data', 'path', 'ssh://git@github.com/siliconcompiler/freepdk45/')"],
135
+ help=trim("""
136
+ Data directory path, this points the location where the data can be
137
+ retrieved or accessed.
138
+ Allowed roots:
139
+
140
+ * /path/on/network/drive
141
+ * file:///path/on/network/drive
142
+ * git+https://github.com/xyz/xyz
143
+ * git://github.com/xyz/xyz
144
+ * git+ssh://github.com/xyz/xyz
145
+ * ssh://github.com/xyz/xyz
146
+ * https://github.com/xyz/xyz/archive
147
+ * https://zeroasic.com/xyz.tar.gz
148
+ * github://siliconcompiler/lambdapdk/v1.0/asap7.tar.gz
149
+ * python://siliconcompiler
150
+ """)))
151
+
152
+ schema.insert(
153
+ 'dataroot', 'default', 'tag',
154
+ Parameter(
155
+ 'str',
156
+ scope=Scope.GLOBAL,
157
+ shorthelp="Data directory reference tag/version",
158
+ example=[
159
+ "api: chip.set('dataroot', 'freepdk45_data', 'tag', '07ec4aa')"],
160
+ help=trim("""
161
+ Data directory reference tag. The meaning of the this tag depends on the
162
+ context of the path.
163
+ For git, this can be a tag, branch, or commit id. For https this is the version
164
+ of the file that will be downloaded.
165
+ """)))
166
+
167
+ def set_dataroot(self, name: str, path: str, tag: str = None):
168
+ """
169
+ Registers a data directory by its name with the root and associated tag. If the path
170
+ provided is a file, the path recorded will be the directory the file is located in.
171
+
172
+ Args:
173
+ name (str): Data directory name
174
+ path (str): Path to the root of the data directory, can be directory, git url,
175
+ archive url, or path to a file
176
+ tag (str): Reference of the sources, can be commitid, branch name, tag
177
+
178
+ Examples:
179
+ >>> schema.set_dataroot('siliconcompiler_data',
180
+ 'git+https://github.com/siliconcompiler/siliconcompiler',
181
+ 'v1.0.0')
182
+ Records the data directory for siliconcompiler_data as a git clone for tag v1.0.0
183
+ >>> schema.set_dataroot('file_data', __file__)
184
+ Records the data directory for file_data as the directory that __file__ is found in.
185
+ """
186
+
187
+ if os.path.isfile(path):
188
+ path = os.path.dirname(os.path.abspath(path))
189
+
190
+ BaseSchema.set(self, "dataroot", name, "path", path)
191
+ if tag:
192
+ BaseSchema.set(self, "dataroot", name, "tag", tag)
193
+
194
+ def get_dataroot(self, name: str) -> str:
195
+ """
196
+ Returns absolute path to the data directory.
197
+
198
+ Raises:
199
+ ValueError: is data directory is not found
200
+
201
+ Args:
202
+ name (str): name of the data directory to find.
203
+
204
+ Returns:
205
+ Path to the directory root.
206
+
207
+ Examples:
208
+ >>> schema.get_dataroot('siliconcompiler')
209
+ Returns the path to the root of the siliconcompiler data directory.
210
+ """
211
+
212
+ if not BaseSchema.valid(self, "dataroot", name):
213
+ raise ValueError(f"{name} is not a recognized source")
214
+
215
+ path = BaseSchema.get(self, "dataroot", name, "path")
216
+ tag = BaseSchema.get(self, "dataroot", name, "tag")
217
+
218
+ resolver = Resolver.find_resolver(path)
219
+ return resolver(name, self._parent(root=True), path, tag).get_path()
220
+
221
+ def _find_files_dataroot_resolvers(self):
222
+ """
223
+ Returns a dictionary of path resolevrs data directory handling for find_files
224
+
225
+ Returns:
226
+ dictionary of str to resolver mapping
227
+ """
228
+ schema_root = self._parent(root=True)
229
+ resolver_map = {}
230
+ for dataroot in self.getkeys("dataroot"):
231
+ path = BaseSchema.get(self, "dataroot", dataroot, "path")
232
+ tag = BaseSchema.get(self, "dataroot", dataroot, "tag")
233
+ resolver = Resolver.find_resolver(path)
234
+ resolver_map[dataroot] = resolver(dataroot, schema_root, path, tag).get_path
235
+ return resolver_map
236
+
237
+ @contextlib.contextmanager
238
+ def active_dataroot(self, dataroot: str = None):
239
+ '''
240
+ Use this context to set the dataroot parameter on files and directory parameters.
241
+
242
+ Args:
243
+ dataroot (str): name of the dataroot
244
+
245
+ Example:
246
+ >>> with schema.active_dataroot("lambdalib"):
247
+ ... schema.set("file", "top.v")
248
+ Sets the file to top.v and associates lambdalib as the dataroot.
249
+ '''
250
+
251
+ if dataroot and dataroot not in self.getkeys("dataroot"):
252
+ raise ValueError(f"{dataroot} is not a recognized dataroot")
253
+
254
+ with self._active(package=dataroot):
255
+ yield