siliconcompiler 0.34.0__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.
- siliconcompiler/__init__.py +14 -2
- siliconcompiler/_metadata.py +1 -1
- siliconcompiler/apps/_common.py +1 -1
- siliconcompiler/apps/sc.py +1 -1
- siliconcompiler/apps/sc_issue.py +1 -1
- siliconcompiler/apps/sc_remote.py +3 -3
- siliconcompiler/apps/sc_show.py +3 -3
- siliconcompiler/apps/utils/replay.py +4 -4
- siliconcompiler/checklist.py +203 -2
- siliconcompiler/constraints/__init__.py +17 -0
- siliconcompiler/constraints/asic_component.py +378 -0
- siliconcompiler/constraints/asic_floorplan.py +449 -0
- siliconcompiler/constraints/asic_pins.py +489 -0
- siliconcompiler/constraints/asic_timing.py +517 -0
- siliconcompiler/core.py +31 -249
- siliconcompiler/data/templates/email/general.j2 +3 -3
- siliconcompiler/data/templates/email/summary.j2 +1 -1
- siliconcompiler/data/templates/issue/README.txt +1 -1
- siliconcompiler/data/templates/report/sc_report.j2 +7 -7
- siliconcompiler/dependencyschema.py +10 -174
- siliconcompiler/design.py +325 -114
- siliconcompiler/flowgraph.py +63 -15
- siliconcompiler/library.py +133 -0
- siliconcompiler/metric.py +94 -72
- siliconcompiler/metrics/__init__.py +7 -0
- siliconcompiler/metrics/asic.py +245 -0
- siliconcompiler/metrics/fpga.py +220 -0
- siliconcompiler/optimizer/vizier.py +2 -2
- siliconcompiler/package/__init__.py +138 -35
- siliconcompiler/package/github.py +6 -10
- siliconcompiler/packageschema.py +256 -12
- siliconcompiler/pathschema.py +226 -0
- siliconcompiler/pdk.py +5 -5
- siliconcompiler/project.py +459 -0
- siliconcompiler/remote/client.py +18 -12
- siliconcompiler/remote/server.py +2 -2
- siliconcompiler/report/dashboard/cli/__init__.py +6 -6
- siliconcompiler/report/dashboard/cli/board.py +3 -3
- siliconcompiler/report/dashboard/web/components/__init__.py +5 -5
- siliconcompiler/report/dashboard/web/components/flowgraph.py +4 -4
- siliconcompiler/report/dashboard/web/components/graph.py +2 -2
- siliconcompiler/report/dashboard/web/state.py +1 -1
- siliconcompiler/report/dashboard/web/utils/__init__.py +5 -5
- siliconcompiler/report/html_report.py +1 -1
- siliconcompiler/report/report.py +4 -4
- siliconcompiler/report/summary_table.py +2 -2
- siliconcompiler/report/utils.py +5 -5
- siliconcompiler/scheduler/docker.py +4 -10
- siliconcompiler/scheduler/run_node.py +4 -8
- siliconcompiler/scheduler/scheduler.py +18 -24
- siliconcompiler/scheduler/schedulernode.py +161 -143
- siliconcompiler/scheduler/send_messages.py +3 -3
- siliconcompiler/scheduler/slurm.py +5 -3
- siliconcompiler/scheduler/taskscheduler.py +10 -8
- siliconcompiler/schema/__init__.py +0 -2
- siliconcompiler/schema/baseschema.py +148 -26
- siliconcompiler/schema/editableschema.py +14 -6
- siliconcompiler/schema/journal.py +23 -15
- siliconcompiler/schema/namedschema.py +30 -4
- siliconcompiler/schema/parameter.py +34 -19
- siliconcompiler/schema/parametertype.py +2 -0
- siliconcompiler/schema/parametervalue.py +198 -15
- siliconcompiler/schema/schema_cfg.py +18 -14
- siliconcompiler/schema_obj.py +5 -3
- siliconcompiler/tool.py +591 -179
- siliconcompiler/tools/__init__.py +2 -0
- siliconcompiler/tools/builtin/_common.py +5 -5
- siliconcompiler/tools/builtin/concatenate.py +5 -5
- siliconcompiler/tools/builtin/minimum.py +4 -4
- siliconcompiler/tools/builtin/mux.py +4 -4
- siliconcompiler/tools/builtin/nop.py +4 -4
- siliconcompiler/tools/builtin/verify.py +7 -7
- siliconcompiler/tools/execute/exec_input.py +1 -1
- siliconcompiler/tools/genfasm/genfasm.py +1 -6
- siliconcompiler/tools/openroad/_apr.py +5 -1
- siliconcompiler/tools/openroad/antenna_repair.py +1 -1
- siliconcompiler/tools/openroad/macro_placement.py +1 -1
- siliconcompiler/tools/openroad/power_grid.py +1 -1
- siliconcompiler/tools/openroad/scripts/common/procs.tcl +5 -0
- siliconcompiler/tools/opensta/timing.py +26 -3
- siliconcompiler/tools/slang/__init__.py +2 -2
- siliconcompiler/tools/surfer/__init__.py +0 -0
- siliconcompiler/tools/surfer/show.py +53 -0
- siliconcompiler/tools/surfer/surfer.py +30 -0
- siliconcompiler/tools/vpr/route.py +27 -14
- siliconcompiler/tools/vpr/vpr.py +23 -6
- siliconcompiler/tools/yosys/__init__.py +1 -1
- siliconcompiler/tools/yosys/scripts/procs.tcl +143 -0
- siliconcompiler/tools/yosys/{sc_synth_asic.tcl → scripts/sc_synth_asic.tcl} +4 -0
- siliconcompiler/tools/yosys/{sc_synth_fpga.tcl → scripts/sc_synth_fpga.tcl} +24 -77
- siliconcompiler/tools/yosys/syn_fpga.py +14 -0
- siliconcompiler/toolscripts/_tools.json +9 -13
- siliconcompiler/toolscripts/rhel9/install-vpr.sh +0 -2
- siliconcompiler/toolscripts/ubuntu22/install-surfer.sh +33 -0
- siliconcompiler/toolscripts/ubuntu24/install-surfer.sh +33 -0
- siliconcompiler/utils/__init__.py +2 -1
- siliconcompiler/utils/flowgraph.py +24 -23
- siliconcompiler/utils/issue.py +23 -29
- siliconcompiler/utils/logging.py +35 -6
- siliconcompiler/utils/showtools.py +6 -1
- {siliconcompiler-0.34.0.dist-info → siliconcompiler-0.34.2.dist-info}/METADATA +15 -25
- {siliconcompiler-0.34.0.dist-info → siliconcompiler-0.34.2.dist-info}/RECORD +109 -97
- siliconcompiler/schema/packageschema.py +0 -101
- siliconcompiler/tools/yosys/procs.tcl +0 -71
- siliconcompiler/toolscripts/rhel9/install-yosys-parmys.sh +0 -68
- siliconcompiler/toolscripts/ubuntu22/install-yosys-parmys.sh +0 -68
- siliconcompiler/toolscripts/ubuntu24/install-yosys-parmys.sh +0 -68
- /siliconcompiler/tools/yosys/{sc_lec.tcl → scripts/sc_lec.tcl} +0 -0
- /siliconcompiler/tools/yosys/{sc_screenshot.tcl → scripts/sc_screenshot.tcl} +0 -0
- /siliconcompiler/tools/yosys/{syn_strategies.tcl → scripts/syn_strategies.tcl} +0 -0
- {siliconcompiler-0.34.0.dist-info → siliconcompiler-0.34.2.dist-info}/WHEEL +0 -0
- {siliconcompiler-0.34.0.dist-info → siliconcompiler-0.34.2.dist-info}/entry_points.txt +0 -0
- {siliconcompiler-0.34.0.dist-info → siliconcompiler-0.34.2.dist-info}/licenses/LICENSE +0 -0
- {siliconcompiler-0.34.0.dist-info → siliconcompiler-0.34.2.dist-info}/top_level.txt +0 -0
siliconcompiler/design.py
CHANGED
|
@@ -1,28 +1,38 @@
|
|
|
1
1
|
import contextlib
|
|
2
2
|
import re
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
import os.path
|
|
5
|
+
|
|
6
|
+
from typing import List, Union, Tuple, Dict
|
|
6
7
|
|
|
7
8
|
from siliconcompiler import utils
|
|
8
|
-
|
|
9
|
+
|
|
10
|
+
from siliconcompiler import PackageSchema
|
|
9
11
|
|
|
10
12
|
from siliconcompiler.dependencyschema import DependencySchema
|
|
13
|
+
from siliconcompiler.pathschema import PathSchema
|
|
11
14
|
from siliconcompiler.schema import NamedSchema
|
|
12
15
|
from siliconcompiler.schema import EditableSchema, Parameter, Scope
|
|
13
16
|
from siliconcompiler.schema.utils import trim
|
|
14
17
|
|
|
15
18
|
|
|
16
19
|
###########################################################################
|
|
17
|
-
class DesignSchema(NamedSchema, DependencySchema):
|
|
20
|
+
class DesignSchema(PackageSchema, NamedSchema, DependencySchema, PathSchema):
|
|
18
21
|
|
|
19
|
-
def __init__(self, name: str):
|
|
20
|
-
|
|
21
|
-
|
|
22
|
+
def __init__(self, name: str = None):
|
|
23
|
+
super().__init__()
|
|
24
|
+
self.set_name(name)
|
|
22
25
|
|
|
23
26
|
schema_design(self)
|
|
24
27
|
|
|
25
|
-
|
|
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)
|
|
26
36
|
|
|
27
37
|
############################################
|
|
28
38
|
def set_topmodule(self,
|
|
@@ -38,9 +48,8 @@ class DesignSchema(NamedSchema, DependencySchema):
|
|
|
38
48
|
str: Topmodule name
|
|
39
49
|
|
|
40
50
|
Notes:
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
51
|
+
- first character must be letter or underscore
|
|
52
|
+
- remaining characters can be letters, digits, or underscores
|
|
44
53
|
"""
|
|
45
54
|
|
|
46
55
|
# topmodule safety check
|
|
@@ -58,7 +67,6 @@ class DesignSchema(NamedSchema, DependencySchema):
|
|
|
58
67
|
|
|
59
68
|
Returns:
|
|
60
69
|
str: Topmodule name
|
|
61
|
-
|
|
62
70
|
"""
|
|
63
71
|
return self.__get(fileset, 'topmodule')
|
|
64
72
|
|
|
@@ -67,20 +75,20 @@ class DesignSchema(NamedSchema, DependencySchema):
|
|
|
67
75
|
value: str,
|
|
68
76
|
fileset: str = None,
|
|
69
77
|
clobber: bool = False,
|
|
70
|
-
|
|
78
|
+
dataroot: str = None) -> List[str]:
|
|
71
79
|
"""Adds include directories to a fileset.
|
|
72
80
|
|
|
73
81
|
Args:
|
|
74
82
|
value (str or Path): Include directory name.
|
|
75
83
|
fileset (str, optional): Fileset name.
|
|
76
84
|
clobber (bool, optional): Clears existing list before adding item
|
|
77
|
-
|
|
85
|
+
dataroot (str, optional): Data directory reference name
|
|
78
86
|
|
|
79
87
|
Returns:
|
|
80
88
|
list[str]: List of include directories
|
|
81
|
-
|
|
82
89
|
"""
|
|
83
|
-
return self.__set_add(fileset, 'idir', value, clobber, typelist=[str, list]
|
|
90
|
+
return self.__set_add(fileset, 'idir', value, clobber, typelist=[str, list],
|
|
91
|
+
dataroot=dataroot)
|
|
84
92
|
|
|
85
93
|
def get_idir(self, fileset: str = None) -> List[str]:
|
|
86
94
|
"""Returns include directories for a fileset.
|
|
@@ -90,9 +98,8 @@ class DesignSchema(NamedSchema, DependencySchema):
|
|
|
90
98
|
|
|
91
99
|
Returns:
|
|
92
100
|
list[str]: List of include directories
|
|
93
|
-
|
|
94
101
|
"""
|
|
95
|
-
return self.__get(fileset, 'idir')
|
|
102
|
+
return self.__get(fileset, 'idir', is_file=True)
|
|
96
103
|
|
|
97
104
|
##############################################
|
|
98
105
|
def add_define(self,
|
|
@@ -120,7 +127,6 @@ class DesignSchema(NamedSchema, DependencySchema):
|
|
|
120
127
|
|
|
121
128
|
Returns:
|
|
122
129
|
list[str]: List of macro definitions
|
|
123
|
-
|
|
124
130
|
"""
|
|
125
131
|
return self.__get(fileset, 'define')
|
|
126
132
|
|
|
@@ -138,7 +144,6 @@ class DesignSchema(NamedSchema, DependencySchema):
|
|
|
138
144
|
|
|
139
145
|
Returns:
|
|
140
146
|
list[str]: List of macro (un)definitions
|
|
141
|
-
|
|
142
147
|
"""
|
|
143
148
|
return self.__set_add(fileset, 'undefine', value, clobber, typelist=[str, list])
|
|
144
149
|
|
|
@@ -159,20 +164,20 @@ class DesignSchema(NamedSchema, DependencySchema):
|
|
|
159
164
|
value: str,
|
|
160
165
|
fileset: str = None,
|
|
161
166
|
clobber: bool = False,
|
|
162
|
-
|
|
167
|
+
dataroot: str = None) -> List[str]:
|
|
163
168
|
"""Adds dynamic library directories to a fileset.
|
|
164
169
|
|
|
165
170
|
Args:
|
|
166
171
|
value (str or List[str]): Library directories
|
|
167
172
|
fileset (str, optional): Fileset name.
|
|
168
173
|
clobber (bool, optional): Clears existing list before adding item.
|
|
169
|
-
|
|
174
|
+
dataroot (str, optional): Data directory reference name
|
|
170
175
|
|
|
171
176
|
Returns:
|
|
172
177
|
list[str]: List of library directories.
|
|
173
|
-
|
|
174
178
|
"""
|
|
175
|
-
return self.__set_add(fileset, 'libdir', value, clobber, typelist=[str, list]
|
|
179
|
+
return self.__set_add(fileset, 'libdir', value, clobber, typelist=[str, list],
|
|
180
|
+
dataroot=dataroot)
|
|
176
181
|
|
|
177
182
|
def get_libdir(self, fileset: str = None) -> List[str]:
|
|
178
183
|
"""Returns dynamic library directories for a fileset.
|
|
@@ -182,9 +187,8 @@ class DesignSchema(NamedSchema, DependencySchema):
|
|
|
182
187
|
|
|
183
188
|
Returns:
|
|
184
189
|
list[str]: List of library directories.
|
|
185
|
-
|
|
186
190
|
"""
|
|
187
|
-
return self.__get(fileset, 'libdir')
|
|
191
|
+
return self.__get(fileset, 'libdir', is_file=True)
|
|
188
192
|
|
|
189
193
|
###############################################
|
|
190
194
|
def add_lib(self,
|
|
@@ -200,7 +204,6 @@ class DesignSchema(NamedSchema, DependencySchema):
|
|
|
200
204
|
|
|
201
205
|
Returns:
|
|
202
206
|
list[str]: List of libraries.
|
|
203
|
-
|
|
204
207
|
"""
|
|
205
208
|
return self.__set_add(fileset, 'lib', value, clobber, typelist=[str, list])
|
|
206
209
|
|
|
@@ -212,7 +215,6 @@ class DesignSchema(NamedSchema, DependencySchema):
|
|
|
212
215
|
|
|
213
216
|
Returns:
|
|
214
217
|
list[str]: List of libraries.
|
|
215
|
-
|
|
216
218
|
"""
|
|
217
219
|
return self.__get(fileset, 'lib')
|
|
218
220
|
|
|
@@ -230,11 +232,10 @@ class DesignSchema(NamedSchema, DependencySchema):
|
|
|
230
232
|
|
|
231
233
|
Returns:
|
|
232
234
|
str: Parameter value
|
|
233
|
-
|
|
234
235
|
"""
|
|
235
236
|
|
|
236
237
|
if fileset is None:
|
|
237
|
-
fileset = self.
|
|
238
|
+
fileset = self._get_active("fileset")
|
|
238
239
|
|
|
239
240
|
if not isinstance(fileset, str):
|
|
240
241
|
raise ValueError("fileset key must be a string")
|
|
@@ -257,24 +258,74 @@ class DesignSchema(NamedSchema, DependencySchema):
|
|
|
257
258
|
str: Parameter value
|
|
258
259
|
"""
|
|
259
260
|
if fileset is None:
|
|
260
|
-
fileset = self.
|
|
261
|
+
fileset = self._get_active("fileset")
|
|
261
262
|
|
|
262
263
|
if not isinstance(fileset, str):
|
|
263
|
-
raise ValueError("fileset
|
|
264
|
+
raise ValueError("fileset key must be a string")
|
|
264
265
|
return self.get('fileset', fileset, 'param', name)
|
|
265
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
|
+
|
|
266
319
|
###############################################
|
|
267
320
|
def add_file(self,
|
|
268
321
|
filename: str,
|
|
269
322
|
fileset: str = None,
|
|
270
323
|
filetype: str = None,
|
|
271
324
|
clobber: bool = False,
|
|
272
|
-
|
|
325
|
+
dataroot: str = None) -> List[str]:
|
|
273
326
|
"""
|
|
274
327
|
Adds files to a fileset.
|
|
275
328
|
|
|
276
|
-
|
|
277
|
-
|
|
278
329
|
.v → (source, verilog)
|
|
279
330
|
.vhd → (source, vhdl)
|
|
280
331
|
.sdc → (constraint, sdc)
|
|
@@ -287,7 +338,7 @@ class DesignSchema(NamedSchema, DependencySchema):
|
|
|
287
338
|
fileset (str): Logical group to associate the file with.
|
|
288
339
|
filetype (str, optional): Type of the file (e.g., 'verilog', 'sdc').
|
|
289
340
|
clobber (bool, optional): Clears list before adding item
|
|
290
|
-
|
|
341
|
+
dataroot (str, optional): Data directory reference name
|
|
291
342
|
|
|
292
343
|
Raises:
|
|
293
344
|
SiliconCompilerError: If fileset or filetype cannot be inferred from
|
|
@@ -300,23 +351,26 @@ class DesignSchema(NamedSchema, DependencySchema):
|
|
|
300
351
|
- This method normalizes `filename` to a string for consistency.
|
|
301
352
|
|
|
302
353
|
- If no filetype is specified, filetype is inferred based on
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
354
|
+
the file extension via a mapping table. (eg. .v is verilog).
|
|
306
355
|
"""
|
|
307
356
|
|
|
308
357
|
if fileset is None:
|
|
309
|
-
fileset = self.
|
|
358
|
+
fileset = self._get_active("fileset")
|
|
359
|
+
|
|
360
|
+
if not isinstance(fileset, str):
|
|
361
|
+
raise ValueError("fileset key must be a string")
|
|
310
362
|
|
|
311
363
|
# handle list inputs
|
|
312
364
|
if isinstance(filename, (list, tuple)):
|
|
365
|
+
params = []
|
|
313
366
|
for item in filename:
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
367
|
+
params.extend(
|
|
368
|
+
self.add_file(
|
|
369
|
+
item,
|
|
370
|
+
fileset=fileset,
|
|
371
|
+
clobber=clobber,
|
|
372
|
+
filetype=filetype))
|
|
373
|
+
return params
|
|
320
374
|
|
|
321
375
|
if filename is None:
|
|
322
376
|
raise ValueError("add_file cannot process None")
|
|
@@ -325,27 +379,24 @@ class DesignSchema(NamedSchema, DependencySchema):
|
|
|
325
379
|
filename = str(filename)
|
|
326
380
|
|
|
327
381
|
# map extension to default filetype/fileset
|
|
328
|
-
|
|
329
382
|
if not filetype:
|
|
330
383
|
ext = utils.get_file_ext(filename)
|
|
331
384
|
iomap = utils.get_default_iomap()
|
|
332
385
|
if ext in iomap:
|
|
333
|
-
|
|
386
|
+
_, default_filetype = iomap[ext]
|
|
334
387
|
filetype = default_filetype
|
|
335
388
|
else:
|
|
336
|
-
raise ValueError("
|
|
389
|
+
raise ValueError(f"Unrecognized file extension: {ext}")
|
|
337
390
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
raise SiliconCompilerError(
|
|
341
|
-
f'Unable to infer fileset and/or filetype for '
|
|
342
|
-
f'{filename} based on file extension.')
|
|
391
|
+
if not dataroot:
|
|
392
|
+
dataroot = self._get_active("package")
|
|
343
393
|
|
|
344
394
|
# adding files to dictionary
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
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)
|
|
349
400
|
|
|
350
401
|
###############################################
|
|
351
402
|
def get_file(self,
|
|
@@ -362,7 +413,7 @@ class DesignSchema(NamedSchema, DependencySchema):
|
|
|
362
413
|
"""
|
|
363
414
|
|
|
364
415
|
if fileset is None:
|
|
365
|
-
fileset = self.
|
|
416
|
+
fileset = self._get_active("fileset")
|
|
366
417
|
|
|
367
418
|
if not isinstance(fileset, list):
|
|
368
419
|
fileset = [fileset]
|
|
@@ -371,79 +422,174 @@ class DesignSchema(NamedSchema, DependencySchema):
|
|
|
371
422
|
filetype = [filetype]
|
|
372
423
|
|
|
373
424
|
filelist = []
|
|
374
|
-
for
|
|
375
|
-
if not isinstance(
|
|
425
|
+
for fs in fileset:
|
|
426
|
+
if not isinstance(fs, str):
|
|
376
427
|
raise ValueError("fileset key must be a string")
|
|
377
428
|
# handle scalar+list in argument
|
|
378
429
|
if not filetype:
|
|
379
|
-
filetype =
|
|
430
|
+
filetype = self.getkeys('fileset', fs, 'file')
|
|
380
431
|
# grab the files
|
|
381
|
-
for
|
|
382
|
-
filelist.extend(self.
|
|
432
|
+
for ftype in filetype:
|
|
433
|
+
filelist.extend(self.find_files('fileset', fs, 'file', ftype))
|
|
383
434
|
|
|
384
435
|
return filelist
|
|
385
436
|
|
|
437
|
+
def __write_flist(self,
|
|
438
|
+
filename: str,
|
|
439
|
+
filesets: List[str],
|
|
440
|
+
depalias: Dict[str, Tuple[NamedSchema, str]]):
|
|
441
|
+
written_cmd = set()
|
|
442
|
+
|
|
443
|
+
with open(filename, "w") as f:
|
|
444
|
+
def write(cmd):
|
|
445
|
+
if cmd in written_cmd:
|
|
446
|
+
f.write(f"// {cmd}\n")
|
|
447
|
+
else:
|
|
448
|
+
written_cmd.add(cmd)
|
|
449
|
+
f.write(f"{cmd}\n")
|
|
450
|
+
|
|
451
|
+
def write_header(header):
|
|
452
|
+
f.write(f"// {header}\n")
|
|
453
|
+
|
|
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}")
|
|
464
|
+
|
|
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)
|
|
470
|
+
|
|
471
|
+
def __map_fileformat(self, path):
|
|
472
|
+
_, ext = os.path.splitext(path)
|
|
473
|
+
|
|
474
|
+
if ext == ".f":
|
|
475
|
+
return "flist"
|
|
476
|
+
else:
|
|
477
|
+
raise ValueError(f"Unable to determine filetype of: {path}")
|
|
478
|
+
|
|
386
479
|
###############################################
|
|
387
480
|
def write_fileset(self,
|
|
388
481
|
filename: str,
|
|
389
482
|
fileset: str = None,
|
|
390
|
-
fileformat: str = None
|
|
483
|
+
fileformat: str = None,
|
|
484
|
+
depalias: Dict[str, Tuple[NamedSchema, str]] = None) -> None:
|
|
391
485
|
"""Exports filesets to a standard formatted text file.
|
|
392
486
|
|
|
393
487
|
Currently supports Verilog `flist` format only.
|
|
394
488
|
Intended to support other formats in the future.
|
|
489
|
+
Inferred from file extension if not given.
|
|
395
490
|
|
|
396
491
|
Args:
|
|
397
492
|
filename (str or Path): Output file name.
|
|
398
493
|
fileset (str or list[str]): Fileset(s) to export.
|
|
399
494
|
fileformat (str, optional): Export format.
|
|
400
|
-
|
|
401
|
-
Inferred from file extension if not given.
|
|
402
|
-
|
|
495
|
+
depalias (dict of schema objects): Map of aliased objects
|
|
403
496
|
"""
|
|
404
497
|
|
|
405
498
|
if filename is None:
|
|
406
|
-
raise ValueError("
|
|
499
|
+
raise ValueError("filename cannot be None")
|
|
407
500
|
|
|
408
501
|
if fileset is None:
|
|
409
|
-
fileset = self.
|
|
502
|
+
fileset = self._get_active("fileset")
|
|
410
503
|
|
|
411
504
|
if not isinstance(fileset, list):
|
|
412
505
|
fileset = [fileset]
|
|
413
506
|
|
|
507
|
+
for fset in fileset:
|
|
508
|
+
if not isinstance(fset, str):
|
|
509
|
+
raise ValueError("fileset key must be a string")
|
|
510
|
+
|
|
414
511
|
# file extension lookup
|
|
415
512
|
if not fileformat:
|
|
416
|
-
|
|
417
|
-
formats['f'] = 'flist'
|
|
418
|
-
fileformat = formats[Path(filename).suffix.strip('.')]
|
|
513
|
+
fileformat = self.__map_fileformat(filename)
|
|
419
514
|
|
|
420
515
|
if fileformat == "flist":
|
|
421
|
-
|
|
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")
|
|
516
|
+
self.__write_flist(filename, fileset, depalias)
|
|
440
517
|
else:
|
|
441
|
-
raise ValueError(f"{fileformat} is not supported")
|
|
518
|
+
raise ValueError(f"{fileformat} is not a supported filetype")
|
|
519
|
+
|
|
520
|
+
def __read_flist(self, filename: str, fileset: str):
|
|
521
|
+
# Extract information
|
|
522
|
+
rel_path = os.path.dirname(os.path.abspath(filename))
|
|
523
|
+
|
|
524
|
+
def expand_path(path):
|
|
525
|
+
path = os.path.expandvars(path)
|
|
526
|
+
path = os.path.expanduser(path)
|
|
527
|
+
if os.path.isabs(path):
|
|
528
|
+
return path
|
|
529
|
+
return os.path.join(rel_path, path)
|
|
530
|
+
|
|
531
|
+
include_dirs = []
|
|
532
|
+
defines = []
|
|
533
|
+
files = []
|
|
534
|
+
with utils.sc_open(filename) as f:
|
|
535
|
+
for line in f:
|
|
536
|
+
line = line.strip()
|
|
537
|
+
if not line:
|
|
538
|
+
continue
|
|
539
|
+
if line.startswith("//"):
|
|
540
|
+
continue
|
|
541
|
+
if line.startswith("+incdir+"):
|
|
542
|
+
include_dirs.append(expand_path(line[8:]))
|
|
543
|
+
elif line.startswith("+define+"):
|
|
544
|
+
defines.append(os.path.expandvars(line[8:]))
|
|
545
|
+
else:
|
|
546
|
+
files.append(expand_path(line))
|
|
547
|
+
|
|
548
|
+
# Create dataroots
|
|
549
|
+
all_paths = include_dirs + [os.path.dirname(f) for f in files]
|
|
550
|
+
all_paths = sorted(set(all_paths))
|
|
551
|
+
|
|
552
|
+
dataroot_root_name = f'flist-{self.name()}-{fileset}-{os.path.basename(filename)}'
|
|
553
|
+
dataroots = {}
|
|
554
|
+
|
|
555
|
+
for path_dir in all_paths:
|
|
556
|
+
found = False
|
|
557
|
+
for pdir in dataroots:
|
|
558
|
+
if path_dir.startswith(pdir):
|
|
559
|
+
found = True
|
|
560
|
+
break
|
|
561
|
+
if not found:
|
|
562
|
+
dataroot_name = f"{dataroot_root_name}-{len(dataroots)}"
|
|
563
|
+
self.set_dataroot(dataroot_name, path_dir)
|
|
564
|
+
dataroots[path_dir] = dataroot_name
|
|
565
|
+
|
|
566
|
+
def get_dataroot(path):
|
|
567
|
+
for pdir, name in dataroots.items():
|
|
568
|
+
if path.startswith(pdir):
|
|
569
|
+
return name, pdir
|
|
570
|
+
return None, None
|
|
571
|
+
|
|
572
|
+
# Assign data
|
|
573
|
+
with self.active_fileset(fileset):
|
|
574
|
+
if defines:
|
|
575
|
+
self.add_define(defines)
|
|
576
|
+
if include_dirs:
|
|
577
|
+
for dir in include_dirs:
|
|
578
|
+
dataroot_name, pdir = get_dataroot(dir)
|
|
579
|
+
if dataroot_name:
|
|
580
|
+
dir = os.path.relpath(dir, pdir)
|
|
581
|
+
self.add_idir(dir, dataroot=dataroot_name)
|
|
582
|
+
if files:
|
|
583
|
+
for f in files:
|
|
584
|
+
dataroot_name, pdir = get_dataroot(f)
|
|
585
|
+
if dataroot_name:
|
|
586
|
+
f = os.path.relpath(f, pdir)
|
|
587
|
+
self.add_file(f, dataroot=dataroot_name)
|
|
442
588
|
|
|
443
589
|
################################################
|
|
444
590
|
def read_fileset(self,
|
|
445
591
|
filename: str,
|
|
446
|
-
fileset: str,
|
|
592
|
+
fileset: str = None,
|
|
447
593
|
fileformat=None) -> None:
|
|
448
594
|
"""Imports filesets from a standard formatted text file.
|
|
449
595
|
|
|
@@ -454,31 +600,31 @@ class DesignSchema(NamedSchema, DependencySchema):
|
|
|
454
600
|
filename (str or Path): Output file name.
|
|
455
601
|
fileset (str or list[str]): Filesets to import.
|
|
456
602
|
fileformat (str, optional): Export format.
|
|
457
|
-
|
|
458
603
|
"""
|
|
459
604
|
|
|
460
605
|
if filename is None:
|
|
461
|
-
raise ValueError("
|
|
606
|
+
raise ValueError("filename cannot be None")
|
|
462
607
|
|
|
463
608
|
if not fileformat:
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
609
|
+
fileformat = self.__map_fileformat(filename)
|
|
610
|
+
|
|
611
|
+
if fileset is None:
|
|
612
|
+
fileset = self._get_active("fileset")
|
|
467
613
|
|
|
468
614
|
if fileformat == "flist":
|
|
469
|
-
|
|
615
|
+
self.__read_flist(filename, fileset)
|
|
470
616
|
else:
|
|
471
|
-
raise ValueError(f"{fileformat} is not supported")
|
|
617
|
+
raise ValueError(f"{fileformat} is not a supported filetype")
|
|
472
618
|
|
|
473
619
|
################################################
|
|
474
620
|
# Helper Functions
|
|
475
621
|
################################################
|
|
476
|
-
def __set_add(self, fileset, option, value, clobber=False, typelist=None):
|
|
622
|
+
def __set_add(self, fileset, option, value, clobber=False, typelist=None, dataroot=None):
|
|
477
623
|
'''Sets a parameter value in schema.
|
|
478
624
|
'''
|
|
479
625
|
|
|
480
626
|
if fileset is None:
|
|
481
|
-
fileset = self.
|
|
627
|
+
fileset = self._get_active("fileset")
|
|
482
628
|
|
|
483
629
|
# check for a legal fileset
|
|
484
630
|
if not fileset or not isinstance(fileset, str):
|
|
@@ -496,19 +642,27 @@ class DesignSchema(NamedSchema, DependencySchema):
|
|
|
496
642
|
if value is None:
|
|
497
643
|
raise ValueError(f"None is an illegal {option} value")
|
|
498
644
|
|
|
499
|
-
if
|
|
500
|
-
|
|
501
|
-
else:
|
|
502
|
-
return self.set('fileset', fileset, option, value)
|
|
645
|
+
if not dataroot:
|
|
646
|
+
dataroot = self._get_active("package")
|
|
503
647
|
|
|
504
|
-
|
|
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)
|
|
653
|
+
|
|
654
|
+
return params
|
|
655
|
+
|
|
656
|
+
def __get(self, fileset, option, is_file=False):
|
|
505
657
|
'''Gets a parameter value from schema.
|
|
506
658
|
'''
|
|
507
659
|
if fileset is None:
|
|
508
|
-
fileset = self.
|
|
660
|
+
fileset = self._get_active("fileset")
|
|
509
661
|
|
|
510
662
|
if not isinstance(fileset, str):
|
|
511
663
|
raise ValueError("fileset key must be a string")
|
|
664
|
+
if is_file:
|
|
665
|
+
return self.find_files('fileset', fileset, option)
|
|
512
666
|
return self.get('fileset', fileset, option)
|
|
513
667
|
|
|
514
668
|
@contextlib.contextmanager
|
|
@@ -533,9 +687,57 @@ class DesignSchema(NamedSchema, DependencySchema):
|
|
|
533
687
|
if not fileset:
|
|
534
688
|
raise ValueError("fileset cannot be an empty string")
|
|
535
689
|
|
|
536
|
-
self.
|
|
537
|
-
|
|
538
|
-
|
|
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
|
|
539
741
|
|
|
540
742
|
|
|
541
743
|
###########################################################################
|
|
@@ -632,8 +834,7 @@ def schema_design(schema):
|
|
|
632
834
|
help=trim("""
|
|
633
835
|
Specifies directories to scan for libraries provided with the
|
|
634
836
|
:keypath:`lib` parameter. If multiple paths are provided, they are
|
|
635
|
-
searched based on the order of the libdir list.
|
|
636
|
-
parameter is translated to the '-y' option in verilog based tools.""")))
|
|
837
|
+
searched based on the order of the libdir list.""")))
|
|
637
838
|
|
|
638
839
|
schema.insert(
|
|
639
840
|
'fileset', fileset, 'lib',
|
|
@@ -662,3 +863,13 @@ def schema_design(schema):
|
|
|
662
863
|
data literals. The types of parameters and values supported is tightly
|
|
663
864
|
coupled to tools being used. For example, in Verilog only integer
|
|
664
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.""")))
|