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.
- siliconcompiler/__init__.py +2 -0
- siliconcompiler/_metadata.py +1 -1
- siliconcompiler/apps/sc_issue.py +5 -3
- siliconcompiler/apps/sc_remote.py +0 -17
- siliconcompiler/apps/utils/replay.py +5 -5
- siliconcompiler/checklist.py +1 -1
- siliconcompiler/core.py +39 -48
- siliconcompiler/data/templates/replay/replay.sh.j2 +18 -1
- siliconcompiler/dependencyschema.py +392 -0
- siliconcompiler/design.py +664 -0
- siliconcompiler/flowgraph.py +32 -1
- siliconcompiler/metric.py +19 -0
- siliconcompiler/package/__init__.py +383 -223
- siliconcompiler/package/git.py +75 -77
- siliconcompiler/package/github.py +70 -97
- siliconcompiler/package/https.py +77 -93
- siliconcompiler/packageschema.py +260 -0
- siliconcompiler/pdk.py +2 -2
- siliconcompiler/record.py +57 -5
- siliconcompiler/remote/client.py +61 -13
- siliconcompiler/remote/server.py +109 -64
- siliconcompiler/report/dashboard/cli/board.py +1 -2
- siliconcompiler/scheduler/__init__.py +3 -1375
- siliconcompiler/scheduler/docker.py +268 -0
- siliconcompiler/scheduler/run_node.py +20 -19
- siliconcompiler/scheduler/scheduler.py +308 -0
- siliconcompiler/scheduler/schedulernode.py +934 -0
- siliconcompiler/scheduler/slurm.py +147 -163
- siliconcompiler/scheduler/taskscheduler.py +39 -52
- siliconcompiler/schema/__init__.py +3 -3
- siliconcompiler/schema/baseschema.py +256 -11
- siliconcompiler/schema/editableschema.py +4 -0
- siliconcompiler/schema/journal.py +210 -0
- siliconcompiler/schema/namedschema.py +31 -2
- siliconcompiler/schema/parameter.py +14 -1
- siliconcompiler/schema/parametervalue.py +1 -34
- siliconcompiler/schema/schema_cfg.py +211 -350
- siliconcompiler/tool.py +139 -37
- siliconcompiler/tools/_common/__init__.py +14 -11
- siliconcompiler/tools/builtin/concatenate.py +2 -2
- siliconcompiler/tools/builtin/verify.py +1 -2
- siliconcompiler/tools/openroad/scripts/common/procs.tcl +27 -25
- siliconcompiler/tools/slang/__init__.py +3 -2
- siliconcompiler/tools/vpr/route.py +69 -0
- siliconcompiler/tools/yosys/sc_synth_asic.tcl +0 -4
- siliconcompiler/toolscripts/_tools.json +13 -8
- siliconcompiler/toolscripts/ubuntu22/install-klayout.sh +4 -0
- siliconcompiler/toolscripts/ubuntu24/install-klayout.sh +4 -0
- siliconcompiler/utils/__init__.py +2 -23
- siliconcompiler/utils/flowgraph.py +5 -5
- siliconcompiler/utils/logging.py +2 -1
- {siliconcompiler-0.33.1.dist-info → siliconcompiler-0.34.0.dist-info}/METADATA +8 -6
- {siliconcompiler-0.33.1.dist-info → siliconcompiler-0.34.0.dist-info}/RECORD +57 -52
- {siliconcompiler-0.33.1.dist-info → siliconcompiler-0.34.0.dist-info}/WHEEL +1 -1
- siliconcompiler/scheduler/docker_runner.py +0 -254
- siliconcompiler/schema/journalingschema.py +0 -238
- {siliconcompiler-0.33.1.dist-info → siliconcompiler-0.34.0.dist-info}/entry_points.txt +0 -0
- {siliconcompiler-0.33.1.dist-info → siliconcompiler-0.34.0.dist-info}/licenses/LICENSE +0 -0
- {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.""")))
|
siliconcompiler/flowgraph.py
CHANGED
|
@@ -9,7 +9,7 @@ from siliconcompiler import NodeStatus
|
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
class FlowgraphSchema(NamedSchema):
|
|
12
|
-
def __init__(self, name
|
|
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
|
'''
|