opencos-eda 0.2.56__tar.gz → 0.2.57__tar.gz

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 (102) hide show
  1. {opencos_eda-0.2.56/opencos_eda.egg-info → opencos_eda-0.2.57}/PKG-INFO +1 -1
  2. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/commands/lec.py +4 -0
  3. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/commands/multi.py +4 -0
  4. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/eda.py +13 -1
  5. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/eda_config.py +35 -1
  6. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/eda_config_defaults.yml +1 -0
  7. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/export_helper.py +5 -1
  8. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/tests/helpers.py +9 -0
  9. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/tools/cocotb.py +25 -0
  10. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/tools/modelsim_ase.py +49 -8
  11. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/tools/slang_yosys.py +4 -1
  12. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/tools/yosys.py +50 -20
  13. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/utils/vsim_helper.py +1 -2
  14. {opencos_eda-0.2.56 → opencos_eda-0.2.57/opencos_eda.egg-info}/PKG-INFO +1 -1
  15. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/pyproject.toml +1 -1
  16. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/LICENSE +0 -0
  17. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/LICENSE.spdx +0 -0
  18. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/README.md +0 -0
  19. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/__init__.py +0 -0
  20. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/_version.py +0 -0
  21. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/_waves_pkg.sv +0 -0
  22. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/commands/__init__.py +0 -0
  23. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/commands/build.py +0 -0
  24. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/commands/deps_help.py +0 -0
  25. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/commands/elab.py +0 -0
  26. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/commands/export.py +0 -0
  27. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/commands/flist.py +0 -0
  28. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/commands/lint.py +0 -0
  29. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/commands/open.py +0 -0
  30. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/commands/proj.py +0 -0
  31. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/commands/shell.py +0 -0
  32. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/commands/sim.py +0 -0
  33. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/commands/sweep.py +0 -0
  34. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/commands/synth.py +0 -0
  35. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/commands/targets.py +0 -0
  36. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/commands/upload.py +0 -0
  37. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/commands/waves.py +0 -0
  38. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/deps/__init__.py +0 -0
  39. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/deps/defaults.py +0 -0
  40. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/deps/deps_commands.py +0 -0
  41. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/deps/deps_file.py +0 -0
  42. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/deps/deps_processor.py +0 -0
  43. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/deps_schema.py +0 -0
  44. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/eda_base.py +0 -0
  45. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/eda_config_max_verilator_waivers.yml +0 -0
  46. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/eda_config_reduced.yml +0 -0
  47. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/eda_deps_bash_completion.bash +0 -0
  48. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/eda_deps_sanitize.py +0 -0
  49. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/eda_extract_targets.py +0 -0
  50. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/eda_tool_helper.py +0 -0
  51. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/export_json_convert.py +0 -0
  52. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/files.py +0 -0
  53. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/hw/__init__.py +0 -0
  54. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/hw/oc_cli.py +0 -0
  55. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/hw/pcie.py +0 -0
  56. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/names.py +0 -0
  57. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/peakrdl_cleanup.py +0 -0
  58. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/seed.py +0 -0
  59. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/tests/__init__.py +0 -0
  60. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/tests/custom_config.yml +0 -0
  61. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/tests/deps_files/command_order/DEPS.yml +0 -0
  62. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/tests/deps_files/error_msgs/DEPS.yml +0 -0
  63. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/tests/deps_files/iverilog_test/DEPS.yml +0 -0
  64. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/tests/deps_files/no_deps_here/DEPS.yml +0 -0
  65. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/tests/deps_files/non_sv_reqs/DEPS.yml +0 -0
  66. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/tests/deps_files/tags_with_tools/DEPS.yml +0 -0
  67. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/tests/deps_files/test_err_fatal/DEPS.yml +0 -0
  68. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/tests/test_build.py +0 -0
  69. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/tests/test_deps_helpers.py +0 -0
  70. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/tests/test_deps_schema.py +0 -0
  71. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/tests/test_eda.py +0 -0
  72. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/tests/test_eda_elab.py +0 -0
  73. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/tests/test_eda_synth.py +0 -0
  74. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/tests/test_oc_cli.py +0 -0
  75. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/tests/test_tools.py +0 -0
  76. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/tools/__init__.py +0 -0
  77. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/tools/invio.py +0 -0
  78. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/tools/invio_helpers.py +0 -0
  79. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/tools/invio_yosys.py +0 -0
  80. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/tools/iverilog.py +0 -0
  81. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/tools/quartus.py +0 -0
  82. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/tools/questa.py +0 -0
  83. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/tools/questa_fse.py +0 -0
  84. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/tools/riviera.py +0 -0
  85. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/tools/slang.py +0 -0
  86. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/tools/surelog.py +0 -0
  87. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/tools/tabbycad_yosys.py +0 -0
  88. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/tools/verilator.py +0 -0
  89. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/tools/vivado.py +0 -0
  90. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/util.py +0 -0
  91. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/utils/__init__.py +0 -0
  92. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/utils/markup_helpers.py +0 -0
  93. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/utils/status_constants.py +0 -0
  94. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/utils/str_helpers.py +0 -0
  95. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/utils/subprocess_helpers.py +0 -0
  96. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos/utils/vscode_helper.py +0 -0
  97. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos_eda.egg-info/SOURCES.txt +0 -0
  98. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos_eda.egg-info/dependency_links.txt +0 -0
  99. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos_eda.egg-info/entry_points.txt +0 -0
  100. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos_eda.egg-info/requires.txt +0 -0
  101. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/opencos_eda.egg-info/top_level.txt +0 -0
  102. {opencos_eda-0.2.56 → opencos_eda-0.2.57}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: opencos-eda
3
- Version: 0.2.56
3
+ Version: 0.2.57
4
4
  Summary: A simple Python package for wrapping RTL simuliatons and synthesis
5
5
  Author-email: Simon Sabato <simon@cognichip.ai>, Drew Ranck <drew@cognichip.ai>
6
6
  Project-URL: Homepage, https://github.com/cognichip/opencos
@@ -27,6 +27,7 @@ class CommandLec(CommandDesign):
27
27
  self.args.update({
28
28
  'designs': [],
29
29
  'synth': True,
30
+ 'flatten-all': True,
30
31
  })
31
32
  self.args_help.update({
32
33
  'designs': (
@@ -34,6 +35,9 @@ class CommandLec(CommandDesign):
34
35
  ' use this arg twice'
35
36
  ),
36
37
  'synth': 'run synthesis on the two designs prior to running LEC',
38
+ 'flatten-all': (
39
+ 'arg passed to "synth" if run with --synth, to disable use --no-flatten-all'
40
+ ),
37
41
  })
38
42
 
39
43
  self.synth_design_verilog_fpaths = ['', '']
@@ -327,6 +327,10 @@ class CommandMulti(CommandParallel):
327
327
 
328
328
  if parsed.fail_if_no_targets and len(self.targets) == 0:
329
329
  self.error(f'Multi: --fail-if-no-targets set, and {self.targets=}')
330
+ if not all_multi_tools:
331
+ possible_tools = self.all_handler_commands.get(command, [])
332
+ self.error(f'Multi: no tools to run for {command=}, available tools: {possible_tools}')
333
+
330
334
  util.info("Multi: About to run: ", end="")
331
335
 
332
336
  def get_pretty_targets_tuple_as_list(l:list):
@@ -49,6 +49,9 @@ def init_config(
49
49
 
50
50
  # For key DEFAULT_HANDLERS, we'll update config['command_handler'] with
51
51
  # the actual class using importlib (via opencos.util)
52
+
53
+ eda_config.tool_try_add_to_path(tool)
54
+
52
55
  config['command_handler'] = {}
53
56
  for _cmd, str_class in config['DEFAULT_HANDLERS'].items():
54
57
  cls = util.import_class_from_string(str_class)
@@ -329,7 +332,7 @@ def tool_setup(tool: str, config: dict, quiet: bool = False, auto_setup: bool =
329
332
  config['tools_loaded'].add(tool)
330
333
 
331
334
 
332
- def process_tokens( # pylint: disable=too-many-branches,too-many-statements,too-many-locals
335
+ def process_tokens( # pylint: disable=too-many-branches,too-many-statements,too-many-locals,too-many-return-statements
333
336
  tokens: list, original_args: list, config: dict, is_interactive=False
334
337
  ) -> int:
335
338
  '''Returns bash/sh style return code int (0 pass, non-zero fail).
@@ -416,6 +419,15 @@ def process_tokens( # pylint: disable=too-many-branches,too-many-statements,too-
416
419
  return 2
417
420
 
418
421
  sco = config['command_handler'][command](config=config) # sub command object
422
+ if not parsed.tool:
423
+ # then what was the auto selected tool?
424
+ sco_tool = getattr(sco, '_TOOL', '')
425
+ if sco_tool in config['auto_tools_order'][0] and \
426
+ config['auto_tools_order'][0][sco_tool].get('disable-auto', False):
427
+ util.error(f'Cannot use tool={sco_tool} without arg --tool, it cannot be selected',
428
+ 'automatically')
429
+ return status_constants.EDA_COMMAND_OR_ARGS_ERROR
430
+
419
431
  util.debug(f'{command=}')
420
432
  util.debug(f'{sco.config=}')
421
433
  util.debug(f'{type(sco)=}')
@@ -47,7 +47,7 @@ class Defaults:
47
47
  'exe', 'handlers',
48
48
  'requires_env', 'requires_py', 'requires_cmd', 'requires_in_exe_path',
49
49
  'requires_vsim_helper', 'requires_vscode_extension',
50
- 'disable-tools-multi',
50
+ 'disable-tools-multi', 'disable-auto',
51
51
  ])
52
52
  supported_config_tool_keys = set([
53
53
  'defines',
@@ -158,6 +158,9 @@ def update_config_auto_tool_order_for_tool(tool: str, config: dict) -> str:
158
158
 
159
159
  user_exe = shutil.which(user_exe)
160
160
 
161
+ # try adding to $PATH if in form --tool=/path/to/exe
162
+ tool_try_add_to_path(tool)
163
+
161
164
  if tool not in config['auto_tools_order'][0]:
162
165
  return tool
163
166
  if not user_exe:
@@ -322,3 +325,34 @@ def write_eda_config_and_args(
322
325
  data['config'][k] = str(v)
323
326
 
324
327
  yaml_safe_writer(data=data, filepath=fullpath)
328
+
329
+
330
+ def tool_try_add_to_path(tool: str) -> None:
331
+ '''Since we support --tool=<name>=/path/to/bin/exe, attempt to prepend $PATH
332
+
333
+ with this information for this tool (which will nicely affect all subprocesses,
334
+ but not wreck our original shell).'''
335
+
336
+ if not tool or '=' not in tool:
337
+ return
338
+
339
+ name, exe = tool.split('=')
340
+ if os.path.isdir(name):
341
+ # Someone passes us --tool=<name>=/path/to/bin/ (did not have exe)
342
+ path = name
343
+ else:
344
+ # Someone passes us --tool=<name>=/path/to/bin/exe, remove the exe.
345
+ path, _ = os.path.split(exe)
346
+ if not path:
347
+ return
348
+
349
+ path = os.path.abspath(path)
350
+ if os.path.isdir(path):
351
+ paths = os.environ['PATH'].split(':')
352
+ if path not in paths:
353
+ os.environ['PATH'] = path + ':' + os.environ['PATH']
354
+ util.info(f'--tool={tool} has path information, prepending PATH with: {path}')
355
+ else:
356
+ util.info(f'--tool={tool} has path information, but {path} already in $PATH')
357
+ if exe and os.path.isfile(exe):
358
+ util.info(f'--tool={tool} has path information, using exe {shutil.which(exe)}')
@@ -516,6 +516,7 @@ auto_tools_order:
516
516
  sim: opencos.tools.iverilog.CommandSimIverilog
517
517
 
518
518
  cocotb:
519
+ disable-auto: True # do not allow this to run `eda sim` with --tool not set
519
520
  exe: python
520
521
  requires_cmd:
521
522
  - python -c "import cocotb; print(cocotb.__version__)"
@@ -286,7 +286,11 @@ def get_list_sv_included_files(
286
286
  # If we have more than N levels of `include hunting, then rethink this.
287
287
  # For example, some codebases would do their file dependencies as `include
288
288
  # as part of their header guards, which could be ~100 levels of nesting.
289
- for fname,traversed in sv_included_files_dict.items():
289
+
290
+ # make a copy of keys so we don't alter during traversal of the dict:
291
+ fnames = list(sv_included_files_dict.keys())
292
+ for fname in fnames:
293
+ traversed = sv_included_files_dict[fname]
290
294
  if not traversed:
291
295
  included_files_list = find_sv_included_files_within_file(
292
296
  filename=fname,
@@ -39,6 +39,15 @@ def can_run_eda_command(*commands, config: dict) -> bool:
39
39
  if handler and getattr(handler, 'CHECK_REQUIRES', []):
40
40
  if not all(issubclass(handler, x) for x in getattr(handler, 'CHECK_REQUIRES', [])):
41
41
  return False
42
+
43
+ # We cannot run tools that have disable-auto set:
44
+ tool = getattr(handler, '_TOOL', '')
45
+ if handler and tool:
46
+ entry = config['auto_tools_order'][0].get(tool, {})
47
+ if entry and entry.get('disable-auto', False):
48
+ # This tool cannot automatically run our command.
49
+ return False
50
+
42
51
  runnable.append(True)
43
52
  return runnable and all(runnable)
44
53
 
@@ -100,9 +100,34 @@ class CommandSimCocotb(CommandSim, ToolCocotb):
100
100
  def set_tool_defines(self):
101
101
  ToolCocotb.set_tool_defines(self)
102
102
 
103
+ def help( # pylint: disable=dangerous-default-value
104
+ self, tokens: list = [], no_targets: bool = False
105
+ ) -> None:
106
+ '''Override for Command.help(...)'''
107
+
108
+ super().help(tokens=tokens, no_targets=no_targets)
109
+ self._warn_if_simulator_not_present()
110
+
111
+ def _warn_if_simulator_not_present(self) -> None:
112
+ '''Warn if --cocotb-simulator is not set, or if the exe is not in PATH'''
113
+
114
+ simulator = self.args['cocotb-simulator']
115
+ if not simulator:
116
+ util.warning('--cocotb-simulator is not set, a simulation cannot be run with'
117
+ 'this arg value')
118
+ return
119
+ exe = shutil.which(simulator)
120
+ if not exe:
121
+ util.warning(f'--cocotb-simulator={simulator}, {simulator} is not present in PATH',
122
+ 'a simulation cannot be run with this arg value')
123
+
124
+
103
125
  def prepare_compile(self):
104
126
  self.set_tool_defines()
105
127
 
128
+ # Check existence of cocotb-simulator:
129
+ self._warn_if_simulator_not_present()
130
+
106
131
  # Fix iverilog -> icarus
107
132
  if self.args['cocotb-simulator'] == 'iverilog':
108
133
  self.args['cocotb-simulator'] = 'icarus'
@@ -10,7 +10,7 @@ Note that this is for 32-bit Modelsim Student Edition. Consider using --tool=que
10
10
  import os
11
11
 
12
12
  from opencos import util
13
- from opencos.commands import CommandSim
13
+ from opencos.commands import sim, CommandSim
14
14
  from opencos.tools.questa import ToolQuesta
15
15
  from opencos.utils.str_helpers import sanitize_defines_for_sh
16
16
 
@@ -201,6 +201,44 @@ class CommandSimModelsimAse(CommandSim, ToolModelsimAse):
201
201
  with open(vlog_dot_f_fpath, 'w', encoding='utf-8') as f:
202
202
  f.writelines(line + "\n" for line in vlog_dot_f_lines)
203
203
 
204
+ def vopt_handle_parameters(self) -> (str, list):
205
+ '''Returns str for vopt or voptargs, and list of vopt tcl
206
+
207
+ Note this is used for self.use_vopt = True or False.
208
+ '''
209
+
210
+ voptargs_str = ''
211
+ vopt_do_lines = []
212
+
213
+ # Note that if self.use_vopt=True, we have to do some workarounds for how
214
+ # some questa-like tools behave for: tcl/.do + vopt arg processing
215
+ # This affects string based parameters that have spaces (vopt treats spaces unique args,
216
+ # vsim does not). Since we'd like to keep the vopt/vsim split into separate steps, we can
217
+ # work around this by setting tcl varaibles for each parameter.
218
+ if self.parameters:
219
+ if not self.use_vopt:
220
+ voptargs_str += ' ' + ' '.join(self.process_parameters_get_list(arg_prefix='-G'))
221
+ else:
222
+ for k,v in self.parameters.items():
223
+ s = sim.parameters_dict_get_command_list(params={k: v}, arg_prefix='')[0]
224
+ # At this point, s should be a str in form {k}={v}
225
+ if not s or '=' not in s:
226
+ continue
227
+ if ' ' in s:
228
+ # Instead of:
229
+ # vopt -GMyParam="hi bye"
230
+ # we'll do:
231
+ # set PARAMETERS(MyParam) "hi bye"
232
+ # vopt -GMyParam=$PARAMETERS(MyParam)
233
+ s = s.replace(f'{k}=', f'set PARAMETERS({k}) ')
234
+ vopt_do_lines.append(s)
235
+ voptargs_str += f' -G{k}=$PARAMETERS({k}) '
236
+ else:
237
+ voptargs_str += f' -G{s} '
238
+
239
+ return voptargs_str, vopt_do_lines
240
+
241
+
204
242
  def write_vsim_dot_do( # pylint: disable=too-many-locals
205
243
  self, dot_do_to_write: list
206
244
  ) -> None:
@@ -223,9 +261,13 @@ class CommandSimModelsimAse(CommandSim, ToolModelsimAse):
223
261
  typ='waveform', description='Modelsim/Questa Waveform WLF (Wave Log Format) file'
224
262
  )
225
263
 
226
- # parameters
227
- if self.parameters:
228
- voptargs_str += ' ' + ' '.join(self.process_parameters_get_list(arg_prefix='-G'))
264
+ vlog_do_lines = []
265
+ vsim_do_lines = []
266
+
267
+ # parameters, use helper method to get voptargs_str and vopt_do_lines
268
+ more_voptargs_str, vopt_do_lines = self.vopt_handle_parameters()
269
+ voptargs_str += more_voptargs_str
270
+
229
271
 
230
272
  # TODO(drew): support self.args['sim_libary', 'elab-args', sim-args'] (3 lists)
231
273
  # to add to vsim_one_liner.
@@ -251,7 +293,7 @@ class CommandSimModelsimAse(CommandSim, ToolModelsimAse):
251
293
 
252
294
  vsim_one_liner = vsim_one_liner.replace('\n', ' ')
253
295
 
254
- vlog_do_lines = [
296
+ vlog_do_lines += [
255
297
  "if {[file exists work]} { vdel -all work; }",
256
298
  "vlib work;",
257
299
  "quietly set qc 30;",
@@ -263,9 +305,8 @@ class CommandSimModelsimAse(CommandSim, ToolModelsimAse):
263
305
  "}",
264
306
  ]
265
307
 
266
- vopt_do_lines = []
267
308
  if self.use_vopt:
268
- vopt_do_lines = [
309
+ vopt_do_lines += [
269
310
  "if {[catch { " + vopt_one_liner + " } result] } {",
270
311
  " echo \"Caught $result\";",
271
312
  " if {[batch_mode]} {",
@@ -274,7 +315,7 @@ class CommandSimModelsimAse(CommandSim, ToolModelsimAse):
274
315
  "}",
275
316
  ]
276
317
 
277
- vsim_do_lines = [
318
+ vsim_do_lines += [
278
319
  "if {[catch { " + vsim_one_liner + " } result] } {",
279
320
  " echo \"Caught $result\";",
280
321
  " if {[batch_mode]} {",
@@ -118,7 +118,10 @@ class CommandSynthSlangYosys(CommonSynthYosys, ToolSlangYosys):
118
118
  params=self.parameters, arg_prefix='-G '
119
119
  )
120
120
 
121
- read_slang_cmd.append(f'--top {self.args["top"]}')
121
+ # In case --top was not set:
122
+ if not any(x.startswith('--top') for x in read_slang_cmd):
123
+ read_slang_cmd.append(f'--top {self.args["top"]}')
124
+
122
125
  return ' '.join(read_slang_cmd)
123
126
 
124
127
 
@@ -536,7 +536,6 @@ class CommandLecYosys(CommandLec, ToolYosys):
536
536
 
537
537
  self.synth_designs_tops = [None, None]
538
538
  self.synth_designs_fpaths = [None, None]
539
- self.synth_design_top_module_names = [None, None]
540
539
 
541
540
  def get_synth_result_fpath(self, target: str) -> str:
542
541
  '''Overridden from CommandLec'''
@@ -547,7 +546,7 @@ class CommandLecYosys(CommandLec, ToolYosys):
547
546
  def get_synth_command_list(self, design_num: int) -> list:
548
547
  '''Returns one of the synthesis command lists, for design_num=0 or 1'''
549
548
 
550
- if not design_num in [0, 1]:
549
+ if not design_num in (0, 1):
551
550
  self.error(f'{design_num=} we only support LEC on designs 0 and 1')
552
551
 
553
552
  synth_cmd_list = [
@@ -561,31 +560,43 @@ class CommandLecYosys(CommandLec, ToolYosys):
561
560
  synth_cmd_list += [
562
561
  '--work-dir=' + self.synth_work_dirs[design_num],
563
562
  self.args['designs'][design_num],
564
- f'--rename-module=Design{design_num + 1}'
563
+ f'--rename-module=Design{design_num + 1}',
565
564
  ]
566
565
 
567
- self.synth_design_top_module_names[design_num] = f'Design{design_num + 1}'
566
+ if self.args['flatten-all']:
567
+ # We have to do this or may get conflicts on black-boxed modules, but can
568
+ # be avoided with --no-flatten-all.
569
+ synth_cmd_list.append(
570
+ '--flatten-all'
571
+ )
572
+
573
+ self.synth_designs_tops[design_num] = f'Design{design_num + 1}'
568
574
 
569
575
  return synth_cmd_list
570
576
 
571
577
 
572
- def get_synth_top_from_output_config(self, design_num: int) -> str:
573
- '''Returns the top name given the design number that we synthesized'''
578
+ def get_synth_top_from_output_config(self, design_num: int) -> (str, str):
579
+ '''Returns the (orignal top name, module name) tuple given the design number
580
+
581
+ that we synthesized'''
574
582
 
575
583
  work_dir = self.synth_work_dirs[design_num]
576
584
  output_cfg_fpath = os.path.join(work_dir, eda_config.EDA_OUTPUT_CONFIG_FNAME)
577
585
  data = yaml_safe_load(output_cfg_fpath)
578
586
  top = data.get('args', {}).get('top', '')
579
- if not top:
587
+ rename_module = data.get('args', {}).get('rename-module', '')
588
+ if not top and not rename_module:
580
589
  self.error(f'"top" not found in synth run from {work_dir=} in',
581
590
  f'config {output_cfg_fpath}')
582
- return top
591
+ if not rename_module:
592
+ return top, top
593
+ return top, rename_module
583
594
 
584
595
 
585
596
  def get_synth_results_fpath(self, design_num: int, top: str) -> str:
586
- '''Returns the synthesized .v file fpath'''
597
+ '''Returns the synthesized .v file fpath, using orignal top (not renamed)'''
587
598
  if not top:
588
- top = self.get_synth_top_from_output_config(design_num=design_num)
599
+ top, _ = self.get_synth_top_from_output_config(design_num=design_num)
589
600
 
590
601
  work_dir = self.synth_work_dirs[design_num]
591
602
  fpath = os.path.join(work_dir, 'yosys', f'{top}.v')
@@ -594,7 +605,7 @@ class CommandLecYosys(CommandLec, ToolYosys):
594
605
  return fpath
595
606
 
596
607
 
597
- def do_it(self) -> None:
608
+ def do_it(self) -> None: # pylint: disable=too-many-locals,too-many-statements,too-many-branches
598
609
  self.set_tool_defines()
599
610
  self.write_eda_config_and_args()
600
611
 
@@ -622,6 +633,9 @@ class CommandLecYosys(CommandLec, ToolYosys):
622
633
  self.exec(work_dir=self.args['work-dir'], command_list=x,
623
634
  tee_fpath=x.tee_fpath)
624
635
 
636
+ util.info(f'LEC ran via --yosys-scriptfile: {self.args["yosys-scriptfile"]}')
637
+ return
638
+
625
639
 
626
640
  if self.args['synth']:
627
641
  synth1_cmd_list = self.get_synth_command_list(design_num=0)
@@ -636,23 +650,23 @@ class CommandLecYosys(CommandLec, ToolYosys):
636
650
  self.exec(pwd, synth2_cmd_list, background=True)
637
651
  util.info(f'Finished with 2nd LEC synthesis {self.args["designs"][1]}')
638
652
 
639
- self.synth_designs_tops = [
640
- self.get_synth_top_from_output_config(design_num=0),
641
- self.get_synth_top_from_output_config(design_num=1)
642
- ]
653
+
654
+ top0, module0 = self.get_synth_top_from_output_config(design_num=0)
655
+ top1, module1 = self.get_synth_top_from_output_config(design_num=1)
656
+ self.synth_designs_tops = [module0, module1]
643
657
  util.info(f'Design tops: {self.synth_designs_tops}')
644
658
 
645
659
  # read the output config
646
660
  self.synth_designs_fpaths = [
647
661
  os.path.abspath(
648
- self.get_synth_results_fpath(design_num=0, top=self.synth_designs_tops[0])),
662
+ self.get_synth_results_fpath(design_num=0, top=top0)),
649
663
  os.path.abspath(
650
- self.get_synth_results_fpath(design_num=1, top=self.synth_designs_tops[1]))
664
+ self.get_synth_results_fpath(design_num=1, top=top1))
651
665
  ]
652
666
  util.info(f'Design tops: {self.synth_designs_fpaths}')
653
667
 
654
668
  else:
655
- # don't run synthesis, need the two top level .v files in
669
+ # don't run synthesis, need the two top level .v|.sv files in
656
670
  # self.synth_designs_fpaths, and need the two top module names in
657
671
  # self.synth_designs_tops
658
672
  self.synth_designs_fpaths = [
@@ -660,11 +674,19 @@ class CommandLecYosys(CommandLec, ToolYosys):
660
674
  os.path.abspath(self.args['designs'][1])
661
675
  ]
662
676
 
677
+ for i in (0, 1):
678
+ if not os.path.isfile(self.args['designs'][i]):
679
+ self.error(
680
+ 'Using synth=False (--no-synth) --designs=<value> must be a single',
681
+ f'filename, however {self.args["designs"][i]} does not exist'
682
+ )
683
+
663
684
  path, fname = os.path.split(self.synth_designs_fpaths[0])
664
685
  module_guess, _ = os.path.splitext(fname)
665
686
  top1 = util.get_inferred_top_module_name(
666
687
  module_guess=module_guess, module_fpath=self.synth_designs_fpaths[0]
667
688
  )
689
+ util.debug(f'design1 {module_guess=} {fname=} {path=}')
668
690
  util.info(f'design1 top module name = {top1} (from {path} / {fname})')
669
691
 
670
692
  path, fname = os.path.split(self.synth_designs_fpaths[1])
@@ -672,6 +694,7 @@ class CommandLecYosys(CommandLec, ToolYosys):
672
694
  top2 = util.get_inferred_top_module_name(
673
695
  module_guess=module_guess, module_fpath=self.synth_designs_fpaths[1]
674
696
  )
697
+ util.debug(f'design2 {module_guess=} {fname=} {path=}')
675
698
  util.info(f'design2 top module name = {top2} (from {path} / {fname})')
676
699
 
677
700
  self.synth_designs_tops = [top1, top2]
@@ -691,13 +714,20 @@ class CommandLecYosys(CommandLec, ToolYosys):
691
714
  ]
692
715
  else:
693
716
  self.error(f' --pre-read-verilog file {x} does not exist')
717
+
718
+ nooverwrite = ''
719
+ if self.args['synth'] and not self.args['flatten-all']:
720
+ # If we don't flatten-all from synthesis, and we had to run synthesis,
721
+ # then read the 2nd file with -overwrite
722
+ nooverwrite = '-nooverwrite'
723
+
694
724
  lec_cmd_f_list += [
695
725
  '# Design1 (module):',
696
726
  f'read_verilog -sv -icells {self.synth_designs_fpaths[0]}',
697
727
  '# Design2 (module):',
698
- f'read_verilog -sv -icells {self.synth_designs_fpaths[1]}',
728
+ f'read_verilog -sv -icells {self.synth_designs_fpaths[1]} {nooverwrite}',
699
729
  'clk2fflogic;',
700
- f'miter -equiv -flatten {" ".join(self.synth_design_top_module_names)} miter',
730
+ f'miter -equiv -flatten {" ".join(self.synth_designs_tops)} miter',
701
731
  ('sat -seq 50 -verify -prove trigger 0 -show-all -show-inputs -show-outputs'
702
732
  ' -set-init-zero miter'),
703
733
  ]
@@ -10,8 +10,6 @@ import subprocess
10
10
 
11
11
  from opencos.util import debug
12
12
 
13
- vsim_path = shutil.which('vsim')
14
-
15
13
  INIT_HAS_RUN = False
16
14
  TOOL_IS = {
17
15
  'riviera': False,
@@ -29,6 +27,7 @@ def init() -> None:
29
27
  return
30
28
 
31
29
  INIT_HAS_RUN = True
30
+ vsim_path = shutil.which('vsim')
32
31
 
33
32
  if not vsim_path:
34
33
  return
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: opencos-eda
3
- Version: 0.2.56
3
+ Version: 0.2.57
4
4
  Summary: A simple Python package for wrapping RTL simuliatons and synthesis
5
5
  Author-email: Simon Sabato <simon@cognichip.ai>, Drew Ranck <drew@cognichip.ai>
6
6
  Project-URL: Homepage, https://github.com/cognichip/opencos
@@ -2,7 +2,7 @@
2
2
 
3
3
  [project]
4
4
  name = "opencos-eda"
5
- version = "0.2.56"
5
+ version = "0.2.57"
6
6
  dependencies = [
7
7
  # opencos/eda.py dependencies
8
8
  "mergedeep >= 1.3.4",
File without changes
File without changes
File without changes
File without changes