siliconcompiler 0.32.3__py3-none-any.whl → 0.33.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 +19 -2
- siliconcompiler/_metadata.py +1 -1
- siliconcompiler/apps/sc.py +2 -2
- siliconcompiler/apps/sc_install.py +3 -3
- siliconcompiler/apps/sc_issue.py +1 -1
- siliconcompiler/apps/sc_remote.py +4 -4
- siliconcompiler/apps/sc_show.py +2 -2
- siliconcompiler/apps/utils/replay.py +5 -3
- siliconcompiler/asic.py +120 -0
- siliconcompiler/checklist.py +150 -0
- siliconcompiler/core.py +267 -289
- siliconcompiler/flowgraph.py +803 -515
- siliconcompiler/fpga.py +84 -0
- siliconcompiler/metric.py +420 -0
- siliconcompiler/optimizer/vizier.py +2 -3
- siliconcompiler/package/__init__.py +29 -6
- siliconcompiler/pdk.py +415 -0
- siliconcompiler/record.py +449 -0
- siliconcompiler/remote/client.py +6 -3
- siliconcompiler/remote/schema.py +116 -112
- siliconcompiler/remote/server.py +3 -5
- siliconcompiler/report/dashboard/cli/__init__.py +13 -722
- siliconcompiler/report/dashboard/cli/board.py +895 -0
- siliconcompiler/report/dashboard/web/__init__.py +10 -10
- siliconcompiler/report/dashboard/web/components/__init__.py +5 -4
- siliconcompiler/report/dashboard/web/components/flowgraph.py +3 -3
- siliconcompiler/report/dashboard/web/components/graph.py +6 -3
- siliconcompiler/report/dashboard/web/state.py +1 -1
- siliconcompiler/report/dashboard/web/utils/__init__.py +4 -3
- siliconcompiler/report/html_report.py +2 -3
- siliconcompiler/report/report.py +13 -7
- siliconcompiler/report/summary_image.py +1 -1
- siliconcompiler/report/summary_table.py +3 -3
- siliconcompiler/report/utils.py +11 -10
- siliconcompiler/scheduler/__init__.py +145 -280
- siliconcompiler/scheduler/run_node.py +2 -1
- siliconcompiler/scheduler/send_messages.py +4 -4
- siliconcompiler/scheduler/slurm.py +2 -2
- siliconcompiler/schema/__init__.py +19 -2
- siliconcompiler/schema/baseschema.py +493 -0
- siliconcompiler/schema/cmdlineschema.py +250 -0
- siliconcompiler/{sphinx_ext → schema/docs}/__init__.py +3 -1
- siliconcompiler/{sphinx_ext → schema/docs}/dynamicgen.py +63 -81
- siliconcompiler/{sphinx_ext → schema/docs}/schemagen.py +73 -85
- siliconcompiler/{sphinx_ext → schema/docs}/utils.py +12 -13
- siliconcompiler/schema/editableschema.py +136 -0
- siliconcompiler/schema/journalingschema.py +238 -0
- siliconcompiler/schema/namedschema.py +41 -0
- siliconcompiler/schema/packageschema.py +101 -0
- siliconcompiler/schema/parameter.py +791 -0
- siliconcompiler/schema/parametertype.py +323 -0
- siliconcompiler/schema/parametervalue.py +736 -0
- siliconcompiler/schema/safeschema.py +37 -0
- siliconcompiler/schema/schema_cfg.py +109 -1789
- siliconcompiler/schema/utils.py +5 -68
- siliconcompiler/schema_obj.py +119 -0
- siliconcompiler/tool.py +1308 -0
- siliconcompiler/tools/_common/__init__.py +6 -10
- siliconcompiler/tools/_common/sdc/sc_constraints.sdc +1 -1
- siliconcompiler/tools/bluespec/convert.py +7 -7
- siliconcompiler/tools/builtin/_common.py +1 -1
- siliconcompiler/tools/builtin/concatenate.py +2 -2
- siliconcompiler/tools/builtin/minimum.py +1 -1
- siliconcompiler/tools/builtin/mux.py +2 -1
- siliconcompiler/tools/builtin/nop.py +1 -1
- siliconcompiler/tools/builtin/verify.py +6 -4
- siliconcompiler/tools/chisel/convert.py +4 -4
- siliconcompiler/tools/genfasm/bitstream.py +3 -3
- siliconcompiler/tools/ghdl/convert.py +1 -1
- siliconcompiler/tools/icarus/compile.py +4 -4
- siliconcompiler/tools/icepack/bitstream.py +6 -1
- siliconcompiler/tools/klayout/convert_drc_db.py +5 -0
- siliconcompiler/tools/klayout/klayout_export.py +0 -1
- siliconcompiler/tools/klayout/klayout_utils.py +3 -10
- siliconcompiler/tools/nextpnr/apr.py +6 -1
- siliconcompiler/tools/nextpnr/nextpnr.py +4 -4
- siliconcompiler/tools/openroad/_apr.py +13 -0
- siliconcompiler/tools/openroad/rdlroute.py +3 -3
- siliconcompiler/tools/openroad/scripts/apr/postamble.tcl +1 -1
- siliconcompiler/tools/openroad/scripts/apr/preamble.tcl +5 -5
- siliconcompiler/tools/openroad/scripts/apr/sc_antenna_repair.tcl +2 -2
- siliconcompiler/tools/openroad/scripts/apr/sc_clock_tree_synthesis.tcl +2 -2
- siliconcompiler/tools/openroad/scripts/apr/sc_detailed_placement.tcl +2 -2
- siliconcompiler/tools/openroad/scripts/apr/sc_detailed_route.tcl +2 -2
- siliconcompiler/tools/openroad/scripts/apr/sc_endcap_tapcell_insertion.tcl +2 -2
- siliconcompiler/tools/openroad/scripts/apr/sc_fillercell_insertion.tcl +2 -2
- siliconcompiler/tools/openroad/scripts/apr/sc_fillmetal_insertion.tcl +2 -2
- siliconcompiler/tools/openroad/scripts/apr/sc_global_placement.tcl +2 -2
- siliconcompiler/tools/openroad/scripts/apr/sc_global_route.tcl +2 -2
- siliconcompiler/tools/openroad/scripts/apr/sc_init_floorplan.tcl +2 -2
- siliconcompiler/tools/openroad/scripts/apr/sc_macro_placement.tcl +3 -3
- siliconcompiler/tools/openroad/scripts/apr/sc_metrics.tcl +2 -2
- siliconcompiler/tools/openroad/scripts/apr/sc_pin_placement.tcl +2 -2
- siliconcompiler/tools/openroad/scripts/apr/sc_power_grid.tcl +2 -2
- siliconcompiler/tools/openroad/scripts/apr/sc_repair_design.tcl +2 -2
- siliconcompiler/tools/openroad/scripts/apr/sc_repair_timing.tcl +2 -2
- siliconcompiler/tools/openroad/scripts/apr/sc_write_data.tcl +2 -2
- siliconcompiler/tools/openroad/scripts/common/procs.tcl +57 -1
- siliconcompiler/tools/openroad/scripts/common/screenshot.tcl +2 -2
- siliconcompiler/tools/openroad/scripts/common/write_images.tcl +28 -3
- siliconcompiler/tools/openroad/scripts/sc_rcx.tcl +1 -1
- siliconcompiler/tools/openroad/scripts/sc_rdlroute.tcl +3 -3
- siliconcompiler/tools/openroad/scripts/sc_show.tcl +6 -6
- siliconcompiler/tools/slang/__init__.py +10 -10
- siliconcompiler/tools/surelog/parse.py +4 -4
- siliconcompiler/tools/sv2v/convert.py +20 -3
- siliconcompiler/tools/verilator/compile.py +2 -2
- siliconcompiler/tools/verilator/verilator.py +3 -3
- siliconcompiler/tools/vpr/place.py +1 -1
- siliconcompiler/tools/vpr/route.py +4 -4
- siliconcompiler/tools/vpr/screenshot.py +1 -1
- siliconcompiler/tools/vpr/show.py +5 -5
- siliconcompiler/tools/vpr/vpr.py +24 -24
- siliconcompiler/tools/xdm/convert.py +2 -2
- siliconcompiler/tools/xyce/simulate.py +1 -1
- siliconcompiler/tools/yosys/sc_synth_asic.tcl +74 -68
- siliconcompiler/tools/yosys/syn_asic.py +2 -2
- siliconcompiler/toolscripts/_tools.json +7 -7
- siliconcompiler/toolscripts/ubuntu22/install-vpr.sh +0 -2
- siliconcompiler/toolscripts/ubuntu24/install-vpr.sh +0 -2
- siliconcompiler/utils/__init__.py +8 -112
- siliconcompiler/utils/flowgraph.py +339 -0
- siliconcompiler/{issue.py → utils/issue.py} +4 -3
- siliconcompiler/utils/logging.py +1 -2
- {siliconcompiler-0.32.3.dist-info → siliconcompiler-0.33.0.dist-info}/METADATA +9 -8
- {siliconcompiler-0.32.3.dist-info → siliconcompiler-0.33.0.dist-info}/RECORD +151 -134
- {siliconcompiler-0.32.3.dist-info → siliconcompiler-0.33.0.dist-info}/WHEEL +1 -1
- {siliconcompiler-0.32.3.dist-info → siliconcompiler-0.33.0.dist-info}/entry_points.txt +8 -8
- siliconcompiler/schema/schema_obj.py +0 -1936
- siliconcompiler/toolscripts/ubuntu20/install-vpr.sh +0 -29
- siliconcompiler/toolscripts/ubuntu20/install-yosys-parmys.sh +0 -61
- /siliconcompiler/{templates → data/templates}/__init__.py +0 -0
- /siliconcompiler/{templates → data/templates}/email/__init__.py +0 -0
- /siliconcompiler/{templates → data/templates}/email/general.j2 +0 -0
- /siliconcompiler/{templates → data/templates}/email/summary.j2 +0 -0
- /siliconcompiler/{templates → data/templates}/issue/README.txt +0 -0
- /siliconcompiler/{templates → data/templates}/issue/__init__.py +0 -0
- /siliconcompiler/{templates → data/templates}/issue/run.sh +0 -0
- /siliconcompiler/{templates → data/templates}/replay/replay.py.j2 +0 -0
- /siliconcompiler/{templates → data/templates}/replay/replay.sh.j2 +0 -0
- /siliconcompiler/{templates → data/templates}/replay/requirements.txt +0 -0
- /siliconcompiler/{templates → data/templates}/replay/setup.sh +0 -0
- /siliconcompiler/{templates → data/templates}/report/__init__.py +0 -0
- /siliconcompiler/{templates → data/templates}/report/bootstrap.min.css +0 -0
- /siliconcompiler/{templates → data/templates}/report/bootstrap.min.js +0 -0
- /siliconcompiler/{templates → data/templates}/report/bootstrap_LICENSE.md +0 -0
- /siliconcompiler/{templates → data/templates}/report/sc_report.j2 +0 -0
- /siliconcompiler/{templates → data/templates}/slurm/__init__.py +0 -0
- /siliconcompiler/{templates → data/templates}/slurm/run.sh +0 -0
- /siliconcompiler/{templates → data/templates}/tcl/__init__.py +0 -0
- /siliconcompiler/{templates → data/templates}/tcl/manifest.tcl.j2 +0 -0
- /siliconcompiler/{units.py → utils/units.py} +0 -0
- {siliconcompiler-0.32.3.dist-info → siliconcompiler-0.33.0.dist-info}/licenses/LICENSE +0 -0
- {siliconcompiler-0.32.3.dist-info → siliconcompiler-0.33.0.dist-info}/top_level.txt +0 -0
|
@@ -93,7 +93,8 @@ def main():
|
|
|
93
93
|
chip.set('record', 'remoteid', args.remoteid)
|
|
94
94
|
|
|
95
95
|
if args.unset_scheduler:
|
|
96
|
-
for vals, step, index in chip.schema.
|
|
96
|
+
for vals, step, index in chip.schema.get('option', 'scheduler', 'name',
|
|
97
|
+
field=None).getvalues():
|
|
97
98
|
chip.unset('option', 'scheduler', 'name', step=step, index=index)
|
|
98
99
|
|
|
99
100
|
# Init logger to ensure consistent view
|
|
@@ -6,11 +6,11 @@ from email.mime.application import MIMEApplication
|
|
|
6
6
|
import json
|
|
7
7
|
import os
|
|
8
8
|
from siliconcompiler import sc_open
|
|
9
|
-
from siliconcompiler
|
|
9
|
+
from siliconcompiler import Schema
|
|
10
10
|
from siliconcompiler.report import utils as report_utils
|
|
11
11
|
import fastjsonschema
|
|
12
12
|
from pathlib import Path
|
|
13
|
-
from siliconcompiler.flowgraph import
|
|
13
|
+
from siliconcompiler.utils.flowgraph import nodes_to_execute
|
|
14
14
|
import uuid
|
|
15
15
|
|
|
16
16
|
|
|
@@ -91,9 +91,9 @@ def send(chip, msg_type, step, index):
|
|
|
91
91
|
filename=os.path.basename(layout_img))
|
|
92
92
|
msg.attach(img_attach)
|
|
93
93
|
|
|
94
|
-
nodes_to_execute = get_executed_nodes(chip, flow)
|
|
95
94
|
nodes, errors, metrics, metrics_unit, metrics_to_show, _ = \
|
|
96
|
-
report_utils._collect_data(chip, flow=flow,
|
|
95
|
+
report_utils._collect_data(chip, flow=flow,
|
|
96
|
+
flowgraph_nodes=nodes_to_execute(chip, flow))
|
|
97
97
|
|
|
98
98
|
text_msg = get_file_template('email/summary.j2').render(
|
|
99
99
|
design=chip.design,
|
|
@@ -7,7 +7,7 @@ import uuid
|
|
|
7
7
|
import json
|
|
8
8
|
import shutil
|
|
9
9
|
from siliconcompiler import utils, SiliconCompilerError
|
|
10
|
-
from siliconcompiler.flowgraph import nodes_to_execute
|
|
10
|
+
from siliconcompiler.utils.flowgraph import nodes_to_execute
|
|
11
11
|
from siliconcompiler.package import get_cache_path
|
|
12
12
|
|
|
13
13
|
# Full list of Slurm states, split into 'active' and 'inactive' categories.
|
|
@@ -59,7 +59,7 @@ def init(chip):
|
|
|
59
59
|
|
|
60
60
|
collect = False
|
|
61
61
|
flow = chip.get('option', 'flow')
|
|
62
|
-
entry_nodes =
|
|
62
|
+
entry_nodes = chip.schema.get("flowgraph", flow, field="schema").get_entry_nodes()
|
|
63
63
|
for (step, index) in nodes_to_execute(chip, flow):
|
|
64
64
|
if (step, index) in entry_nodes:
|
|
65
65
|
collect = True
|
|
@@ -1,7 +1,24 @@
|
|
|
1
|
+
from .parameter import Parameter, Scope, PerNode
|
|
2
|
+
from .safeschema import SafeSchema
|
|
3
|
+
from .editableschema import EditableSchema
|
|
4
|
+
from .baseschema import BaseSchema
|
|
5
|
+
from .cmdlineschema import CommandLineSchema
|
|
6
|
+
from .journalingschema import JournalingSchema
|
|
7
|
+
from .namedschema import NamedSchema
|
|
8
|
+
from .packageschema import PackageSchema
|
|
9
|
+
|
|
1
10
|
from .schema_cfg import SCHEMA_VERSION
|
|
2
|
-
from .schema_obj import Schema
|
|
3
11
|
|
|
4
12
|
__all__ = [
|
|
5
13
|
"SCHEMA_VERSION",
|
|
6
|
-
"
|
|
14
|
+
"BaseSchema",
|
|
15
|
+
"SafeSchema",
|
|
16
|
+
"EditableSchema",
|
|
17
|
+
"CommandLineSchema",
|
|
18
|
+
"JournalingSchema",
|
|
19
|
+
"NamedSchema",
|
|
20
|
+
"PackageSchema",
|
|
21
|
+
"Parameter",
|
|
22
|
+
"Scope",
|
|
23
|
+
"PerNode"
|
|
7
24
|
]
|
|
@@ -0,0 +1,493 @@
|
|
|
1
|
+
# Copyright 2025 Silicon Compiler Authors. All Rights Reserved.
|
|
2
|
+
|
|
3
|
+
# NOTE: this file cannot rely on any third-party dependencies, including other
|
|
4
|
+
# SC dependencies outside of its directory, since it may be used by tool drivers
|
|
5
|
+
# that have isolated Python environments.
|
|
6
|
+
|
|
7
|
+
import copy
|
|
8
|
+
|
|
9
|
+
try:
|
|
10
|
+
import gzip
|
|
11
|
+
_has_gzip = True
|
|
12
|
+
except ModuleNotFoundError:
|
|
13
|
+
_has_gzip = False
|
|
14
|
+
|
|
15
|
+
try:
|
|
16
|
+
import orjson as json
|
|
17
|
+
_has_orjson = True
|
|
18
|
+
except ModuleNotFoundError:
|
|
19
|
+
import json
|
|
20
|
+
_has_orjson = False
|
|
21
|
+
|
|
22
|
+
import os.path
|
|
23
|
+
|
|
24
|
+
from .parameter import Parameter
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class BaseSchema:
|
|
28
|
+
'''
|
|
29
|
+
This class maintains the access and file IO operations for the schema.
|
|
30
|
+
It can be modified using :class:`EditableSchema`.
|
|
31
|
+
'''
|
|
32
|
+
|
|
33
|
+
def __init__(self):
|
|
34
|
+
# Data storage for the schema
|
|
35
|
+
self.__manifest = {}
|
|
36
|
+
self.__default = None
|
|
37
|
+
|
|
38
|
+
def _from_dict(self, manifest, keypath, version=None):
|
|
39
|
+
'''
|
|
40
|
+
Decodes a dictionary into a schema object
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
manifest (dict): Manifest to decide.
|
|
44
|
+
keypath (list of str): Path to the current keypath.
|
|
45
|
+
version (packaging.Version): Version of the dictionary schema
|
|
46
|
+
'''
|
|
47
|
+
|
|
48
|
+
handled = set()
|
|
49
|
+
missing = set()
|
|
50
|
+
|
|
51
|
+
if self.__default:
|
|
52
|
+
data = manifest.get("default", None)
|
|
53
|
+
if data:
|
|
54
|
+
del manifest["default"]
|
|
55
|
+
self.__default._from_dict(data, keypath + ["default"], version=version)
|
|
56
|
+
handled.add("default")
|
|
57
|
+
|
|
58
|
+
for key, data in manifest.items():
|
|
59
|
+
obj = self.__manifest.get(key, None)
|
|
60
|
+
if not obj and self.__default:
|
|
61
|
+
obj = self.__default.copy()
|
|
62
|
+
self.__manifest[key] = obj
|
|
63
|
+
if obj:
|
|
64
|
+
obj._from_dict(data, keypath + [key], version=version)
|
|
65
|
+
handled.add(key)
|
|
66
|
+
else:
|
|
67
|
+
missing.add(key)
|
|
68
|
+
|
|
69
|
+
return missing, set(self.__manifest.keys()).difference(handled)
|
|
70
|
+
|
|
71
|
+
# Manifest methods
|
|
72
|
+
@classmethod
|
|
73
|
+
def from_manifest(cls, filepath=None, cfg=None):
|
|
74
|
+
'''
|
|
75
|
+
Create a new schema based on the provided source files.
|
|
76
|
+
|
|
77
|
+
The two arguments to this class are mutually exclusive.
|
|
78
|
+
|
|
79
|
+
Args:
|
|
80
|
+
filepath (path): Initial manifest.
|
|
81
|
+
cfg (dict): Initial configuration dictionary.
|
|
82
|
+
'''
|
|
83
|
+
|
|
84
|
+
schema = cls()
|
|
85
|
+
if not filepath and cfg is None:
|
|
86
|
+
raise RuntimeError("filepath or dictionary is required")
|
|
87
|
+
if filepath:
|
|
88
|
+
schema.read_manifest(filepath)
|
|
89
|
+
if cfg:
|
|
90
|
+
schema._from_dict(cfg, [])
|
|
91
|
+
return schema
|
|
92
|
+
|
|
93
|
+
@staticmethod
|
|
94
|
+
def __open_file(filepath, is_read=True):
|
|
95
|
+
_, ext = os.path.splitext(filepath)
|
|
96
|
+
if ext.lower() == ".gz":
|
|
97
|
+
if not _has_gzip:
|
|
98
|
+
raise RuntimeError("gzip is not available")
|
|
99
|
+
return gzip.open(filepath, mode="rt" if is_read else "wt", encoding="utf-8")
|
|
100
|
+
return open(filepath, mode="r" if is_read else "w", encoding="utf-8")
|
|
101
|
+
|
|
102
|
+
def read_manifest(self, filepath):
|
|
103
|
+
"""
|
|
104
|
+
Reads a manifest from disk and replaces the current data with the data in the file.
|
|
105
|
+
|
|
106
|
+
Args:
|
|
107
|
+
filename (path): Path to a manifest file to be loaded.
|
|
108
|
+
|
|
109
|
+
Examples:
|
|
110
|
+
>>> schema.read_manifest('mychip.json')
|
|
111
|
+
Loads the file mychip.json into the current Schema object.
|
|
112
|
+
"""
|
|
113
|
+
|
|
114
|
+
fin = BaseSchema.__open_file(filepath)
|
|
115
|
+
manifest = json.loads(fin.read())
|
|
116
|
+
fin.close()
|
|
117
|
+
|
|
118
|
+
self._from_dict(manifest, [])
|
|
119
|
+
|
|
120
|
+
def write_manifest(self, filepath):
|
|
121
|
+
'''
|
|
122
|
+
Writes the manifest to a file.
|
|
123
|
+
|
|
124
|
+
Args:
|
|
125
|
+
filename (filepath): Output filepath.
|
|
126
|
+
|
|
127
|
+
Examples:
|
|
128
|
+
>>> schema.write_manifest('mydump.json')
|
|
129
|
+
Dumps the current manifest into mydump.json
|
|
130
|
+
'''
|
|
131
|
+
|
|
132
|
+
fout = BaseSchema.__open_file(filepath, is_read=False)
|
|
133
|
+
|
|
134
|
+
if _has_orjson:
|
|
135
|
+
manifest_str = json.dumps(self.getdict(), option=json.OPT_INDENT_2).decode()
|
|
136
|
+
else:
|
|
137
|
+
manifest_str = json.dumps(self.getdict(), indent=2)
|
|
138
|
+
fout.write(manifest_str)
|
|
139
|
+
|
|
140
|
+
fout.close()
|
|
141
|
+
|
|
142
|
+
# Accessor methods
|
|
143
|
+
def __search(self,
|
|
144
|
+
*keypath,
|
|
145
|
+
insert_defaults=False,
|
|
146
|
+
use_default=False,
|
|
147
|
+
require_leaf=True,
|
|
148
|
+
complete_path=None):
|
|
149
|
+
if len(keypath) == 0:
|
|
150
|
+
if require_leaf:
|
|
151
|
+
raise KeyError
|
|
152
|
+
else:
|
|
153
|
+
return self
|
|
154
|
+
|
|
155
|
+
if complete_path is None:
|
|
156
|
+
complete_path = []
|
|
157
|
+
complete_path.append(keypath[0])
|
|
158
|
+
|
|
159
|
+
if keypath[0] == "default":
|
|
160
|
+
key_param = self.__default
|
|
161
|
+
else:
|
|
162
|
+
key_param = self.__manifest.get(keypath[0], None)
|
|
163
|
+
if not key_param:
|
|
164
|
+
if insert_defaults and self.__default:
|
|
165
|
+
if isinstance(self.__default, Parameter) and self.__default.get(field='lock'):
|
|
166
|
+
raise KeyError
|
|
167
|
+
key_param = self.__default.copy(key=complete_path)
|
|
168
|
+
self.__manifest[keypath[0]] = key_param
|
|
169
|
+
elif use_default and self.__default:
|
|
170
|
+
key_param = self.__default
|
|
171
|
+
else:
|
|
172
|
+
raise KeyError
|
|
173
|
+
if isinstance(key_param, BaseSchema):
|
|
174
|
+
if len(keypath) == 1:
|
|
175
|
+
if require_leaf:
|
|
176
|
+
raise KeyError
|
|
177
|
+
else:
|
|
178
|
+
return key_param
|
|
179
|
+
return key_param.__search(*keypath[1:],
|
|
180
|
+
insert_defaults=insert_defaults,
|
|
181
|
+
use_default=use_default,
|
|
182
|
+
require_leaf=require_leaf,
|
|
183
|
+
complete_path=complete_path)
|
|
184
|
+
return key_param
|
|
185
|
+
|
|
186
|
+
def get(self, *keypath, field='value', step=None, index=None):
|
|
187
|
+
"""
|
|
188
|
+
Returns a parameter field from the schema.
|
|
189
|
+
|
|
190
|
+
Returns a schema parameter field based on the keypath provided in the
|
|
191
|
+
``*keypath``. The returned type is consistent with the type field of the parameter.
|
|
192
|
+
Accessing a non-existent keypath raises a KeyError.
|
|
193
|
+
|
|
194
|
+
Args:
|
|
195
|
+
keypath (list of str): Keypath to access.
|
|
196
|
+
field (str): Parameter field to fetch, if None will return the :class:`Parameter`
|
|
197
|
+
object stored, if field is 'schema' the schema at this keypath will be returned.
|
|
198
|
+
step (str): Step name to access for parameters that may be specified
|
|
199
|
+
on a per-node basis.
|
|
200
|
+
index (str): Index name to access for parameters that may be specified
|
|
201
|
+
on a per-node basis.
|
|
202
|
+
|
|
203
|
+
Returns:
|
|
204
|
+
Value found for the keypath and field provided.
|
|
205
|
+
|
|
206
|
+
Examples:
|
|
207
|
+
>>> foundry = schema.get('pdk', 'virtual', 'foundry')
|
|
208
|
+
Returns the value of [pdk,virtual,foundry].
|
|
209
|
+
"""
|
|
210
|
+
|
|
211
|
+
try:
|
|
212
|
+
require_leaf = True
|
|
213
|
+
if field == 'schema':
|
|
214
|
+
require_leaf = False
|
|
215
|
+
param = self.__search(
|
|
216
|
+
*keypath,
|
|
217
|
+
insert_defaults=False,
|
|
218
|
+
use_default=True,
|
|
219
|
+
require_leaf=require_leaf)
|
|
220
|
+
if field == 'schema':
|
|
221
|
+
if isinstance(param, Parameter):
|
|
222
|
+
raise ValueError(f"[{','.join(keypath)}] is a complete keypath")
|
|
223
|
+
return param
|
|
224
|
+
except KeyError:
|
|
225
|
+
raise KeyError(f"[{','.join(keypath)}] is not a valid keypath")
|
|
226
|
+
if field is None:
|
|
227
|
+
return param
|
|
228
|
+
return param.get(field, step=step, index=index)
|
|
229
|
+
|
|
230
|
+
def set(self, *args, field='value', clobber=True, step=None, index=None):
|
|
231
|
+
'''
|
|
232
|
+
Sets a schema parameter field.
|
|
233
|
+
|
|
234
|
+
Sets a schema parameter field based on the keypath and value provided in
|
|
235
|
+
the ``*args``. New schema entries are automatically created for keypaths
|
|
236
|
+
that overlap with 'default' entries.
|
|
237
|
+
|
|
238
|
+
Args:
|
|
239
|
+
args (list): Parameter keypath followed by a value to set.
|
|
240
|
+
field (str): Parameter field to set.
|
|
241
|
+
clobber (bool): Existing value is overwritten if True.
|
|
242
|
+
step (str): Step name to set for parameters that may be specified
|
|
243
|
+
on a per-node basis.
|
|
244
|
+
index (str): Index name to set for parameters that may be specified
|
|
245
|
+
on a per-node basis.
|
|
246
|
+
|
|
247
|
+
Examples:
|
|
248
|
+
>>> schema.set('design', 'top')
|
|
249
|
+
Sets the [design] value to 'top'
|
|
250
|
+
'''
|
|
251
|
+
|
|
252
|
+
if len(args) < 2:
|
|
253
|
+
raise KeyError("keypath and value is required")
|
|
254
|
+
|
|
255
|
+
*keypath, value = args
|
|
256
|
+
|
|
257
|
+
try:
|
|
258
|
+
param = self.__search(*keypath, insert_defaults=True)
|
|
259
|
+
except KeyError:
|
|
260
|
+
raise KeyError(f"[{','.join(keypath)}] is not a valid keypath")
|
|
261
|
+
|
|
262
|
+
return param.set(value, field=field, clobber=clobber, step=step, index=index)
|
|
263
|
+
|
|
264
|
+
def add(self, *args, field='value', step=None, index=None):
|
|
265
|
+
'''
|
|
266
|
+
Adds item(s) to a schema parameter list.
|
|
267
|
+
|
|
268
|
+
Adds item(s) to schema parameter list based on the keypath and value
|
|
269
|
+
provided in the ``*args``. New schema entries are automatically created
|
|
270
|
+
for keypaths that overlap with 'default' entries.
|
|
271
|
+
|
|
272
|
+
Args:
|
|
273
|
+
args (list): Parameter keypath followed by a value to add.
|
|
274
|
+
field (str): Parameter field to modify.
|
|
275
|
+
step (str): Step name to modify for parameters that may be specified
|
|
276
|
+
on a per-node basis.
|
|
277
|
+
index (str): Index name to modify for parameters that may be specified
|
|
278
|
+
on a per-node basis.
|
|
279
|
+
|
|
280
|
+
Examples:
|
|
281
|
+
>>> schema.add('input', 'rtl', 'verilog', 'hello.v')
|
|
282
|
+
Adds the file 'hello.v' to the [input,rtl,verilog] key.
|
|
283
|
+
'''
|
|
284
|
+
|
|
285
|
+
if len(args) < 2:
|
|
286
|
+
raise KeyError("keypath and value is required")
|
|
287
|
+
|
|
288
|
+
*keypath, value = args
|
|
289
|
+
|
|
290
|
+
try:
|
|
291
|
+
param = self.__search(*keypath, insert_defaults=True)
|
|
292
|
+
except KeyError:
|
|
293
|
+
raise KeyError(f"[{','.join(keypath)}] is not a valid keypath")
|
|
294
|
+
|
|
295
|
+
return param.add(value, field=field, step=step, index=index)
|
|
296
|
+
|
|
297
|
+
def unset(self, *keypath, step=None, index=None):
|
|
298
|
+
'''
|
|
299
|
+
Unsets a schema parameter.
|
|
300
|
+
|
|
301
|
+
This method effectively undoes any previous calls to :meth:`set()` made to
|
|
302
|
+
the given keypath and step/index. For parameters with required or no
|
|
303
|
+
per-node values, unsetting a parameter always causes it to revert to its
|
|
304
|
+
default value, and future calls to :meth:`set()` with ``clobber=False`` will
|
|
305
|
+
once again be able to modify the value.
|
|
306
|
+
|
|
307
|
+
If you unset a particular step/index for a parameter with optional
|
|
308
|
+
per-node values, note that the newly returned value will be the global
|
|
309
|
+
value if it has been set. To completely return the parameter to its
|
|
310
|
+
default state, the global value has to be unset as well.
|
|
311
|
+
|
|
312
|
+
``unset()`` has no effect if called on a parameter that has not been
|
|
313
|
+
previously set.
|
|
314
|
+
|
|
315
|
+
Args:
|
|
316
|
+
keypath (list): Parameter keypath to clear.
|
|
317
|
+
step (str): Step name to unset for parameters that may be specified
|
|
318
|
+
on a per-node basis.
|
|
319
|
+
index (str): Index name to unset for parameters that may be specified
|
|
320
|
+
on a per-node basis.
|
|
321
|
+
'''
|
|
322
|
+
|
|
323
|
+
try:
|
|
324
|
+
param = self.__search(*keypath, use_default=True)
|
|
325
|
+
except KeyError:
|
|
326
|
+
raise KeyError(f"[{','.join(keypath)}] is not a valid keypath")
|
|
327
|
+
|
|
328
|
+
param.unset(step=step, index=index)
|
|
329
|
+
|
|
330
|
+
def remove(self, *keypath):
|
|
331
|
+
'''
|
|
332
|
+
Remove a schema parameter and its subparameters.
|
|
333
|
+
|
|
334
|
+
Args:
|
|
335
|
+
keypath (list): Parameter keypath to clear.
|
|
336
|
+
'''
|
|
337
|
+
|
|
338
|
+
search_path = keypath[0:-1]
|
|
339
|
+
removal_key = keypath[-1]
|
|
340
|
+
if removal_key == "default":
|
|
341
|
+
return
|
|
342
|
+
|
|
343
|
+
try:
|
|
344
|
+
key_param = self.__search(*search_path, require_leaf=False)
|
|
345
|
+
except KeyError:
|
|
346
|
+
raise KeyError(f"[{','.join(keypath)}] is not a valid keypath")
|
|
347
|
+
|
|
348
|
+
if removal_key not in key_param.__manifest:
|
|
349
|
+
return
|
|
350
|
+
|
|
351
|
+
if not key_param.__default:
|
|
352
|
+
return
|
|
353
|
+
|
|
354
|
+
if any([key_param.get(*key, field='lock') for key in key_param.allkeys()]):
|
|
355
|
+
return
|
|
356
|
+
|
|
357
|
+
del key_param.__manifest[removal_key]
|
|
358
|
+
|
|
359
|
+
def valid(self, *keypath, default_valid=False, check_complete=False):
|
|
360
|
+
"""
|
|
361
|
+
Checks validity of a keypath.
|
|
362
|
+
|
|
363
|
+
Checks the validity of a parameter keypath and returns True if the
|
|
364
|
+
keypath is valid and False if invalid.
|
|
365
|
+
|
|
366
|
+
Args:
|
|
367
|
+
keypath (list of str): keypath to check if valid.
|
|
368
|
+
default_valid (bool): Whether to consider "default" in valid
|
|
369
|
+
keypaths as a wildcard.
|
|
370
|
+
check_complete (bool): Require the keypath be a complete path.
|
|
371
|
+
|
|
372
|
+
Returns:
|
|
373
|
+
Boolean indicating validity of keypath.
|
|
374
|
+
|
|
375
|
+
Examples:
|
|
376
|
+
>>> check = schema.valid('design')
|
|
377
|
+
Returns True
|
|
378
|
+
>>> check = schema.valid('blah')
|
|
379
|
+
Returns False.
|
|
380
|
+
>>> check = schema.valid('metric', 'foo', '0', 'tasktime', default_valid=True)
|
|
381
|
+
Returns True, even if "foo" and "0" aren't in current configuration.
|
|
382
|
+
"""
|
|
383
|
+
|
|
384
|
+
try:
|
|
385
|
+
param = self.__search(*keypath, use_default=default_valid, require_leaf=False)
|
|
386
|
+
except KeyError:
|
|
387
|
+
return False
|
|
388
|
+
|
|
389
|
+
if check_complete:
|
|
390
|
+
return isinstance(param, Parameter)
|
|
391
|
+
return True
|
|
392
|
+
|
|
393
|
+
def getkeys(self, *keypath):
|
|
394
|
+
"""
|
|
395
|
+
Returns a tuple of schema dictionary keys.
|
|
396
|
+
|
|
397
|
+
Searches the schema for the keypath provided and returns a list of
|
|
398
|
+
keys found, excluding the generic 'default' key.
|
|
399
|
+
|
|
400
|
+
Args:
|
|
401
|
+
keypath (list of str): Keypath to get keys for.
|
|
402
|
+
|
|
403
|
+
Returns:
|
|
404
|
+
tuple of keys found for the keypath provided.
|
|
405
|
+
|
|
406
|
+
Examples:
|
|
407
|
+
>>> keylist = chip.getkeys('pdk')
|
|
408
|
+
Returns all keys for the [pdk] keypath.
|
|
409
|
+
"""
|
|
410
|
+
|
|
411
|
+
if keypath:
|
|
412
|
+
try:
|
|
413
|
+
key_param = self.__search(*keypath, require_leaf=False)
|
|
414
|
+
except KeyError:
|
|
415
|
+
raise KeyError(f"[{','.join(keypath)}] is not a valid keypath")
|
|
416
|
+
if isinstance(key_param, Parameter):
|
|
417
|
+
return tuple()
|
|
418
|
+
else:
|
|
419
|
+
key_param = self
|
|
420
|
+
|
|
421
|
+
return tuple(key_param.__manifest.keys())
|
|
422
|
+
|
|
423
|
+
def allkeys(self, *keypath, include_default=True):
|
|
424
|
+
'''
|
|
425
|
+
Returns all keypaths in the schema as a set of tuples.
|
|
426
|
+
|
|
427
|
+
Arg:
|
|
428
|
+
keypath (list of str): Keypath prefix to search under. The
|
|
429
|
+
returned keypaths do not include the prefix.
|
|
430
|
+
'''
|
|
431
|
+
|
|
432
|
+
if keypath:
|
|
433
|
+
key_param = self.__manifest.get(keypath[0], None)
|
|
434
|
+
if not key_param or isinstance(key_param, Parameter):
|
|
435
|
+
return set()
|
|
436
|
+
return key_param.allkeys(*keypath[1:], include_default=include_default)
|
|
437
|
+
|
|
438
|
+
def add(keys, key, item):
|
|
439
|
+
if isinstance(item, Parameter):
|
|
440
|
+
keys.append((key,))
|
|
441
|
+
else:
|
|
442
|
+
for subkeypath in item.allkeys(include_default=include_default):
|
|
443
|
+
keys.append((key, *subkeypath))
|
|
444
|
+
|
|
445
|
+
keys = []
|
|
446
|
+
if include_default and self.__default:
|
|
447
|
+
add(keys, "default", self.__default)
|
|
448
|
+
for key, item in self.__manifest.items():
|
|
449
|
+
add(keys, key, item)
|
|
450
|
+
return set(keys)
|
|
451
|
+
|
|
452
|
+
def getdict(self, *keypath, include_default=True):
|
|
453
|
+
"""
|
|
454
|
+
Returns a schema dictionary.
|
|
455
|
+
|
|
456
|
+
Searches the schema for the keypath provided and returns a complete
|
|
457
|
+
dictionary.
|
|
458
|
+
|
|
459
|
+
Args:
|
|
460
|
+
keypath (list of str): Variable length ordered schema key list
|
|
461
|
+
include_default (boolean): If true will include default key paths
|
|
462
|
+
|
|
463
|
+
Returns:
|
|
464
|
+
A schema dictionary
|
|
465
|
+
|
|
466
|
+
Examples:
|
|
467
|
+
>>> pdk = schema.getdict('pdk')
|
|
468
|
+
Returns the complete dictionary found for the keypath [pdk]
|
|
469
|
+
"""
|
|
470
|
+
|
|
471
|
+
if keypath:
|
|
472
|
+
key_param = self.__manifest.get(keypath[0], None)
|
|
473
|
+
if not key_param:
|
|
474
|
+
return {}
|
|
475
|
+
return key_param.getdict(*keypath[1:], include_default=include_default)
|
|
476
|
+
|
|
477
|
+
manifest = {}
|
|
478
|
+
if include_default and self.__default:
|
|
479
|
+
manifest["default"] = self.__default.getdict(include_default=include_default)
|
|
480
|
+
for key, item in self.__manifest.items():
|
|
481
|
+
manifest[key] = item.getdict(include_default=include_default)
|
|
482
|
+
return manifest
|
|
483
|
+
|
|
484
|
+
# Utility functions
|
|
485
|
+
def copy(self, key=None):
|
|
486
|
+
"""
|
|
487
|
+
Returns a copy of this schema.
|
|
488
|
+
|
|
489
|
+
Args:
|
|
490
|
+
key (list of str): keypath to this schema
|
|
491
|
+
"""
|
|
492
|
+
|
|
493
|
+
return copy.deepcopy(self)
|