opencos-eda 0.2.57__py3-none-any.whl → 0.3.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 (36) hide show
  1. opencos/_version.py +6 -3
  2. opencos/_waves_pkg.sv +34 -2
  3. opencos/commands/build.py +1 -0
  4. opencos/commands/export.py +1 -0
  5. opencos/commands/flist.py +1 -0
  6. opencos/commands/lec.py +1 -0
  7. opencos/commands/proj.py +1 -0
  8. opencos/commands/shell.py +4 -0
  9. opencos/commands/sim.py +47 -1
  10. opencos/commands/synth.py +4 -0
  11. opencos/deps/defaults.py +15 -7
  12. opencos/deps/deps_commands.py +84 -74
  13. opencos/deps/deps_file.py +11 -5
  14. opencos/deps/deps_processor.py +79 -3
  15. opencos/deps_schema.py +3 -0
  16. opencos/eda.py +2 -1
  17. opencos/eda_base.py +105 -34
  18. opencos/eda_config_defaults.yml +5 -1
  19. opencos/files.py +1 -0
  20. opencos/tests/deps_files/command_order/DEPS.yml +11 -0
  21. opencos/tests/helpers.py +50 -20
  22. opencos/tests/test_deps_helpers.py +37 -25
  23. opencos/tests/test_eda.py +26 -60
  24. opencos/tools/modelsim_ase.py +17 -9
  25. opencos/tools/riviera.py +31 -6
  26. opencos/tools/verilator.py +28 -38
  27. opencos/util.py +111 -16
  28. opencos/utils/vscode_helper.py +1 -1
  29. opencos/utils/vsim_helper.py +1 -1
  30. {opencos_eda-0.2.57.dist-info → opencos_eda-0.3.1.dist-info}/METADATA +2 -1
  31. {opencos_eda-0.2.57.dist-info → opencos_eda-0.3.1.dist-info}/RECORD +36 -36
  32. {opencos_eda-0.2.57.dist-info → opencos_eda-0.3.1.dist-info}/WHEEL +0 -0
  33. {opencos_eda-0.2.57.dist-info → opencos_eda-0.3.1.dist-info}/entry_points.txt +0 -0
  34. {opencos_eda-0.2.57.dist-info → opencos_eda-0.3.1.dist-info}/licenses/LICENSE +0 -0
  35. {opencos_eda-0.2.57.dist-info → opencos_eda-0.3.1.dist-info}/licenses/LICENSE.spdx +0 -0
  36. {opencos_eda-0.2.57.dist-info → opencos_eda-0.3.1.dist-info}/top_level.txt +0 -0
@@ -59,26 +59,26 @@ def test_get_all_targets_eda_multi():
59
59
 
60
60
  def test_parse_deps_shell_str__no_parse():
61
61
  line = 'some_file.sv'
62
- d = deps_commands.parse_deps_shell_str(line, '', '')
62
+ d = deps_commands.parse_deps_shell_str(line, '', '', attributes={})
63
63
  assert not d, f'{d=}'
64
64
 
65
65
  line = 'some_target:'
66
- d = deps_commands.parse_deps_shell_str(line, '', '')
66
+ d = deps_commands.parse_deps_shell_str(line, '', '', attributes={})
67
67
  assert not d, f'{d=}'
68
68
 
69
69
  line = ' csr@some_file.sv'
70
- d = deps_commands.parse_deps_shell_str(line, '', '')
70
+ d = deps_commands.parse_deps_shell_str(line, '', '', attributes={})
71
71
  assert not d, f'{d=}'
72
72
 
73
73
  def test_parse_deps_shell_str__cp():
74
74
  line = ' shell@ cp ./oclib_fifo_test.sv oclib_fifo_test_COPY.sv ;'
75
- d = deps_commands.parse_deps_shell_str(line, '', '')
75
+ d = deps_commands.parse_deps_shell_str(line, '', '', attributes={})
76
76
  assert d, f'{d=}'
77
77
  assert d['exec_list'] == ['cp', './oclib_fifo_test.sv', 'oclib_fifo_test_COPY.sv', ';'], f'{d=}'
78
78
 
79
79
  def test_parse_deps_shell_str__echo():
80
80
  line = ' shell@echo "hello world"'
81
- d = deps_commands.parse_deps_shell_str(line, '', '')
81
+ d = deps_commands.parse_deps_shell_str(line, '', '', attributes={})
82
82
  assert d, f'{d=}'
83
83
  assert d['exec_list'] == ['echo', '"hello', 'world"'], f'{d=}'
84
84
 
@@ -88,7 +88,9 @@ def test_parse_deps_shell_str__enable_filepath_replacement():
88
88
  module_dir = os.path.dirname(os.path.abspath(__file__))
89
89
  os.chdir(module_dir)
90
90
  line = 'shell@cp ../deps/deps_commands.py .pytest.copied.py'
91
- d = deps_commands.parse_deps_shell_str(line, target_path='./', target_node='foo_target')
91
+ d = deps_commands.parse_deps_shell_str(
92
+ line, target_path='./', target_node='foo_target', attributes={}
93
+ )
92
94
  assert d, f'{d=}'
93
95
  spath = os.path.abspath(os.path.join('..', 'deps', 'deps_commands.py'))
94
96
  assert d['exec_list'] == ['cp', spath, '.pytest.copied.py'], f'{d=}'
@@ -100,8 +102,10 @@ def test_parse_deps_shell_str__disable_filepath_replacement():
100
102
  module_dir = os.path.dirname(os.path.abspath(__file__))
101
103
  os.chdir(module_dir)
102
104
  line = 'shell@cp ../deps/deps_commands.py .pytest.copied.py'
103
- d = deps_commands.parse_deps_shell_str(line, target_path='./', target_node='foo_target',
104
- enable_filepath_subst_target_dir=False)
105
+ d = deps_commands.parse_deps_shell_str(
106
+ line, target_path='./', target_node='foo_target',
107
+ attributes={'filepath-subst-target-dir': False}
108
+ )
105
109
  assert d, f'{d=}'
106
110
  assert d['exec_list'] == ['cp', '../deps/deps_commands.py', '.pytest.copied.py'], f'{d=}'
107
111
  assert d['target_node'] == 'foo_target'
@@ -112,8 +116,10 @@ def test_parse_deps_shell_str__enable_dirpath_replacement():
112
116
  module_dir = os.path.dirname(os.path.abspath(__file__))
113
117
  os.chdir(module_dir)
114
118
  line = 'shell@ls -ltr ./'
115
- d = deps_commands.parse_deps_shell_str(line, target_path='./', target_node='foo_target',
116
- enable_dirpath_subst_target_dir=True)
119
+ d = deps_commands.parse_deps_shell_str(
120
+ line, target_path='./', target_node='foo_target',
121
+ attributes={'dirpath-subst-target-dir': True}
122
+ )
117
123
  assert d, f'{d=}'
118
124
  assert d['exec_list'] == ['ls', '-ltr', os.path.abspath('./')], f'{d=}'
119
125
  assert d['target_node'] == 'foo_target'
@@ -125,7 +131,10 @@ def test_parse_deps_shell_str__disable_dirpath_replacement():
125
131
  module_dir = os.path.dirname(os.path.abspath(__file__))
126
132
  os.chdir(module_dir)
127
133
  line = 'shell@ls -ltr ./'
128
- d = deps_commands.parse_deps_shell_str(line, target_path='./', target_node='foo_target')
134
+ d = deps_commands.parse_deps_shell_str(
135
+ line, target_path='./', target_node='foo_target',
136
+ attributes={}
137
+ )
129
138
  assert d, f'{d=}'
130
139
  assert d['exec_list'] == ['ls', '-ltr', './'], f'{d=}'
131
140
  assert d['target_node'] == 'foo_target'
@@ -134,26 +143,26 @@ def test_parse_deps_shell_str__disable_dirpath_replacement():
134
143
 
135
144
  def test_parse_deps_work_dir_add_srcs__no_parse():
136
145
  line = 'some_file.sv'
137
- d = deps_commands.parse_deps_work_dir_add_srcs(line, '', '')
146
+ d = deps_commands.parse_deps_work_dir_add_srcs(line, '', '', {})
138
147
  assert not d, f'{d=}'
139
148
 
140
149
  line = 'some_target:'
141
- d = deps_commands.parse_deps_work_dir_add_srcs(line, '', '')
150
+ d = deps_commands.parse_deps_work_dir_add_srcs(line, '', '', {})
142
151
  assert not d, f'{d=}'
143
152
 
144
153
  line = ' csr@some_file.sv'
145
- d = deps_commands.parse_deps_work_dir_add_srcs(line, '', '')
154
+ d = deps_commands.parse_deps_work_dir_add_srcs(line, '', '', {})
146
155
  assert not d, f'{d=}'
147
156
 
148
157
  def test_parse_deps_work_dir_add_srcs__single_file():
149
158
  line = ' work_dir_add_srcs@ single_file.txt'
150
- d = deps_commands.parse_deps_work_dir_add_srcs(line, '', '')
159
+ d = deps_commands.parse_deps_work_dir_add_srcs(line, '', '', {})
151
160
  assert d, f'{d=}'
152
161
  assert d['file_list'] == ['single_file.txt']
153
162
 
154
163
  def test_parse_deps_work_dir_add_srcs__several_file():
155
164
  line = ' work_dir_add_srcs@ single_file.txt another.sv gen-verilog/mine.v ./gen-vhdl/wordy.vhdl'
156
- d = deps_commands.parse_deps_work_dir_add_srcs(line, '', '')
165
+ d = deps_commands.parse_deps_work_dir_add_srcs(line, '', '', {})
157
166
  assert d, f'{d=}'
158
167
  assert d['file_list'] == [
159
168
  'single_file.txt', 'another.sv', 'gen-verilog/mine.v', './gen-vhdl/wordy.vhdl'
@@ -162,34 +171,37 @@ def test_parse_deps_work_dir_add_srcs__several_file():
162
171
 
163
172
  def test_parse_deps_peakrdl__no_parse():
164
173
  line = 'some_file.sv'
165
- d = deps_commands.parse_deps_peakrdl(line, '', '')
174
+ d = deps_commands.parse_deps_peakrdl(line, '', '', {})
166
175
  assert not d, f'{d=}'
167
176
 
168
177
  line = 'some_target:'
169
- d = deps_commands.parse_deps_peakrdl(line, '', '')
178
+ d = deps_commands.parse_deps_peakrdl(line, '', '', {})
170
179
  assert not d, f'{d=}'
171
180
 
172
181
  line = ' csr@some_file.sv'
173
- d = deps_commands.parse_deps_peakrdl(line, '', '')
182
+ d = deps_commands.parse_deps_peakrdl(line, '', '', {})
174
183
  assert not d, f'{d=}'
175
184
 
176
185
  def test_parse_deps_peakrdl__with_top():
177
186
  line = ' peakrdl@ --cpuif axi4-lite-flat --top my_fancy_csrs ./my_csrs.rdl'
178
- d = deps_commands.parse_deps_peakrdl(line, '', '')
187
+ d = deps_commands.parse_deps_peakrdl(line, '', '', {})
179
188
  assert d, f'{d=}'
180
189
  assert len(d['shell_commands_list']) > 0
181
- assert d['work_dir_add_srcs']['file_list'] == ['peakrdl/my_fancy_csrs_pkg.sv', 'peakrdl/my_fancy_csrs.sv']
190
+ assert d['work_dir_add_srcs']['file_list'] == ['peakrdl/my_fancy_csrs_pkg.sv',
191
+ 'peakrdl/my_fancy_csrs.sv']
182
192
 
183
193
  def test_parse_deps_peakrdl__with_top2():
184
194
  line = ' peakrdl@ --cpuif axi4-lite-flat --top=my_fancy_csrs ./my_csrs.rdl'
185
- d = deps_commands.parse_deps_peakrdl(line, '', '')
195
+ d = deps_commands.parse_deps_peakrdl(line, '', '', {})
186
196
  assert d, f'{d=}'
187
197
  assert len(d['shell_commands_list']) > 0
188
- assert d['work_dir_add_srcs']['file_list'] == ['peakrdl/my_fancy_csrs_pkg.sv', 'peakrdl/my_fancy_csrs.sv']
198
+ assert d['work_dir_add_srcs']['file_list'] == ['peakrdl/my_fancy_csrs_pkg.sv',
199
+ 'peakrdl/my_fancy_csrs.sv']
189
200
 
190
201
  def test_parse_deps_peakrdl__infer_top():
191
202
  line = ' peakrdl@ --cpuif axi4-lite-flat ./my_csrs.rdl'
192
- d = deps_commands.parse_deps_peakrdl(line, '', '')
203
+ d = deps_commands.parse_deps_peakrdl(line, '', '', {})
193
204
  assert d, f'{d=}'
194
205
  assert len(d['shell_commands_list']) > 0
195
- assert d['work_dir_add_srcs']['file_list'] == ['peakrdl/my_csrs_pkg.sv', 'peakrdl/my_csrs.sv']
206
+ assert d['work_dir_add_srcs']['file_list'] == ['peakrdl/my_csrs_pkg.sv',
207
+ 'peakrdl/my_csrs.sv']
opencos/tests/test_eda.py CHANGED
@@ -20,7 +20,6 @@ and should be more gracefully handled.
20
20
  import os
21
21
  import shutil
22
22
  import subprocess
23
- from contextlib import redirect_stdout, redirect_stderr
24
23
 
25
24
  import pytest
26
25
 
@@ -107,6 +106,7 @@ class TestsRequiresVerilator( # pylint: disable=too-many-public-methods
107
106
  assert rc == 0
108
107
 
109
108
 
109
+
110
110
  def test_args_sim_tool_with_path(self):
111
111
  '''Test for calling a tool as --tool=<tool>=</path/to/tool-exe>'''
112
112
  verilator_fullpath = shutil.which('verilator')
@@ -659,6 +659,31 @@ class TestsRequiresIVerilog(Helpers):
659
659
  assert rc == 0
660
660
 
661
661
 
662
+ @pytest.mark.skipif(not can_run_eda_sim(), reason='no tool found to handle command: sim')
663
+ class TestArgs(Helpers):
664
+ '''Test some args features, needs a sim tool'''
665
+ DEFAULT_DIR = os.path.join(THISPATH, '..', '..', 'lib', 'tests')
666
+
667
+ def test_duplicate_args(self):
668
+ '''Use oclib_fifo_test to make sure we don't lose (do NOT uniquify) duplicate
669
+ list-style args'''
670
+ self.chdir()
671
+ rc = self.log_it(
672
+ 'sim --stop-before-compile oclib_fifo_test --compile-args=-hi --compile-args=-hi',
673
+ use_eda_wrap=False
674
+ )
675
+ assert rc == 0
676
+ # Confirm we have two args in self.args['compile-args'] for: -hi
677
+ eda_config_yml_path = os.path.join(
678
+ os.getcwd(), 'eda.work', 'oclib_fifo_test.sim', 'eda_output_config.yml'
679
+ )
680
+ data = yaml_safe_load(eda_config_yml_path)
681
+ assert 'args' in data
682
+ assert 'compile-args' in data['args']
683
+ assert len(data['args']['compile-args']) == 2
684
+ assert data['args']['compile-args'] == ['-hi', '-hi']
685
+
686
+
662
687
  @pytest.mark.skipif(not can_run_eda_sim(), reason='no tool found to handle command: sim')
663
688
  class TestDepsReqs:
664
689
  '''Tests for 'reqs' in the DEPS files. 'reqs' are requirements, like a .pcap or file
@@ -708,65 +733,6 @@ class TestDepsReqs:
708
733
  assert rc > 1
709
734
 
710
735
 
711
- @pytest.mark.parametrize("command", ['sim', 'shell'])
712
- def test_deps_command_order(command):
713
- '''Test for various "commands" within a DEPS target. This test checks that command
714
- order is preserved in the top-to-bottom deps order, meaning that eda.py has to collect
715
- all commands deps order, and then execute them in that order.'''
716
-
717
- chdir_remove_work_dir('deps_files/command_order')
718
- if command == 'sim' and not can_run_eda_sim():
719
- pytest.skip(f'sim skipped, {can_run_eda_sim()=}')
720
- return # skip/pass
721
-
722
- if command == 'shell':
723
- cmd_list = 'shell target_test'.split()
724
- else:
725
- cmd_list = 'sim --stop-before-compile target_test'.split()
726
-
727
- with open('eda.log', 'w', encoding='utf-8') as f:
728
- with redirect_stdout(f):
729
- with redirect_stderr(f):
730
- rc = eda.main(*cmd_list)
731
-
732
- print(f'{rc=}')
733
- assert rc == 0
734
-
735
- # We should see "hi" before "bye" to confirm deps + command order is correct.
736
- # see ./deps_files/command_order/DEPS.yml - target = target_test
737
- found_str_list = [
738
- 'exec: echo "hi"',
739
- 'exec: echo "bye"',
740
- ]
741
- found_lines_list = [None, None]
742
-
743
- with open('eda.log', encoding='utf-8') as f:
744
- for lineno, line in enumerate(f.readlines()):
745
- line = line.rstrip()
746
- for idx,key in enumerate(found_str_list):
747
- if key in line:
748
- found_lines_list[idx] = lineno
749
-
750
- assert found_lines_list[0] # found hi
751
- assert found_lines_list[1] # found bye
752
- assert found_lines_list[0] < found_lines_list[1] # hi before bye
753
-
754
- # Added check, we redirected to create eda.log earlier to confirm the targets worked,
755
- # but as a general eda.py check, all shell commands should create their own
756
- # {target}__shell_0.log file:
757
- work_dir = os.path.join(
758
- THISPATH, 'deps_files', 'command_order', 'eda.work', f'target_test.{command}'
759
- )
760
- # Note that eda will write out the returncode INFO line to tee'd log files, so
761
- # there is more in the log file than "hi" or "bye".
762
- with open(os.path.join(work_dir, 'target_echo_hi__shell_0.log'), encoding='utf-8') as f:
763
- text = ' '.join(f.readlines()).strip()
764
- assert any(text.startswith(x) for x in ['hi', '"hi"', '\\"hi\\"'])
765
- # Added check, one of the targets uses a custom 'tee' file name, instead of the default log.
766
- with open(os.path.join(work_dir, 'custom_tee_echo_bye.log'), encoding='utf-8') as f:
767
- text = ''.join(f.readlines()).strip()
768
- assert any(text.startswith(x) for x in ['bye', '"bye"', '\\"bye\\"'])
769
-
770
736
 
771
737
  @pytest.mark.skipif('verilator' not in tools_loaded, reason="requires verilator")
772
738
  class TestDepsOtherMarkup:
@@ -32,6 +32,14 @@ class CommandSimModelsimAse(CommandSim, ToolModelsimAse):
32
32
  self.args.update({
33
33
  'tool': self._TOOL, # override
34
34
  'gui': False,
35
+ 'vopt': self.use_vopt,
36
+ })
37
+ self.args_help.update({
38
+ 'vopt': (
39
+ 'Boolean to enable/disable use of vopt step prior to vsim step'
40
+ ' Note that vopt args can be controlled with --elab-args=<value1>'
41
+ ' --elab-args=<value2> ...'
42
+ )
35
43
  })
36
44
 
37
45
  def set_tool_defines(self):
@@ -158,7 +166,7 @@ class CommandSimModelsimAse(CommandSim, ToolModelsimAse):
158
166
  'compile-waivers',
159
167
  [ #defaults:
160
168
  '2275', # 2275 - Existing package 'foo_pkg' will be overwritten.
161
- ]):
169
+ ]) + self.args['compile-waivers']:
162
170
  vlog_dot_f_lines += ['-suppress', str(waiver)]
163
171
 
164
172
  if self.args['gui'] or self.args['waves']:
@@ -252,15 +260,18 @@ class CommandSimModelsimAse(CommandSim, ToolModelsimAse):
252
260
 
253
261
  sim_plusargs_str = self._get_sim_plusargs_str()
254
262
  vsim_suppress_list_str = self._get_vsim_suppress_list_str()
263
+ vsim_ext_args = ' '.join(self.args.get('sim-args', []))
255
264
 
256
- voptargs_str = ""
265
+ voptargs_str = self.tool_config.get('elab-args', '')
266
+ voptargs_str += ' '.join(self.args.get('elab-args', []))
257
267
  if self.args['gui'] or self.args['waves']:
258
- voptargs_str = self.tool_config.get('simulate-waves-args', '+acc')
268
+ voptargs_str += ' ' + self.tool_config.get('simulate-waves-args', '+acc')
259
269
  util.artifacts.add_extension(
260
270
  search_paths=self.args['work-dir'], file_extension='wlf',
261
271
  typ='waveform', description='Modelsim/Questa Waveform WLF (Wave Log Format) file'
262
272
  )
263
273
 
274
+ # TODO(drew): support self.args['sim_libary'] (1 lists)
264
275
  vlog_do_lines = []
265
276
  vsim_do_lines = []
266
277
 
@@ -269,9 +280,6 @@ class CommandSimModelsimAse(CommandSim, ToolModelsimAse):
269
280
  voptargs_str += more_voptargs_str
270
281
 
271
282
 
272
- # TODO(drew): support self.args['sim_libary', 'elab-args', sim-args'] (3 lists)
273
- # to add to vsim_one_liner.
274
-
275
283
  vopt_one_liner = ""
276
284
  if self.use_vopt:
277
285
  vopt_one_liner = (
@@ -283,12 +291,12 @@ class CommandSimModelsimAse(CommandSim, ToolModelsimAse):
283
291
 
284
292
  vsim_one_liner = "vsim -onfinish stop" \
285
293
  + f" -sv_seed {self.args['seed']} {sim_plusargs_str} {vsim_suppress_list_str}" \
286
- + f" opt__{self.args['top']}"
294
+ + f" {vsim_ext_args} opt__{self.args['top']}"
287
295
  else:
288
296
  # vopt doesn't exist, use single vsim call after vlog call:
289
297
  vsim_one_liner = "vsim -onfinish stop" \
290
298
  + f" -sv_seed {self.args['seed']} {sim_plusargs_str} {vsim_suppress_list_str}" \
291
- + f" {voptargs_str} work.{self.args['top']}"
299
+ + f" {voptargs_str} {vsim_ext_args} work.{self.args['top']}"
292
300
 
293
301
 
294
302
  vsim_one_liner = vsim_one_liner.replace('\n', ' ')
@@ -393,7 +401,7 @@ class CommandSimModelsimAse(CommandSim, ToolModelsimAse):
393
401
  #defaults:
394
402
  '3009', # 3009: [TSCALE] - Module 'foo' does not have a timeunit/timeprecision
395
403
  # specification in effect, but other modules do.
396
- ]):
404
+ ]) + self.args['sim-waivers']:
397
405
  vsim_suppress_list += ['-suppress', str(waiver)]
398
406
 
399
407
  return ' '.join(vsim_suppress_list)
opencos/tools/riviera.py CHANGED
@@ -59,6 +59,17 @@ class CommandSimRiviera(CommandSimModelsimAse, ToolRiviera):
59
59
  self.args.update({
60
60
  'tool': self._TOOL, # override
61
61
  'gui': False,
62
+ 'waves-fst': True,
63
+ 'waves-vcd': False,
64
+ })
65
+ self.args_help.update({
66
+ 'waves-fst': (
67
+ '(Default True) If using --waves, apply simulation runtime arg +trace.'
68
+ ' Note that if you do not have SV code using $dumpfile, eda will add'
69
+ ' _waves_pkg.sv to handle this for you with +trace runtime plusarg.'
70
+ ),
71
+ 'waves-vcd': 'If using --waves, apply simulation runtime arg +trace=vcd',
72
+ 'waves': 'Save a .asdb offline wavefile, can be used with --waves-fst or --waves-vcd',
62
73
  })
63
74
 
64
75
  def set_tool_defines(self):
@@ -76,6 +87,9 @@ class CommandSimRiviera(CommandSimModelsimAse, ToolRiviera):
76
87
 
77
88
  def compile(self):
78
89
  '''Override for CommandSimModelsimAse.compile() so we can set our own must_strings'''
90
+
91
+ self.add_waves_pkg_file()
92
+
79
93
  if self.args['stop-before-compile']:
80
94
  # don't run anything, save everyting we've already run in _prep_compile()
81
95
  return
@@ -126,7 +140,8 @@ class CommandSimRiviera(CommandSimModelsimAse, ToolRiviera):
126
140
  '-sv -input_ports net').split()
127
141
 
128
142
  # Add waivers from config.tool.riviera, convert to warning:
129
- for waiver in self.tool_config.get('compile-waivers', []):
143
+ for waiver in self.tool_config.get('compile-waivers', []) + \
144
+ self.args['compile-waivers']:
130
145
  vlog_dot_f_lines += [f'-err {waiver} W1']
131
146
 
132
147
  vlog_dot_f_fname = filename
@@ -167,6 +182,7 @@ class CommandSimRiviera(CommandSimModelsimAse, ToolRiviera):
167
182
  f.writelines(line + "\n" for line in vlog_dot_f_lines)
168
183
 
169
184
 
185
+
170
186
  def write_vsim_dot_do(self, dot_do_to_write: list) -> None:
171
187
  '''Writes files(s) based on dot_do_to_write(list of str)
172
188
 
@@ -177,9 +193,18 @@ class CommandSimRiviera(CommandSimModelsimAse, ToolRiviera):
177
193
  vsim_vlogonly_dot_do_fpath = os.path.join(self.args['work-dir'], 'vsim_vlogonly.do')
178
194
 
179
195
  sim_plusargs_str = self._get_sim_plusargs_str()
180
-
181
- voptargs_str = ""
182
- if self.args['gui'] or self.args['waves'] or self.args['coverage']:
196
+ vsim_ext_args = ' '.join(self.args.get('sim-args', []))
197
+
198
+ if self.args['waves'] and '+trace' not in sim_plusargs_str:
199
+ if self.args.get('waves-vcd', False):
200
+ sim_plusargs_str += ' +trace=vcd'
201
+ elif self.args.get('waves-fst', False):
202
+ sim_plusargs_str += ' +trace'
203
+
204
+ voptargs_str = self.tool_config.get('elab-args', '')
205
+ voptargs_str += ' '.join(self.args.get('elab-args', []))
206
+ if self.args['gui'] or self.args['waves'] or self.args['coverage']: # \
207
+ #or self.args['waves-asdb']:
183
208
  voptargs_str += self.tool_config.get('simulate-waves-args',
184
209
  '+accb +accr +access +r+w')
185
210
  if self.args['coverage']:
@@ -195,7 +220,7 @@ class CommandSimRiviera(CommandSimModelsimAse, ToolRiviera):
195
220
  vsim_one_liner = (
196
221
  "vsim"
197
222
  f" -sv_seed {self.args['seed']} {sim_plusargs_str}"
198
- f" {voptargs_str} work.{self.args['top']}"
223
+ f" {voptargs_str} {vsim_ext_args} work.{self.args['top']}"
199
224
  )
200
225
 
201
226
  vsim_one_liner = vsim_one_liner.replace('\n', ' ') # needs to be a one-liner
@@ -294,7 +319,7 @@ class CommandSimRiviera(CommandSimModelsimAse, ToolRiviera):
294
319
  for waiver in self.tool_config.get(
295
320
  'simulate-waivers', [
296
321
  #defaults: none
297
- ]):
322
+ ]) + self.args['sim-waivers']:
298
323
  vsim_suppress_list += ['-filter', str(waiver)]
299
324
 
300
325
  return ' '.join(vsim_suppress_list)
@@ -76,6 +76,8 @@ class VerilatorSim(CommandSim, ToolVerilator):
76
76
  'gui': False,
77
77
  'tcl-file': None,
78
78
  'dump-vcd': False,
79
+ 'waves-fst': True,
80
+ 'waves-vcd': False,
79
81
  'lint-only': False,
80
82
  'cc-mode': False,
81
83
  'verilator-coverage-args': [],
@@ -84,12 +86,22 @@ class VerilatorSim(CommandSim, ToolVerilator):
84
86
  })
85
87
 
86
88
  self.args_help.update({
87
- 'waves': ('Include waveforms, if possible for Verilator by applying'
88
- ' simulation runtime arg +trace. User will need SV code to interpret the'
89
- 'plusarg and apply $dumpfile("dump.fst").'),
90
- 'dump-vcd': ('If using --waves, apply simulation runtime arg +trace=vcd. User'
91
- ' will need SV code to interpret the plusarg and apply'
92
- ' $dumpfile("dump.vcd").'),
89
+ 'waves': (
90
+ 'Include waveforms, if possible for Verilator by applying'
91
+ ' simulation runtime arg +trace. User will need SV code to interpret the'
92
+ ' plusarg and apply $dumpfile("dump.fst").'
93
+ ),
94
+ 'waves-fst': (
95
+ '(Default True) If using --waves, apply simulation runtime arg +trace.'
96
+ ' Note that if you do not have SV code using $dumpfile, eda will add'
97
+ ' _waves_pkg.sv to handle this for you with +trace runtime plusarg.'
98
+ ),
99
+ 'waves-vcd': (
100
+ 'If using --waves, apply simulation runtime arg +trace=vcd. User'
101
+ ' will need SV code to interpret the plusarg and apply'
102
+ ' $dumpfile("dump.vcd").'
103
+ ),
104
+ 'dump-vcd': 'Same as --waves-vcd',
93
105
  'lint-only': 'Run verilator with --lint-only, instead of --binary',
94
106
  'gui': 'Not supported for Verilator',
95
107
  'cc-mode': 'Run verilator with --cc, requires a sim_main.cpp or similar sources',
@@ -124,7 +136,7 @@ class VerilatorSim(CommandSim, ToolVerilator):
124
136
  if self.files_cpp:
125
137
  self.args['cc-mode'] = True
126
138
 
127
- self._add_verilator_waves_files()
139
+ self.add_waves_pkg_file()
128
140
 
129
141
  # Each of these should be a list of util.ShellCommandList()
130
142
  self.verilate_command_lists = self.get_compile_command_lists()
@@ -300,9 +312,10 @@ class VerilatorSim(CommandSim, ToolVerilator):
300
312
  # Built-in support for eda args --waves and/or --dump-vcd to become runtime
301
313
  # plusargs +trace or +trace=vcd, if +trace or +trace= was not already in our
302
314
  # plusargs.
303
- if self.args.get('dump-vcd', False):
315
+ if self.args.get('dump-vcd', False) or \
316
+ self.args.get('waves-vcd', False):
304
317
  sim_plusargs.append('+trace=vcd')
305
- else:
318
+ elif self.args.get('waves-fst', False):
306
319
  sim_plusargs.append('+trace')
307
320
 
308
321
  verilated_exec_command_list += config_sim_args + sim_plusargs + self.args['sim-args']
@@ -351,40 +364,17 @@ class VerilatorSim(CommandSim, ToolVerilator):
351
364
 
352
365
  return []
353
366
 
354
- def _add_verilator_waves_files(self) -> None:
367
+ def add_waves_pkg_file(self) -> None:
355
368
  '''If --waves present, and the user is missing any $dumpfile(), then adds a pre-written
356
369
  SystemVerilog package to their source code.
357
370
  '''
358
- if not self.args['waves']:
359
- return
360
371
  if self.args['cc-mode']:
361
- # We won't do this if the user bround a .cpp file and verilator not
372
+ # We won't do this if the user brought a .cpp file and verilator not
362
373
  # called with --binary.
363
374
  return
364
- found_dumpfile = False
365
- for fname in self.files_v + self.files_sv:
366
- if found_dumpfile:
367
- break
368
- with open(fname, encoding='utf-8') as f:
369
- for line in f.readlines():
370
- if '$dumpfile' in line:
371
- found_dumpfile = True
372
- break
373
- if not found_dumpfile:
374
- thispath = os.path.dirname(__file__)
375
- file_to_add = os.path.join(thispath, '..', '_waves_pkg.sv')
376
- util.info(f'--waves arg present, no $dumpfile found, adding SV file: {file_to_add}')
377
- self.add_file(file_to_add)
378
-
379
- # register .vcd or .fst artifacts:
380
- util.artifacts.add_extension(
381
- search_paths=self.args['work-dir'], file_extension='fst',
382
- typ='waveform', description='Simulation Waveform FST (Fast Signal Trace) file'
383
- )
384
- util.artifacts.add_extension(
385
- search_paths=self.args['work-dir'], file_extension='vcd',
386
- typ='waveform', description='Simulation Waveform VCD (Value Change Dump) file'
387
- )
375
+
376
+ super().add_waves_pkg_file() # call from CommandSim
377
+
388
378
 
389
379
 
390
380
  def _get_start_verilator_command_list(self, lint_only: bool = False) -> list:
@@ -415,7 +405,7 @@ class VerilatorSim(CommandSim, ToolVerilator):
415
405
  [ #defaults:
416
406
  'CASEINCOMPLETE',
417
407
  'TIMESCALEMOD', # If one file has `timescale, then they all must
418
- ]):
408
+ ]) + self.args['compile-waivers']:
419
409
  ret.append(f'-Wno-{waiver}')
420
410
  return ret
421
411