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,449 @@
1
+ # Copyright 2025 Silicon Compiler Authors. All Rights Reserved.
2
+
3
+ import distro
4
+ import getpass
5
+ import platform
6
+ import psutil
7
+ import shlex
8
+ import socket
9
+
10
+ from datetime import datetime, timezone
11
+ from enum import Enum
12
+
13
+ from siliconcompiler.schema import BaseSchema
14
+ from siliconcompiler.schema import EditableSchema, Parameter, PerNode, Scope
15
+ from siliconcompiler.schema.utils import trim
16
+
17
+ from siliconcompiler import _metadata
18
+
19
+
20
+ class RecordTime(Enum):
21
+ START = "starttime"
22
+ END = "endtime"
23
+
24
+
25
+ class RecordTool(Enum):
26
+ EXITCODE = "toolexitcode"
27
+ VERSION = "toolversion"
28
+ PATH = "toolpath"
29
+ ARGS = "toolargs"
30
+
31
+
32
+ class RecordSchema(BaseSchema):
33
+ __TIMEFORMAT = "%Y-%m-%d %H:%M:%S"
34
+
35
+ def __init__(self):
36
+ super().__init__()
37
+
38
+ schema_record(self)
39
+
40
+ def clear(self, step, index, keep=None):
41
+ '''
42
+ Clear all saved metrics for a given step and index
43
+
44
+ Args:
45
+ step (str): Step name to clear.
46
+ index (str): Index name to clear.
47
+ keep (list of str): list of records to keep.
48
+ '''
49
+
50
+ if not keep:
51
+ keep = []
52
+
53
+ for record in self.getkeys():
54
+ if record in keep:
55
+ continue
56
+ param = self.get(record, field=None)
57
+
58
+ if param.get(field='pernode').is_never():
59
+ param.unset()
60
+ else:
61
+ param.unset(step=step, index=index)
62
+
63
+ def record_python_packages(self):
64
+ '''
65
+ Record the python packages currently available in the environment.
66
+ '''
67
+ try:
68
+ from pip._internal.operations.freeze import freeze
69
+ except: # noqa E722
70
+ freeze = None
71
+
72
+ if freeze:
73
+ # clear record
74
+ self.set('pythonpackage', [])
75
+
76
+ for pkg in freeze():
77
+ self.add('pythonpackage', pkg)
78
+
79
+ def record_version(self, step, index):
80
+ '''
81
+ Records the versions for SiliconCompiler and python.
82
+
83
+ Args:
84
+ step (str): Step name to associate.
85
+ index (str): Index name to associate.
86
+ '''
87
+ self.set('scversion', _metadata.version, step=step, index=index)
88
+ self.set('pythonversion', platform.python_version(), step=step, index=index)
89
+
90
+ @staticmethod
91
+ def get_cloud_information():
92
+ '''
93
+ Return information about the cloud environment.
94
+
95
+ Return format: {
96
+ "region": str
97
+ }
98
+ '''
99
+ # TODO: add logic to figure out if we're running on a remote cluster and
100
+ # extract the region in a provider-specific way.
101
+ return {"region": "local"}
102
+
103
+ @staticmethod
104
+ def get_ip_information():
105
+ '''
106
+ Return information about the ip and mac address of this machine.
107
+
108
+ Return format: {
109
+ "ip": str,
110
+ "mac": str
111
+ }
112
+ '''
113
+ try:
114
+ for interface, addrs in psutil.net_if_addrs().items():
115
+ if interface == 'lo':
116
+ # don't consider loopback device
117
+ continue
118
+
119
+ if not addrs:
120
+ # skip missing addrs
121
+ continue
122
+
123
+ use_addr = False
124
+ for addr in addrs:
125
+ if addr.family == socket.AF_INET:
126
+ if not addr.address.startswith('127.'):
127
+ use_addr = True
128
+ break
129
+ if addr.family == socket.AF_INET6:
130
+ if addr.address != "::1":
131
+ use_addr = True
132
+ break
133
+
134
+ if use_addr:
135
+ ipaddr = None
136
+ macaddr = None
137
+ for addr in addrs:
138
+ if not ipaddr and addr.family == socket.AF_INET:
139
+ ipaddr = addr.address
140
+ if not ipaddr and addr.family == socket.AF_INET6:
141
+ ipaddr = addr.address
142
+ if not macaddr and addr.family == psutil.AF_LINK:
143
+ macaddr = addr.address
144
+
145
+ return {"ip": ipaddr, "mac": macaddr}
146
+ except: # noqa E722
147
+ pass
148
+
149
+ return {"ip": None, "mac": None}
150
+
151
+ @staticmethod
152
+ def get_machine_information():
153
+ '''
154
+ Return information about the machine.
155
+
156
+ Return format: {
157
+ "machine": str,
158
+ "system": str,
159
+ "distro": str,
160
+ "osversion": str,
161
+ "kernelversion": str,
162
+ "arch": str
163
+ }
164
+ '''
165
+ system = platform.system()
166
+ if system == 'Darwin':
167
+ lower_sys_name = 'macos'
168
+ else:
169
+ lower_sys_name = system.lower()
170
+
171
+ if system == 'Linux':
172
+ distro_name = distro.id()
173
+ else:
174
+ distro_name = None
175
+
176
+ if system == 'Darwin':
177
+ osversion, _, _ = platform.mac_ver()
178
+ elif system == 'Linux':
179
+ osversion = distro.version()
180
+ else:
181
+ osversion = platform.release()
182
+
183
+ kernelversion = None
184
+ if system == 'Linux':
185
+ kernelversion = platform.release()
186
+ elif system == 'Windows':
187
+ kernelversion = platform.version()
188
+ elif system == 'Darwin':
189
+ kernelversion = platform.release()
190
+
191
+ return {'name': platform.node(),
192
+ 'system': lower_sys_name,
193
+ 'distro': distro_name,
194
+ 'osversion': osversion,
195
+ 'kernelversion': kernelversion,
196
+ 'arch': platform.machine()}
197
+
198
+ @staticmethod
199
+ def get_user_information():
200
+ '''
201
+ Return information about the user.
202
+
203
+ Return format: {"username": str}
204
+ '''
205
+ return {'username': getpass.getuser()}
206
+
207
+ def record_userinformation(self, step, index):
208
+ '''
209
+ Records information about the current machine and user.
210
+ Uses information from :meth:`get_machine_information`, :meth:`get_user_information`,
211
+ :meth:`get_cloud_information`, and :meth:`get_ip_information`.
212
+
213
+ Args:
214
+ step (str): Step name to associate.
215
+ index (str): Index name to associate.
216
+ '''
217
+ machine_info = RecordSchema.get_machine_information()
218
+ user_info = RecordSchema.get_user_information()
219
+ cloud_info = RecordSchema.get_cloud_information()
220
+ ip_information = RecordSchema.get_ip_information()
221
+
222
+ self.set('platform', machine_info['system'], step=step, index=index)
223
+ if machine_info['distro']:
224
+ self.set('distro', machine_info['distro'], step=step, index=index)
225
+ self.set('osversion', machine_info['osversion'], step=step, index=index)
226
+ if machine_info['kernelversion']:
227
+ self.set('kernelversion', machine_info['kernelversion'], step=step, index=index)
228
+ self.set('arch', machine_info['arch'], step=step, index=index)
229
+ self.set('machine', machine_info['name'], step=step, index=index)
230
+ self.set('userid', user_info['username'], step=step, index=index)
231
+ self.set('region', cloud_info['region'], step=step, index=index)
232
+
233
+ if ip_information['ip']:
234
+ self.set('ipaddr', ip_information['ip'], step=step, index=index)
235
+ if ip_information['mac']:
236
+ self.set('macaddr', ip_information['mac'], step=step, index=index)
237
+
238
+ def record_time(self, step, index, type):
239
+ '''
240
+ Record the time of the record.
241
+
242
+ Returns:
243
+ time recorded.
244
+
245
+ Args:
246
+ step (str): Step name to associate.
247
+ index (str): Index name to associate.
248
+ type (:class:`RecordTime`): type of time to record
249
+ '''
250
+ type = RecordTime(type)
251
+
252
+ now = datetime.now(timezone.utc)
253
+
254
+ self.set(type.value,
255
+ now.strftime(RecordSchema.__TIMEFORMAT),
256
+ step=step, index=index)
257
+
258
+ return now.timestamp()
259
+
260
+ def get_recorded_time(self, step, index, type):
261
+ '''
262
+ Returns the time recorded for a given record.
263
+
264
+ Args:
265
+ step (str): Step name to associate.
266
+ index (str): Index name to associate.
267
+ type (:class:`RecordTime`): type of time to record
268
+ '''
269
+ type = RecordTime(type)
270
+ return datetime.strptime(
271
+ self.get(type.value, step=step, index=index)+"+0000",
272
+ RecordSchema.__TIMEFORMAT+"%z").timestamp()
273
+
274
+ def record_tool(self, step, index, info, type):
275
+ '''
276
+ Record information about the tool used during this record.
277
+
278
+ Args:
279
+ step (str): Step name to associate.
280
+ index (str): Index name to associate.
281
+ info (any): Information to record.
282
+ type (:class:`RecordTool`): type of tool information being recorded
283
+ '''
284
+ if type == RecordTool.ARGS:
285
+ info = shlex.join(info)
286
+ self.set(type.value, info, step=step, index=index)
287
+
288
+
289
+ ###########################################################################
290
+ # Run Record
291
+ ###########################################################################
292
+ def schema_record(schema):
293
+ schema = EditableSchema(schema)
294
+ records = {'userid': ['userid',
295
+ 'wiley',
296
+ ''],
297
+ 'publickey': ['public key',
298
+ '<key>',
299
+ ''],
300
+ 'machine': ['machine name',
301
+ 'carbon',
302
+ '(myhost, localhost, ...'],
303
+ 'macaddr': ['MAC address',
304
+ '<addr>',
305
+ ''],
306
+ 'ipaddr': ['IP address',
307
+ '<addr>',
308
+ ''],
309
+ 'platform': ['platform name',
310
+ 'linux',
311
+ '(linux, windows, freebsd)'],
312
+ 'distro': ['distro name',
313
+ 'ubuntu',
314
+ '(ubuntu, redhat, centos)'],
315
+ 'arch': ['hardware architecture',
316
+ 'x86_64',
317
+ '(x86_64, rv64imafdc)'],
318
+ 'starttime': ['start time',
319
+ '\"2021-09-06 12:20:20\"',
320
+ 'Time is reported in the ISO 8601 format YYYY-MM-DD HR:MIN:SEC'],
321
+ 'endtime': ['end time',
322
+ '\"2021-09-06 12:20:20\"',
323
+ 'Time is reported in the ISO 8601 format YYYY-MM-DD HR:MIN:SEC'],
324
+ 'region': ['cloud region',
325
+ '\"US Gov Boston\"',
326
+ """Recommended naming methodology:
327
+
328
+ * local: node is the local machine
329
+ * onprem: node in on-premises IT infrastructure
330
+ * public: generic public cloud
331
+ * govcloud: generic US government cloud
332
+ * <region>: cloud and entity specific region string name
333
+ """],
334
+ 'scversion': ['software version',
335
+ '1.0',
336
+ """Version number for the SiliconCompiler software."""],
337
+ 'toolversion': ['tool version',
338
+ '1.0',
339
+ """The tool version captured corresponds to the 'tool'
340
+ parameter within the 'tool' dictionary."""],
341
+ 'toolpath': ['tool path',
342
+ '/usr/bin/openroad',
343
+ """Full path to tool executable used to run this
344
+ task."""],
345
+ 'toolargs': ['tool CLI arguments',
346
+ '\"-I include/ foo.v\"',
347
+ 'Arguments passed to tool via CLI.'],
348
+ 'pythonversion': ['Python version',
349
+ '3.12.3',
350
+ """Version of python used to run this task."""],
351
+ 'osversion': ['O/S version',
352
+ '20.04.1-Ubuntu',
353
+ """Since there is not standard version system for operating
354
+ systems, extracting information from is platform dependent.
355
+ For Linux based operating systems, the 'osversion' is the
356
+ version of the distro."""],
357
+ 'kernelversion': ['O/S kernel version',
358
+ '5.11.0-34-generic',
359
+ """Used for platforms that support a distinction
360
+ between os kernels and os distributions."""]}
361
+
362
+ for key, (shorthelp, example, longhelp) in records.items():
363
+ schema.insert(
364
+ key,
365
+ Parameter(
366
+ "str",
367
+ scope=Scope.JOB,
368
+ shorthelp=f"Record: {shorthelp}",
369
+ switch=f"-record_{key} 'step index <str>'",
370
+ example=[
371
+ f"cli: -record_{key} 'dfm 0 {example}'",
372
+ f"api: chip.set('record', '{key}', '{example}', step='dfm', index=0)"],
373
+ pernode=PerNode.REQUIRED,
374
+ help=f'Record tracking the {shorthelp} per step and index basis.'
375
+ f'{" " + trim(longhelp) if longhelp else ""}'
376
+ ))
377
+
378
+ schema.insert(
379
+ "toolexitcode",
380
+ Parameter(
381
+ "int",
382
+ scope=Scope.JOB,
383
+ shorthelp="Record: tool exit code",
384
+ switch="-record_toolexitcode 'step index <int>'",
385
+ example=[
386
+ "cli: -record_toolexitcode 'dfm 0 0'",
387
+ "api: chip.set('record', 'toolexitcode', 0, step='dfm', index=0)"],
388
+ pernode=PerNode.REQUIRED,
389
+ help='Record tracking the tool exit code per step and index basis.'
390
+ ))
391
+
392
+ # Non-per-node records.
393
+ schema.insert(
394
+ "remoteid",
395
+ Parameter(
396
+ "str",
397
+ scope=Scope.JOB,
398
+ shorthelp="Record: remote job ID",
399
+ switch="-record_remoteid '<str>'",
400
+ example=[
401
+ "cli: -record_remoteid '0123456789abcdeffedcba9876543210'",
402
+ "api: chip.set('record', 'remoteid', '0123456789abcdeffedcba9876543210')"],
403
+ help='Record tracking the job ID for a remote run.'
404
+ ))
405
+
406
+ schema.insert(
407
+ "pythonpackage",
408
+ Parameter(
409
+ "[str]",
410
+ scope=Scope.JOB,
411
+ shorthelp="Record: python packages",
412
+ switch="-record_pythonpackage '<str>'",
413
+ example=[
414
+ "cli: -record_pythonpackage 'siliconcompiler==0.28.0'",
415
+ "api: chip.set('record', 'pythonpackage', 'siliconcompiler==0.28.0')"],
416
+ help='Record tracking for the python packages installed.'
417
+ ))
418
+
419
+ # flowgraph status
420
+ schema.insert(
421
+ "status",
422
+ Parameter(
423
+ "<pending,queued,running,success,error,skipped,timeout>", # sync with NodeStatus
424
+ pernode=PerNode.REQUIRED,
425
+ scope=Scope.JOB,
426
+ shorthelp="Record: node execution status",
427
+ switch="-record_status 'step index <str>'",
428
+ example=[
429
+ "cli: -record_status 'syn 0 success'",
430
+ "api: chip.set('record', 'status', 'success', step='syn', index='0')"],
431
+ help="""Record tracking for the status of a node."""
432
+ ))
433
+
434
+ # flowgraph select
435
+ schema.insert(
436
+ "inputnode",
437
+ Parameter(
438
+ "[(str,str)]",
439
+ pernode=PerNode.REQUIRED,
440
+ scope=Scope.JOB,
441
+ shorthelp="Record: node inputs",
442
+ switch="-record_inputnode 'step index <(str,str)>'",
443
+ example=[
444
+ "cli: -record_inputnode 'cts 0 (place,42)'",
445
+ "api: chip.set('record', 'inputnode', ('place', '42'), step='syn', index='0')"],
446
+ help=trim("""
447
+ List of selected inputs for the current step/index specified as
448
+ (in_step, in_index) tuple.""")
449
+ ))
@@ -13,7 +13,7 @@ import multiprocessing
13
13
  from siliconcompiler import utils, SiliconCompilerError, NodeStatus
14
14
  from siliconcompiler import NodeStatus as SCNodeStatus
15
15
  from siliconcompiler._metadata import default_server
16
- from siliconcompiler.flowgraph import nodes_to_execute
16
+ from siliconcompiler.utils.flowgraph import nodes_to_execute
17
17
  from siliconcompiler.remote import JobStatus
18
18
  from siliconcompiler.report.dashboard import DashboardType
19
19
 
@@ -504,7 +504,7 @@ service, provided by SiliconCompiler, is not intended to process proprietary IP.
504
504
  # Redirected POST requests are translated to GETs. This is actually
505
505
  # part of the HTTP spec, so we need to manually follow the trail.
506
506
  post_params = {
507
- 'chip_cfg': self.__chip.schema.cfg,
507
+ 'chip_cfg': self.__chip.schema.getdict(),
508
508
  'params': self.__get_post_params(include_job_id=True)
509
509
  }
510
510
 
@@ -546,8 +546,11 @@ service, provided by SiliconCompiler, is not intended to process proprietary IP.
546
546
  key_type = self.__chip.get(*key, field='type')
547
547
 
548
548
  if 'dir' in key_type or 'file' in key_type:
549
- for _, step, index in self.__chip.schema._getvals(*key, return_defvalue=False):
549
+ for _, step, index in self.__chip.schema.get(*key, field=None).getvalues(
550
+ return_defvalue=False):
550
551
  packages = self.__chip.get(*key, field='package', step=step, index=index)
552
+ if not isinstance(packages, list):
553
+ packages = [packages]
551
554
  force_copy = False
552
555
  for package in packages:
553
556
  if not package: