siliconcompiler 0.35.0__py3-none-any.whl → 0.35.1__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 (49) hide show
  1. siliconcompiler/_metadata.py +1 -1
  2. siliconcompiler/apps/_common.py +3 -2
  3. siliconcompiler/apps/sc_dashboard.py +3 -1
  4. siliconcompiler/apps/sc_install.py +149 -37
  5. siliconcompiler/apps/smake.py +9 -3
  6. siliconcompiler/checklist.py +3 -3
  7. siliconcompiler/data/demo_fpga/z1000_yosys_config.json +24 -0
  8. siliconcompiler/design.py +51 -45
  9. siliconcompiler/flowgraph.py +2 -2
  10. siliconcompiler/library.py +23 -12
  11. siliconcompiler/package/__init__.py +77 -49
  12. siliconcompiler/package/git.py +11 -6
  13. siliconcompiler/package/github.py +11 -6
  14. siliconcompiler/package/https.py +6 -4
  15. siliconcompiler/pdk.py +23 -16
  16. siliconcompiler/scheduler/scheduler.py +30 -22
  17. siliconcompiler/scheduler/schedulernode.py +60 -50
  18. siliconcompiler/scheduler/taskscheduler.py +52 -32
  19. siliconcompiler/schema/baseschema.py +88 -69
  20. siliconcompiler/schema/docs/schemagen.py +4 -3
  21. siliconcompiler/schema/editableschema.py +5 -5
  22. siliconcompiler/schema/journal.py +19 -13
  23. siliconcompiler/schema/namedschema.py +16 -10
  24. siliconcompiler/schema/parameter.py +64 -37
  25. siliconcompiler/schema/parametervalue.py +126 -80
  26. siliconcompiler/schema/safeschema.py +16 -7
  27. siliconcompiler/schema/utils.py +3 -1
  28. siliconcompiler/schema_support/cmdlineschema.py +9 -9
  29. siliconcompiler/schema_support/dependencyschema.py +12 -7
  30. siliconcompiler/schema_support/filesetschema.py +15 -10
  31. siliconcompiler/schema_support/metric.py +29 -17
  32. siliconcompiler/schema_support/packageschema.py +2 -2
  33. siliconcompiler/schema_support/pathschema.py +30 -18
  34. siliconcompiler/schema_support/record.py +30 -23
  35. siliconcompiler/tool.py +265 -210
  36. siliconcompiler/tools/opensta/timing.py +13 -0
  37. siliconcompiler/tools/yosys/syn_fpga.py +3 -2
  38. siliconcompiler/toolscripts/_tools.json +3 -3
  39. siliconcompiler/utils/__init__.py +23 -16
  40. siliconcompiler/utils/curation.py +11 -5
  41. siliconcompiler/utils/multiprocessing.py +16 -14
  42. siliconcompiler/utils/paths.py +24 -12
  43. siliconcompiler/utils/units.py +16 -12
  44. {siliconcompiler-0.35.0.dist-info → siliconcompiler-0.35.1.dist-info}/METADATA +3 -4
  45. {siliconcompiler-0.35.0.dist-info → siliconcompiler-0.35.1.dist-info}/RECORD +49 -48
  46. {siliconcompiler-0.35.0.dist-info → siliconcompiler-0.35.1.dist-info}/entry_points.txt +4 -3
  47. {siliconcompiler-0.35.0.dist-info → siliconcompiler-0.35.1.dist-info}/WHEEL +0 -0
  48. {siliconcompiler-0.35.0.dist-info → siliconcompiler-0.35.1.dist-info}/licenses/LICENSE +0 -0
  49. {siliconcompiler-0.35.0.dist-info → siliconcompiler-0.35.1.dist-info}/top_level.txt +0 -0
@@ -1,5 +1,5 @@
1
1
  # Version number following semver standard.
2
- version = '0.35.0'
2
+ version = '0.35.1'
3
3
 
4
4
  # Default server address for remote runs, if unspecified.
5
5
  default_server = 'https://server.siliconcompiler.com'
@@ -90,7 +90,8 @@ def _get_manifests(cwd: str) -> Dict:
90
90
  return organized_manifest
91
91
 
92
92
 
93
- def pick_manifest_from_file(cliproject: Project, src_file: str, all_manifests: Dict):
93
+ def pick_manifest_from_file(cliproject: Project, src_file: Optional[str], all_manifests: Dict) \
94
+ -> Optional[str]:
94
95
  """
95
96
  Tries to find a manifest located in the same directory as a given source file.
96
97
 
@@ -125,7 +126,7 @@ def pick_manifest_from_file(cliproject: Project, src_file: str, all_manifests: D
125
126
  return None
126
127
 
127
128
 
128
- def pick_manifest(cliproject: Project, src_file: Optional[str] = None):
129
+ def pick_manifest(cliproject: Project, src_file: Optional[str] = None) -> Optional[str]:
129
130
  """
130
131
  Selects the most appropriate manifest based on the project's configuration.
131
132
 
@@ -4,6 +4,8 @@ import shlex
4
4
 
5
5
  import os.path
6
6
 
7
+ from typing import Union
8
+
7
9
  from siliconcompiler import Project
8
10
  from siliconcompiler.apps._common import pick_manifest
9
11
  from siliconcompiler.report.dashboard.web import WebDashboard
@@ -56,7 +58,7 @@ To include another project object to compare to:
56
58
  '-graph_cfg'],
57
59
  use_sources=False)
58
60
 
59
- manifest = cli.get("cmdarg", "cfg")
61
+ manifest: Union[None, str] = cli.get("cmdarg", "cfg")
60
62
 
61
63
  # Attempt to load a manifest
62
64
  if not manifest:
@@ -8,12 +8,53 @@ import sys
8
8
 
9
9
  import os.path
10
10
 
11
+ from typing import Dict, List, Optional, Set
12
+
11
13
  from collections.abc import Container
12
14
  from pathlib import Path
13
15
 
14
16
  import siliconcompiler
15
17
 
16
18
  from siliconcompiler.schema_support.record import RecordSchema
19
+ from siliconcompiler.utils import get_plugins
20
+
21
+
22
+ def get_install_groups() -> Dict[str, List[str]]:
23
+ """
24
+ Provide recommended install tool groups for common workflows.
25
+
26
+ Each mapping key is a high-level group name and each value is an ordered list of tool
27
+ identifiers suitable for that group.
28
+
29
+ Returns:
30
+ dict: Mapping from group name (str) to a list of tool identifiers (List[str]).
31
+ """
32
+ return {
33
+ "asic": ["sv2v", "yosys", "yosys-slang", "openroad", "klayout"],
34
+ "asic-hls": ["bambu", "yosys", "yosys-slang", "openroad", "klayout"],
35
+ "fpga": ["sv2v", "yosys", "yosys-slang", "vpr", "yosys-wildebeest"],
36
+ "digital-simulation": ["verilator", "icarus", "surfer"],
37
+ "analog-simulation": ["xyce"]
38
+ }
39
+
40
+
41
+ def get_install_tools(osname: str) -> Dict[str, str]:
42
+ tools_root = _get_tool_script_dir()
43
+
44
+ script_dir = None
45
+ if osname:
46
+ script_dir = tools_root / osname
47
+ if not script_dir.exists():
48
+ script_dir = None
49
+
50
+ tools = {}
51
+ if script_dir:
52
+ for script in glob.glob(str(script_dir / "install-*.sh")):
53
+ tool = re.match(r"install-(.*)\.sh", os.path.basename(script).lower())
54
+ if tool:
55
+ tools[tool.group(1)] = script
56
+
57
+ return tools
17
58
 
18
59
 
19
60
  class ChoiceOptional(Container):
@@ -29,18 +70,45 @@ class ChoiceOptional(Container):
29
70
  return item in self.__choices
30
71
 
31
72
  def __iter__(self):
73
+ """
74
+ Iterate over the stored choices.
75
+
76
+ Returns:
77
+ iterator: An iterator over the stored choice strings.
78
+ """
32
79
  return self.__choices.__iter__()
33
80
 
34
- def get_items(self, choices):
81
+ def get_items(self, choices: List[str]) -> List[str]:
82
+ """
83
+ Return a sorted list of unique choice strings.
84
+
85
+ Parameters:
86
+ choices (List[str]): Iterable of choice strings which may contain duplicates.
87
+
88
+ Returns:
89
+ List[str]: Sorted list containing each unique choice from `choices`.
90
+ """
35
91
  items = set(choices)
36
92
  return sorted(items)
37
93
 
38
94
 
39
- def install_tool(tool, script, build_dir, prefix):
40
- # Ensure build dir is available
41
- build_dir = Path(build_dir) / tool
42
- shutil.rmtree(str(build_dir), ignore_errors=True)
43
- build_dir.mkdir(parents=True, exist_ok=True)
95
+ def install_tool(tool: str, script: str, build_dir: str, prefix: str) -> bool:
96
+ """
97
+ Prepare a build directory, configure the environment, and execute an install script for a tool.
98
+
99
+ Parameters:
100
+ tool (str): Tool identifier used to create a per-tool build subdirectory under `build_dir`.
101
+ script (str): Path to the install script to execute.
102
+ build_dir (str): Base directory where a per-tool build directory will be created.
103
+ prefix (str): Installation prefix; added to PATH and used to determine whether
104
+ sudo is required.
105
+
106
+ Returns:
107
+ bool: `True` if the install script exited with status 0, `False` otherwise.
108
+ """
109
+ build_path = Path(build_dir) / tool
110
+ shutil.rmtree(str(build_path), ignore_errors=True)
111
+ build_path.mkdir(parents=True, exist_ok=True)
44
112
 
45
113
  # setup environment
46
114
  env = os.environ.copy()
@@ -57,14 +125,22 @@ def install_tool(tool, script, build_dir, prefix):
57
125
  env["USE_SUDO_INSTALL"] = "yes"
58
126
 
59
127
  # run
60
- ret = subprocess.call(script, env=env, cwd=build_dir)
128
+ ret = subprocess.call(script, env=env, cwd=build_path)
61
129
  if ret != 0:
62
130
  print(f"Error occurred while building/installing {tool}")
63
131
  return False
64
132
  return True
65
133
 
66
134
 
67
- def show_tool(tool, script):
135
+ def show_tool(tool: str, script: str) -> None:
136
+ """
137
+ Print a bordered header, the contents of the given install script, and a
138
+ closing bordered footer.
139
+
140
+ Parameters:
141
+ tool (str): Tool identifier used in the printed header.
142
+ script (str): Path to the install script file whose contents will be displayed.
143
+ """
68
144
  def print_header(head):
69
145
  border_len = max(80, len(script) + 2)
70
146
  border = border_len*"#"
@@ -83,7 +159,19 @@ def show_tool(tool, script):
83
159
  print_header("end")
84
160
 
85
161
 
86
- def _get_os_name():
162
+ def _get_os_name() -> Optional[str]:
163
+ """
164
+ Map recorded machine information to a short OS identifier used by the installer.
165
+
166
+ This inspects the machine information provided by RecordSchema and, for supported
167
+ Linux distributions, returns a compact identifier composed of the distro and
168
+ major version (for example, "ubuntu20" or "rhel8"). Returns None for
169
+ non-Linux systems or unrecognized distributions.
170
+
171
+ Returns:
172
+ os_name (Optional[str]): Mapped OS identifier (e.g., "ubuntu20", "rhel8") or
173
+ `None` if the OS cannot be mapped.
174
+ """
87
175
  machine_info = RecordSchema.get_machine_information()
88
176
  system = machine_info.get('system', "").lower()
89
177
  if system == 'linux':
@@ -103,7 +191,14 @@ def _get_os_name():
103
191
  return None
104
192
 
105
193
 
106
- def print_machine_info():
194
+ def print_machine_info() -> None:
195
+ """
196
+ Prints detected machine and mapped OS information.
197
+
198
+ Prints the system name, distribution name, OS version, mapped OS identifier, and the path to
199
+ the install tools scripts directory as obtained from RecordSchema.get_machine_information()
200
+ and internal helpers.
201
+ """
107
202
  machine_info = RecordSchema.get_machine_information()
108
203
  mapped_os = _get_os_name()
109
204
 
@@ -114,7 +209,20 @@ def print_machine_info():
114
209
  print("Scripts: ", _get_tool_script_dir())
115
210
 
116
211
 
117
- def __print_summary(successful, failed):
212
+ def __print_summary(successful: Optional[Set[str]],
213
+ failed: Optional[str],
214
+ notstarted: Optional[Set[str]]) -> None:
215
+ """
216
+ Prints a fixed-width summary banner listing installed, failed, and pending tools.
217
+
218
+ Parameters:
219
+ successful (Optional[Set[str]]): Set of tool names that were installed; when provided,
220
+ they are shown under "Installed".
221
+ failed (Optional[str]): Name of a tool that failed to install; when provided, it is shown
222
+ under "Failed to install".
223
+ notstarted (Optional[Set[str]]): Set of tool names that were not started or are pending;
224
+ when provided, they are shown under "Pending".
225
+ """
118
226
  max_len = 64
119
227
  print("#"*max_len)
120
228
  if successful:
@@ -124,40 +232,31 @@ def __print_summary(successful, failed):
124
232
  if failed:
125
233
  msg = f"Failed to install: {failed}"
126
234
  print(f"# {msg}")
127
- print("#"*max_len)
128
235
 
236
+ if notstarted:
237
+ msg = f"Pending: {', '.join(sorted(notstarted))}"
238
+ print(f"# {msg}")
129
239
 
130
- def _get_tool_script_dir():
131
- return Path(siliconcompiler.__file__).parent / "toolscripts"
240
+ print("#"*max_len)
132
241
 
133
242
 
134
- def _get_tools_list():
135
- tools_root = _get_tool_script_dir()
243
+ def _get_tool_script_dir() -> Path:
244
+ return Path(siliconcompiler.__file__).parent / "toolscripts"
136
245
 
137
- script_dir = None
138
- os_dir = _get_os_name()
139
- if os_dir:
140
- script_dir = tools_root / os_dir
141
- if not script_dir.exists():
142
- script_dir = None
143
246
 
247
+ def _get_tools_list() -> Dict[str, str]:
144
248
  tools = {}
145
- if script_dir:
146
- for script in glob.glob(str(script_dir / "install-*.sh")):
147
- tool = re.match(r"install-(.*)\.sh", os.path.basename(script).lower())
148
- tools[tool.group(1)] = script
249
+ os = _get_os_name()
250
+ for plugin in get_plugins("install", name="tools"):
251
+ tools.update(plugin(os))
149
252
 
150
253
  return tools
151
254
 
152
255
 
153
- def _recommended_tool_groups(tools):
154
- groups = {
155
- "asic": {"sv2v", "yosys", "yosys-slang", "openroad", "klayout"},
156
- "asic-hls": {"bambu", "yosys", "yosys-slang", "openroad", "klayout"},
157
- "fpga": {"sv2v", "yosys", "yosys-slang", "vpr"},
158
- "digital-simulation": {"verilator", "icarus", "surfer"},
159
- "analog-simulation": {"xyce"}
160
- }
256
+ def _recommended_tool_groups(tools) -> Dict[str, List[str]]:
257
+ groups = {}
258
+ for plugin in get_plugins("install", name="groups"):
259
+ groups.update(plugin())
161
260
 
162
261
  filter_groups = {}
163
262
  for group, group_tools in groups.items():
@@ -174,7 +273,19 @@ class HelpFormatter(argparse.ArgumentDefaultsHelpFormatter, argparse.RawDescript
174
273
  pass
175
274
 
176
275
 
177
- def main():
276
+ def main() -> int:
277
+ """
278
+ CLI entry point for installing tools, showing install scripts, or printing machine
279
+ debug information.
280
+
281
+ Parses command-line arguments, validates the host OS, expands tool groups, and either
282
+ displays install scripts (-show), prints machine info (-debug_machine), or runs install
283
+ scripts for the requested tools, then prints a summary and optional shell-path guidance.
284
+
285
+ Returns:
286
+ `0` on successful completion, `1` on failure (e.g., unsupported OS or
287
+ any tool installation failure).
288
+ """
178
289
  progname = "sc-install"
179
290
 
180
291
  tools = _get_tools_list()
@@ -286,13 +397,14 @@ Tool groups:
286
397
  show_tool(tool, tools[tool])
287
398
  else:
288
399
  if not install_tool(tool, tools[tool], args.build_dir, args.prefix):
289
- __print_summary(tools_completed, tool)
400
+ notstarted = set(args.tool) - tools_completed - tools_handled
401
+ __print_summary(tools_completed, tool, notstarted)
290
402
  return 1
291
403
  else:
292
404
  tools_completed.add(tool)
293
405
 
294
406
  if not args.show:
295
- __print_summary(tools_completed, None)
407
+ __print_summary(tools_completed, None, None)
296
408
 
297
409
  msgs = []
298
410
  for env, path in (
@@ -11,9 +11,15 @@ This allows for creating simple, self-documenting build or task scripts in
11
11
  Python without the need for complex boilerplate code.
12
12
  """
13
13
  import argparse
14
- import importlib
15
14
  import sys
15
+
16
+ import importlib.util
16
17
  import os.path
18
+
19
+ from typing import Union, Tuple, Optional, Dict
20
+
21
+ from pathlib import Path
22
+
17
23
  from inspect import getmembers, isfunction, getfullargspec
18
24
 
19
25
  from siliconcompiler._metadata import version
@@ -23,7 +29,7 @@ from siliconcompiler.schema import utils
23
29
  __default_source_file = "make.py"
24
30
 
25
31
 
26
- def __process_file(path):
32
+ def __process_file(path: Union[Path, str]) -> Tuple[Dict, Optional[str], Optional[str]]:
27
33
  """
28
34
  Dynamically loads a Python module and inspects it for runnable targets.
29
35
 
@@ -99,7 +105,7 @@ def __process_file(path):
99
105
  return args, default_arg, module_help
100
106
 
101
107
 
102
- def main(source_file=None):
108
+ def main(source_file: Optional[Union[str, Path]] = None) -> int:
103
109
  """
104
110
  The main entry point for the smake command-line application.
105
111
 
@@ -2,7 +2,7 @@ import re
2
2
 
3
3
  import os.path
4
4
 
5
- from typing import Tuple
5
+ from typing import Tuple, Optional
6
6
 
7
7
  from siliconcompiler.schema import NamedSchema
8
8
  from siliconcompiler.schema import EditableSchema, Parameter, Scope, BaseSchema
@@ -231,13 +231,13 @@ class Checklist(NamedSchema):
231
231
 
232
232
  def _generate_doc(self, doc,
233
233
  ref_root: str = "",
234
- key_offset: Tuple[str] = None,
234
+ key_offset: Optional[Tuple[str, ...]] = None,
235
235
  detailed: bool = True):
236
236
  from .schema.docs.utils import build_section
237
237
  settings = build_section('Configuration', f"{ref_root}-config")
238
238
 
239
239
  if not key_offset:
240
- key_offset = []
240
+ key_offset = tuple()
241
241
 
242
242
  for key in self.getkeys():
243
243
  criteria = build_section(key, f"{ref_root}-config-{key}")
@@ -0,0 +1,24 @@
1
+ {
2
+ "version": 1,
3
+ "partname": "z1000",
4
+ "lut_size": 4,
5
+ "flipflops": {
6
+ "features": [
7
+ "async_reset",
8
+ "flop_enable"
9
+ ],
10
+ "models": {
11
+ "dffer": "cad/techlib_custom_plugin/dffer.v",
12
+ "dffr": "cad/techlib_custom_plugin/dffr.v",
13
+ "dffe": "cad/techlib_custom_plugin/dffe.v",
14
+ "dff": "cad/techlib_custom_plugin/dff.v"
15
+ },
16
+ "legalize_list": [
17
+ "$_DFF_PN0_",
18
+ "$_DFF_P_",
19
+ "$_DFFE_PP_",
20
+ "$_DFFE_PN0P_"
21
+ ],
22
+ "techmap": "tech_flops.v"
23
+ }
24
+ }