opencos-eda 0.2.53__tar.gz → 0.2.55__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.53/opencos_eda.egg-info → opencos_eda-0.2.55}/PKG-INFO +2 -2
  2. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/commands/__init__.py +2 -0
  3. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/commands/flist.py +1 -1
  4. opencos_eda-0.2.55/opencos/commands/lint.py +51 -0
  5. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/commands/sim.py +44 -0
  6. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/deps/deps_file.py +3 -1
  7. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/eda.py +16 -5
  8. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/eda_base.py +19 -14
  9. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/eda_config_defaults.yml +13 -1
  10. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/tests/helpers.py +5 -0
  11. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/tests/test_eda.py +1 -1
  12. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/tests/test_eda_elab.py +26 -5
  13. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/tools/cocotb.py +7 -15
  14. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/tools/invio.py +8 -1
  15. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/tools/invio_helpers.py +24 -6
  16. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/tools/invio_yosys.py +3 -2
  17. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/tools/iverilog.py +17 -24
  18. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/tools/modelsim_ase.py +16 -6
  19. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/tools/quartus.py +183 -86
  20. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/tools/questa.py +19 -16
  21. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/tools/questa_fse.py +13 -0
  22. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/tools/riviera.py +13 -0
  23. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/tools/slang.py +12 -1
  24. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/tools/surelog.py +13 -0
  25. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/tools/verilator.py +22 -14
  26. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/tools/vivado.py +38 -20
  27. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/tools/yosys.py +15 -0
  28. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/util.py +77 -14
  29. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/utils/status_constants.py +1 -0
  30. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/utils/str_helpers.py +8 -4
  31. {opencos_eda-0.2.53 → opencos_eda-0.2.55/opencos_eda.egg-info}/PKG-INFO +2 -2
  32. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos_eda.egg-info/SOURCES.txt +1 -0
  33. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos_eda.egg-info/requires.txt +1 -1
  34. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/pyproject.toml +2 -2
  35. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/LICENSE +0 -0
  36. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/LICENSE.spdx +0 -0
  37. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/README.md +0 -0
  38. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/__init__.py +0 -0
  39. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/_version.py +0 -0
  40. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/_waves_pkg.sv +0 -0
  41. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/commands/build.py +0 -0
  42. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/commands/deps_help.py +0 -0
  43. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/commands/elab.py +0 -0
  44. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/commands/export.py +0 -0
  45. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/commands/lec.py +0 -0
  46. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/commands/multi.py +0 -0
  47. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/commands/open.py +0 -0
  48. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/commands/proj.py +0 -0
  49. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/commands/shell.py +0 -0
  50. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/commands/sweep.py +0 -0
  51. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/commands/synth.py +0 -0
  52. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/commands/targets.py +0 -0
  53. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/commands/upload.py +0 -0
  54. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/commands/waves.py +0 -0
  55. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/deps/__init__.py +0 -0
  56. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/deps/defaults.py +0 -0
  57. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/deps/deps_commands.py +0 -0
  58. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/deps/deps_processor.py +0 -0
  59. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/deps_schema.py +0 -0
  60. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/eda_config.py +0 -0
  61. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/eda_config_max_verilator_waivers.yml +0 -0
  62. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/eda_config_reduced.yml +0 -0
  63. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/eda_deps_bash_completion.bash +0 -0
  64. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/eda_deps_sanitize.py +0 -0
  65. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/eda_extract_targets.py +0 -0
  66. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/eda_tool_helper.py +0 -0
  67. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/export_helper.py +0 -0
  68. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/export_json_convert.py +0 -0
  69. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/files.py +0 -0
  70. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/hw/__init__.py +0 -0
  71. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/hw/oc_cli.py +0 -0
  72. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/hw/pcie.py +0 -0
  73. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/names.py +0 -0
  74. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/peakrdl_cleanup.py +0 -0
  75. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/seed.py +0 -0
  76. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/tests/__init__.py +0 -0
  77. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/tests/custom_config.yml +0 -0
  78. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/tests/deps_files/command_order/DEPS.yml +0 -0
  79. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/tests/deps_files/error_msgs/DEPS.yml +0 -0
  80. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/tests/deps_files/iverilog_test/DEPS.yml +0 -0
  81. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/tests/deps_files/no_deps_here/DEPS.yml +0 -0
  82. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/tests/deps_files/non_sv_reqs/DEPS.yml +0 -0
  83. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/tests/deps_files/tags_with_tools/DEPS.yml +0 -0
  84. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/tests/deps_files/test_err_fatal/DEPS.yml +0 -0
  85. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/tests/test_build.py +0 -0
  86. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/tests/test_deps_helpers.py +0 -0
  87. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/tests/test_deps_schema.py +0 -0
  88. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/tests/test_eda_synth.py +0 -0
  89. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/tests/test_oc_cli.py +0 -0
  90. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/tests/test_tools.py +0 -0
  91. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/tools/__init__.py +0 -0
  92. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/tools/slang_yosys.py +0 -0
  93. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/tools/tabbycad_yosys.py +0 -0
  94. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/utils/__init__.py +0 -0
  95. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/utils/markup_helpers.py +0 -0
  96. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/utils/subprocess_helpers.py +0 -0
  97. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/utils/vscode_helper.py +0 -0
  98. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos/utils/vsim_helper.py +0 -0
  99. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos_eda.egg-info/dependency_links.txt +0 -0
  100. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos_eda.egg-info/entry_points.txt +0 -0
  101. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/opencos_eda.egg-info/top_level.txt +0 -0
  102. {opencos_eda-0.2.53 → opencos_eda-0.2.55}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: opencos-eda
3
- Version: 0.2.53
3
+ Version: 0.2.55
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
@@ -15,5 +15,5 @@ Requires-Dist: schema>=0.7.7
15
15
  Requires-Dist: toml>=0.10.2
16
16
  Requires-Dist: yamllint>=1.35.1
17
17
  Requires-Dist: PySerial>=3.5
18
- Requires-Dist: cocotb>=2.0.0b1
18
+ Requires-Dist: cocotb>=2.0
19
19
  Dynamic: license-file
@@ -10,6 +10,7 @@ from .elab import CommandElab
10
10
  from .export import CommandExport
11
11
  from .flist import CommandFList
12
12
  from .multi import CommandMulti, CommandToolsMulti
13
+ from .lint import CommandLint
13
14
  from .open import CommandOpen
14
15
  from .proj import CommandProj
15
16
  from .sim import CommandSim
@@ -28,6 +29,7 @@ __all__ = [
28
29
  'CommandExport',
29
30
  'CommandFList',
30
31
  'CommandMulti',
32
+ 'CommandLint',
31
33
  'CommandOpen',
32
34
  'CommandProj',
33
35
  'CommandSim',
@@ -214,6 +214,6 @@ class CommandFList(CommandDesign):
214
214
  print() # don't need to close fo (None)
215
215
  else:
216
216
  fo.close()
217
- util.info(f"Created {self.args['out']}")
217
+ util.info(f"Created file: {self.args['out']}")
218
218
 
219
219
  self.write_eda_config_and_args()
@@ -0,0 +1,51 @@
1
+ '''opencos.commands.lint - Base class command handler for: eda lint ...
2
+
3
+ Intended to be overriden by Tool based classes (such as CommandLintVivado, etc)
4
+
5
+ Note that many 'lint' command handlers that also can perform simulations, such
6
+ as VerilatorLint, will instead inherit from VerilatorSim and simply perform a
7
+ shortened sim as the lint, instead of inheriting CommandLint.
8
+
9
+ Tools that don't support a 'sim' command will generally use CommandLint, such
10
+ as CommandLintSlang.'''
11
+
12
+ from opencos.commands.sim import CommandSim
13
+
14
+ class CommandLint(CommandSim):
15
+ '''Base class command handler for: eda lint ...'''
16
+
17
+ command_name = 'lint'
18
+
19
+ def __init__(self, config: dict):
20
+ CommandSim.__init__(self, config=config)
21
+ # add args specific to this simulator
22
+ self.args['stop-after-compile'] = True
23
+ self.args['lint'] = True
24
+ self.args['verilate-args'] = []
25
+
26
+
27
+
28
+ def compile(self) -> None:
29
+ raise NotImplementedError
30
+
31
+ def elaborate(self) -> None:
32
+ raise NotImplementedError
33
+
34
+ def get_compile_command_lists(self, **kwargs) -> list:
35
+ ''' Returns a list of lists (list of command lists).'''
36
+ raise NotImplementedError
37
+
38
+ def get_elaborate_command_lists(self, **kwargs) -> list:
39
+ ''' Returns a list of lists (list of command lists).'''
40
+ raise NotImplementedError
41
+
42
+ # CommandSim methods that elab does not use:
43
+
44
+ def simulate(self):
45
+ pass
46
+
47
+ def get_simulate_command_lists(self, **kwargs) -> list:
48
+ return []
49
+
50
+ def get_post_simulate_command_lists(self, **kwargs) -> list:
51
+ return []
@@ -355,6 +355,50 @@ class CommandSim(CommandDesign):
355
355
  error_code=status_constants.EDA_SIM_LOG_MISSING_MUST_STRING
356
356
  )
357
357
 
358
+ def write_sh_scripts_to_work_dir(
359
+ self, compile_lists: list, elaborate_lists: list, simulate_lists: list,
360
+ compile_line_breaks: bool = True,
361
+ elaborate_line_breaks: bool = False,
362
+ simulate_line_breaks: bool = False,
363
+ simulate_sh_fname: str = 'simulate.sh'
364
+ ) -> None:
365
+ '''Writes compile.sh, elaborate.sh, simulate.sh (if present), all.sh to work-dir
366
+
367
+ Will include the pre_compile_dep_shell_commands.sh if those are present.
368
+ compile_line_breaks defaults to True (one word per line w/ line breaks added)
369
+ '''
370
+
371
+ all_lists = [] # list - of - (command-list)
372
+ if self.has_dep_shell_commands:
373
+ all_lists = [
374
+ ['./pre_compile_dep_shell_commands.sh']
375
+ ]
376
+
377
+ if compile_lists:
378
+ util.write_shell_command_file(dirpath=self.args['work-dir'], filename='compile.sh',
379
+ command_lists=compile_lists,
380
+ line_breaks=compile_line_breaks)
381
+ all_lists.append(['./compile.sh'])
382
+
383
+ if elaborate_lists:
384
+ util.write_shell_command_file(dirpath=self.args['work-dir'], filename='elaborate.sh',
385
+ command_lists=elaborate_lists,
386
+ line_breaks=elaborate_line_breaks)
387
+ all_lists.append(['./elaborate.sh'])
388
+
389
+ if simulate_lists:
390
+ util.write_shell_command_file(dirpath=self.args['work-dir'], filename=simulate_sh_fname,
391
+ command_lists=simulate_lists,
392
+ line_breaks=simulate_line_breaks)
393
+ all_lists.append(['./' + simulate_sh_fname])
394
+
395
+ util.write_shell_command_file(dirpath=self.args['work-dir'], filename='all.sh',
396
+ command_lists=all_lists)
397
+
398
+ self.write_eda_config_and_args()
399
+
400
+
401
+
358
402
  # Methods that derived classes must override:
359
403
 
360
404
  def compile(self) -> None:
@@ -306,7 +306,9 @@ class DepsFile:
306
306
  return False
307
307
 
308
308
  if not is_valid_target_name(target_node):
309
- util.warning(f"In file {self.rel_deps_file}, {target_node} {VALID_TARGET_INFO_STR}")
309
+ util.warning(
310
+ f"In file {self.rel_deps_file}, {target_node} {VALID_TARGET_INFO_STR}"
311
+ )
310
312
 
311
313
  if not caller_info:
312
314
  # If we don't have caller_info, likely came from command line (or DEPS JSON data):
@@ -23,7 +23,7 @@ from opencos import util, eda_config, eda_base
23
23
  from opencos.eda_base import Tool, which_tool, get_eda_exec
24
24
  from opencos.utils import vsim_helper, vscode_helper
25
25
  from opencos.utils.subprocess_helpers import subprocess_run_background
26
- from opencos.utils import status_constants
26
+ from opencos.utils import status_constants, str_helpers
27
27
 
28
28
  # Configure util:
29
29
  util.progname = "EDA"
@@ -78,7 +78,7 @@ def get_all_commands_help_str(config: dict) -> str:
78
78
  return '\n'.join(all_commands_help)
79
79
 
80
80
 
81
- def usage(tokens: list, config: dict, command="") -> int:
81
+ def usage(tokens: list, config: dict, command: str = "", tool: str = "") -> int:
82
82
  '''Returns an int shell return code, given remaining args (tokens list) and eda command.
83
83
 
84
84
  config is the config dict. Used to check valid commands in config['command_handler']
@@ -112,6 +112,9 @@ And <files|targets, ...> is one or more source file or DEPS markup file target,
112
112
 
113
113
  if command in config['command_handler'].keys():
114
114
  sco = config['command_handler'][command](config=config) # sub command object
115
+ sco_tool = getattr(sco, '_TOOL', '')
116
+ if tool and tool != sco_tool:
117
+ util.warning(f'{tool=} does not support {command=}')
115
118
  sco.help(tokens=tokens)
116
119
  return util.exit(0)
117
120
 
@@ -282,9 +285,15 @@ def tool_setup(tool: str, config: dict, quiet: bool = False, auto_setup: bool =
282
285
  if tool not in config['auto_tools_order'][0]:
283
286
  tools = list(config.get('auto_tools_order', [{}])[0].keys())
284
287
  cfg_yaml_fname = config.get('config-yml', None)
288
+ util.warning(f'Unknown tool: {tool}')
289
+ if tools:
290
+ util.info('Known tools:')
291
+ pretty_tools = str_helpers.pretty_list_columns_manual(data=tools)
292
+ for row in pretty_tools:
293
+ if row:
294
+ util.info(row)
285
295
  util.error(f"Don't know how to run tool_setup({tool=}), is not in",
286
- f"config['auto_tools_order'] for {tools=}",
287
- f"from {cfg_yaml_fname}")
296
+ f"config['auto_tools_order'] from {cfg_yaml_fname}")
288
297
  return
289
298
 
290
299
  if tool not in config['auto_tools_found']:
@@ -394,7 +403,9 @@ def process_tokens( # pylint: disable=too-many-branches,too-many-statements,too-
394
403
  for arg in unparsed:
395
404
  if not arg.startswith('-'):
396
405
  command = arg
397
- return usage(tokens=unparsed, config=config, command=command)
406
+ if parsed.tool:
407
+ tool_setup(parsed.tool, config=config)
408
+ return usage(tokens=unparsed, config=config, command=command, tool=parsed.tool)
398
409
 
399
410
  if parsed.tool:
400
411
  tool_setup(parsed.tool, config=config)
@@ -252,7 +252,7 @@ class Command: # pylint: disable=too-many-public-methods
252
252
  })
253
253
  self.modified_args = {}
254
254
  self.config = copy.deepcopy(config) # avoid external modifications.
255
- self.target = ""
255
+ self.target = "" # is set as the 'top' or final target short-name (no path info)
256
256
  self.target_path = ""
257
257
  self.status = 0
258
258
  self.errors_log_f = None
@@ -943,6 +943,8 @@ class CommandDesign(Command): # pylint: disable=too-many-instance-attributes
943
943
  self.targets_dict = {} # key = targets that we've already processed in DEPS files
944
944
  self.last_added_source_file_inferred_top = ''
945
945
 
946
+ self.has_dep_shell_commands = False
947
+
946
948
 
947
949
  def run_dep_commands(self) -> None:
948
950
  '''Run shell/peakrdl style commands from DEPS files
@@ -993,10 +995,12 @@ class CommandDesign(Command): # pylint: disable=too-many-instance-attributes
993
995
 
994
996
  d['exec_list'] = clist # update to tee_fpath is set.
995
997
 
996
- util.write_shell_command_file(
997
- dirpath=self.args['work-dir'], filename='pre_compile_dep_shell_commands.sh',
998
- command_lists=all_cmds_lists
999
- )
998
+ if all_cmds_lists:
999
+ util.write_shell_command_file(
1000
+ dirpath=self.args['work-dir'], filename='pre_compile_dep_shell_commands.sh',
1001
+ command_lists=all_cmds_lists
1002
+ )
1003
+ self.has_dep_shell_commands = True
1000
1004
 
1001
1005
  for i, d in enumerate(self.dep_shell_commands):
1002
1006
  util.info(f'run_dep_shell_commands {i=}: {d=}')
@@ -1556,11 +1560,12 @@ class CommandDesign(Command): # pylint: disable=too-many-instance-attributes
1556
1560
 
1557
1561
  # handle a missing self.args['top'] with last filepath or last target:
1558
1562
  if not self.args.get('top', ''):
1563
+ top_path = ''
1559
1564
  if not last_potential_top_isfile and last_potential_top_target[0]:
1560
1565
  # If we have a target name from DEPS, prefer to use that.
1561
- self.args['top'], self.args['top-path'] = last_potential_top_target
1566
+ self.args['top'], top_path = last_potential_top_target
1562
1567
  util.info("--top not specified, inferred from target:",
1563
- f"{self.args['top']} ({self.args['top-path']})")
1568
+ f"{self.args['top']} ({top_path})")
1564
1569
 
1565
1570
  else:
1566
1571
  best_top_fname = self.last_added_source_file_inferred_top
@@ -1570,26 +1575,29 @@ class CommandDesign(Command): # pylint: disable=too-many-instance-attributes
1570
1575
  if not self.args['top'] and last_potential_top_file[0]:
1571
1576
  # If we don't have a target name, and no top name yet, then go looking for the
1572
1577
  # module name in the final source file added.
1573
- self.args['top-path'] = last_potential_top_file[1] # from tuple: (top, fpath)
1578
+ top_path = last_potential_top_file[1] # from tuple: (top, fpath)
1574
1579
  self.args['top'] = util.get_inferred_top_module_name(
1575
1580
  module_guess=last_potential_top_file[0],
1576
1581
  module_fpath=last_potential_top_file[1]
1577
1582
  )
1578
1583
  if self.args['top']:
1579
1584
  util.info("--top not specified, inferred from final source file:",
1580
- f"{self.args['top']} ({self.args['top-path']})")
1585
+ f"{self.args['top']} ({top_path})")
1581
1586
  # If top wasn't set, and we're using the final command-line 'arg' filename
1582
1587
  # (not from DEPS.yml) we need to override self.target if that was set. Otherwise
1583
1588
  # it won't save to the correct work-dir:
1584
1589
  self.target = self.args['top']
1585
1590
 
1591
+
1592
+ util.info(f'{self.command_name}: top-most target name: {self.target}')
1593
+
1586
1594
  if self.error_on_missing_top and not self.args.get('top', ''):
1587
1595
  self.error("Did not get a --top or DEPS top, required to run command",
1588
1596
  f"'{self.command_name}' for tool={self.args.get('tool', None)}",
1589
1597
  error_code=status_constants.EDA_COMMAND_MISSING_TOP)
1590
1598
 
1591
1599
  if self.tool_changed_respawn:
1592
- util.warning(
1600
+ util.info(
1593
1601
  'CommandDesign: need to respawn due to tool change to',
1594
1602
  f'\'{self.tool_changed_respawn["tool"]}\' from',
1595
1603
  f'\'{self.tool_changed_respawn["orig_tool"]}\'',
@@ -1615,7 +1623,7 @@ class CommandDesign(Command): # pylint: disable=too-many-instance-attributes
1615
1623
  for k,v in self.args.items():
1616
1624
 
1617
1625
  # Some args cannot be extracted and work, so omit these:
1618
- if k in ['top-path'] + remove_args:
1626
+ if k in remove_args:
1619
1627
  continue
1620
1628
  if any(k.startswith(x) for x in remove_args_startswith):
1621
1629
  continue
@@ -1637,9 +1645,6 @@ class CommandDesign(Command): # pylint: disable=too-many-instance-attributes
1637
1645
  return ret
1638
1646
 
1639
1647
 
1640
- #_THREADS_START = 0
1641
- #_THREADS_DONE = 0
1642
-
1643
1648
  class ThreadStats:
1644
1649
  '''To avoid globals for two ints, keep a class holder so CommandParallel and
1645
1650
  CommandParallelWorker can share values'''
@@ -7,6 +7,7 @@ DEFAULT_HANDLERS:
7
7
  # These commands (sim, elab, etc) require a tool, but have a default handler
8
8
  # base class:
9
9
  sim : opencos.commands.CommandSim
10
+ lint : opencos.commands.CommandLint
10
11
  elab : opencos.commands.CommandElab
11
12
  synth : opencos.commands.CommandSynth
12
13
  proj : opencos.commands.CommandProj
@@ -29,7 +30,8 @@ DEFAULT_HANDLERS:
29
30
 
30
31
  DEFAULT_HANDLERS_HELP:
31
32
  sim: Simulates a DEPS target.
32
- elab: Elaborates a DEPS target (lint, tool specific).
33
+ lint: Syntax check, lint a DEPS target
34
+ elab: Elaborates a DEPS target (lint + elab, tool specific).
33
35
  synth: Synthesizes a DEPS target.
34
36
  flist: Create dependency from a DEPS target.
35
37
  proj: Create a project from a DEPS target for GUI sim/waves/debug.
@@ -362,11 +364,13 @@ auto_tools_order:
362
364
  requires_cmd:
363
365
  - slang --version
364
366
  handlers:
367
+ lint: opencos.tools.slang.CommandLintSlang
365
368
  elab: opencos.tools.slang.CommandElabSlang
366
369
 
367
370
  verilator:
368
371
  exe: verilator
369
372
  handlers:
373
+ lint: opencos.tools.verilator.VerilatorLint
370
374
  elab: opencos.tools.verilator.VerilatorElab
371
375
  sim: opencos.tools.verilator.VerilatorSim
372
376
 
@@ -382,6 +386,7 @@ auto_tools_order:
382
386
  requires_cmd:
383
387
  - surelog --version
384
388
  handlers:
389
+ lint: opencos.tools.surelog.CommandLintSurelog
385
390
  elab: opencos.tools.surelog.CommandElabSurelog
386
391
 
387
392
  invio:
@@ -391,6 +396,7 @@ auto_tools_order:
391
396
  requires_py:
392
397
  - invio
393
398
  handlers:
399
+ lint: opencos.tools.invio.CommandLintInvio
394
400
  elab: opencos.tools.invio.CommandElabInvio
395
401
 
396
402
  vaporview:
@@ -422,6 +428,7 @@ auto_tools_order:
422
428
  vivado:
423
429
  exe: vivado
424
430
  handlers:
431
+ lint: opencos.tools.vivado.CommandLintVivado
425
432
  elab: opencos.tools.vivado.CommandElabVivado
426
433
  sim: opencos.tools.vivado.CommandSimVivado
427
434
  synth: opencos.tools.vivado.CommandSynthVivado
@@ -469,6 +476,7 @@ auto_tools_order:
469
476
  exe: qrun
470
477
  requires_vsim_helper: True
471
478
  handlers:
479
+ lint: opencos.tools.questa.CommandLintQuesta
472
480
  elab: opencos.tools.questa.CommandElabQuesta
473
481
  sim: opencos.tools.questa.CommandSimQuesta
474
482
  flist: opencos.tools.questa.CommandFListQuesta
@@ -479,6 +487,7 @@ auto_tools_order:
479
487
  - which riviera # Do not run it, make sure it's in PATH
480
488
  requires_vsim_helper: True
481
489
  handlers:
490
+ lint: opencos.tools.riviera.CommandLintRiviera
482
491
  elab: opencos.tools.riviera.CommandElabRiviera
483
492
  sim: opencos.tools.riviera.CommandSimRiviera
484
493
 
@@ -486,6 +495,7 @@ auto_tools_order:
486
495
  exe: vsim
487
496
  requires_vsim_helper: True
488
497
  handlers:
498
+ lint: opencos.tools.modelsim_ase.CommandLintModelsimAse
489
499
  elab: opencos.tools.modelsim_ase.CommandElabModelsimAse
490
500
  sim: opencos.tools.modelsim_ase.CommandSimModelsimAse
491
501
 
@@ -493,6 +503,7 @@ auto_tools_order:
493
503
  exe: vsim
494
504
  requires_vsim_helper: True
495
505
  handlers:
506
+ lint: opencos.tools.questa_fse.CommandLintQuestaFse
496
507
  elab: opencos.tools.questa_fse.CommandElabQuestaFse
497
508
  sim: opencos.tools.questa_fse.CommandSimQuestaFse
498
509
  flist: opencos.tools.questa_fse.CommandFListQuestaFse
@@ -500,6 +511,7 @@ auto_tools_order:
500
511
  iverilog:
501
512
  exe: iverilog
502
513
  handlers:
514
+ lint: opencos.tools.iverilog.CommandLintIverilog
503
515
  elab: opencos.tools.iverilog.CommandElabIverilog
504
516
  sim: opencos.tools.iverilog.CommandSimIverilog
505
517
 
@@ -65,6 +65,11 @@ def eda_elab_wrap(*args):
65
65
  main_args = [x for x in list(args) if (x != 'elab' and '--seed' not in x)]
66
66
  return eda.main('elab', *main_args)
67
67
 
68
+ def eda_lint_wrap(*args):
69
+ '''Calls eda.main for 'elab'.'''
70
+ main_args = [x for x in list(args) if (x != 'lint' and '--seed' not in x)]
71
+ return eda.main('lint', *main_args)
72
+
68
73
  def assert_sim_log_passes(
69
74
  filepath: str, want_str: str = 'TEST PASS',
70
75
  err_strs: list = ['Error', 'ERROR', 'TEST FAIL']
@@ -170,7 +170,7 @@ class TestsRequiresVerilator( # pylint: disable=too-many-public-methods
170
170
  assert res.stderr == b''
171
171
 
172
172
  res = subprocess.run(
173
- [ './simulate_only.sh' ], stdout=subprocess.PIPE, stderr=subprocess.PIPE,
173
+ [ './simulate.sh' ], stdout=subprocess.PIPE, stderr=subprocess.PIPE,
174
174
  check=True
175
175
  )
176
176
  rc = res.returncode
@@ -5,7 +5,7 @@ import pytest
5
5
 
6
6
  from opencos import eda_tool_helper
7
7
  from opencos.tests import helpers
8
- from opencos.tests.helpers import eda_wrap, eda_elab_wrap
8
+ from opencos.tests.helpers import eda_wrap, eda_elab_wrap, eda_lint_wrap
9
9
 
10
10
 
11
11
  thispath = os.path.dirname(__file__)
@@ -29,6 +29,16 @@ list_of_elab_tools = [
29
29
  'invio_yosys',
30
30
  ]
31
31
 
32
+ list_of_lint_tools = [
33
+ 'slang',
34
+ 'verilator',
35
+ 'vivado',
36
+ 'modelsim_ase'
37
+ 'questa_fse',
38
+ 'invio',
39
+ 'surelog',
40
+ ]
41
+
32
42
  list_of_elab_tools_cant_sim = [
33
43
  'slang',
34
44
  'invio',
@@ -36,6 +46,11 @@ list_of_elab_tools_cant_sim = [
36
46
  'invio_yosys',
37
47
  ]
38
48
 
49
+ list_of_commands = [
50
+ 'elab',
51
+ 'lint',
52
+ ]
53
+
39
54
  def skip_it(tool) -> bool:
40
55
  '''Returns True if this test should be skipped
41
56
 
@@ -44,27 +59,33 @@ def skip_it(tool) -> bool:
44
59
  '''
45
60
  return bool( tool not in tools_loaded )
46
61
 
62
+ @pytest.mark.parametrize("command", list_of_commands)
47
63
  @pytest.mark.parametrize("tool", list_of_elab_tools)
48
64
  class Tests:
49
65
  '''Test tools from list_of_elab_tools for 'eda elab' and 'eda multi elab'.'''
50
66
 
51
- def test_args_elab(self, tool):
67
+ def test_args_elab(self, command, tool):
52
68
  '''tests: eda elab --tool oclib_priarb'''
69
+ if command == 'lint' and tool not in list_of_lint_tools:
70
+ pytest.skip(f"lint skipped for {tool=} b/c it can't run lint")
53
71
  if skip_it(tool):
54
72
  pytest.skip(f"{tool=} skipped, {tools_loaded=}")
55
73
  return # skip/pass
56
74
  chdir_remove_work_dir('../../lib')
57
- rc = eda_elab_wrap('--tool', tool, 'oclib_priarb')
75
+ if command == 'elab':
76
+ rc = eda_elab_wrap('--tool', tool, 'oclib_priarb')
77
+ else:
78
+ rc = eda_lint_wrap('--tool', tool, 'oclib_priarb')
58
79
  print(f'{rc=}')
59
80
  assert rc == 0
60
81
 
61
- def test_args_multi_elab(self, tool):
82
+ def test_args_multi_elab(self, command, tool):
62
83
  '''tests: eda multi elab --tool oclib_*arb'''
63
84
  if skip_it(tool):
64
85
  pytest.skip(f"{tool=} skipped, {tools_loaded=}")
65
86
  return # skip/pass
66
87
  chdir_remove_work_dir('../../lib')
67
- rc = eda_wrap('multi', 'elab', '--tool', tool, 'oclib_*arb')
88
+ rc = eda_wrap('multi', command, '--tool', tool, 'oclib_*arb')
68
89
  print(f'{rc=}')
69
90
  assert rc == 0
70
91
 
@@ -122,20 +122,12 @@ class CommandSimCocotb(CommandSim, ToolCocotb):
122
122
  util.safe_mkdirs(base=self.args['work-dir'], new_dirs=paths)
123
123
 
124
124
  # Write shell scripts
125
- util.write_shell_command_file(
126
- dirpath=self.args['work-dir'],
127
- filename='cocotb_test.sh',
128
- command_lists=self.cocotb_command_lists,
129
- line_breaks=True
130
- )
131
-
132
- util.write_shell_command_file(
133
- dirpath=self.args['work-dir'],
134
- filename='all.sh',
135
- command_lists=[
136
- ['./pre_compile_dep_shell_commands.sh'],
137
- ['./cocotb_test.sh'],
138
- ]
125
+ self.write_sh_scripts_to_work_dir(
126
+ compile_lists=[],
127
+ elaborate_lists=[],
128
+ simulate_lists=self.cocotb_command_lists,
129
+ simulate_line_breaks=True,
130
+ simulate_sh_fname='cocotb_test.sh'
139
131
  )
140
132
 
141
133
  def _find_cocotb_test_files(self):
@@ -317,7 +309,7 @@ def run_cocotb_test():
317
309
  runner = get_runner(simulator)
318
310
 
319
311
  build_args = []
320
-
312
+
321
313
  if simulator == "verilator":
322
314
  build_args.extend({list(self.args.get('verilate-args', []))!r})
323
315
 
@@ -38,6 +38,8 @@ class ToolInvio(Tool):
38
38
  class CommandElabInvio(CommandElab, ToolInvio):
39
39
  '''Command handler for: eda elab --tool=invio'''
40
40
 
41
+ command_name = 'elab'
42
+
41
43
  def __init__(self, config:dict):
42
44
  CommandElab.__init__(self, config)
43
45
  ToolInvio.__init__(self, config=self.config)
@@ -72,7 +74,7 @@ class CommandElabInvio(CommandElab, ToolInvio):
72
74
  '''Returns list of util.ShellCommandList, for slang we'll run this in elaborate()'''
73
75
  invio_blackbox_list = self.args.get('invio-blackbox', [])
74
76
  invio_dict = invio_helpers.get_invio_command_dict(
75
- self, blackbox_list=invio_blackbox_list, sim_elab=True
77
+ self, blackbox_list=invio_blackbox_list,
76
78
  )
77
79
  return invio_dict['command_lists']
78
80
 
@@ -84,3 +86,8 @@ class CommandElabInvio(CommandElab, ToolInvio):
84
86
  def get_elaborate_command_lists(self, **kwargs) -> list:
85
87
  '''We only use 'compile' commands for invio elab, do not use elaborate commands'''
86
88
  return []
89
+
90
+ class CommandLintInvio(CommandElabInvio):
91
+ '''Command handler for: eda lint --tool=invio'''
92
+
93
+ command_name = 'lint'
@@ -34,6 +34,7 @@ def write_py_file(
34
34
  py_filename: str = 'run_invio.py',
35
35
  v_filename: str = '',
36
36
  blackbox_list: list = [],
37
+ sim_lint: bool = False,
37
38
  sim_elab: bool = False,
38
39
  **kwargs
39
40
  ) -> dict:
@@ -137,7 +138,15 @@ def write_py_file(
137
138
  tee_fpath = 'invio.log')]
138
139
  })
139
140
 
140
- if sim_elab:
141
+ if sim_lint:
142
+ # lint (skip elaborate steps -- from eda.CommandLintInvio)
143
+ lines += [
144
+ 'assert analyze()',
145
+ '',
146
+ 'report_analyzed_files()',
147
+ 'print_instance_hierarchy()',
148
+ ]
149
+ elif sim_elab:
141
150
  # elab (non-synthesis), runs the following (from eda.CommandElabInvio)
142
151
  lines += [
143
152
  'assert analyze()',
@@ -206,14 +215,23 @@ def write_py_file(
206
215
 
207
216
 
208
217
 
209
- def get_invio_command_dict(command_design_obj:object, v_filename='', py_filename='run_invio.py',
210
- blackbox_list=[], sim_elab:bool=False, **kwargs) -> dict:
218
+ def get_invio_command_dict(
219
+ command_design_obj:object, v_filename='', py_filename='run_invio.py',
220
+ blackbox_list=[],
221
+ **kwargs
222
+ ) -> dict:
211
223
  '''Creates a .py file from an eda.CommandDesign. Returns a dict with
212
224
 
213
225
  information about what to run.'''
214
226
 
215
- invio_dict = write_py_file( command_design_obj, v_filename=v_filename,
216
- py_filename=py_filename, blackbox_list=blackbox_list,
217
- sim_elab=sim_elab, **kwargs )
227
+ cmd_name = getattr(command_design_obj, 'command_name', '')
228
+ sim_lint = cmd_name == 'lint'
229
+ sim_elab = cmd_name == 'elab'
230
+
231
+ invio_dict = write_py_file(
232
+ command_design_obj, v_filename=v_filename,
233
+ py_filename=py_filename, blackbox_list=blackbox_list,
234
+ sim_elab=sim_elab, sim_lint=sim_lint, **kwargs
235
+ )
218
236
 
219
237
  return invio_dict
@@ -59,7 +59,7 @@ class CommandSynthInvioYosys(CommonSynthYosys, ToolInvioYosys):
59
59
 
60
60
  # Generate run_invio.py:
61
61
  invio_dict = invio_helpers.get_invio_command_dict(
62
- self, blackbox_list=invio_blackbox_list, sim_elab=False
62
+ self, blackbox_list=invio_blackbox_list,
63
63
  )
64
64
  # run run_invio.py:
65
65
  if not self.args.get('stop-before-compile', False):
@@ -146,9 +146,10 @@ class CommandSynthInvioYosys(CommonSynthYosys, ToolInvioYosys):
146
146
  class CommandElabInvioYosys(CommandSynthInvioYosys):
147
147
  '''Run invio + yosys as elab only (does not run the synthesis portion)'''
148
148
 
149
+ command_name = 'elab'
150
+
149
151
  def __init__(self, config):
150
152
  super().__init__(config)
151
- self.command_name = 'elab'
152
153
  self.args.update({
153
154
  'stop-after-compile': True, # In the case of Invio/Yosys we run the Invio step
154
155
  'lint': True