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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. siliconcompiler/__init__.py +2 -0
  2. siliconcompiler/_metadata.py +1 -1
  3. siliconcompiler/apps/_common.py +1 -1
  4. siliconcompiler/apps/sc.py +1 -1
  5. siliconcompiler/apps/sc_issue.py +6 -4
  6. siliconcompiler/apps/sc_remote.py +3 -20
  7. siliconcompiler/apps/sc_show.py +2 -2
  8. siliconcompiler/apps/utils/replay.py +4 -4
  9. siliconcompiler/checklist.py +202 -1
  10. siliconcompiler/core.py +62 -293
  11. siliconcompiler/data/templates/email/general.j2 +3 -3
  12. siliconcompiler/data/templates/email/summary.j2 +1 -1
  13. siliconcompiler/data/templates/issue/README.txt +1 -1
  14. siliconcompiler/data/templates/report/sc_report.j2 +7 -7
  15. siliconcompiler/dependencyschema.py +392 -0
  16. siliconcompiler/design.py +758 -0
  17. siliconcompiler/flowgraph.py +79 -13
  18. siliconcompiler/optimizer/vizier.py +2 -2
  19. siliconcompiler/package/__init__.py +383 -223
  20. siliconcompiler/package/git.py +75 -77
  21. siliconcompiler/package/github.py +70 -97
  22. siliconcompiler/package/https.py +77 -93
  23. siliconcompiler/packageschema.py +260 -0
  24. siliconcompiler/pdk.py +5 -5
  25. siliconcompiler/remote/client.py +33 -15
  26. siliconcompiler/remote/server.py +2 -2
  27. siliconcompiler/report/dashboard/cli/__init__.py +6 -6
  28. siliconcompiler/report/dashboard/cli/board.py +4 -4
  29. siliconcompiler/report/dashboard/web/components/__init__.py +5 -5
  30. siliconcompiler/report/dashboard/web/components/flowgraph.py +4 -4
  31. siliconcompiler/report/dashboard/web/components/graph.py +2 -2
  32. siliconcompiler/report/dashboard/web/state.py +1 -1
  33. siliconcompiler/report/dashboard/web/utils/__init__.py +5 -5
  34. siliconcompiler/report/html_report.py +1 -1
  35. siliconcompiler/report/report.py +4 -4
  36. siliconcompiler/report/summary_table.py +2 -2
  37. siliconcompiler/report/utils.py +5 -5
  38. siliconcompiler/scheduler/__init__.py +3 -1382
  39. siliconcompiler/scheduler/docker.py +263 -0
  40. siliconcompiler/scheduler/run_node.py +10 -21
  41. siliconcompiler/scheduler/scheduler.py +311 -0
  42. siliconcompiler/scheduler/schedulernode.py +944 -0
  43. siliconcompiler/scheduler/send_messages.py +3 -3
  44. siliconcompiler/scheduler/slurm.py +149 -163
  45. siliconcompiler/scheduler/taskscheduler.py +45 -57
  46. siliconcompiler/schema/__init__.py +3 -3
  47. siliconcompiler/schema/baseschema.py +234 -11
  48. siliconcompiler/schema/editableschema.py +4 -0
  49. siliconcompiler/schema/journal.py +210 -0
  50. siliconcompiler/schema/namedschema.py +55 -2
  51. siliconcompiler/schema/parameter.py +14 -1
  52. siliconcompiler/schema/parametervalue.py +1 -34
  53. siliconcompiler/schema/schema_cfg.py +210 -349
  54. siliconcompiler/tool.py +412 -148
  55. siliconcompiler/tools/__init__.py +2 -0
  56. siliconcompiler/tools/builtin/_common.py +5 -5
  57. siliconcompiler/tools/builtin/concatenate.py +7 -7
  58. siliconcompiler/tools/builtin/minimum.py +4 -4
  59. siliconcompiler/tools/builtin/mux.py +4 -4
  60. siliconcompiler/tools/builtin/nop.py +4 -4
  61. siliconcompiler/tools/builtin/verify.py +8 -9
  62. siliconcompiler/tools/execute/exec_input.py +1 -1
  63. siliconcompiler/tools/genfasm/genfasm.py +1 -6
  64. siliconcompiler/tools/openroad/_apr.py +5 -1
  65. siliconcompiler/tools/openroad/antenna_repair.py +1 -1
  66. siliconcompiler/tools/openroad/macro_placement.py +1 -1
  67. siliconcompiler/tools/openroad/power_grid.py +1 -1
  68. siliconcompiler/tools/openroad/scripts/common/procs.tcl +32 -25
  69. siliconcompiler/tools/opensta/timing.py +26 -3
  70. siliconcompiler/tools/slang/__init__.py +2 -2
  71. siliconcompiler/tools/surfer/__init__.py +0 -0
  72. siliconcompiler/tools/surfer/show.py +53 -0
  73. siliconcompiler/tools/surfer/surfer.py +30 -0
  74. siliconcompiler/tools/vpr/route.py +82 -0
  75. siliconcompiler/tools/vpr/vpr.py +23 -6
  76. siliconcompiler/tools/yosys/__init__.py +1 -1
  77. siliconcompiler/tools/yosys/scripts/procs.tcl +143 -0
  78. siliconcompiler/tools/yosys/{sc_synth_asic.tcl → scripts/sc_synth_asic.tcl} +4 -0
  79. siliconcompiler/tools/yosys/{sc_synth_fpga.tcl → scripts/sc_synth_fpga.tcl} +24 -77
  80. siliconcompiler/tools/yosys/syn_fpga.py +14 -0
  81. siliconcompiler/toolscripts/_tools.json +9 -13
  82. siliconcompiler/toolscripts/rhel9/install-vpr.sh +0 -2
  83. siliconcompiler/toolscripts/ubuntu22/install-surfer.sh +33 -0
  84. siliconcompiler/toolscripts/ubuntu24/install-surfer.sh +33 -0
  85. siliconcompiler/utils/__init__.py +4 -24
  86. siliconcompiler/utils/flowgraph.py +29 -28
  87. siliconcompiler/utils/issue.py +23 -29
  88. siliconcompiler/utils/logging.py +37 -7
  89. siliconcompiler/utils/showtools.py +6 -1
  90. {siliconcompiler-0.33.2.dist-info → siliconcompiler-0.34.1.dist-info}/METADATA +16 -25
  91. {siliconcompiler-0.33.2.dist-info → siliconcompiler-0.34.1.dist-info}/RECORD +98 -91
  92. siliconcompiler/scheduler/docker_runner.py +0 -254
  93. siliconcompiler/schema/journalingschema.py +0 -242
  94. siliconcompiler/tools/yosys/procs.tcl +0 -71
  95. siliconcompiler/toolscripts/rhel9/install-yosys-parmys.sh +0 -68
  96. siliconcompiler/toolscripts/ubuntu22/install-yosys-parmys.sh +0 -68
  97. siliconcompiler/toolscripts/ubuntu24/install-yosys-parmys.sh +0 -68
  98. /siliconcompiler/tools/yosys/{sc_lec.tcl → scripts/sc_lec.tcl} +0 -0
  99. /siliconcompiler/tools/yosys/{sc_screenshot.tcl → scripts/sc_screenshot.tcl} +0 -0
  100. /siliconcompiler/tools/yosys/{syn_strategies.tcl → scripts/syn_strategies.tcl} +0 -0
  101. {siliconcompiler-0.33.2.dist-info → siliconcompiler-0.34.1.dist-info}/WHEEL +0 -0
  102. {siliconcompiler-0.33.2.dist-info → siliconcompiler-0.34.1.dist-info}/entry_points.txt +0 -0
  103. {siliconcompiler-0.33.2.dist-info → siliconcompiler-0.34.1.dist-info}/licenses/LICENSE +0 -0
  104. {siliconcompiler-0.33.2.dist-info → siliconcompiler-0.34.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,758 @@
1
+ import contextlib
2
+ import re
3
+
4
+ import os.path
5
+
6
+ from pathlib import Path
7
+ from typing import List
8
+
9
+ from siliconcompiler import utils
10
+
11
+ from siliconcompiler.dependencyschema import DependencySchema
12
+ from siliconcompiler.schema import NamedSchema
13
+ from siliconcompiler.schema import EditableSchema, Parameter, Scope
14
+ from siliconcompiler.schema.utils import trim
15
+
16
+
17
+ ###########################################################################
18
+ class DesignSchema(NamedSchema, DependencySchema):
19
+
20
+ def __init__(self, name: str = None):
21
+ super().__init__()
22
+ self.set_name(name)
23
+
24
+ schema_design(self)
25
+
26
+ self.__fileset = None
27
+
28
+ ############################################
29
+ def set_topmodule(self,
30
+ value: str,
31
+ fileset: str = None) -> str:
32
+ """Sets the topmodule of a fileset.
33
+
34
+ Args:
35
+ value (str): Topmodule name.
36
+ fileset (str, optional): Fileset name.
37
+
38
+ Returns:
39
+ str: Topmodule name
40
+
41
+ Notes:
42
+ - first character must be letter or underscore
43
+ - remaining characters can be letters, digits, or underscores
44
+ """
45
+
46
+ # topmodule safety check
47
+ if (value is not None) and isinstance(value, str):
48
+ if not re.match(r'^[_a-zA-Z]\w*$', value):
49
+ raise ValueError(f"{value} is not a legal topmodule string")
50
+
51
+ return self.__set_add(fileset, 'topmodule', value, typelist=[str])
52
+
53
+ def get_topmodule(self, fileset: str = None) -> str:
54
+ """Returns the topmodule of a fileset.
55
+
56
+ Args:
57
+ fileset (str): Fileset name.
58
+
59
+ Returns:
60
+ str: Topmodule name
61
+ """
62
+ return self.__get(fileset, 'topmodule')
63
+
64
+ ##############################################
65
+ def add_idir(self,
66
+ value: str,
67
+ fileset: str = None,
68
+ clobber: bool = False,
69
+ package: str = None) -> List[str]:
70
+ """Adds include directories to a fileset.
71
+
72
+ Args:
73
+ value (str or Path): Include directory name.
74
+ fileset (str, optional): Fileset name.
75
+ clobber (bool, optional): Clears existing list before adding item
76
+ package (str, optional): Package name
77
+
78
+ Returns:
79
+ list[str]: List of include directories
80
+ """
81
+ return self.__set_add(fileset, 'idir', value, clobber, typelist=[str, list],
82
+ package=package)
83
+
84
+ def get_idir(self, fileset: str = None) -> List[str]:
85
+ """Returns include directories for a fileset.
86
+
87
+ Args:
88
+ fileset (str): Fileset name.
89
+
90
+ Returns:
91
+ list[str]: List of include directories
92
+ """
93
+ return self.__get(fileset, 'idir')
94
+
95
+ ##############################################
96
+ def add_define(self,
97
+ value: str,
98
+ fileset: str = None,
99
+ clobber: bool = False) -> List[str]:
100
+ """Adds preprocessor macro definitions to a fileset.
101
+
102
+ Args:
103
+ value (str or List[str]): Macro definition.
104
+ fileset (str, optional): Fileset name.
105
+ clobber (bool, optional): Clears existing list before adding item.
106
+
107
+ Returns:
108
+ list[str]: List of macro definitions
109
+
110
+ """
111
+ return self.__set_add(fileset, 'define', value, clobber, typelist=[str, list])
112
+
113
+ def get_define(self, fileset: str = None) -> List[str]:
114
+ """Returns defined macros for a fileset.
115
+
116
+ Args:
117
+ fileset (str): Fileset name.
118
+
119
+ Returns:
120
+ list[str]: List of macro definitions
121
+ """
122
+ return self.__get(fileset, 'define')
123
+
124
+ ##############################################
125
+ def add_undefine(self,
126
+ value: str,
127
+ fileset: str = None,
128
+ clobber: bool = False) -> List[str]:
129
+ """Adds preprocessor macro (un)definitions to a fileset.
130
+
131
+ Args:
132
+ value (str or List[str]): Macro (un)definition.
133
+ fileset (str, optional): Fileset name.
134
+ clobber (bool, optional): CClears existing list before adding item.
135
+
136
+ Returns:
137
+ list[str]: List of macro (un)definitions
138
+ """
139
+ return self.__set_add(fileset, 'undefine', value, clobber, typelist=[str, list])
140
+
141
+ def get_undefine(self, fileset: str = None) -> List[str]:
142
+ """Returns undefined macros for a fileset.
143
+
144
+ Args:
145
+ fileset (str): Fileset name.
146
+
147
+ Returns:
148
+ list[str]: List of macro (un)definitions
149
+
150
+ """
151
+ return self.__get(fileset, 'undefine')
152
+
153
+ ###############################################
154
+ def add_libdir(self,
155
+ value: str,
156
+ fileset: str = None,
157
+ clobber: bool = False,
158
+ package: str = None) -> List[str]:
159
+ """Adds dynamic library directories to a fileset.
160
+
161
+ Args:
162
+ value (str or List[str]): Library directories
163
+ fileset (str, optional): Fileset name.
164
+ clobber (bool, optional): Clears existing list before adding item.
165
+ package (str, optional): Package name
166
+
167
+ Returns:
168
+ list[str]: List of library directories.
169
+ """
170
+ return self.__set_add(fileset, 'libdir', value, clobber, typelist=[str, list],
171
+ package=package)
172
+
173
+ def get_libdir(self, fileset: str = None) -> List[str]:
174
+ """Returns dynamic library directories for a fileset.
175
+
176
+ Args:
177
+ fileset (str): Fileset name.
178
+
179
+ Returns:
180
+ list[str]: List of library directories.
181
+ """
182
+ return self.__get(fileset, 'libdir')
183
+
184
+ ###############################################
185
+ def add_lib(self,
186
+ value: str,
187
+ fileset: str = None,
188
+ clobber: bool = False) -> List[str]:
189
+ """Adds dynamic libraries to a fileset.
190
+
191
+ Args:
192
+ value (str or List[str]): Libraries
193
+ fileset (str, optional): Fileset name.
194
+ clobber (bool, optional): Clears existing list before adding item.
195
+
196
+ Returns:
197
+ list[str]: List of libraries.
198
+ """
199
+ return self.__set_add(fileset, 'lib', value, clobber, typelist=[str, list])
200
+
201
+ def get_lib(self, fileset: str = None) -> List[str]:
202
+ """Returns list of dynamic libraries for a fileset.
203
+
204
+ Args:
205
+ fileset (str): Fileset name.
206
+
207
+ Returns:
208
+ list[str]: List of libraries.
209
+ """
210
+ return self.__get(fileset, 'lib')
211
+
212
+ ###############################################
213
+ def set_param(self,
214
+ name: str,
215
+ value: str,
216
+ fileset: str = None) -> str:
217
+ """Sets a named parameter for a fileset.
218
+
219
+ Args:
220
+ name (str): Parameter name.
221
+ value (str): Parameter value.
222
+ fileset (str, optional): Fileset name.
223
+
224
+ Returns:
225
+ str: Parameter value
226
+ """
227
+
228
+ if fileset is None:
229
+ fileset = self.__fileset
230
+
231
+ if not isinstance(fileset, str):
232
+ raise ValueError("fileset key must be a string")
233
+
234
+ if not isinstance(value, str) or value is None:
235
+ raise ValueError("param value must be a string")
236
+
237
+ return self.set('fileset', fileset, 'param', name, value)
238
+
239
+ def get_param(self,
240
+ name: str,
241
+ fileset: str = None) -> str:
242
+ """Returns value of a named fileset parameter.
243
+
244
+ Args:
245
+ name (str): Parameter name.
246
+ fileset (str): Fileset name.
247
+
248
+ Returns:
249
+ str: Parameter value
250
+ """
251
+ if fileset is None:
252
+ fileset = self.__fileset
253
+
254
+ if not isinstance(fileset, str):
255
+ raise ValueError("fileset value must be a string")
256
+ return self.get('fileset', fileset, 'param', name)
257
+
258
+ ###############################################
259
+ def add_file(self,
260
+ filename: str,
261
+ fileset: str = None,
262
+ filetype: str = None,
263
+ clobber: bool = False,
264
+ package: str = None) -> List[str]:
265
+ """
266
+ Adds files to a fileset.
267
+
268
+ .v → (source, verilog)
269
+ .vhd → (source, vhdl)
270
+ .sdc → (constraint, sdc)
271
+ .lef → (input, lef)
272
+ .def → (input, def)
273
+ ... → etc.
274
+
275
+ Args:
276
+ filename (Path or list[Path]): File path or list of paths to add.
277
+ fileset (str): Logical group to associate the file with.
278
+ filetype (str, optional): Type of the file (e.g., 'verilog', 'sdc').
279
+ clobber (bool, optional): Clears list before adding item
280
+ package (str, optional): Package name
281
+
282
+ Raises:
283
+ SiliconCompilerError: If fileset or filetype cannot be inferred from
284
+ the file extension.
285
+
286
+ Returns:
287
+ list[str]: List of file paths.
288
+
289
+ Notes:
290
+ - This method normalizes `filename` to a string for consistency.
291
+
292
+ - If no filetype is specified, filetype is inferred based on
293
+ the file extension via a mapping table. (eg. .v is verilog).
294
+ """
295
+
296
+ if fileset is None:
297
+ fileset = self.__fileset
298
+
299
+ # handle list inputs
300
+ if isinstance(filename, (list, tuple)):
301
+ for item in filename:
302
+ self.add_file(
303
+ item,
304
+ fileset=fileset,
305
+ clobber=clobber,
306
+ filetype=filetype)
307
+ return
308
+
309
+ if filename is None:
310
+ raise ValueError("add_file cannot process None")
311
+
312
+ # Normalize value to string in case we receive a pathlib.Path
313
+ filename = str(filename)
314
+
315
+ # map extension to default filetype/fileset
316
+
317
+ if not filetype:
318
+ ext = utils.get_file_ext(filename)
319
+ iomap = utils.get_default_iomap()
320
+ if ext in iomap:
321
+ default_fileset, default_filetype = iomap[ext]
322
+ filetype = default_filetype
323
+ else:
324
+ raise ValueError("illegal file extension")
325
+
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.')
331
+
332
+ # 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
346
+
347
+ ###############################################
348
+ def get_file(self,
349
+ fileset: str = None,
350
+ filetype: str = None):
351
+ """Returns a list of files from one or more filesets.
352
+
353
+ Args:
354
+ fileset (str or list[str]): Fileset(s) to query.
355
+ filetype (str or list[str], optional): File type(s) to filter by (e.g., 'verilog').
356
+
357
+ Returns:
358
+ list[str]: List of file paths.
359
+ """
360
+
361
+ if fileset is None:
362
+ fileset = self.__fileset
363
+
364
+ if not isinstance(fileset, list):
365
+ fileset = [fileset]
366
+
367
+ if filetype and not isinstance(filetype, list):
368
+ filetype = [filetype]
369
+
370
+ filelist = []
371
+ for i in fileset:
372
+ if not isinstance(i, str):
373
+ raise ValueError("fileset key must be a string")
374
+ # handle scalar+list in argument
375
+ if not filetype:
376
+ filetype = list(self.getkeys('fileset', i, 'file'))
377
+ # grab the files
378
+ for j in filetype:
379
+ filelist.extend(self.get('fileset', i, 'file', j))
380
+
381
+ return filelist
382
+
383
+ def __write_flist(self, filename: str, filesets: list):
384
+ written_cmd = set()
385
+
386
+ with open(filename, "w") as f:
387
+ def write(cmd):
388
+ if cmd in written_cmd:
389
+ f.write(f"// {cmd}\n")
390
+ else:
391
+ written_cmd.add(cmd)
392
+ f.write(f"{cmd}\n")
393
+
394
+ def write_header(header):
395
+ f.write(f"// {header}\n")
396
+
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
402
+
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}")
407
+
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}")
412
+
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)
418
+
419
+ ###############################################
420
+ def write_fileset(self,
421
+ filename: str,
422
+ fileset: str = None,
423
+ fileformat: str = None) -> None:
424
+ """Exports filesets to a standard formatted text file.
425
+
426
+ Currently supports Verilog `flist` format only.
427
+ Intended to support other formats in the future.
428
+ Inferred from file extension if not given.
429
+
430
+ Args:
431
+ filename (str or Path): Output file name.
432
+ fileset (str or list[str]): Fileset(s) to export.
433
+ fileformat (str, optional): Export format.
434
+ """
435
+
436
+ if filename is None:
437
+ raise ValueError("write_fileset() filename cannot be None")
438
+
439
+ if fileset is None:
440
+ fileset = self.__fileset
441
+
442
+ if not isinstance(fileset, list):
443
+ fileset = [fileset]
444
+
445
+ for fset in fileset:
446
+ if not isinstance(fset, str):
447
+ raise ValueError("fileset key must be a string")
448
+
449
+ # file extension lookup
450
+ if not fileformat:
451
+ formats = {}
452
+ formats['f'] = 'flist'
453
+ fileformat = formats[Path(filename).suffix.strip('.')]
454
+
455
+ if fileformat == "flist":
456
+ self.__write_flist(filename, fileset)
457
+ else:
458
+ raise ValueError(f"{fileformat} is not supported")
459
+
460
+ def __read_flist(self, filename: str, fileset: str):
461
+ # Extract information
462
+ rel_path = os.path.dirname(os.path.abspath(filename))
463
+
464
+ def expand_path(path):
465
+ path = os.path.expandvars(path)
466
+ path = os.path.expanduser(path)
467
+ if os.path.isabs(path):
468
+ return path
469
+ return os.path.join(rel_path, path)
470
+
471
+ include_dirs = []
472
+ defines = []
473
+ files = []
474
+ with utils.sc_open(filename) as f:
475
+ for line in f:
476
+ line = line.strip()
477
+ if not line:
478
+ continue
479
+ if line.startswith("//"):
480
+ continue
481
+ if line.startswith("+incdir+"):
482
+ include_dirs.append(expand_path(line[8:]))
483
+ elif line.startswith("+define+"):
484
+ defines.append(os.path.expandvars(line[8:]))
485
+ else:
486
+ files.append(expand_path(line))
487
+
488
+ # Create packages
489
+ all_paths = include_dirs + [os.path.dirname(f) for f in files]
490
+ all_paths = sorted(set(all_paths))
491
+
492
+ package_root_name = f'flist-{self.name()}-{fileset}-{os.path.basename(filename)}'
493
+ packages = {}
494
+
495
+ for path_dir in all_paths:
496
+ found = False
497
+ for pdir in packages:
498
+ if path_dir.startswith(pdir):
499
+ found = True
500
+ break
501
+ 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
505
+
506
+ def get_package(path):
507
+ for pdir, name in packages.items():
508
+ if path.startswith(pdir):
509
+ return name, pdir
510
+ return None, None
511
+
512
+ # Assign data
513
+ with self.active_fileset(fileset):
514
+ if defines:
515
+ self.add_define(defines)
516
+ if include_dirs:
517
+ for dir in include_dirs:
518
+ package_name, pdir = get_package(dir)
519
+ if package_name:
520
+ dir = os.path.relpath(dir, pdir)
521
+ self.add_idir(dir, package=package_name)
522
+ if files:
523
+ for f in files:
524
+ package_name, pdir = get_package(f)
525
+ if package_name:
526
+ f = os.path.relpath(f, pdir)
527
+ self.add_file(f, package=package_name)
528
+
529
+ ################################################
530
+ def read_fileset(self,
531
+ filename: str,
532
+ fileset: str,
533
+ fileformat=None) -> None:
534
+ """Imports filesets from a standard formatted text file.
535
+
536
+ Currently supports Verilog `flist` format only.
537
+ Intended to support other formats in the future.
538
+
539
+ Args:
540
+ filename (str or Path): Output file name.
541
+ fileset (str or list[str]): Filesets to import.
542
+ fileformat (str, optional): Export format.
543
+ """
544
+
545
+ if filename is None:
546
+ raise ValueError("read_fileset() filename cannot be None")
547
+
548
+ if not fileformat:
549
+ formats = {}
550
+ formats['f'] = 'flist'
551
+ fileformat = formats[Path(filename).suffix.strip('.')]
552
+
553
+ if fileformat == "flist":
554
+ self.__read_flist(filename, fileset)
555
+ else:
556
+ raise ValueError(f"{fileformat} is not supported")
557
+
558
+ ################################################
559
+ # Helper Functions
560
+ ################################################
561
+ def __set_add(self, fileset, option, value, clobber=False, typelist=None, package=None):
562
+ '''Sets a parameter value in schema.
563
+ '''
564
+
565
+ if fileset is None:
566
+ fileset = self.__fileset
567
+
568
+ # check for a legal fileset
569
+ if not fileset or not isinstance(fileset, str):
570
+ raise ValueError("fileset key must be a string")
571
+
572
+ # Check for legal types
573
+ legalval = False
574
+ for item in typelist:
575
+ if isinstance(value, item) and not isinstance(value, tuple):
576
+ legalval = True
577
+ if not legalval:
578
+ raise ValueError("value must be of type string")
579
+
580
+ # None is illegal for all setters
581
+ if value is None:
582
+ raise ValueError(f"None is an illegal {option} value")
583
+
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]
592
+
593
+ for param in params:
594
+ param.set(package, field="package")
595
+
596
+ return params
597
+
598
+ def __get(self, fileset, option):
599
+ '''Gets a parameter value from schema.
600
+ '''
601
+ if fileset is None:
602
+ fileset = self.__fileset
603
+
604
+ if not isinstance(fileset, str):
605
+ raise ValueError("fileset key must be a string")
606
+ return self.get('fileset', fileset, option)
607
+
608
+ @contextlib.contextmanager
609
+ def active_fileset(self, fileset: str):
610
+ """
611
+ Use this context to temporarily set a design fileset.
612
+
613
+ Raises:
614
+ TypeError: if fileset is not a string
615
+ ValueError: if fileset if an empty string
616
+
617
+ Args:
618
+ fileset (str): name of the fileset
619
+
620
+ Example:
621
+ >>> with design.active_fileset("rtl"):
622
+ ... design.set_topmodule("top")
623
+ Sets the top module for the rtl fileset as top.
624
+ """
625
+ if not isinstance(fileset, str):
626
+ raise TypeError("fileset must a string")
627
+ if not fileset:
628
+ raise ValueError("fileset cannot be an empty string")
629
+
630
+ self.__fileset = fileset
631
+ yield
632
+ self.__fileset = None
633
+
634
+
635
+ ###########################################################################
636
+ # Schema
637
+ ###########################################################################
638
+ def schema_design(schema):
639
+
640
+ schema = EditableSchema(schema)
641
+
642
+ ###########################
643
+ # Files
644
+ ###########################
645
+
646
+ fileset = 'default'
647
+ filetype = 'default'
648
+ schema.insert(
649
+ 'fileset', fileset, 'file', filetype,
650
+ Parameter(
651
+ ['file'],
652
+ scope=Scope.GLOBAL,
653
+ shorthelp="Design files",
654
+ example=[
655
+ "api: chip.set('fileset', 'rtl', 'file', 'verilog', 'mytop.v')",
656
+ "api: chip.set('fileset', 'testbench', 'file', 'verilog', 'tb.v')"],
657
+ help=trim("""
658
+ List of files grouped as a named set ('fileset'). The exact names of
659
+ filetypes and filesets must match the names used in tasks
660
+ called during flowgraph execution. The files are processed in
661
+ the order specified by the ordered file list.""")))
662
+
663
+ ###########################
664
+ # Options
665
+ ###########################
666
+
667
+ schema.insert(
668
+ 'fileset', fileset, 'topmodule',
669
+ Parameter(
670
+ 'str',
671
+ scope=Scope.GLOBAL,
672
+ shorthelp="Top module name",
673
+ example=[
674
+ "api: chip.set('fileset', 'rtl', 'topmodule', 'mytop')",
675
+ "api: chip.set('fileset', 'testbench', 'topmodule', 'tb')"],
676
+ help=trim("""
677
+ Name of top module specified on a per fileset basis.""")))
678
+
679
+ schema.insert(
680
+ 'fileset', fileset, 'idir',
681
+ Parameter(
682
+ ['dir'],
683
+ scope=Scope.GLOBAL,
684
+ shorthelp="Include file search paths",
685
+ example=[
686
+ "api: chip.set('fileset', 'rtl, 'idir', './rtl')",
687
+ "api: chip.set('fileset', 'testbench', 'idir', '/testbench')"],
688
+ help=trim("""
689
+ Include paths specify directories to scan for header files during
690
+ compilation. If multiple paths are provided, they are searched
691
+ in the order given.""")))
692
+
693
+ schema.insert(
694
+ 'fileset', fileset, 'define',
695
+ Parameter(
696
+ ['str'],
697
+ scope=Scope.GLOBAL,
698
+ shorthelp="Preprocessor macro definitions",
699
+ example=[
700
+ "api: chip.set('fileset', 'rtl', 'define', 'CFG_TARGET=FPGA')"],
701
+ help=trim("""
702
+ Defines macros at compile time for design languages that support
703
+ preprocessing, such as Verilog, C, and C++. The macro format is
704
+ is `MACRONAME[=value]`, where [=value] is optional.""")))
705
+
706
+ schema.insert(
707
+ 'fileset', fileset, 'undefine',
708
+ Parameter(
709
+ ['str'],
710
+ scope=Scope.GLOBAL,
711
+ shorthelp="Preprocessor macro undefine",
712
+ example=[
713
+ "api: chip.set('fileset', 'rtl', 'undefine', 'CFG_TARGET')"],
714
+ help=trim("""
715
+ Undefines a macro that may have been previously defined via the
716
+ compiler, options, or header files.""")))
717
+
718
+ schema.insert(
719
+ 'fileset', fileset, 'libdir',
720
+ Parameter(
721
+ ['dir'],
722
+ scope=Scope.GLOBAL,
723
+ shorthelp="Library search paths",
724
+ example=[
725
+ "api: chip.set('fileset', 'rtl, 'libdir', '/usr/lib')"],
726
+ help=trim("""
727
+ Specifies directories to scan for libraries provided with the
728
+ :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.""")))
731
+
732
+ schema.insert(
733
+ 'fileset', fileset, 'lib',
734
+ Parameter(
735
+ ['str'],
736
+ scope=Scope.GLOBAL,
737
+ shorthelp="Design libraries to include",
738
+ example=[
739
+ "api: chip.set('fileset', 'rtl', 'lib', 'mylib')"],
740
+ help=trim("""
741
+ Specifies libraries to use during compilation. The compiler searches for
742
+ library in the compiler standard library paths and in the
743
+ paths specified by :keypath:`libdir` parameter.""")))
744
+
745
+ name = 'default'
746
+ schema.insert(
747
+ 'fileset', fileset, 'param', name,
748
+ Parameter(
749
+ 'str',
750
+ scope=Scope.GLOBAL,
751
+ shorthelp="Design parameters",
752
+ example=[
753
+ "api: chip.set('fileset', 'rtl, 'param', 'N', '64'"],
754
+ help=trim("""
755
+ Sets a named parameter to a string value. The value is limited to basic
756
+ data literals. The types of parameters and values supported is tightly
757
+ coupled to tools being used. For example, in Verilog only integer
758
+ literals (64'h4, 2'b0, 4) and strings are supported.""")))