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
siliconcompiler/design.py CHANGED
@@ -3,19 +3,21 @@ import re
3
3
 
4
4
  import os.path
5
5
 
6
- from pathlib import Path
7
- from typing import List
6
+ from typing import List, Union, Tuple, Dict
8
7
 
9
8
  from siliconcompiler import utils
10
9
 
10
+ from siliconcompiler import PackageSchema
11
+
11
12
  from siliconcompiler.dependencyschema import DependencySchema
13
+ from siliconcompiler.pathschema import PathSchema
12
14
  from siliconcompiler.schema import NamedSchema
13
15
  from siliconcompiler.schema import EditableSchema, Parameter, Scope
14
16
  from siliconcompiler.schema.utils import trim
15
17
 
16
18
 
17
19
  ###########################################################################
18
- class DesignSchema(NamedSchema, DependencySchema):
20
+ class DesignSchema(PackageSchema, NamedSchema, DependencySchema, PathSchema):
19
21
 
20
22
  def __init__(self, name: str = None):
21
23
  super().__init__()
@@ -23,7 +25,14 @@ class DesignSchema(NamedSchema, DependencySchema):
23
25
 
24
26
  schema_design(self)
25
27
 
26
- self.__fileset = None
28
+ def add_dep(self, obj: NamedSchema, clobber: bool = True) -> bool:
29
+ if not isinstance(obj, NamedSchema):
30
+ raise TypeError(f"Cannot add an object of type: {type(obj)}")
31
+
32
+ if obj.name() == self.name():
33
+ raise ValueError("Cannot add a dependency with the same name")
34
+
35
+ return super().add_dep(obj, clobber=clobber)
27
36
 
28
37
  ############################################
29
38
  def set_topmodule(self,
@@ -66,20 +75,20 @@ class DesignSchema(NamedSchema, DependencySchema):
66
75
  value: str,
67
76
  fileset: str = None,
68
77
  clobber: bool = False,
69
- package: str = None) -> List[str]:
78
+ dataroot: str = None) -> List[str]:
70
79
  """Adds include directories to a fileset.
71
80
 
72
81
  Args:
73
82
  value (str or Path): Include directory name.
74
83
  fileset (str, optional): Fileset name.
75
84
  clobber (bool, optional): Clears existing list before adding item
76
- package (str, optional): Package name
85
+ dataroot (str, optional): Data directory reference name
77
86
 
78
87
  Returns:
79
88
  list[str]: List of include directories
80
89
  """
81
90
  return self.__set_add(fileset, 'idir', value, clobber, typelist=[str, list],
82
- package=package)
91
+ dataroot=dataroot)
83
92
 
84
93
  def get_idir(self, fileset: str = None) -> List[str]:
85
94
  """Returns include directories for a fileset.
@@ -90,7 +99,7 @@ class DesignSchema(NamedSchema, DependencySchema):
90
99
  Returns:
91
100
  list[str]: List of include directories
92
101
  """
93
- return self.__get(fileset, 'idir')
102
+ return self.__get(fileset, 'idir', is_file=True)
94
103
 
95
104
  ##############################################
96
105
  def add_define(self,
@@ -155,20 +164,20 @@ class DesignSchema(NamedSchema, DependencySchema):
155
164
  value: str,
156
165
  fileset: str = None,
157
166
  clobber: bool = False,
158
- package: str = None) -> List[str]:
167
+ dataroot: str = None) -> List[str]:
159
168
  """Adds dynamic library directories to a fileset.
160
169
 
161
170
  Args:
162
171
  value (str or List[str]): Library directories
163
172
  fileset (str, optional): Fileset name.
164
173
  clobber (bool, optional): Clears existing list before adding item.
165
- package (str, optional): Package name
174
+ dataroot (str, optional): Data directory reference name
166
175
 
167
176
  Returns:
168
177
  list[str]: List of library directories.
169
178
  """
170
179
  return self.__set_add(fileset, 'libdir', value, clobber, typelist=[str, list],
171
- package=package)
180
+ dataroot=dataroot)
172
181
 
173
182
  def get_libdir(self, fileset: str = None) -> List[str]:
174
183
  """Returns dynamic library directories for a fileset.
@@ -179,7 +188,7 @@ class DesignSchema(NamedSchema, DependencySchema):
179
188
  Returns:
180
189
  list[str]: List of library directories.
181
190
  """
182
- return self.__get(fileset, 'libdir')
191
+ return self.__get(fileset, 'libdir', is_file=True)
183
192
 
184
193
  ###############################################
185
194
  def add_lib(self,
@@ -226,7 +235,7 @@ class DesignSchema(NamedSchema, DependencySchema):
226
235
  """
227
236
 
228
237
  if fileset is None:
229
- fileset = self.__fileset
238
+ fileset = self._get_active("fileset")
230
239
 
231
240
  if not isinstance(fileset, str):
232
241
  raise ValueError("fileset key must be a string")
@@ -249,19 +258,71 @@ class DesignSchema(NamedSchema, DependencySchema):
249
258
  str: Parameter value
250
259
  """
251
260
  if fileset is None:
252
- fileset = self.__fileset
261
+ fileset = self._get_active("fileset")
253
262
 
254
263
  if not isinstance(fileset, str):
255
- raise ValueError("fileset value must be a string")
264
+ raise ValueError("fileset key must be a string")
256
265
  return self.get('fileset', fileset, 'param', name)
257
266
 
267
+ ###############################################
268
+ def add_depfileset(self, dep: Union["DesignSchema", str], depfileset: str, fileset: str = None):
269
+ """
270
+ Record a reference to an imported dependency's fileset.
271
+
272
+ Args:
273
+ dep (:class:`DesignSchema` or str): Dependency name or object.
274
+ depfileset (str): Dependency fileset
275
+ fileset (str): Fileset name.
276
+
277
+ """
278
+ if fileset is None:
279
+ fileset = self._get_active("fileset")
280
+
281
+ if not isinstance(fileset, str):
282
+ raise ValueError("fileset key must be a string")
283
+
284
+ if isinstance(dep, str):
285
+ dep_name = dep
286
+ dep = self.get_dep(dep_name)
287
+ elif isinstance(dep, DesignSchema):
288
+ dep_name = dep.name()
289
+ self.add_dep(dep, clobber=True)
290
+ else:
291
+ raise TypeError("dep is not a valid type")
292
+
293
+ if not isinstance(dep, DesignSchema):
294
+ raise ValueError(f"cannot associate fileset ({depfileset}) with {dep.name()}")
295
+
296
+ if depfileset not in dep.getkeys("fileset"):
297
+ raise ValueError(f"{dep.name()} does not have {depfileset} as a fileset")
298
+
299
+ return self.add("fileset", fileset, "depfileset", (dep_name, depfileset))
300
+
301
+ def get_depfileset(self, fileset: str = None):
302
+ """
303
+ Returns list of dependency filesets.
304
+
305
+ Args:
306
+ fileset (str): Fileset name.
307
+
308
+ Returns:
309
+ list[str]: List of dependencies and filesets.
310
+ """
311
+ if fileset is None:
312
+ fileset = self._get_active("fileset")
313
+
314
+ if not isinstance(fileset, str):
315
+ raise ValueError("fileset key must be a string")
316
+
317
+ return self.get("fileset", fileset, "depfileset")
318
+
258
319
  ###############################################
259
320
  def add_file(self,
260
321
  filename: str,
261
322
  fileset: str = None,
262
323
  filetype: str = None,
263
324
  clobber: bool = False,
264
- package: str = None) -> List[str]:
325
+ dataroot: str = None) -> List[str]:
265
326
  """
266
327
  Adds files to a fileset.
267
328
 
@@ -277,7 +338,7 @@ class DesignSchema(NamedSchema, DependencySchema):
277
338
  fileset (str): Logical group to associate the file with.
278
339
  filetype (str, optional): Type of the file (e.g., 'verilog', 'sdc').
279
340
  clobber (bool, optional): Clears list before adding item
280
- package (str, optional): Package name
341
+ dataroot (str, optional): Data directory reference name
281
342
 
282
343
  Raises:
283
344
  SiliconCompilerError: If fileset or filetype cannot be inferred from
@@ -294,17 +355,22 @@ class DesignSchema(NamedSchema, DependencySchema):
294
355
  """
295
356
 
296
357
  if fileset is None:
297
- fileset = self.__fileset
358
+ fileset = self._get_active("fileset")
359
+
360
+ if not isinstance(fileset, str):
361
+ raise ValueError("fileset key must be a string")
298
362
 
299
363
  # handle list inputs
300
364
  if isinstance(filename, (list, tuple)):
365
+ params = []
301
366
  for item in filename:
302
- self.add_file(
303
- item,
304
- fileset=fileset,
305
- clobber=clobber,
306
- filetype=filetype)
307
- return
367
+ params.extend(
368
+ self.add_file(
369
+ item,
370
+ fileset=fileset,
371
+ clobber=clobber,
372
+ filetype=filetype))
373
+ return params
308
374
 
309
375
  if filename is None:
310
376
  raise ValueError("add_file cannot process None")
@@ -313,36 +379,24 @@ class DesignSchema(NamedSchema, DependencySchema):
313
379
  filename = str(filename)
314
380
 
315
381
  # map extension to default filetype/fileset
316
-
317
382
  if not filetype:
318
383
  ext = utils.get_file_ext(filename)
319
384
  iomap = utils.get_default_iomap()
320
385
  if ext in iomap:
321
- default_fileset, default_filetype = iomap[ext]
386
+ _, default_filetype = iomap[ext]
322
387
  filetype = default_filetype
323
388
  else:
324
- raise ValueError("illegal file extension")
389
+ raise ValueError(f"Unrecognized file extension: {ext}")
325
390
 
326
- # final error checking
327
- if not fileset or not filetype:
328
- raise ValueError(
329
- f'Unable to infer fileset and/or filetype for '
330
- f'{filename} based on file extension.')
391
+ if not dataroot:
392
+ dataroot = self._get_active("package")
331
393
 
332
394
  # adding files to dictionary
333
- if clobber:
334
- params = self.set('fileset', fileset, 'file', filetype, filename)
335
- else:
336
- params = self.add('fileset', fileset, 'file', filetype, filename)
337
-
338
- if package and params:
339
- if not isinstance(params, (list, set, tuple)):
340
- params = [params]
341
-
342
- for param in params:
343
- param.set(package, field="package")
344
-
345
- return params
395
+ with self.active_dataroot(dataroot):
396
+ if clobber:
397
+ return self.set('fileset', fileset, 'file', filetype, filename)
398
+ else:
399
+ return self.add('fileset', fileset, 'file', filetype, filename)
346
400
 
347
401
  ###############################################
348
402
  def get_file(self,
@@ -359,7 +413,7 @@ class DesignSchema(NamedSchema, DependencySchema):
359
413
  """
360
414
 
361
415
  if fileset is None:
362
- fileset = self.__fileset
416
+ fileset = self._get_active("fileset")
363
417
 
364
418
  if not isinstance(fileset, list):
365
419
  fileset = [fileset]
@@ -368,19 +422,22 @@ class DesignSchema(NamedSchema, DependencySchema):
368
422
  filetype = [filetype]
369
423
 
370
424
  filelist = []
371
- for i in fileset:
372
- if not isinstance(i, str):
425
+ for fs in fileset:
426
+ if not isinstance(fs, str):
373
427
  raise ValueError("fileset key must be a string")
374
428
  # handle scalar+list in argument
375
429
  if not filetype:
376
- filetype = list(self.getkeys('fileset', i, 'file'))
430
+ filetype = self.getkeys('fileset', fs, 'file')
377
431
  # grab the files
378
- for j in filetype:
379
- filelist.extend(self.get('fileset', i, 'file', j))
432
+ for ftype in filetype:
433
+ filelist.extend(self.find_files('fileset', fs, 'file', ftype))
380
434
 
381
435
  return filelist
382
436
 
383
- def __write_flist(self, filename: str, filesets: list):
437
+ def __write_flist(self,
438
+ filename: str,
439
+ filesets: List[str],
440
+ depalias: Dict[str, Tuple[NamedSchema, str]]):
384
441
  written_cmd = set()
385
442
 
386
443
  with open(filename, "w") as f:
@@ -394,33 +451,37 @@ class DesignSchema(NamedSchema, DependencySchema):
394
451
  def write_header(header):
395
452
  f.write(f"// {header}\n")
396
453
 
397
- for lib in [self, *self.get_dep()]:
398
- write_header(f"{lib.name()}")
399
- for fileset in filesets:
400
- if not lib.valid('fileset', fileset):
401
- continue
454
+ for lib, fileset in self.get_fileset(filesets, depalias):
455
+ if lib.get('fileset', fileset, 'idir'):
456
+ write_header(f"{lib.name()} / {fileset} / include directories")
457
+ for idir in lib.find_files('fileset', fileset, 'idir'):
458
+ write(f"+incdir+{idir}")
459
+
460
+ if lib.get('fileset', fileset, 'define'):
461
+ write_header(f"{lib.name()} / {fileset} / defines")
462
+ for define in lib.get('fileset', fileset, 'define'):
463
+ write(f"+define+{define}")
402
464
 
403
- if lib.get('fileset', fileset, 'idir'):
404
- write_header(f"{lib.name()} / {fileset} / include directories")
405
- for idir in lib.find_files('fileset', fileset, 'idir'):
406
- write(f"+incdir+{idir}")
465
+ for filetype in lib.getkeys('fileset', fileset, 'file'):
466
+ if lib.get('fileset', fileset, 'file', filetype):
467
+ write_header(f"{lib.name()} / {fileset} / {filetype} files")
468
+ for file in lib.find_files('fileset', fileset, 'file', filetype):
469
+ write(file)
407
470
 
408
- if lib.get('fileset', fileset, 'define'):
409
- write_header(f"{lib.name()} / {fileset} / defines")
410
- for define in lib.get('fileset', fileset, 'define'):
411
- write(f"+define+{define}")
471
+ def __map_fileformat(self, path):
472
+ _, ext = os.path.splitext(path)
412
473
 
413
- for filetype in lib.getkeys('fileset', fileset, 'file'):
414
- if lib.get('fileset', fileset, 'file', filetype):
415
- write_header(f"{lib.name()} / {fileset} / {filetype} files")
416
- for file in lib.find_files('fileset', fileset, 'file', filetype):
417
- write(file)
474
+ if ext == ".f":
475
+ return "flist"
476
+ else:
477
+ raise ValueError(f"Unable to determine filetype of: {path}")
418
478
 
419
479
  ###############################################
420
480
  def write_fileset(self,
421
481
  filename: str,
422
482
  fileset: str = None,
423
- fileformat: str = None) -> None:
483
+ fileformat: str = None,
484
+ depalias: Dict[str, Tuple[NamedSchema, str]] = None) -> None:
424
485
  """Exports filesets to a standard formatted text file.
425
486
 
426
487
  Currently supports Verilog `flist` format only.
@@ -431,13 +492,14 @@ class DesignSchema(NamedSchema, DependencySchema):
431
492
  filename (str or Path): Output file name.
432
493
  fileset (str or list[str]): Fileset(s) to export.
433
494
  fileformat (str, optional): Export format.
495
+ depalias (dict of schema objects): Map of aliased objects
434
496
  """
435
497
 
436
498
  if filename is None:
437
- raise ValueError("write_fileset() filename cannot be None")
499
+ raise ValueError("filename cannot be None")
438
500
 
439
501
  if fileset is None:
440
- fileset = self.__fileset
502
+ fileset = self._get_active("fileset")
441
503
 
442
504
  if not isinstance(fileset, list):
443
505
  fileset = [fileset]
@@ -448,14 +510,12 @@ class DesignSchema(NamedSchema, DependencySchema):
448
510
 
449
511
  # file extension lookup
450
512
  if not fileformat:
451
- formats = {}
452
- formats['f'] = 'flist'
453
- fileformat = formats[Path(filename).suffix.strip('.')]
513
+ fileformat = self.__map_fileformat(filename)
454
514
 
455
515
  if fileformat == "flist":
456
- self.__write_flist(filename, fileset)
516
+ self.__write_flist(filename, fileset, depalias)
457
517
  else:
458
- raise ValueError(f"{fileformat} is not supported")
518
+ raise ValueError(f"{fileformat} is not a supported filetype")
459
519
 
460
520
  def __read_flist(self, filename: str, fileset: str):
461
521
  # Extract information
@@ -485,26 +545,26 @@ class DesignSchema(NamedSchema, DependencySchema):
485
545
  else:
486
546
  files.append(expand_path(line))
487
547
 
488
- # Create packages
548
+ # Create dataroots
489
549
  all_paths = include_dirs + [os.path.dirname(f) for f in files]
490
550
  all_paths = sorted(set(all_paths))
491
551
 
492
- package_root_name = f'flist-{self.name()}-{fileset}-{os.path.basename(filename)}'
493
- packages = {}
552
+ dataroot_root_name = f'flist-{self.name()}-{fileset}-{os.path.basename(filename)}'
553
+ dataroots = {}
494
554
 
495
555
  for path_dir in all_paths:
496
556
  found = False
497
- for pdir in packages:
557
+ for pdir in dataroots:
498
558
  if path_dir.startswith(pdir):
499
559
  found = True
500
560
  break
501
561
  if not found:
502
- package_name = f"{package_root_name}-{len(packages)}"
503
- self.register_package(package_name, path_dir)
504
- packages[path_dir] = package_name
562
+ dataroot_name = f"{dataroot_root_name}-{len(dataroots)}"
563
+ self.set_dataroot(dataroot_name, path_dir)
564
+ dataroots[path_dir] = dataroot_name
505
565
 
506
- def get_package(path):
507
- for pdir, name in packages.items():
566
+ def get_dataroot(path):
567
+ for pdir, name in dataroots.items():
508
568
  if path.startswith(pdir):
509
569
  return name, pdir
510
570
  return None, None
@@ -515,21 +575,21 @@ class DesignSchema(NamedSchema, DependencySchema):
515
575
  self.add_define(defines)
516
576
  if include_dirs:
517
577
  for dir in include_dirs:
518
- package_name, pdir = get_package(dir)
519
- if package_name:
578
+ dataroot_name, pdir = get_dataroot(dir)
579
+ if dataroot_name:
520
580
  dir = os.path.relpath(dir, pdir)
521
- self.add_idir(dir, package=package_name)
581
+ self.add_idir(dir, dataroot=dataroot_name)
522
582
  if files:
523
583
  for f in files:
524
- package_name, pdir = get_package(f)
525
- if package_name:
584
+ dataroot_name, pdir = get_dataroot(f)
585
+ if dataroot_name:
526
586
  f = os.path.relpath(f, pdir)
527
- self.add_file(f, package=package_name)
587
+ self.add_file(f, dataroot=dataroot_name)
528
588
 
529
589
  ################################################
530
590
  def read_fileset(self,
531
591
  filename: str,
532
- fileset: str,
592
+ fileset: str = None,
533
593
  fileformat=None) -> None:
534
594
  """Imports filesets from a standard formatted text file.
535
595
 
@@ -543,27 +603,28 @@ class DesignSchema(NamedSchema, DependencySchema):
543
603
  """
544
604
 
545
605
  if filename is None:
546
- raise ValueError("read_fileset() filename cannot be None")
606
+ raise ValueError("filename cannot be None")
547
607
 
548
608
  if not fileformat:
549
- formats = {}
550
- formats['f'] = 'flist'
551
- fileformat = formats[Path(filename).suffix.strip('.')]
609
+ fileformat = self.__map_fileformat(filename)
610
+
611
+ if fileset is None:
612
+ fileset = self._get_active("fileset")
552
613
 
553
614
  if fileformat == "flist":
554
615
  self.__read_flist(filename, fileset)
555
616
  else:
556
- raise ValueError(f"{fileformat} is not supported")
617
+ raise ValueError(f"{fileformat} is not a supported filetype")
557
618
 
558
619
  ################################################
559
620
  # Helper Functions
560
621
  ################################################
561
- def __set_add(self, fileset, option, value, clobber=False, typelist=None, package=None):
622
+ def __set_add(self, fileset, option, value, clobber=False, typelist=None, dataroot=None):
562
623
  '''Sets a parameter value in schema.
563
624
  '''
564
625
 
565
626
  if fileset is None:
566
- fileset = self.__fileset
627
+ fileset = self._get_active("fileset")
567
628
 
568
629
  # check for a legal fileset
569
630
  if not fileset or not isinstance(fileset, str):
@@ -581,28 +642,27 @@ class DesignSchema(NamedSchema, DependencySchema):
581
642
  if value is None:
582
643
  raise ValueError(f"None is an illegal {option} value")
583
644
 
584
- if list in typelist and not clobber:
585
- params = self.add('fileset', fileset, option, value)
586
- else:
587
- params = self.set('fileset', fileset, option, value)
588
-
589
- if package and params:
590
- if not isinstance(params, (list, set, tuple)):
591
- params = [params]
645
+ if not dataroot:
646
+ dataroot = self._get_active("package")
592
647
 
593
- for param in params:
594
- param.set(package, field="package")
648
+ with self.active_dataroot(dataroot):
649
+ if list in typelist and not clobber:
650
+ params = self.add('fileset', fileset, option, value)
651
+ else:
652
+ params = self.set('fileset', fileset, option, value)
595
653
 
596
654
  return params
597
655
 
598
- def __get(self, fileset, option):
656
+ def __get(self, fileset, option, is_file=False):
599
657
  '''Gets a parameter value from schema.
600
658
  '''
601
659
  if fileset is None:
602
- fileset = self.__fileset
660
+ fileset = self._get_active("fileset")
603
661
 
604
662
  if not isinstance(fileset, str):
605
663
  raise ValueError("fileset key must be a string")
664
+ if is_file:
665
+ return self.find_files('fileset', fileset, option)
606
666
  return self.get('fileset', fileset, option)
607
667
 
608
668
  @contextlib.contextmanager
@@ -627,9 +687,57 @@ class DesignSchema(NamedSchema, DependencySchema):
627
687
  if not fileset:
628
688
  raise ValueError("fileset cannot be an empty string")
629
689
 
630
- self.__fileset = fileset
631
- yield
632
- self.__fileset = None
690
+ with self._active(fileset=fileset):
691
+ yield
692
+
693
+ def get_fileset(self,
694
+ filesets: Union[List[str], str],
695
+ alias: Dict[str, Tuple[NamedSchema, str]] = None) -> \
696
+ List[Tuple[NamedSchema, str]]:
697
+ """
698
+ Computes the filesets this object required for a given set of filesets
699
+
700
+ Args:
701
+ filesets (list of str): List of filesets to evaluate
702
+ alias (dict of schema objects): Map of aliased objects
703
+
704
+ Returns:
705
+ List of tuples (dependency object, fileset)
706
+ """
707
+ if alias is None:
708
+ alias = {}
709
+
710
+ if isinstance(filesets, str):
711
+ # Ensure we have a list
712
+ filesets = [filesets]
713
+
714
+ mapping = []
715
+ for fileset in filesets:
716
+ if not self.valid("fileset", fileset):
717
+ raise ValueError(f"{fileset} is not defined in {self.name()}")
718
+
719
+ mapping.append((self, fileset))
720
+ for dep, depfileset in self.get("fileset", fileset, "depfileset"):
721
+ if (dep, depfileset) in alias:
722
+ dep_obj, new_depfileset = alias[(dep, depfileset)]
723
+ if dep_obj is None:
724
+ continue
725
+
726
+ if new_depfileset:
727
+ depfileset = new_depfileset
728
+ else:
729
+ dep_obj = self.get_dep(dep)
730
+ if not isinstance(dep_obj, DesignSchema):
731
+ raise TypeError(f"{dep} must be a design object.")
732
+
733
+ mapping.extend(dep_obj.get_fileset(depfileset, alias))
734
+
735
+ # Cleanup
736
+ final_map = []
737
+ for cmap in mapping:
738
+ if cmap not in final_map:
739
+ final_map.append(cmap)
740
+ return final_map
633
741
 
634
742
 
635
743
  ###########################################################################
@@ -726,8 +834,7 @@ def schema_design(schema):
726
834
  help=trim("""
727
835
  Specifies directories to scan for libraries provided with the
728
836
  :keypath:`lib` parameter. If multiple paths are provided, they are
729
- searched based on the order of the libdir list. The libdir
730
- parameter is translated to the '-y' option in verilog based tools.""")))
837
+ searched based on the order of the libdir list.""")))
731
838
 
732
839
  schema.insert(
733
840
  'fileset', fileset, 'lib',
@@ -756,3 +863,13 @@ def schema_design(schema):
756
863
  data literals. The types of parameters and values supported is tightly
757
864
  coupled to tools being used. For example, in Verilog only integer
758
865
  literals (64'h4, 2'b0, 4) and strings are supported.""")))
866
+
867
+ schema.insert(
868
+ 'fileset', fileset, 'depfileset',
869
+ Parameter(
870
+ '[(str,str)]',
871
+ scope=Scope.GLOBAL,
872
+ shorthelp="Design dependency fileset",
873
+ example=[
874
+ "api: chip.set('fileset', 'rtl, 'depfileset', ('lambdalib', 'rtl')"],
875
+ help=trim("""Sets the mapping for dependency filesets.""")))