opencos-eda 0.3.15__py3-none-any.whl → 0.3.17__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 (38) hide show
  1. opencos/commands/flist.py +143 -88
  2. opencos/commands/shell.py +1 -1
  3. opencos/commands/sim.py +21 -8
  4. opencos/commands/waves.py +3 -1
  5. opencos/deps/defaults.py +6 -2
  6. opencos/deps/deps_file.py +30 -9
  7. opencos/deps/deps_processor.py +99 -65
  8. opencos/deps_schema.py +8 -0
  9. opencos/docs/DEPS.md +6 -0
  10. opencos/eda.py +30 -5
  11. opencos/eda_base.py +21 -9
  12. opencos/eda_config.py +2 -1
  13. opencos/eda_config_defaults.yml +9 -1
  14. opencos/eda_tool_helper.py +84 -9
  15. opencos/files.py +41 -0
  16. opencos/tools/cocotb.py +1 -1
  17. opencos/tools/invio.py +1 -1
  18. opencos/tools/invio_yosys.py +1 -1
  19. opencos/tools/iverilog.py +1 -1
  20. opencos/tools/quartus.py +1 -1
  21. opencos/tools/questa_common.py +6 -3
  22. opencos/tools/riviera.py +5 -3
  23. opencos/tools/slang.py +1 -1
  24. opencos/tools/slang_yosys.py +36 -8
  25. opencos/tools/surelog.py +1 -1
  26. opencos/tools/verilator.py +209 -20
  27. opencos/tools/vivado.py +1 -1
  28. opencos/tools/yosys.py +155 -30
  29. opencos/util.py +5 -1
  30. opencos/utils/docker_checks.py +224 -0
  31. opencos/utils/subprocess_helpers.py +3 -1
  32. {opencos_eda-0.3.15.dist-info → opencos_eda-0.3.17.dist-info}/METADATA +1 -1
  33. {opencos_eda-0.3.15.dist-info → opencos_eda-0.3.17.dist-info}/RECORD +38 -37
  34. {opencos_eda-0.3.15.dist-info → opencos_eda-0.3.17.dist-info}/WHEEL +0 -0
  35. {opencos_eda-0.3.15.dist-info → opencos_eda-0.3.17.dist-info}/entry_points.txt +0 -0
  36. {opencos_eda-0.3.15.dist-info → opencos_eda-0.3.17.dist-info}/licenses/LICENSE +0 -0
  37. {opencos_eda-0.3.15.dist-info → opencos_eda-0.3.17.dist-info}/licenses/LICENSE.spdx +0 -0
  38. {opencos_eda-0.3.15.dist-info → opencos_eda-0.3.17.dist-info}/top_level.txt +0 -0
@@ -7,14 +7,24 @@ Contains classes for ToolVerilator and VerilatorSim, VerilatorElab.
7
7
 
8
8
  import multiprocessing
9
9
  import os
10
+ from pathlib import Path
10
11
  import subprocess
11
12
 
12
13
 
13
14
  from opencos import util
14
15
  from opencos.commands import CommandSim
15
16
  from opencos.eda_base import Tool
16
- from opencos.files import safe_shutil_which
17
+ from opencos.files import safe_shutil_which, get_source_files_paths
18
+ from opencos.util import Colors
17
19
  from opencos.utils.str_helpers import sanitize_defines_for_sh
20
+ from opencos.utils.docker_checks import docker_ok, get_docker_run_command, \
21
+ get_error_str_cant_run_docker
22
+
23
+ class Warned:
24
+ '''So we only make the same warnings once, ToolVerilator may be called > 1 times'''
25
+ tool_get_versions_docker: bool = False
26
+ tool_get_versions_verilator_coverage: bool = False
27
+
18
28
 
19
29
  class ToolVerilator(Tool):
20
30
  '''ToolVerilator used by opencos.eda for --tool=verilator'''
@@ -23,17 +33,32 @@ class ToolVerilator(Tool):
23
33
  _EXE = 'verilator'
24
34
  _URL = 'github.com/verilator/verilator'
25
35
 
36
+ DEFAULT_DOCKER_IMAGE = 'verilator/verilator:latest'
37
+
26
38
  verilator_base_path = ''
27
39
  verilator_exe = ''
28
40
  verilator_coverage_exe = ''
41
+ no_verilator_but_has_docker = False
29
42
 
30
- def get_versions(self) -> str:
43
+ def get_versions(self, **kwargs) -> str: # pylint: disable=too-many-branches
31
44
  if self._VERSION:
32
45
  return self._VERSION
33
46
  # __init__ would have set self.EXE to full path.
34
47
  path = safe_shutil_which(self._EXE)
35
48
  if not path:
36
- self.error(f'"{self._EXE}" not in path or not installed, see {self._URL})')
49
+ # but can we run via docker?
50
+ if docker_ok():
51
+ if not Warned.tool_get_versions_docker:
52
+ Warned.tool_get_versions_docker = True
53
+ util.info(f'{Colors.cyan}"verilator"{Colors.green} not in path,',
54
+ f'may use {Colors.cyan}--docker-run{Colors.green}',
55
+ f'to run with {self.DEFAULT_DOCKER_IMAGE}, see',
56
+ f'{Colors.cyan}--help{Colors.green} for other options.')
57
+ self.verilator_exe = 'verilator'
58
+ self.verilator_base_path = ''
59
+ self.no_verilator_but_has_docker = True
60
+ else:
61
+ self.error(f'"{self._EXE}" not in path or not installed, see {self._URL})')
37
62
  else:
38
63
  self.verilator_exe = path
39
64
  self.verilator_base_path, _ = os.path.split(path)
@@ -43,27 +68,42 @@ class ToolVerilator(Tool):
43
68
  self.verilator_coverage_exe = safe_shutil_which(
44
69
  os.path.join(self.verilator_base_path, 'verilator_coverage')
45
70
  )
46
- if not self.verilator_coverage_exe:
71
+ if not self.verilator_coverage_exe and not docker_ok() and \
72
+ not Warned.tool_get_versions_verilator_coverage:
73
+ Warned.tool_get_versions_verilator_coverage = True
47
74
  util.warning('"verilator_coverage" not in path, need from same path',
48
75
  f'as "{self.verilator_exe}"')
49
76
 
50
- version_ret = subprocess.run(
51
- [self.verilator_exe, '--version'],
52
- capture_output=True,
53
- check=False
54
- )
77
+ if path:
78
+ version_ret = subprocess.run(
79
+ [self.verilator_exe, '--version'],
80
+ capture_output=True,
81
+ check=False
82
+ )
83
+ elif docker_ok():
84
+ version_ret = subprocess.run(
85
+ ['docker', 'run', self.DEFAULT_DOCKER_IMAGE, '--version'],
86
+ capture_output=True,
87
+ check=False
88
+ )
89
+ else:
90
+ self._VERSION = 'unknown'
91
+ return self._VERSION
92
+
55
93
  stdout = version_ret.stdout.decode('utf-8', errors='replace')
56
94
  util.debug(f'{path=} {version_ret=}')
57
95
  words = stdout.split() # 'Verilator 5.027 devel rev v5.026-92-g403a197e2
58
- if len(words) < 1:
96
+ if len(words) < 2:
59
97
  util.warning(
60
98
  f'{self.verilator_exe} --version: returned unexpected string {version_ret=}'
61
99
  )
62
- version = words[1]
63
- ver_list = version.split('.')
64
- if len(ver_list) != 2:
65
- util.warning(f'{self.verilator_exe} --version: returned unexpected',
66
- f'string {version_ret=} {version=}')
100
+ version = ''
101
+ else:
102
+ version = words[1]
103
+ ver_list = version.split('.')
104
+ if len(ver_list) != 2:
105
+ util.warning(f'{self.verilator_exe} --version: returned unexpected',
106
+ f'string {version_ret=} {version=}')
67
107
  self._VERSION = version
68
108
  return self._VERSION
69
109
 
@@ -84,6 +124,7 @@ class VerilatorSim(CommandSim, ToolVerilator):
84
124
  'verilator-coverage-args': [],
85
125
  'x-assign': '',
86
126
  'x-initial': '',
127
+ 'docker-image': self.DEFAULT_DOCKER_IMAGE
87
128
  })
88
129
 
89
130
  self.args_help.update({
@@ -137,6 +178,8 @@ class VerilatorSim(CommandSim, ToolVerilator):
137
178
  self.verilated_exec_command_lists = []
138
179
  self.verilated_post_exec_coverage_command_lists = []
139
180
 
181
+ self.docker_arg_set = False
182
+
140
183
 
141
184
  def set_tool_defines(self):
142
185
  ToolVerilator.set_tool_defines(self)
@@ -149,6 +192,27 @@ class VerilatorSim(CommandSim, ToolVerilator):
149
192
  self.set_tool_defines()
150
193
  self.update_library_map()
151
194
 
195
+ self.docker_arg_set = self.args['docker-run']
196
+ if self.no_verilator_but_has_docker and not self.docker_arg_set:
197
+ self.error('"verilator" was not found in PATH, but can be run with --docker-run',
198
+ 'and optionally --docker-image=verilator/verilator:vX.YYY')
199
+ return
200
+
201
+ if self.docker_arg_set:
202
+ # check that user can run docker?
203
+ if docker_ok():
204
+ # If this is docker, we cannot use the full path from self.verilator_exe,
205
+ # we have to simply use 'verilator' in the shell script that the docker image
206
+ # will run.
207
+ self.verilator_exe = 'verilator'
208
+ arg = '--docker-run'
209
+ util.info(
210
+ f'Running with {arg} --docker-image={self.args["docker-image"]}',
211
+ color=Colors.byellow
212
+ )
213
+ else:
214
+ self.error(get_error_str_cant_run_docker())
215
+
152
216
  # If there are C++ files here, then we will run Verilator in --cc mode:
153
217
  if self.files_cpp:
154
218
  self.args['cc-mode'] = True
@@ -164,12 +228,18 @@ class VerilatorSim(CommandSim, ToolVerilator):
164
228
  paths = ['obj_dir', 'logs']
165
229
  util.safe_mkdirs(base=self.args['work-dir'], new_dirs=paths)
166
230
 
167
- util.write_shell_command_file(dirpath=self.args['work-dir'], filename='lint_only.sh',
168
- command_lists=self.lint_only_command_lists, line_breaks=True)
169
231
 
170
- sim_cmd_lists = self.verilated_exec_command_lists + \
171
- (self.verilated_post_exec_coverage_command_lists
172
- if self.args.get('coverage', True) else [])
232
+ util.write_shell_command_file(
233
+ dirpath=self.args['work-dir'], filename='lint_only.sh',
234
+ command_lists=self.lint_only_command_lists, line_breaks=True
235
+ )
236
+
237
+ if self.args.get('lint-only', False):
238
+ sim_cmd_lists = []
239
+ else:
240
+ sim_cmd_lists = self.verilated_exec_command_lists + \
241
+ (self.verilated_post_exec_coverage_command_lists
242
+ if self.args.get('coverage', True) else [])
173
243
 
174
244
  self.write_sh_scripts_to_work_dir(
175
245
  compile_lists=self.verilate_command_lists,
@@ -177,6 +247,125 @@ class VerilatorSim(CommandSim, ToolVerilator):
177
247
  simulate_lists=sim_cmd_lists
178
248
  )
179
249
 
250
+ if self.docker_arg_set:
251
+ self.prepare_compile_docker()
252
+
253
+
254
+ def prepare_compile_docker(self) -> None:
255
+ '''Takes existing generated shell scripts, and saves out different ones.
256
+
257
+ will be used in compile() and simulate() steps.
258
+
259
+ 1. Assume the existing compile.sh exists.
260
+ a. Create docker_wrap_compile.sh that has:
261
+ docker [run|exec] --entrypoint /bin/bash IMAGE \
262
+ -c "cd WORK-DIR && ./copmile.sh"
263
+ b. where compile.sh is
264
+ i. The original contents from self.verilate_command_lists, but with
265
+ 'verilator' instead of '/path/to/verilator', which was handled
266
+ elsewhere looking at self.args['docker']
267
+
268
+ 2. Assume simulate.sh exists (or not)
269
+ a. Create docker_wrap_simulate.sh that has:
270
+ docker [run|exec] --entrypoint /bin/bash IMAGE \
271
+ -c "cd WORK-DIR && ./in_docker_simulate.sh"
272
+ b. simulate.sh unchanged, should already have the coverage commands
273
+
274
+ 3. Overwrite all.sh to call:
275
+ - docker_wrap_compile.sh
276
+ - docker_wrap_simulate.sh
277
+
278
+ 4. Destroy the self.*_command_lists so they point to the bash scripts.
279
+ '''
280
+ if not self.docker_arg_set:
281
+ return
282
+
283
+ # TODO(drew): Windows friendly? Probably not. a lot of ./ going on here.
284
+
285
+ work_dir_abs = Path(self.args['work-dir']).resolve()
286
+
287
+ docker_command = 'run'
288
+ docker_run_base_cmd = get_docker_run_command(
289
+ image=self.args['docker-image'],
290
+ docker_command=docker_command,
291
+ env_dict={'CCACHE_DIR': '/tmp/ccache'}, # For macos verilator compatibility
292
+ ro_volumes=get_source_files_paths(cmd_des_obj=self, minimal_root_paths=True),
293
+ rw_volumes=[work_dir_abs],
294
+ )
295
+
296
+ util.write_shell_command_file(
297
+ dirpath=self.args['work-dir'],
298
+ filename='docker_wrap_compile.sh',
299
+ command_lists=[
300
+ util.ShellCommandList(docker_run_base_cmd + [
301
+ '-c', f'\'cd {work_dir_abs} && ./compile.sh\'',
302
+ ], tee_fpath='compile.log')
303
+ ],
304
+ line_breaks=False
305
+ )
306
+
307
+ util.write_shell_command_file(
308
+ dirpath=self.args['work-dir'],
309
+ filename='docker_wrap_lint_only.sh',
310
+ command_lists=[
311
+ util.ShellCommandList(docker_run_base_cmd + [
312
+ '-c', f'\'cd {work_dir_abs} && ./lint_only.sh\'',
313
+ ], tee_fpath='lint_only.log')
314
+ ],
315
+ line_breaks=False
316
+ )
317
+
318
+ util.write_shell_command_file(
319
+ dirpath=self.args['work-dir'],
320
+ filename='docker_wrap_simulate.sh',
321
+ command_lists=[
322
+ util.ShellCommandList(docker_run_base_cmd + [
323
+ '-c', f'\'cd {work_dir_abs} && ./simulate.sh\'',
324
+ ], tee_fpath='sim.log')
325
+ ],
326
+ line_breaks=False
327
+ )
328
+
329
+
330
+ all_lists = [] # list - of - (command-list)
331
+ if self.has_pre_compile_dep_shell_commands:
332
+ all_lists.append(['./pre_compile_dep_shell_commands.sh'])
333
+ if self.args.get('lint-only', False):
334
+ all_lists.append(['./docker_wrap_lint_only.sh'])
335
+ else:
336
+ all_lists.append(['./docker_wrap_compile.sh'])
337
+ all_lists.append(['./docker_wrap_simulate.sh'])
338
+ if self.has_post_tool_dep_shell_commands:
339
+ all_lists.append(['./post_tool_dep_shell_commands.sh'])
340
+
341
+ util.write_shell_command_file(
342
+ dirpath=self.args['work-dir'], filename='all.sh',
343
+ command_lists=all_lists, line_breaks=True
344
+ )
345
+
346
+ # Overwrite our command lists so compile(), simulate() work correctly.
347
+ if self.verilate_command_lists:
348
+ self.verilate_command_lists = [
349
+ util.ShellCommandList(
350
+ ['./docker_wrap_compile.sh'], tee_fpath='docker_wrap_compile.log'
351
+ )
352
+ ]
353
+ if self.lint_only_command_lists:
354
+ self.lint_only_command_lists = [
355
+ util.ShellCommandList(
356
+ ['./docker_wrap_lint_only.sh'], tee_fpath='docker_wrap_lint_only.log'
357
+ )
358
+ ]
359
+ if self.verilated_exec_command_lists:
360
+ self.verilated_exec_command_lists = [
361
+ util.ShellCommandList(
362
+ ['./docker_wrap_simulate.sh'], tee_fpath='docker_wrap_simulate.log'
363
+ )
364
+ ]
365
+ self.verilated_post_exec_coverage_command_lists = [ ] # clear, in docker_wrap_simulate
366
+
367
+ return
368
+
180
369
 
181
370
  def compile(self):
182
371
  if self.args['stop-before-compile']:
opencos/tools/vivado.py CHANGED
@@ -46,7 +46,7 @@ class ToolVivado(Tool):
46
46
  })
47
47
 
48
48
 
49
- def get_versions(self) -> str:
49
+ def get_versions(self, **kwargs) -> str:
50
50
  if self._VERSION:
51
51
  return self._VERSION
52
52
 
opencos/tools/yosys.py CHANGED
@@ -9,11 +9,13 @@ import os
9
9
  import subprocess
10
10
 
11
11
  from opencos import util, eda_config
12
- from opencos.commands import CommandSynth, CommandLec
12
+ from opencos.commands import CommandSynth, CommandLec, CommandFList
13
13
  from opencos.eda_base import Tool, get_eda_exec
14
14
  from opencos.files import safe_shutil_which
15
15
  from opencos.utils.markup_helpers import yaml_safe_load
16
16
 
17
+ from opencos.commands.sim import parameters_dict_get_command_list
18
+
17
19
 
18
20
  def get_commands_to_run_scriptfiles(
19
21
  script_fnames_list: list, yosys_exe: str
@@ -37,6 +39,63 @@ def get_commands_to_run_scriptfiles(
37
39
  return yosys_cmdlists
38
40
 
39
41
 
42
+
43
+ def get_yosys_defines_incdirs_files(
44
+ command_design_obj,
45
+ for_synthesis: bool = True,
46
+ **kwargs,
47
+ ) -> list:
48
+ '''
49
+ Returns a partial list of all the args for a read_verilog or read_slang command in yosys
50
+ Handles defines, incdirs, files_sv, files_v
51
+
52
+ command_design_obj is intended to be a opencos.eda_base.CommandDesign or derived class
53
+ object.
54
+
55
+ This should be used by CommandFList or CommandSynth derivations for yosys tools:
56
+ *Yosys, *SlangYosys
57
+
58
+ Valid kwargs bools (default True if ommitted) - defines, incdirs, verilog, systemverilog, top
59
+ '''
60
+
61
+ ret_list = []
62
+
63
+ defines = getattr(command_design_obj, 'defines', {})
64
+ incdirs = getattr(command_design_obj, 'incdirs', [])
65
+ files_v = getattr(command_design_obj, 'files_v', [])
66
+ files_sv = getattr(command_design_obj, 'files_sv', [])
67
+ top = getattr(command_design_obj, 'args', {}).get('top', '')
68
+
69
+
70
+ if kwargs.get('defines', True):
71
+ for name, value in defines.items():
72
+ if not name:
73
+ continue
74
+ if for_synthesis and name in ['SIMULATION']:
75
+ continue
76
+
77
+ if value is None:
78
+ ret_list.append(f'--define-macro {name}')
79
+ else:
80
+ ret_list.append(f'--define-macro {name}={value}')
81
+
82
+ # We must define SYNTHESIS for oclib_defines.vh to work correctly.
83
+ if for_synthesis and 'SYNTHESIS' not in defines:
84
+ ret_list.append('--define-macro SYNTHESIS')
85
+
86
+ if kwargs.get('incdirs', True):
87
+ for path in incdirs:
88
+ ret_list.append(f'-I {path}')
89
+ if kwargs.get('verilog', True):
90
+ ret_list.extend(files_v)
91
+ if kwargs.get('systemverilog', True):
92
+ ret_list.extend(files_sv)
93
+ if kwargs.get('top', True) and top:
94
+ ret_list.append(f'--top {top}')
95
+
96
+ return ret_list
97
+
98
+
40
99
  class ToolYosys(Tool):
41
100
  '''Parent class for ToolTabbyCadYosys, ToolInvioYosys, ToolSlangYosys'''
42
101
 
@@ -48,7 +107,7 @@ class ToolYosys(Tool):
48
107
  sta_exe = ''
49
108
  sta_version = ''
50
109
 
51
- def get_versions(self) -> str:
110
+ def get_versions(self, **kwargs) -> str:
52
111
  if self._VERSION:
53
112
  return self._VERSION
54
113
 
@@ -478,34 +537,7 @@ class CommonSynthYosys(CommandSynth, ToolYosys):
478
537
 
479
538
  Handles defines, incdirs, files_sv, files_v
480
539
  '''
481
- ret_list = []
482
-
483
- for name,value in self.defines.items():
484
- if not name:
485
- continue
486
- if name in ['SIMULATION']:
487
- continue
488
-
489
- if value is None:
490
- ret_list.append(f'--define-macro {name}')
491
- else:
492
- ret_list.append(f'--define-macro {name}={value}')
493
-
494
- # We must define SYNTHESIS for oclib_defines.vh to work correctly.
495
- if 'SYNTHESIS' not in self.defines:
496
- ret_list.append('--define-macro SYNTHESIS')
497
-
498
- for path in self.incdirs:
499
- ret_list.append(f'-I {path}')
500
-
501
- for path in self.files_v:
502
- ret_list.append(path)
503
-
504
- for path in self.files_sv:
505
- ret_list.append(path)
506
-
507
- ret_list.append(f'--top {self.args["top"]}')
508
- return ret_list
540
+ return get_yosys_defines_incdirs_files(command_design_obj=self, for_synthesis=True)
509
541
 
510
542
 
511
543
  class CommandLecYosys(CommandLec, ToolYosys):
@@ -742,3 +774,96 @@ class CommandLecYosys(CommandLec, ToolYosys):
742
774
  lec_cmd_list = 'yosys --scriptfile yosys_lec.f'.split()
743
775
  util.info(f'LEC running {lec_cmd_list}')
744
776
  self.exec(self.args['work-dir'], lec_cmd_list)
777
+
778
+
779
+ class CommonFListYosys(CommandFList, ToolYosys):
780
+ '''
781
+ Handler for: eda flist --tool=yosys
782
+
783
+ This will create a eda.yosys_read_verilog.f flist (or to std-out if --print-to-stdout),
784
+ suitable for args passed to a "read_verilog" command in yosys, such as:
785
+
786
+ read_verilog -f FILE_CREATED_BY_THIS_HANDLER [other args]
787
+
788
+ '''
789
+ def __init__(self, config: dict, **kwargs):
790
+ CommandFList.__init__(self, config=config,
791
+ # Added bonus - remove some CommandFList args that we don't
792
+ # need:
793
+ include_prefix_args=False, include_quote_args=False,
794
+ include_format_define_args=False)
795
+ ToolYosys.__init__(self, config=self.config)
796
+
797
+ self.args.update({
798
+ 'force': True, # always overwrite the output
799
+ 'out': 'eda_flist.yosys.read_verilog.f',
800
+
801
+ 'emit-define' : True,
802
+ 'emit-parameter' : True,
803
+ 'emit-incdir' : True,
804
+ 'emit-plusargs' : True,
805
+ 'emit-v' : True,
806
+ 'emit-sv' : True,
807
+ 'emit-vhd' : True,
808
+ 'emit-cpp' : False,
809
+ 'emit-non-sources' : False, # as comments, from DEPS 'reqs'
810
+ })
811
+
812
+ def get_flist_plusargs_list(self) -> list:
813
+ '''Overriden from CommandFList.'''
814
+ if self.args['unprocessed-plusargs']:
815
+ util.warning(f'Command "flist" for --tool={self._TOOL} is not intended for simulation',
816
+ 'and plusargs were present. They will NOT be included in the flist:',
817
+ f'{self.args["unprocessed-plusargs"]}')
818
+
819
+ return []
820
+
821
+ def get_write_flist_lines(
822
+ self, add_comment_lines: bool = False
823
+ ) -> list:
824
+ '''Override from CommandFList'''
825
+
826
+ # Want: defines + parameters + incdirs + files + --top=VALUE, similar to
827
+ # how we call CommonSynthYosys.get_yosys_read_verilog_defines_incdirs_files(),
828
+ # but without the additional args
829
+
830
+ ret = []
831
+
832
+ # Use our overriden method to post warnings about brining simulation Plusargs to
833
+ # a Yosys tool:
834
+ _ = self.get_flist_plusargs_list()
835
+
836
+ if add_comment_lines:
837
+ ret.append(f"## {self.args=}")
838
+
839
+ if self.files_non_source:
840
+ ret.append('## reqs (non-source files that are dependencies):')
841
+ for f in self.files_non_source:
842
+ if self.args['emit-rel-path']:
843
+ f = os.path.relpath(f)
844
+ ret.append(f'## {f}')
845
+
846
+ # Note - top is included in this:
847
+ include_items = []
848
+ if self.args['emit-define']:
849
+ include_items.append('defines')
850
+ if self.args['emit-incdir']:
851
+ include_items.append('incdirs')
852
+
853
+ ret.extend(get_yosys_defines_incdirs_files(
854
+ command_design_obj=self,
855
+ for_synthesis=True,
856
+ # True/False kwargs if you want that emitted:
857
+ defines=self.args['emit-define'],
858
+ incdirs=self.args['emit-incdir'],
859
+ verilog=self.args['emit-v'],
860
+ systemverilog=self.args['emit-sv'],
861
+ top=True
862
+ ))
863
+
864
+ # and parameters:
865
+ ret.extend(parameters_dict_get_command_list(
866
+ params=self.parameters, arg_prefix='-G '
867
+ ))
868
+
869
+ return ret
opencos/util.py CHANGED
@@ -20,6 +20,7 @@ from importlib import import_module
20
20
  from dotenv import load_dotenv
21
21
  from supports_color import supportsColor
22
22
 
23
+ import opencos
23
24
  from opencos.files import safe_shutil_which
24
25
  from opencos.utils import status_constants
25
26
  from opencos.utils.str_helpers import strip_ansi_color
@@ -359,7 +360,10 @@ def get_argparser() -> argparse.ArgumentParser:
359
360
  # boolean actions:
360
361
  bool_action_kwargs = get_argparse_bool_action_kwargs()
361
362
 
362
- parser.add_argument('--version', default=False, action='store_true')
363
+ parser.add_argument('--version', default=False, action='store_true',
364
+ help=('Shows our version:'
365
+ f' {opencos.__version__} ({opencos.__pyproject_name__})')
366
+ )
363
367
  parser.add_argument('--color', **bool_action_kwargs, default=bool(supportsColor.stdout),
364
368
  help='Use shell colors for info/warning/error messaging')
365
369
  parser.add_argument('--emoji', **bool_action_kwargs, default=args['emoji'],