siliconcompiler 0.33.1__py3-none-any.whl → 0.34.0__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 (59) hide show
  1. siliconcompiler/__init__.py +2 -0
  2. siliconcompiler/_metadata.py +1 -1
  3. siliconcompiler/apps/sc_issue.py +5 -3
  4. siliconcompiler/apps/sc_remote.py +0 -17
  5. siliconcompiler/apps/utils/replay.py +5 -5
  6. siliconcompiler/checklist.py +1 -1
  7. siliconcompiler/core.py +39 -48
  8. siliconcompiler/data/templates/replay/replay.sh.j2 +18 -1
  9. siliconcompiler/dependencyschema.py +392 -0
  10. siliconcompiler/design.py +664 -0
  11. siliconcompiler/flowgraph.py +32 -1
  12. siliconcompiler/metric.py +19 -0
  13. siliconcompiler/package/__init__.py +383 -223
  14. siliconcompiler/package/git.py +75 -77
  15. siliconcompiler/package/github.py +70 -97
  16. siliconcompiler/package/https.py +77 -93
  17. siliconcompiler/packageschema.py +260 -0
  18. siliconcompiler/pdk.py +2 -2
  19. siliconcompiler/record.py +57 -5
  20. siliconcompiler/remote/client.py +61 -13
  21. siliconcompiler/remote/server.py +109 -64
  22. siliconcompiler/report/dashboard/cli/board.py +1 -2
  23. siliconcompiler/scheduler/__init__.py +3 -1375
  24. siliconcompiler/scheduler/docker.py +268 -0
  25. siliconcompiler/scheduler/run_node.py +20 -19
  26. siliconcompiler/scheduler/scheduler.py +308 -0
  27. siliconcompiler/scheduler/schedulernode.py +934 -0
  28. siliconcompiler/scheduler/slurm.py +147 -163
  29. siliconcompiler/scheduler/taskscheduler.py +39 -52
  30. siliconcompiler/schema/__init__.py +3 -3
  31. siliconcompiler/schema/baseschema.py +256 -11
  32. siliconcompiler/schema/editableschema.py +4 -0
  33. siliconcompiler/schema/journal.py +210 -0
  34. siliconcompiler/schema/namedschema.py +31 -2
  35. siliconcompiler/schema/parameter.py +14 -1
  36. siliconcompiler/schema/parametervalue.py +1 -34
  37. siliconcompiler/schema/schema_cfg.py +211 -350
  38. siliconcompiler/tool.py +139 -37
  39. siliconcompiler/tools/_common/__init__.py +14 -11
  40. siliconcompiler/tools/builtin/concatenate.py +2 -2
  41. siliconcompiler/tools/builtin/verify.py +1 -2
  42. siliconcompiler/tools/openroad/scripts/common/procs.tcl +27 -25
  43. siliconcompiler/tools/slang/__init__.py +3 -2
  44. siliconcompiler/tools/vpr/route.py +69 -0
  45. siliconcompiler/tools/yosys/sc_synth_asic.tcl +0 -4
  46. siliconcompiler/toolscripts/_tools.json +13 -8
  47. siliconcompiler/toolscripts/ubuntu22/install-klayout.sh +4 -0
  48. siliconcompiler/toolscripts/ubuntu24/install-klayout.sh +4 -0
  49. siliconcompiler/utils/__init__.py +2 -23
  50. siliconcompiler/utils/flowgraph.py +5 -5
  51. siliconcompiler/utils/logging.py +2 -1
  52. {siliconcompiler-0.33.1.dist-info → siliconcompiler-0.34.0.dist-info}/METADATA +8 -6
  53. {siliconcompiler-0.33.1.dist-info → siliconcompiler-0.34.0.dist-info}/RECORD +57 -52
  54. {siliconcompiler-0.33.1.dist-info → siliconcompiler-0.34.0.dist-info}/WHEEL +1 -1
  55. siliconcompiler/scheduler/docker_runner.py +0 -254
  56. siliconcompiler/schema/journalingschema.py +0 -238
  57. {siliconcompiler-0.33.1.dist-info → siliconcompiler-0.34.0.dist-info}/entry_points.txt +0 -0
  58. {siliconcompiler-0.33.1.dist-info → siliconcompiler-0.34.0.dist-info}/licenses/LICENSE +0 -0
  59. {siliconcompiler-0.33.1.dist-info → siliconcompiler-0.34.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,664 @@
1
+ import contextlib
2
+ import re
3
+
4
+ from pathlib import Path
5
+ from typing import List
6
+
7
+ from siliconcompiler import utils
8
+ from siliconcompiler import SiliconCompilerError
9
+
10
+ from siliconcompiler.dependencyschema import DependencySchema
11
+ from siliconcompiler.schema import NamedSchema
12
+ from siliconcompiler.schema import EditableSchema, Parameter, Scope
13
+ from siliconcompiler.schema.utils import trim
14
+
15
+
16
+ ###########################################################################
17
+ class DesignSchema(NamedSchema, DependencySchema):
18
+
19
+ def __init__(self, name: str):
20
+ NamedSchema.__init__(self, name=name)
21
+ DependencySchema.__init__(self)
22
+
23
+ schema_design(self)
24
+
25
+ self.__fileset = None
26
+
27
+ ############################################
28
+ def set_topmodule(self,
29
+ value: str,
30
+ fileset: str = None) -> str:
31
+ """Sets the topmodule of a fileset.
32
+
33
+ Args:
34
+ value (str): Topmodule name.
35
+ fileset (str, optional): Fileset name.
36
+
37
+ Returns:
38
+ str: Topmodule name
39
+
40
+ Notes:
41
+ - first character must be letter or underscore
42
+ - remaining characters can be letters, digits, or underscores
43
+
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
+ """
63
+ return self.__get(fileset, 'topmodule')
64
+
65
+ ##############################################
66
+ def add_idir(self,
67
+ value: str,
68
+ fileset: str = None,
69
+ clobber: bool = False,
70
+ package: str = None) -> List[str]:
71
+ """Adds include directories to a fileset.
72
+
73
+ Args:
74
+ value (str or Path): Include directory name.
75
+ fileset (str, optional): Fileset name.
76
+ clobber (bool, optional): Clears existing list before adding item
77
+ package (str, optional): Package name
78
+
79
+ Returns:
80
+ list[str]: List of include directories
81
+
82
+ """
83
+ return self.__set_add(fileset, 'idir', value, clobber, typelist=[str, list])
84
+
85
+ def get_idir(self, fileset: str = None) -> List[str]:
86
+ """Returns include directories for a fileset.
87
+
88
+ Args:
89
+ fileset (str): Fileset name.
90
+
91
+ Returns:
92
+ list[str]: List of include directories
93
+
94
+ """
95
+ return self.__get(fileset, 'idir')
96
+
97
+ ##############################################
98
+ def add_define(self,
99
+ value: str,
100
+ fileset: str = None,
101
+ clobber: bool = False) -> List[str]:
102
+ """Adds preprocessor macro definitions to a fileset.
103
+
104
+ Args:
105
+ value (str or List[str]): Macro definition.
106
+ fileset (str, optional): Fileset name.
107
+ clobber (bool, optional): Clears existing list before adding item.
108
+
109
+ Returns:
110
+ list[str]: List of macro definitions
111
+
112
+ """
113
+ return self.__set_add(fileset, 'define', value, clobber, typelist=[str, list])
114
+
115
+ def get_define(self, fileset: str = None) -> List[str]:
116
+ """Returns defined macros for a fileset.
117
+
118
+ Args:
119
+ fileset (str): Fileset name.
120
+
121
+ Returns:
122
+ list[str]: List of macro definitions
123
+
124
+ """
125
+ return self.__get(fileset, 'define')
126
+
127
+ ##############################################
128
+ def add_undefine(self,
129
+ value: str,
130
+ fileset: str = None,
131
+ clobber: bool = False) -> List[str]:
132
+ """Adds preprocessor macro (un)definitions to a fileset.
133
+
134
+ Args:
135
+ value (str or List[str]): Macro (un)definition.
136
+ fileset (str, optional): Fileset name.
137
+ clobber (bool, optional): CClears existing list before adding item.
138
+
139
+ Returns:
140
+ list[str]: List of macro (un)definitions
141
+
142
+ """
143
+ return self.__set_add(fileset, 'undefine', value, clobber, typelist=[str, list])
144
+
145
+ def get_undefine(self, fileset: str = None) -> List[str]:
146
+ """Returns undefined macros for a fileset.
147
+
148
+ Args:
149
+ fileset (str): Fileset name.
150
+
151
+ Returns:
152
+ list[str]: List of macro (un)definitions
153
+
154
+ """
155
+ return self.__get(fileset, 'undefine')
156
+
157
+ ###############################################
158
+ def add_libdir(self,
159
+ value: str,
160
+ fileset: str = None,
161
+ clobber: bool = False,
162
+ package: str = None) -> List[str]:
163
+ """Adds dynamic library directories to a fileset.
164
+
165
+ Args:
166
+ value (str or List[str]): Library directories
167
+ fileset (str, optional): Fileset name.
168
+ clobber (bool, optional): Clears existing list before adding item.
169
+ package (str, optional): Package name
170
+
171
+ Returns:
172
+ list[str]: List of library directories.
173
+
174
+ """
175
+ return self.__set_add(fileset, 'libdir', value, clobber, typelist=[str, list])
176
+
177
+ def get_libdir(self, fileset: str = None) -> List[str]:
178
+ """Returns dynamic library directories for a fileset.
179
+
180
+ Args:
181
+ fileset (str): Fileset name.
182
+
183
+ Returns:
184
+ list[str]: List of library directories.
185
+
186
+ """
187
+ return self.__get(fileset, 'libdir')
188
+
189
+ ###############################################
190
+ def add_lib(self,
191
+ value: str,
192
+ fileset: str = None,
193
+ clobber: bool = False) -> List[str]:
194
+ """Adds dynamic libraries to a fileset.
195
+
196
+ Args:
197
+ value (str or List[str]): Libraries
198
+ fileset (str, optional): Fileset name.
199
+ clobber (bool, optional): Clears existing list before adding item.
200
+
201
+ Returns:
202
+ list[str]: List of libraries.
203
+
204
+ """
205
+ return self.__set_add(fileset, 'lib', value, clobber, typelist=[str, list])
206
+
207
+ def get_lib(self, fileset: str = None) -> List[str]:
208
+ """Returns list of dynamic libraries for a fileset.
209
+
210
+ Args:
211
+ fileset (str): Fileset name.
212
+
213
+ Returns:
214
+ list[str]: List of libraries.
215
+
216
+ """
217
+ return self.__get(fileset, 'lib')
218
+
219
+ ###############################################
220
+ def set_param(self,
221
+ name: str,
222
+ value: str,
223
+ fileset: str = None) -> str:
224
+ """Sets a named parameter for a fileset.
225
+
226
+ Args:
227
+ name (str): Parameter name.
228
+ value (str): Parameter value.
229
+ fileset (str, optional): Fileset name.
230
+
231
+ Returns:
232
+ str: Parameter value
233
+
234
+ """
235
+
236
+ if fileset is None:
237
+ fileset = self.__fileset
238
+
239
+ if not isinstance(fileset, str):
240
+ raise ValueError("fileset key must be a string")
241
+
242
+ if not isinstance(value, str) or value is None:
243
+ raise ValueError("param value must be a string")
244
+
245
+ return self.set('fileset', fileset, 'param', name, value)
246
+
247
+ def get_param(self,
248
+ name: str,
249
+ fileset: str = None) -> str:
250
+ """Returns value of a named fileset parameter.
251
+
252
+ Args:
253
+ name (str): Parameter name.
254
+ fileset (str): Fileset name.
255
+
256
+ Returns:
257
+ str: Parameter value
258
+ """
259
+ if fileset is None:
260
+ fileset = self.__fileset
261
+
262
+ if not isinstance(fileset, str):
263
+ raise ValueError("fileset value must be a string")
264
+ return self.get('fileset', fileset, 'param', name)
265
+
266
+ ###############################################
267
+ def add_file(self,
268
+ filename: str,
269
+ fileset: str = None,
270
+ filetype: str = None,
271
+ clobber: bool = False,
272
+ package: str = None) -> List[str]:
273
+ """
274
+ Adds files to a fileset.
275
+
276
+
277
+
278
+ .v → (source, verilog)
279
+ .vhd → (source, vhdl)
280
+ .sdc → (constraint, sdc)
281
+ .lef → (input, lef)
282
+ .def → (input, def)
283
+ ... → etc.
284
+
285
+ Args:
286
+ filename (Path or list[Path]): File path or list of paths to add.
287
+ fileset (str): Logical group to associate the file with.
288
+ filetype (str, optional): Type of the file (e.g., 'verilog', 'sdc').
289
+ clobber (bool, optional): Clears list before adding item
290
+ package (str, optional): Package name
291
+
292
+ Raises:
293
+ SiliconCompilerError: If fileset or filetype cannot be inferred from
294
+ the file extension.
295
+
296
+ Returns:
297
+ list[str]: List of file paths.
298
+
299
+ Notes:
300
+ - This method normalizes `filename` to a string for consistency.
301
+
302
+ - If no filetype is specified, filetype is inferred based on
303
+ the file extension via a mapping table. (eg. .v is verilog).
304
+
305
+
306
+ """
307
+
308
+ if fileset is None:
309
+ fileset = self.__fileset
310
+
311
+ # handle list inputs
312
+ if isinstance(filename, (list, tuple)):
313
+ for item in filename:
314
+ self.add_file(
315
+ item,
316
+ fileset=fileset,
317
+ clobber=clobber,
318
+ filetype=filetype)
319
+ return
320
+
321
+ if filename is None:
322
+ raise ValueError("add_file cannot process None")
323
+
324
+ # Normalize value to string in case we receive a pathlib.Path
325
+ filename = str(filename)
326
+
327
+ # map extension to default filetype/fileset
328
+
329
+ if not filetype:
330
+ ext = utils.get_file_ext(filename)
331
+ iomap = utils.get_default_iomap()
332
+ if ext in iomap:
333
+ default_fileset, default_filetype = iomap[ext]
334
+ filetype = default_filetype
335
+ else:
336
+ raise ValueError("illegal file extension")
337
+
338
+ # final error checking
339
+ if not fileset or not filetype:
340
+ raise SiliconCompilerError(
341
+ f'Unable to infer fileset and/or filetype for '
342
+ f'{filename} based on file extension.')
343
+
344
+ # adding files to dictionary
345
+ if clobber:
346
+ return self.set('fileset', fileset, 'file', filetype, filename)
347
+ else:
348
+ return self.add('fileset', fileset, 'file', filetype, filename)
349
+
350
+ ###############################################
351
+ def get_file(self,
352
+ fileset: str = None,
353
+ filetype: str = None):
354
+ """Returns a list of files from one or more filesets.
355
+
356
+ Args:
357
+ fileset (str or list[str]): Fileset(s) to query.
358
+ filetype (str or list[str], optional): File type(s) to filter by (e.g., 'verilog').
359
+
360
+ Returns:
361
+ list[str]: List of file paths.
362
+ """
363
+
364
+ if fileset is None:
365
+ fileset = self.__fileset
366
+
367
+ if not isinstance(fileset, list):
368
+ fileset = [fileset]
369
+
370
+ if filetype and not isinstance(filetype, list):
371
+ filetype = [filetype]
372
+
373
+ filelist = []
374
+ for i in fileset:
375
+ if not isinstance(i, str):
376
+ raise ValueError("fileset key must be a string")
377
+ # handle scalar+list in argument
378
+ if not filetype:
379
+ filetype = list(self.getkeys('fileset', i, 'file'))
380
+ # grab the files
381
+ for j in filetype:
382
+ filelist.extend(self.get('fileset', i, 'file', j))
383
+
384
+ return filelist
385
+
386
+ ###############################################
387
+ def write_fileset(self,
388
+ filename: str,
389
+ fileset: str = None,
390
+ fileformat: str = None) -> None:
391
+ """Exports filesets to a standard formatted text file.
392
+
393
+ Currently supports Verilog `flist` format only.
394
+ Intended to support other formats in the future.
395
+
396
+ Args:
397
+ filename (str or Path): Output file name.
398
+ fileset (str or list[str]): Fileset(s) to export.
399
+ fileformat (str, optional): Export format.
400
+
401
+ Inferred from file extension if not given.
402
+
403
+ """
404
+
405
+ if filename is None:
406
+ raise ValueError("write_fileset() filename cannot be None")
407
+
408
+ if fileset is None:
409
+ fileset = self.__fileset
410
+
411
+ if not isinstance(fileset, list):
412
+ fileset = [fileset]
413
+
414
+ # file extension lookup
415
+ if not fileformat:
416
+ formats = {}
417
+ formats['f'] = 'flist'
418
+ fileformat = formats[Path(filename).suffix.strip('.')]
419
+
420
+ if fileformat == "flist":
421
+ # TODO: handle dependency tree
422
+ # TODO: add source info for comments to flist.
423
+ with open(filename, "w") as f:
424
+ for i in fileset:
425
+ if not isinstance(i, str):
426
+ raise ValueError("fileset key must be a string")
427
+ for j in ['idir', 'define', 'file']:
428
+ if j == 'idir':
429
+ vals = self.get('fileset', i, 'idir')
430
+ cmd = "+incdir+"
431
+ elif j == 'define':
432
+ vals = self.get('fileset', i, 'define')
433
+ cmd = "+define+"
434
+ else:
435
+ vals = self.get('fileset', i, 'file', 'verilog')
436
+ cmd = ""
437
+ if vals:
438
+ for item in vals:
439
+ f.write(f"{cmd}{item}\n")
440
+ else:
441
+ raise ValueError(f"{fileformat} is not supported")
442
+
443
+ ################################################
444
+ def read_fileset(self,
445
+ filename: str,
446
+ fileset: str,
447
+ fileformat=None) -> None:
448
+ """Imports filesets from a standard formatted text file.
449
+
450
+ Currently supports Verilog `flist` format only.
451
+ Intended to support other formats in the future.
452
+
453
+ Args:
454
+ filename (str or Path): Output file name.
455
+ fileset (str or list[str]): Filesets to import.
456
+ fileformat (str, optional): Export format.
457
+
458
+ """
459
+
460
+ if filename is None:
461
+ raise ValueError("read_fileset() filename cannot be None")
462
+
463
+ if not fileformat:
464
+ formats = {}
465
+ formats['f'] = 'flist'
466
+ fileformat = formats[Path(filename).suffix.strip('.')]
467
+
468
+ if fileformat == "flist":
469
+ raise NotImplementedError("read_fileset is not implemented yet")
470
+ else:
471
+ raise ValueError(f"{fileformat} is not supported")
472
+
473
+ ################################################
474
+ # Helper Functions
475
+ ################################################
476
+ def __set_add(self, fileset, option, value, clobber=False, typelist=None):
477
+ '''Sets a parameter value in schema.
478
+ '''
479
+
480
+ if fileset is None:
481
+ fileset = self.__fileset
482
+
483
+ # check for a legal fileset
484
+ if not fileset or not isinstance(fileset, str):
485
+ raise ValueError("fileset key must be a string")
486
+
487
+ # Check for legal types
488
+ legalval = False
489
+ for item in typelist:
490
+ if isinstance(value, item) and not isinstance(value, tuple):
491
+ legalval = True
492
+ if not legalval:
493
+ raise ValueError("value must be of type string")
494
+
495
+ # None is illegal for all setters
496
+ if value is None:
497
+ raise ValueError(f"None is an illegal {option} value")
498
+
499
+ if list in typelist and not clobber:
500
+ return self.add('fileset', fileset, option, value)
501
+ else:
502
+ return self.set('fileset', fileset, option, value)
503
+
504
+ def __get(self, fileset, option):
505
+ '''Gets a parameter value from schema.
506
+ '''
507
+ if fileset is None:
508
+ fileset = self.__fileset
509
+
510
+ if not isinstance(fileset, str):
511
+ raise ValueError("fileset key must be a string")
512
+ return self.get('fileset', fileset, option)
513
+
514
+ @contextlib.contextmanager
515
+ def active_fileset(self, fileset: str):
516
+ """
517
+ Use this context to temporarily set a design fileset.
518
+
519
+ Raises:
520
+ TypeError: if fileset is not a string
521
+ ValueError: if fileset if an empty string
522
+
523
+ Args:
524
+ fileset (str): name of the fileset
525
+
526
+ Example:
527
+ >>> with design.active_fileset("rtl"):
528
+ ... design.set_topmodule("top")
529
+ Sets the top module for the rtl fileset as top.
530
+ """
531
+ if not isinstance(fileset, str):
532
+ raise TypeError("fileset must a string")
533
+ if not fileset:
534
+ raise ValueError("fileset cannot be an empty string")
535
+
536
+ self.__fileset = fileset
537
+ yield
538
+ self.__fileset = None
539
+
540
+
541
+ ###########################################################################
542
+ # Schema
543
+ ###########################################################################
544
+ def schema_design(schema):
545
+
546
+ schema = EditableSchema(schema)
547
+
548
+ ###########################
549
+ # Files
550
+ ###########################
551
+
552
+ fileset = 'default'
553
+ filetype = 'default'
554
+ schema.insert(
555
+ 'fileset', fileset, 'file', filetype,
556
+ Parameter(
557
+ ['file'],
558
+ scope=Scope.GLOBAL,
559
+ shorthelp="Design files",
560
+ example=[
561
+ "api: chip.set('fileset', 'rtl', 'file', 'verilog', 'mytop.v')",
562
+ "api: chip.set('fileset', 'testbench', 'file', 'verilog', 'tb.v')"],
563
+ help=trim("""
564
+ List of files grouped as a named set ('fileset'). The exact names of
565
+ filetypes and filesets must match the names used in tasks
566
+ called during flowgraph execution. The files are processed in
567
+ the order specified by the ordered file list.""")))
568
+
569
+ ###########################
570
+ # Options
571
+ ###########################
572
+
573
+ schema.insert(
574
+ 'fileset', fileset, 'topmodule',
575
+ Parameter(
576
+ 'str',
577
+ scope=Scope.GLOBAL,
578
+ shorthelp="Top module name",
579
+ example=[
580
+ "api: chip.set('fileset', 'rtl', 'topmodule', 'mytop')",
581
+ "api: chip.set('fileset', 'testbench', 'topmodule', 'tb')"],
582
+ help=trim("""
583
+ Name of top module specified on a per fileset basis.""")))
584
+
585
+ schema.insert(
586
+ 'fileset', fileset, 'idir',
587
+ Parameter(
588
+ ['dir'],
589
+ scope=Scope.GLOBAL,
590
+ shorthelp="Include file search paths",
591
+ example=[
592
+ "api: chip.set('fileset', 'rtl, 'idir', './rtl')",
593
+ "api: chip.set('fileset', 'testbench', 'idir', '/testbench')"],
594
+ help=trim("""
595
+ Include paths specify directories to scan for header files during
596
+ compilation. If multiple paths are provided, they are searched
597
+ in the order given.""")))
598
+
599
+ schema.insert(
600
+ 'fileset', fileset, 'define',
601
+ Parameter(
602
+ ['str'],
603
+ scope=Scope.GLOBAL,
604
+ shorthelp="Preprocessor macro definitions",
605
+ example=[
606
+ "api: chip.set('fileset', 'rtl', 'define', 'CFG_TARGET=FPGA')"],
607
+ help=trim("""
608
+ Defines macros at compile time for design languages that support
609
+ preprocessing, such as Verilog, C, and C++. The macro format is
610
+ is `MACRONAME[=value]`, where [=value] is optional.""")))
611
+
612
+ schema.insert(
613
+ 'fileset', fileset, 'undefine',
614
+ Parameter(
615
+ ['str'],
616
+ scope=Scope.GLOBAL,
617
+ shorthelp="Preprocessor macro undefine",
618
+ example=[
619
+ "api: chip.set('fileset', 'rtl', 'undefine', 'CFG_TARGET')"],
620
+ help=trim("""
621
+ Undefines a macro that may have been previously defined via the
622
+ compiler, options, or header files.""")))
623
+
624
+ schema.insert(
625
+ 'fileset', fileset, 'libdir',
626
+ Parameter(
627
+ ['dir'],
628
+ scope=Scope.GLOBAL,
629
+ shorthelp="Library search paths",
630
+ example=[
631
+ "api: chip.set('fileset', 'rtl, 'libdir', '/usr/lib')"],
632
+ help=trim("""
633
+ Specifies directories to scan for libraries provided with the
634
+ :keypath:`lib` parameter. If multiple paths are provided, they are
635
+ searched based on the order of the libdir list. The libdir
636
+ parameter is translated to the '-y' option in verilog based tools.""")))
637
+
638
+ schema.insert(
639
+ 'fileset', fileset, 'lib',
640
+ Parameter(
641
+ ['str'],
642
+ scope=Scope.GLOBAL,
643
+ shorthelp="Design libraries to include",
644
+ example=[
645
+ "api: chip.set('fileset', 'rtl', 'lib', 'mylib')"],
646
+ help=trim("""
647
+ Specifies libraries to use during compilation. The compiler searches for
648
+ library in the compiler standard library paths and in the
649
+ paths specified by :keypath:`libdir` parameter.""")))
650
+
651
+ name = 'default'
652
+ schema.insert(
653
+ 'fileset', fileset, 'param', name,
654
+ Parameter(
655
+ 'str',
656
+ scope=Scope.GLOBAL,
657
+ shorthelp="Design parameters",
658
+ example=[
659
+ "api: chip.set('fileset', 'rtl, 'param', 'N', '64'"],
660
+ help=trim("""
661
+ Sets a named parameter to a string value. The value is limited to basic
662
+ data literals. The types of parameters and values supported is tightly
663
+ coupled to tools being used. For example, in Verilog only integer
664
+ literals (64'h4, 2'b0, 4) and strings are supported.""")))
@@ -9,7 +9,7 @@ from siliconcompiler import NodeStatus
9
9
 
10
10
 
11
11
  class FlowgraphSchema(NamedSchema):
12
- def __init__(self, name=None):
12
+ def __init__(self, name):
13
13
  super().__init__(name=name)
14
14
 
15
15
  schema = EditableSchema(self)
@@ -167,6 +167,37 @@ class FlowgraphSchema(NamedSchema):
167
167
 
168
168
  self.__clear_cache()
169
169
 
170
+ def insert_node(self, step, task, before_step, index=0, before_index=0):
171
+ '''
172
+ Insert a new node after the specified node
173
+
174
+ Args:
175
+ step (str): Step name
176
+ index (int/str): Step index
177
+ task (module/str): Task to associate with this node
178
+ before_step (str): name of step to insert task after
179
+ before_index (int/str): index of step to insert task after
180
+ '''
181
+
182
+ index = str(index)
183
+ before_index = str(before_index)
184
+
185
+ if (before_step, before_index) not in self.get_nodes():
186
+ raise ValueError(f'{before_step}{before_index} is not a valid node in {self.name()}')
187
+
188
+ # add the node
189
+ self.node(step, task, index=index)
190
+
191
+ # rewire
192
+ for istep, iindex in self.get_node_outputs(before_step, before_index):
193
+ inputs = self.get(istep, iindex, "input")
194
+ inputs.remove((before_step, before_index))
195
+ self.set(istep, iindex, "input", inputs)
196
+ self.add(istep, iindex, "input", (step, index))
197
+ self.set(step, index, "input", [(before_step, before_index)])
198
+
199
+ self.__clear_cache()
200
+
170
201
  ###########################################################################
171
202
  def graph(self, subflow, name=None):
172
203
  '''