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.
- opencos/_version.py +6 -3
- opencos/_waves_pkg.sv +34 -2
- opencos/commands/build.py +1 -0
- opencos/commands/export.py +1 -0
- opencos/commands/flist.py +1 -0
- opencos/commands/lec.py +1 -0
- opencos/commands/proj.py +1 -0
- opencos/commands/shell.py +4 -0
- opencos/commands/sim.py +47 -1
- opencos/commands/synth.py +4 -0
- opencos/deps/defaults.py +15 -7
- opencos/deps/deps_commands.py +84 -74
- opencos/deps/deps_file.py +11 -5
- opencos/deps/deps_processor.py +79 -3
- opencos/deps_schema.py +3 -0
- opencos/eda.py +2 -1
- opencos/eda_base.py +105 -34
- opencos/eda_config_defaults.yml +5 -1
- opencos/files.py +1 -0
- opencos/tests/deps_files/command_order/DEPS.yml +11 -0
- opencos/tests/helpers.py +50 -20
- opencos/tests/test_deps_helpers.py +37 -25
- opencos/tests/test_eda.py +26 -60
- opencos/tools/modelsim_ase.py +17 -9
- opencos/tools/riviera.py +31 -6
- opencos/tools/verilator.py +28 -38
- opencos/util.py +111 -16
- opencos/utils/vscode_helper.py +1 -1
- opencos/utils/vsim_helper.py +1 -1
- {opencos_eda-0.2.57.dist-info → opencos_eda-0.3.1.dist-info}/METADATA +2 -1
- {opencos_eda-0.2.57.dist-info → opencos_eda-0.3.1.dist-info}/RECORD +36 -36
- {opencos_eda-0.2.57.dist-info → opencos_eda-0.3.1.dist-info}/WHEEL +0 -0
- {opencos_eda-0.2.57.dist-info → opencos_eda-0.3.1.dist-info}/entry_points.txt +0 -0
- {opencos_eda-0.2.57.dist-info → opencos_eda-0.3.1.dist-info}/licenses/LICENSE +0 -0
- {opencos_eda-0.2.57.dist-info → opencos_eda-0.3.1.dist-info}/licenses/LICENSE.spdx +0 -0
- {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(
|
|
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(
|
|
104
|
-
|
|
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(
|
|
116
|
-
|
|
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(
|
|
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',
|
|
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',
|
|
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',
|
|
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:
|
opencos/tools/modelsim_ase.py
CHANGED
|
@@ -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
|
|
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
|
-
|
|
182
|
-
if self.args['
|
|
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)
|
opencos/tools/verilator.py
CHANGED
|
@@ -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':
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
365
|
-
|
|
366
|
-
|
|
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
|
|