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.
Files changed (154) hide show
  1. siliconcompiler/__init__.py +19 -2
  2. siliconcompiler/_metadata.py +1 -1
  3. siliconcompiler/apps/sc.py +2 -2
  4. siliconcompiler/apps/sc_install.py +3 -3
  5. siliconcompiler/apps/sc_issue.py +1 -1
  6. siliconcompiler/apps/sc_remote.py +4 -4
  7. siliconcompiler/apps/sc_show.py +2 -2
  8. siliconcompiler/apps/utils/replay.py +5 -3
  9. siliconcompiler/asic.py +120 -0
  10. siliconcompiler/checklist.py +150 -0
  11. siliconcompiler/core.py +267 -289
  12. siliconcompiler/flowgraph.py +803 -515
  13. siliconcompiler/fpga.py +84 -0
  14. siliconcompiler/metric.py +420 -0
  15. siliconcompiler/optimizer/vizier.py +2 -3
  16. siliconcompiler/package/__init__.py +29 -6
  17. siliconcompiler/pdk.py +415 -0
  18. siliconcompiler/record.py +449 -0
  19. siliconcompiler/remote/client.py +6 -3
  20. siliconcompiler/remote/schema.py +116 -112
  21. siliconcompiler/remote/server.py +3 -5
  22. siliconcompiler/report/dashboard/cli/__init__.py +13 -722
  23. siliconcompiler/report/dashboard/cli/board.py +895 -0
  24. siliconcompiler/report/dashboard/web/__init__.py +10 -10
  25. siliconcompiler/report/dashboard/web/components/__init__.py +5 -4
  26. siliconcompiler/report/dashboard/web/components/flowgraph.py +3 -3
  27. siliconcompiler/report/dashboard/web/components/graph.py +6 -3
  28. siliconcompiler/report/dashboard/web/state.py +1 -1
  29. siliconcompiler/report/dashboard/web/utils/__init__.py +4 -3
  30. siliconcompiler/report/html_report.py +2 -3
  31. siliconcompiler/report/report.py +13 -7
  32. siliconcompiler/report/summary_image.py +1 -1
  33. siliconcompiler/report/summary_table.py +3 -3
  34. siliconcompiler/report/utils.py +11 -10
  35. siliconcompiler/scheduler/__init__.py +145 -280
  36. siliconcompiler/scheduler/run_node.py +2 -1
  37. siliconcompiler/scheduler/send_messages.py +4 -4
  38. siliconcompiler/scheduler/slurm.py +2 -2
  39. siliconcompiler/schema/__init__.py +19 -2
  40. siliconcompiler/schema/baseschema.py +493 -0
  41. siliconcompiler/schema/cmdlineschema.py +250 -0
  42. siliconcompiler/{sphinx_ext → schema/docs}/__init__.py +3 -1
  43. siliconcompiler/{sphinx_ext → schema/docs}/dynamicgen.py +63 -81
  44. siliconcompiler/{sphinx_ext → schema/docs}/schemagen.py +73 -85
  45. siliconcompiler/{sphinx_ext → schema/docs}/utils.py +12 -13
  46. siliconcompiler/schema/editableschema.py +136 -0
  47. siliconcompiler/schema/journalingschema.py +238 -0
  48. siliconcompiler/schema/namedschema.py +41 -0
  49. siliconcompiler/schema/packageschema.py +101 -0
  50. siliconcompiler/schema/parameter.py +791 -0
  51. siliconcompiler/schema/parametertype.py +323 -0
  52. siliconcompiler/schema/parametervalue.py +736 -0
  53. siliconcompiler/schema/safeschema.py +37 -0
  54. siliconcompiler/schema/schema_cfg.py +109 -1789
  55. siliconcompiler/schema/utils.py +5 -68
  56. siliconcompiler/schema_obj.py +119 -0
  57. siliconcompiler/tool.py +1308 -0
  58. siliconcompiler/tools/_common/__init__.py +6 -10
  59. siliconcompiler/tools/_common/sdc/sc_constraints.sdc +1 -1
  60. siliconcompiler/tools/bluespec/convert.py +7 -7
  61. siliconcompiler/tools/builtin/_common.py +1 -1
  62. siliconcompiler/tools/builtin/concatenate.py +2 -2
  63. siliconcompiler/tools/builtin/minimum.py +1 -1
  64. siliconcompiler/tools/builtin/mux.py +2 -1
  65. siliconcompiler/tools/builtin/nop.py +1 -1
  66. siliconcompiler/tools/builtin/verify.py +6 -4
  67. siliconcompiler/tools/chisel/convert.py +4 -4
  68. siliconcompiler/tools/genfasm/bitstream.py +3 -3
  69. siliconcompiler/tools/ghdl/convert.py +1 -1
  70. siliconcompiler/tools/icarus/compile.py +4 -4
  71. siliconcompiler/tools/icepack/bitstream.py +6 -1
  72. siliconcompiler/tools/klayout/convert_drc_db.py +5 -0
  73. siliconcompiler/tools/klayout/klayout_export.py +0 -1
  74. siliconcompiler/tools/klayout/klayout_utils.py +3 -10
  75. siliconcompiler/tools/nextpnr/apr.py +6 -1
  76. siliconcompiler/tools/nextpnr/nextpnr.py +4 -4
  77. siliconcompiler/tools/openroad/_apr.py +13 -0
  78. siliconcompiler/tools/openroad/rdlroute.py +3 -3
  79. siliconcompiler/tools/openroad/scripts/apr/postamble.tcl +1 -1
  80. siliconcompiler/tools/openroad/scripts/apr/preamble.tcl +5 -5
  81. siliconcompiler/tools/openroad/scripts/apr/sc_antenna_repair.tcl +2 -2
  82. siliconcompiler/tools/openroad/scripts/apr/sc_clock_tree_synthesis.tcl +2 -2
  83. siliconcompiler/tools/openroad/scripts/apr/sc_detailed_placement.tcl +2 -2
  84. siliconcompiler/tools/openroad/scripts/apr/sc_detailed_route.tcl +2 -2
  85. siliconcompiler/tools/openroad/scripts/apr/sc_endcap_tapcell_insertion.tcl +2 -2
  86. siliconcompiler/tools/openroad/scripts/apr/sc_fillercell_insertion.tcl +2 -2
  87. siliconcompiler/tools/openroad/scripts/apr/sc_fillmetal_insertion.tcl +2 -2
  88. siliconcompiler/tools/openroad/scripts/apr/sc_global_placement.tcl +2 -2
  89. siliconcompiler/tools/openroad/scripts/apr/sc_global_route.tcl +2 -2
  90. siliconcompiler/tools/openroad/scripts/apr/sc_init_floorplan.tcl +2 -2
  91. siliconcompiler/tools/openroad/scripts/apr/sc_macro_placement.tcl +3 -3
  92. siliconcompiler/tools/openroad/scripts/apr/sc_metrics.tcl +2 -2
  93. siliconcompiler/tools/openroad/scripts/apr/sc_pin_placement.tcl +2 -2
  94. siliconcompiler/tools/openroad/scripts/apr/sc_power_grid.tcl +2 -2
  95. siliconcompiler/tools/openroad/scripts/apr/sc_repair_design.tcl +2 -2
  96. siliconcompiler/tools/openroad/scripts/apr/sc_repair_timing.tcl +2 -2
  97. siliconcompiler/tools/openroad/scripts/apr/sc_write_data.tcl +2 -2
  98. siliconcompiler/tools/openroad/scripts/common/procs.tcl +57 -1
  99. siliconcompiler/tools/openroad/scripts/common/screenshot.tcl +2 -2
  100. siliconcompiler/tools/openroad/scripts/common/write_images.tcl +28 -3
  101. siliconcompiler/tools/openroad/scripts/sc_rcx.tcl +1 -1
  102. siliconcompiler/tools/openroad/scripts/sc_rdlroute.tcl +3 -3
  103. siliconcompiler/tools/openroad/scripts/sc_show.tcl +6 -6
  104. siliconcompiler/tools/slang/__init__.py +10 -10
  105. siliconcompiler/tools/surelog/parse.py +4 -4
  106. siliconcompiler/tools/sv2v/convert.py +20 -3
  107. siliconcompiler/tools/verilator/compile.py +2 -2
  108. siliconcompiler/tools/verilator/verilator.py +3 -3
  109. siliconcompiler/tools/vpr/place.py +1 -1
  110. siliconcompiler/tools/vpr/route.py +4 -4
  111. siliconcompiler/tools/vpr/screenshot.py +1 -1
  112. siliconcompiler/tools/vpr/show.py +5 -5
  113. siliconcompiler/tools/vpr/vpr.py +24 -24
  114. siliconcompiler/tools/xdm/convert.py +2 -2
  115. siliconcompiler/tools/xyce/simulate.py +1 -1
  116. siliconcompiler/tools/yosys/sc_synth_asic.tcl +74 -68
  117. siliconcompiler/tools/yosys/syn_asic.py +2 -2
  118. siliconcompiler/toolscripts/_tools.json +7 -7
  119. siliconcompiler/toolscripts/ubuntu22/install-vpr.sh +0 -2
  120. siliconcompiler/toolscripts/ubuntu24/install-vpr.sh +0 -2
  121. siliconcompiler/utils/__init__.py +8 -112
  122. siliconcompiler/utils/flowgraph.py +339 -0
  123. siliconcompiler/{issue.py → utils/issue.py} +4 -3
  124. siliconcompiler/utils/logging.py +1 -2
  125. {siliconcompiler-0.32.3.dist-info → siliconcompiler-0.33.0.dist-info}/METADATA +9 -8
  126. {siliconcompiler-0.32.3.dist-info → siliconcompiler-0.33.0.dist-info}/RECORD +151 -134
  127. {siliconcompiler-0.32.3.dist-info → siliconcompiler-0.33.0.dist-info}/WHEEL +1 -1
  128. {siliconcompiler-0.32.3.dist-info → siliconcompiler-0.33.0.dist-info}/entry_points.txt +8 -8
  129. siliconcompiler/schema/schema_obj.py +0 -1936
  130. siliconcompiler/toolscripts/ubuntu20/install-vpr.sh +0 -29
  131. siliconcompiler/toolscripts/ubuntu20/install-yosys-parmys.sh +0 -61
  132. /siliconcompiler/{templates → data/templates}/__init__.py +0 -0
  133. /siliconcompiler/{templates → data/templates}/email/__init__.py +0 -0
  134. /siliconcompiler/{templates → data/templates}/email/general.j2 +0 -0
  135. /siliconcompiler/{templates → data/templates}/email/summary.j2 +0 -0
  136. /siliconcompiler/{templates → data/templates}/issue/README.txt +0 -0
  137. /siliconcompiler/{templates → data/templates}/issue/__init__.py +0 -0
  138. /siliconcompiler/{templates → data/templates}/issue/run.sh +0 -0
  139. /siliconcompiler/{templates → data/templates}/replay/replay.py.j2 +0 -0
  140. /siliconcompiler/{templates → data/templates}/replay/replay.sh.j2 +0 -0
  141. /siliconcompiler/{templates → data/templates}/replay/requirements.txt +0 -0
  142. /siliconcompiler/{templates → data/templates}/replay/setup.sh +0 -0
  143. /siliconcompiler/{templates → data/templates}/report/__init__.py +0 -0
  144. /siliconcompiler/{templates → data/templates}/report/bootstrap.min.css +0 -0
  145. /siliconcompiler/{templates → data/templates}/report/bootstrap.min.js +0 -0
  146. /siliconcompiler/{templates → data/templates}/report/bootstrap_LICENSE.md +0 -0
  147. /siliconcompiler/{templates → data/templates}/report/sc_report.j2 +0 -0
  148. /siliconcompiler/{templates → data/templates}/slurm/__init__.py +0 -0
  149. /siliconcompiler/{templates → data/templates}/slurm/run.sh +0 -0
  150. /siliconcompiler/{templates → data/templates}/tcl/__init__.py +0 -0
  151. /siliconcompiler/{templates → data/templates}/tcl/manifest.tcl.j2 +0 -0
  152. /siliconcompiler/{units.py → utils/units.py} +0 -0
  153. {siliconcompiler-0.32.3.dist-info → siliconcompiler-0.33.0.dist-info}/licenses/LICENSE +0 -0
  154. {siliconcompiler-0.32.3.dist-info → siliconcompiler-0.33.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,250 @@
1
+ import argparse
2
+ import re
3
+ import sys
4
+
5
+
6
+ class CommandLineSchema:
7
+ '''
8
+ Class to provide the :meth:`create_cmdline` option to a schema object.
9
+
10
+ This class should not be instantiated by itself.
11
+
12
+ Examples:
13
+ class NewSchema(BaseSchema, CommandLineSchema):
14
+ creates a new class with the commandline options available
15
+ '''
16
+
17
+ ###########################################################################
18
+ def create_cmdline(self,
19
+ progname,
20
+ description=None,
21
+ switchlist=None,
22
+ additional_args=None,
23
+ version=None,
24
+ print_banner=None,
25
+ input_map_handler=None,
26
+ preprocess_keys=None,
27
+ post_process=None,
28
+ logger=None):
29
+ """Creates a Schema command line interface.
30
+
31
+ Exposes parameters in the SC schema as command line switches,
32
+ simplifying creation of SC apps with a restricted set of schema
33
+ parameters exposed at the command line. The order of command
34
+ line switch settings parsed from the command line is as follows:
35
+
36
+ 1. loglevel, if available in schema
37
+ 2. read_manifest([cfg]), if available in schema
38
+ 3. read inputs with input_map_handler
39
+ 4. all other switches
40
+ 5. Run post_process
41
+
42
+ The cmdline interface is implemented using the Python argparse package
43
+ and the following use restrictions apply.
44
+
45
+ * Help is accessed with the '-h' switch.
46
+ * Arguments that include spaces must be enclosed with double quotes.
47
+ * List parameters are entered individually. (ie. -y libdir1 -y libdir2)
48
+ * For parameters with Boolean types, the switch implies "true".
49
+ * Special characters (such as '-') must be enclosed in double quotes.
50
+ * Compiler compatible switches include: -D, -I, -O{0,1,2,3}
51
+ * Legacy switch formats are supported: +libext+, +incdir+
52
+
53
+ Args:
54
+ progname (str): Name of program to be executed.
55
+ description (str): Short program description.
56
+ switchlist (list of str): List of SC parameter switches to expose
57
+ at the command line. By default all SC schema switches are
58
+ available. Parameter switches should be entered based on the
59
+ parameter 'switch' field in the schema. For parameters with
60
+ multiple switches, both will be accepted if any one is included
61
+ in this list.
62
+ input_map (dict of str): Dictionary mapping file extensions to input
63
+ filetypes. This is used to automatically assign positional
64
+ source arguments to ['input', 'fileset', ...] keypaths based on their file
65
+ extension. If None, the CLI will not accept positional source
66
+ arguments.
67
+ additional_args (dict of dict): Dictionary of extra arguments to add
68
+ to the command line parser, with the arguments matching the
69
+ argparse.add_argument() call.
70
+ version (str): Version to report when calling with -version
71
+ print_banner (function): Function callback to print command line banner
72
+ input_map_handler (function): Function callback handle inputs to the input map
73
+ preprocess_keys (function): Function callback to preprocess keys that need to be
74
+ corrected
75
+ post_process (function): Function callback to process arguments before returning
76
+
77
+ Returns:
78
+ None if additional_args is not provided, otherwise a dictionary with the
79
+ command line options detected from the additional_args
80
+
81
+ Examples:
82
+ >>> schema.create_cmdline(progname='sc-show',switchlist=['-input','-cfg'])
83
+ Creates a command line interface for 'sc-show' app.
84
+ >>> schema.create_cmdline(progname='sc', input_map={'v': ('rtl', 'verilog')})
85
+ All sources ending in .v will be stored in ['input', 'rtl', 'verilog']
86
+ >>> extra = schema.create_cmdline(progname='sc',
87
+ additional_args={'-demo': {'action': 'store_true'}})
88
+ Returns extra = {'demo': False/True}
89
+ """
90
+
91
+ # Argparse
92
+ parser = argparse.ArgumentParser(prog=progname,
93
+ prefix_chars='-+',
94
+ formatter_class=argparse.RawDescriptionHelpFormatter,
95
+ description=description,
96
+ allow_abbrev=False)
97
+
98
+ # Create empty copy of schema
99
+ schema = type(self)()
100
+
101
+ # Track arguments
102
+ argument_map = {}
103
+ arguments = set()
104
+
105
+ # Iterate over all keys from an empty schema to add parser arguments
106
+ for keypath in sorted(schema.allkeys()):
107
+ param = schema.get(*keypath, field=None)
108
+
109
+ dest, switches = param.add_commandline_arguments(
110
+ parser,
111
+ *keypath,
112
+ switchlist=switchlist)
113
+
114
+ if switches:
115
+ argument_map[dest] = (keypath, param)
116
+ arguments.update(switches)
117
+
118
+ print_additional_arg_value = {}
119
+ if additional_args:
120
+ # Add additional user specified arguments
121
+ arg_dests = []
122
+ for arg, arg_detail in additional_args.items():
123
+ do_print = True
124
+ if "sc_print" in arg_detail:
125
+ do_print = arg_detail["sc_print"]
126
+ del arg_detail["sc_print"]
127
+ argument = parser.add_argument(arg, **arg_detail)
128
+ print_additional_arg_value[argument.dest] = do_print
129
+
130
+ arg_dests.append(argument.dest)
131
+ arguments.add(arg)
132
+ # rewrite additional_args with new dest information
133
+ additional_args = arg_dests
134
+
135
+ if version:
136
+ parser.add_argument('-version', action='version', version=version)
137
+
138
+ # Check if there are invalid switches
139
+ if switchlist:
140
+ for switch in switchlist:
141
+ if switch not in arguments:
142
+ raise ValueError(f'{switch} is not a valid commandline argument')
143
+
144
+ if input_map_handler:
145
+ parser.add_argument('source',
146
+ nargs='*',
147
+ help='Input files with filetype inferred by extension')
148
+
149
+ # Preprocess sys.argv to enable linux commandline switch formats
150
+ # (gcc, verilator, etc)
151
+ scargs = []
152
+
153
+ # Iterate from index 1, otherwise we end up with script name as a
154
+ # 'source' positional argument
155
+ for argument in sys.argv[1:]:
156
+ # Split switches with one character and a number after (O0,O1,O2)
157
+ opt = re.match(r'(\-\w)(\d+)', argument)
158
+ # Split assign switches (-DCFG_ASIC=1)
159
+ assign = re.search(r'(\-\w)(\w+\=\w+)', argument)
160
+ # Split plusargs (+incdir+/path)
161
+ plusarg = re.search(r'(\+\w+\+)(.*)', argument)
162
+ if opt:
163
+ scargs.append(opt.group(1))
164
+ scargs.append(opt.group(2))
165
+ elif plusarg:
166
+ scargs.append(plusarg.group(1))
167
+ scargs.append(plusarg.group(2))
168
+ elif assign:
169
+ scargs.append(assign.group(1))
170
+ scargs.append(assign.group(2))
171
+ else:
172
+ scargs.append(argument)
173
+
174
+ # Grab argument from pre-process sysargs
175
+ cmdargs = vars(parser.parse_args(scargs))
176
+
177
+ # Set loglevel if set at command line
178
+ do_print_banner = True
179
+ if 'option_loglevel' in cmdargs:
180
+ log_level = cmdargs['option_loglevel']
181
+ if isinstance(log_level, list):
182
+ # if multiple found, pick the first one
183
+ log_level = log_level[0]
184
+ if log_level == 'quiet':
185
+ do_print_banner = False
186
+ if logger:
187
+ logger.setLevel(log_level.split()[-1].upper())
188
+
189
+ if print_banner and do_print_banner:
190
+ print_banner()
191
+
192
+ extra_params = None
193
+ if additional_args:
194
+ # Grab user specified arguments
195
+ extra_params = {}
196
+ for arg in additional_args:
197
+ if arg in cmdargs:
198
+ val = cmdargs[arg]
199
+ if print_additional_arg_value[arg] and val and logger:
200
+ logger.info(
201
+ f'Command line argument entered: "{arg}" Value: {val}')
202
+ extra_params[arg] = val
203
+ # Remove from cmdargs
204
+ del cmdargs[arg]
205
+
206
+ # Read in all cfg files
207
+ if 'option_cfg' in cmdargs.keys():
208
+ for item in cmdargs['option_cfg']:
209
+ self.read_manifest(item)
210
+
211
+ if input_map_handler:
212
+ # Map sources to ['input'] keypath.
213
+ if 'source' in cmdargs:
214
+ input_map_handler(cmdargs['source'])
215
+ # we don't want to handle this in the next loop
216
+ del cmdargs['source']
217
+
218
+ # Cycle through all command args and write to manifest
219
+ for dest, vals in sorted(cmdargs.items(), key=lambda d: d[0]):
220
+ keypath, param = argument_map[dest]
221
+
222
+ # Turn everything into a list for uniformity
223
+ if not isinstance(vals, list):
224
+ vals = [vals]
225
+
226
+ # Cycle through all items
227
+ for item in vals:
228
+ if preprocess_keys:
229
+ item = preprocess_keys(keypath, item)
230
+
231
+ valkeypath, step, index, item = param.parse_commandline_arguments(item, *keypath)
232
+
233
+ if logger:
234
+ msg = f'Command line argument entered: [{",".join(valkeypath)}] Value: {item}'
235
+ if step is not None:
236
+ msg += f' step: {step}'
237
+ if index is not None:
238
+ msg += f' index: {index}'
239
+ logger.info(msg)
240
+
241
+ # Storing in manifest
242
+ if param.is_list():
243
+ self.add(*valkeypath, item, step=step, index=index)
244
+ else:
245
+ self.set(*valkeypath, item, step=step, index=index)
246
+
247
+ if post_process:
248
+ extra_params = post_process(cmdargs, extra_params)
249
+
250
+ return extra_params
@@ -1,5 +1,7 @@
1
1
  import os.path
2
2
 
3
+ from pathlib import PureWindowsPath
4
+
3
5
  import siliconcompiler
4
6
  from siliconcompiler import __version__ as sc_version
5
7
 
@@ -18,7 +20,7 @@ sc_root = os.path.dirname(os.path.dirname(os.path.abspath(siliconcompiler.__file
18
20
  def relpath(file):
19
21
  file = os.path.abspath(file)
20
22
  if file.startswith(sc_root):
21
- return os.path.relpath(file, sc_root)
23
+ return PureWindowsPath(os.path.relpath(file, sc_root)).as_posix()
22
24
  return None
23
25
 
24
26
 
@@ -17,9 +17,9 @@ import os
17
17
  import subprocess
18
18
 
19
19
  import siliconcompiler
20
- from siliconcompiler.sphinx_ext import sc_root as SC_ROOT
21
- from siliconcompiler.schema import Schema, utils
22
- from siliconcompiler.sphinx_ext.utils import (
20
+ from siliconcompiler.schema import utils
21
+ from siliconcompiler.schema.docs import sc_root as SC_ROOT
22
+ from siliconcompiler.schema.docs.utils import (
23
23
  strong,
24
24
  code,
25
25
  para,
@@ -39,15 +39,12 @@ from siliconcompiler.sphinx_ext.utils import (
39
39
  #############
40
40
 
41
41
 
42
- def build_schema_value_table(cfg, refdoc, keypath_prefix=None, skip_zero_weight=False):
42
+ def build_schema_value_table(params, refdoc, keypath_prefix=None):
43
43
  '''Helper function for displaying values set in schema as a docutils table.'''
44
44
  table = [[strong('Keypath'), strong('Value')]]
45
45
 
46
- # Nest received dictionary under keypath_prefix
47
- rooted_cfg = cfg
48
- if keypath_prefix:
49
- for key in reversed(keypath_prefix):
50
- rooted_cfg = {key: rooted_cfg}
46
+ if not keypath_prefix:
47
+ keypath_prefix = []
51
48
 
52
49
  def format_value(is_list, value):
53
50
  if is_list:
@@ -81,33 +78,27 @@ def build_schema_value_table(cfg, refdoc, keypath_prefix=None, skip_zero_weight=
81
78
  val_node = format_single_value_file(value, package)
82
79
  return val_node
83
80
 
84
- schema = Schema(rooted_cfg)
85
- for kp in schema.allkeys():
86
- if skip_zero_weight and \
87
- len(kp) == 6 and kp[0] == 'flowgraph' and kp[-2] == 'weight' and \
88
- schema.get(*kp) == 0:
89
- continue
90
-
91
- values = schema._getvals(*kp, return_defvalue=False)
81
+ for key, param in sorted(params.items(), key=lambda d: d[0]):
82
+ values = param.getvalues(return_defvalue=False)
92
83
  if values:
93
84
  # take first of multiple possible values
94
85
  value, step, index = values[0]
95
- val_type = schema.get(*kp, field='type')
86
+ val_type = param.get(field='type')
96
87
  is_filedir = 'file' in val_type or 'dir' in val_type
97
88
  # Don't display false booleans
98
89
  if val_type == 'bool' and value is False:
99
90
  continue
100
91
  if is_filedir:
101
92
  val_node = format_value_file(val_type.startswith('['), value,
102
- schema.get(*kp, field='package',
103
- step=step, index=index))
93
+ param.get(field='package',
94
+ step=step, index=index))
104
95
  else:
105
96
  val_node = format_value(val_type.startswith('['), value)
106
97
 
107
98
  # HTML builder fails if we don't make a text node the parent of the
108
99
  # reference node returned by keypath()
109
100
  p = nodes.paragraph()
110
- p += keypath(kp, refdoc)
101
+ p += keypath([*keypath_prefix, *key], refdoc)
111
102
  table.append([p, val_node])
112
103
 
113
104
  if len(table) > 1:
@@ -121,21 +112,21 @@ def build_schema_value_table(cfg, refdoc, keypath_prefix=None, skip_zero_weight=
121
112
 
122
113
 
123
114
  def build_package_table(schema):
124
- def collect_packages(cfg):
115
+ def collect_packages():
125
116
  packages = []
126
- if Schema._is_leaf(cfg):
127
- if 'dir' in cfg['type'] or 'file' in cfg['type']:
128
- for _, index_data in cfg['node'].items():
117
+ for key in schema.allkeys(include_default=True):
118
+ param = schema.get(*key, field=None)
119
+ if 'dir' in param.get(field='type') or 'file' in param.get(field='type'):
120
+ for _, index_data in param.getdict()["node"].items():
129
121
  for _, data in index_data.items():
122
+ if not data['package']:
123
+ continue
124
+ if isinstance(data['package'], str):
125
+ data['package'] = [data['package']]
130
126
  packages.extend(data['package'])
131
- else:
132
- for key in cfg:
133
- packages.extend(collect_packages(cfg[key]))
134
- packages = [p for p in packages if p]
135
- return list(set(packages))
127
+ return list(set([p for p in packages if p]))
136
128
 
137
- schema = Schema(cfg=schema)
138
- packages = collect_packages(schema.cfg)
129
+ packages = collect_packages()
139
130
 
140
131
  if not packages:
141
132
  return None
@@ -281,7 +272,7 @@ class DynamicGen(SphinxDirective):
281
272
  nested_parse_with_titles(self.state, rst, s)
282
273
 
283
274
  def package_information(self, chip, modname):
284
- packages = build_package_table(chip.schema.cfg)
275
+ packages = build_package_table(chip.schema)
285
276
  if packages:
286
277
  sec = build_section('Data sources', self.get_data_source_ref_key(modname, chip.design))
287
278
  sec += packages
@@ -435,12 +426,11 @@ class DynamicGen(SphinxDirective):
435
426
  if sec_key_prefix is None:
436
427
  sec_key_prefix = []
437
428
 
438
- leaves = {}
429
+ params = {}
439
430
  child_sections = []
440
431
  for key in schema.getkeys(*keypath):
441
- if Schema._is_leaf(schema.getdict(*keypath, key)):
442
- val = schema.getdict(*keypath, key)
443
- leaves.update({key: val})
432
+ if schema.valid(*keypath, key, check_complete=True):
433
+ params[(key,)] = schema.get(*keypath, key, field=None)
444
434
  else:
445
435
  children = self.build_config_recursive(
446
436
  schema,
@@ -450,9 +440,9 @@ class DynamicGen(SphinxDirective):
450
440
  child_sections.extend(children)
451
441
 
452
442
  schema_table = None
453
- if len(leaves) > 0:
443
+ if len(params) > 0:
454
444
  # Might return None is none of the leaves are displayable
455
- schema_table = build_schema_value_table(leaves, refdoc, keypath_prefix=keypath)
445
+ schema_table = build_schema_value_table(params, refdoc, keypath_prefix=keypath)
456
446
 
457
447
  if schema_table is not None:
458
448
  # If we've found leaves, create a new section where we'll display a
@@ -493,27 +483,22 @@ class FlowGen(DynamicGen):
493
483
  settings = build_section('Configuration', self.get_configuration_ref_key(name))
494
484
 
495
485
  steps = chip.getkeys('flowgraph', chip.design)
486
+ schema = chip.schema
496
487
  # TODO: should try to order?
497
488
 
498
489
  # Build section + table for each step (combining entries under flowgraph
499
490
  # and metric)
500
491
  for step in steps:
501
492
  section = build_section(step, self.get_ref(name, 'step', step))
502
- step_cfg = {}
503
- cfg = chip.getdict('flowgraph', chip.design, step)
504
- if cfg is None:
505
- continue
506
- schema = Schema(cfg=cfg)
507
- schema.prune()
508
- pruned = schema.cfg
509
- if chip.design not in step_cfg:
510
- step_cfg[chip.design] = {}
511
- step_cfg[chip.design][step] = pruned
512
-
513
- section += build_schema_value_table(step_cfg,
493
+
494
+ params = {}
495
+ for item in schema.allkeys('flowgraph', chip.design, step):
496
+ if item[1] == 'weight' and not schema.get('flowgraph', chip.design, step, *item):
497
+ continue
498
+ params[item] = schema.get('flowgraph', chip.design, step, *item, field=None)
499
+ section += build_schema_value_table(params,
514
500
  self.env.docname,
515
- keypath_prefix=['flowgraph'],
516
- skip_zero_weight=True)
501
+ keypath_prefix=['flowgraph', chip.design, step])
517
502
  settings += section
518
503
 
519
504
  return settings
@@ -636,15 +621,12 @@ class ToolGen(DynamicGen):
636
621
 
637
622
  def display_config(self, chip, modname):
638
623
  '''Display config under `eda, <modname>` in a single table.'''
639
- cfg = chip.getdict('tool', modname)
640
- schema = Schema(cfg=cfg)
641
- schema.prune()
642
- pruned = schema.cfg
643
- if 'task' in pruned:
644
- # Remove task specific items since they will be documented
645
- # by the task documentation
646
- del pruned['task']
647
- table = build_schema_value_table(pruned, self.env.docname, keypath_prefix=['tool', modname])
624
+ params = {}
625
+ for key in chip.schema.allkeys('tool', modname):
626
+ if key == 'task':
627
+ continue
628
+ params[key] = chip.schema.get('tool', modname, *key, field=None)
629
+ table = build_schema_value_table(params, self.env.docname, keypath_prefix=['tool', modname])
648
630
  if table is not None:
649
631
  return table
650
632
  else:
@@ -652,14 +634,13 @@ class ToolGen(DynamicGen):
652
634
 
653
635
  def task_display_config(self, chip, toolname, taskname):
654
636
  '''Display config under `eda, <modname>` in a single table.'''
655
- cfg = chip.getdict('tool', toolname, 'task', taskname)
656
- schema = Schema(cfg=cfg)
657
- for vals, step, index in schema._getvals('require'):
658
- schema.set('require', sorted(set(vals)),
659
- step=step, index=index)
660
- schema.prune()
661
- pruned = schema.cfg
662
- table = build_schema_value_table(pruned, self.env.docname,
637
+ params = {}
638
+ for key in chip.schema.allkeys('tool', toolname, 'task', taskname):
639
+ params[key] = chip.schema.get('tool', toolname, 'task', taskname, *key, field=None)
640
+ if key[0] == "require":
641
+ for vals, step, index in params[key].getvalues():
642
+ params[key].set(sorted(set(vals)), step=step, index=index)
643
+ table = build_schema_value_table(params, self.env.docname,
663
644
  keypath_prefix=['tool', toolname, 'task', taskname])
664
645
  if table is not None:
665
646
  return table
@@ -731,7 +712,7 @@ class ToolGen(DynamicGen):
731
712
  s)
732
713
  except Exception as e:
733
714
  print(f'Failed to document task, Chip object probably not configured correctly: {e}')
734
- return None
715
+ raise e
735
716
 
736
717
  return s
737
718
 
@@ -803,7 +784,7 @@ class TargetGen(DynamicGen):
803
784
  if len(modules) > 0:
804
785
  section = build_section(header, self.get_ref(targetname, modtype))
805
786
  modlist = nodes.bullet_list()
806
- for module in modules:
787
+ for module in sorted(modules):
807
788
  list_item = nodes.list_item()
808
789
  # TODO: replace with proper docutils nodes: sphinx.addnodes.pending_xref
809
790
  modkey = get_ref_id(DynamicGen.get_ref_key(*refprefix, module))
@@ -839,14 +820,12 @@ class TargetGen(DynamicGen):
839
820
 
840
821
  filtered_cfg = {}
841
822
  for key in ('asic', 'constraint', 'option'):
842
- filtered_cfg[key] = chip.getdict(key)
843
- schema = Schema(cfg=filtered_cfg)
844
- schema.prune()
845
- pruned_cfg = schema.cfg
823
+ for subkey in chip.schema.allkeys(key):
824
+ filtered_cfg[(key, *subkey)] = chip.schema.get(key, *subkey, field=None)
846
825
 
847
- if len(pruned_cfg) > 0:
826
+ if filtered_cfg:
848
827
  schema_section = build_section('Configuration', self.get_configuration_ref_key(modname))
849
- schema_section += build_schema_value_table(pruned_cfg, self.env.docname)
828
+ schema_section += build_schema_value_table(filtered_cfg, self.env.docname)
850
829
  sections.append(schema_section)
851
830
 
852
831
  return sections
@@ -892,15 +871,18 @@ class ChecklistGen(DynamicGen):
892
871
  name = chip.design
893
872
 
894
873
  keypath_prefix = ['checklist', name]
895
- cfg = chip.getdict(*keypath_prefix)
874
+ schema = chip.schema
896
875
 
897
876
  settings = build_section('Configuration', self.get_configuration_ref_key(name))
898
877
 
899
- for key in cfg.keys():
878
+ for key in schema.getkeys(*keypath_prefix):
900
879
  if key == 'default':
901
880
  continue
902
881
  settings += build_section(key, self.get_ref(name, 'key', key))
903
- settings += build_schema_value_table(cfg[key], self.env.docname,
882
+ params = {}
883
+ for item in schema.allkeys(*keypath_prefix, key):
884
+ params[item] = schema.get(*keypath_prefix, key, *item, field=None)
885
+ settings += build_schema_value_table(params, self.env.docname,
904
886
  keypath_prefix=[*keypath_prefix, key])
905
887
 
906
888
  sections.append(settings)