opencos-eda 0.3.7__py3-none-any.whl → 0.3.9__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/commands/sim.py +61 -11
- opencos/eda.py +62 -8
- opencos/eda_base.py +77 -18
- opencos/eda_config.py +1 -0
- opencos/eda_config_defaults.yml +42 -8
- opencos/tests/test_tools.py +53 -30
- opencos/tools/iverilog.py +2 -2
- opencos/tools/modelsim_ase.py +19 -378
- opencos/tools/questa.py +42 -247
- opencos/tools/questa_common.py +481 -0
- opencos/tools/questa_fe.py +84 -0
- opencos/tools/questa_fse.py +7 -8
- opencos/tools/riviera.py +60 -12
- opencos/tools/slang.py +24 -0
- opencos/tools/surelog.py +22 -0
- opencos/tools/verilator.py +11 -5
- opencos/tools/vivado.py +4 -0
- opencos/util.py +2 -1
- opencos/utils/str_helpers.py +4 -4
- opencos/utils/vsim_helper.py +8 -1
- {opencos_eda-0.3.7.dist-info → opencos_eda-0.3.9.dist-info}/METADATA +2 -1
- {opencos_eda-0.3.7.dist-info → opencos_eda-0.3.9.dist-info}/RECORD +27 -25
- {opencos_eda-0.3.7.dist-info → opencos_eda-0.3.9.dist-info}/WHEEL +0 -0
- {opencos_eda-0.3.7.dist-info → opencos_eda-0.3.9.dist-info}/entry_points.txt +0 -0
- {opencos_eda-0.3.7.dist-info → opencos_eda-0.3.9.dist-info}/licenses/LICENSE +0 -0
- {opencos_eda-0.3.7.dist-info → opencos_eda-0.3.9.dist-info}/licenses/LICENSE.spdx +0 -0
- {opencos_eda-0.3.7.dist-info → opencos_eda-0.3.9.dist-info}/top_level.txt +0 -0
opencos/tests/test_tools.py
CHANGED
|
@@ -7,13 +7,12 @@ import shutil
|
|
|
7
7
|
import sys
|
|
8
8
|
import pytest
|
|
9
9
|
|
|
10
|
-
from opencos import
|
|
11
|
-
|
|
10
|
+
from opencos import eda_base
|
|
12
11
|
from opencos.tools.verilator import ToolVerilator
|
|
13
12
|
from opencos.tools.vivado import ToolVivado
|
|
14
13
|
from opencos.tools.cocotb import ToolCocotb
|
|
15
14
|
from opencos.tests import helpers
|
|
16
|
-
from opencos.tests.helpers import eda_wrap, eda_wrap_is_sim_fail, config, tools_loaded
|
|
15
|
+
from opencos.tests.helpers import Helpers, eda_wrap, eda_wrap_is_sim_fail, config, tools_loaded
|
|
17
16
|
from opencos.utils.markup_helpers import yaml_safe_load
|
|
18
17
|
from opencos.utils import status_constants
|
|
19
18
|
|
|
@@ -24,6 +23,10 @@ def chdir_remove_work_dir(relpath):
|
|
|
24
23
|
'''Changes dir to relpath, removes the work directories (eda.work, eda.export*)'''
|
|
25
24
|
return helpers.chdir_remove_work_dir(THISPATH, relpath)
|
|
26
25
|
|
|
26
|
+
def filter_tools(tools: list) -> list:
|
|
27
|
+
'''Given a list of tool l, filters to return a list of tools that are loaded'''
|
|
28
|
+
return [x for x in tools if x in tools_loaded]
|
|
29
|
+
|
|
27
30
|
|
|
28
31
|
def test_tools_loaded():
|
|
29
32
|
'''Does not directly call 'eda.main' instead create a few Tool
|
|
@@ -107,40 +110,60 @@ list_of_added_sim_args = [
|
|
|
107
110
|
'--gui --test-mode',
|
|
108
111
|
]
|
|
109
112
|
|
|
113
|
+
list_of_loaded_tools = filter_tools(list_of_tools)
|
|
114
|
+
|
|
110
115
|
cannot_use_cocotb = 'cocotb' not in tools_loaded or \
|
|
111
116
|
('iverilog' not in tools_loaded and \
|
|
112
117
|
'verilator' not in tools_loaded)
|
|
113
118
|
CANNOT_USE_COCOTB_REASON = 'requires cocotb in tools_loaded, and one of (iverilog, verilator) too'
|
|
114
119
|
|
|
115
|
-
@pytest.mark.parametrize("command", list_of_commands)
|
|
116
|
-
@pytest.mark.parametrize("tool", list_of_tools)
|
|
117
|
-
@pytest.mark.parametrize("target,sim_expect_pass", list_of_deps_targets)
|
|
118
|
-
@pytest.mark.parametrize("added_sim_args_str", list_of_added_sim_args)
|
|
119
|
-
def test_sim_elab_tools_pass_or_fail(command, tool, target, sim_expect_pass, added_sim_args_str):
|
|
120
|
-
'''tests that: eda <sim|elab> --tool <parameter-tool> <parameter-args> <parameter-target>
|
|
121
120
|
|
|
122
|
-
|
|
121
|
+
class TestSimElabTools(Helpers):
|
|
122
|
+
'''Tests for eda sim|elab for various tools with various args'''
|
|
123
123
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
124
|
+
DEFAULT_DIR = os.path.join(THISPATH, 'deps_files', 'test_err_fatal')
|
|
125
|
+
|
|
126
|
+
@pytest.mark.parametrize("command", list_of_commands)
|
|
127
|
+
@pytest.mark.parametrize("tool", list_of_loaded_tools)
|
|
128
|
+
@pytest.mark.parametrize("target,sim_expect_pass", list_of_deps_targets)
|
|
129
|
+
@pytest.mark.parametrize("added_sim_args_str", list_of_added_sim_args)
|
|
130
|
+
def test_pass_or_fail(
|
|
131
|
+
self, command, tool, target, sim_expect_pass, added_sim_args_str
|
|
132
|
+
):
|
|
133
|
+
'''tests that: eda <sim|elab> --tool <parameter-tool> <parameter-args> <parameter-target>
|
|
134
|
+
|
|
135
|
+
will correctly pass or fail depending on if it is supported or not.
|
|
136
|
+
|
|
137
|
+
Also tests for: non-gui, or --gui --test-mode (runs non-gui, but most python args will
|
|
138
|
+
be for --gui mode, signal logging, etc).
|
|
139
|
+
'''
|
|
140
|
+
added_args_str = ''
|
|
141
|
+
if command == 'sim':
|
|
142
|
+
added_args_str = added_sim_args_str
|
|
143
|
+
|
|
144
|
+
rc = self.log_it(f'{command} --tool {tool} {added_args_str} {target}')
|
|
145
|
+
print(f'{rc=}')
|
|
146
|
+
tool_error_count_lines = self.get_log_lines_with('tool errors')
|
|
147
|
+
if command != 'sim' or sim_expect_pass:
|
|
148
|
+
# command='elab' should pass.
|
|
149
|
+
assert rc == 0
|
|
150
|
+
assert tool_error_count_lines
|
|
151
|
+
assert all('tool warnings' in line for line in tool_error_count_lines)
|
|
152
|
+
assert all(' 0 tool errors' in line for line in tool_error_count_lines)
|
|
153
|
+
|
|
154
|
+
else:
|
|
155
|
+
assert eda_wrap_is_sim_fail(rc)
|
|
156
|
+
assert tool_error_count_lines
|
|
157
|
+
assert all('tool warnings' in line for line in tool_error_count_lines)
|
|
158
|
+
# May or may not have reported tool errors.
|
|
159
|
+
assert all('tool errors' in line for line in tool_error_count_lines)
|
|
160
|
+
# The final line of tool warnings/errors should have > 0 tool errors,
|
|
161
|
+
# since we were checking SV $error and $fatal
|
|
162
|
+
assert ' 0 tool errors' not in tool_error_count_lines[-1]
|
|
163
|
+
# The line should end with ' X tool errors'
|
|
164
|
+
parts = tool_error_count_lines[-1].split()
|
|
165
|
+
assert parts[-3].isdigit()
|
|
166
|
+
assert int(parts[-3]) in (1, 2, 3) # we should have at least 1, but some tools dup.
|
|
144
167
|
|
|
145
168
|
|
|
146
169
|
@pytest.mark.skipif('vivado' not in tools_loaded, reason="requires vivado")
|
opencos/tools/iverilog.py
CHANGED
|
@@ -93,7 +93,7 @@ class CommandSimIverilog(CommandSim, ToolIverilog):
|
|
|
93
93
|
def compile(self):
|
|
94
94
|
if self.args['stop-before-compile']:
|
|
95
95
|
return
|
|
96
|
-
self.run_commands_check_logs(self.iverilog_command_lists
|
|
96
|
+
self.run_commands_check_logs(self.iverilog_command_lists)
|
|
97
97
|
|
|
98
98
|
def elaborate(self):
|
|
99
99
|
pass
|
|
@@ -148,7 +148,7 @@ class CommandSimIverilog(CommandSim, ToolIverilog):
|
|
|
148
148
|
|
|
149
149
|
command_list += list(self.files_sv) + list(self.files_v)
|
|
150
150
|
|
|
151
|
-
return [ util.ShellCommandList(command_list) ]
|
|
151
|
+
return [ util.ShellCommandList(command_list, tee_fpath='compile.log') ]
|
|
152
152
|
|
|
153
153
|
def get_elaborate_command_lists(self, **kwargs) -> list:
|
|
154
154
|
return []
|
opencos/tools/modelsim_ase.py
CHANGED
|
@@ -9,31 +9,29 @@ Note that this is for 32-bit Modelsim Student Edition. Consider using --tool=que
|
|
|
9
9
|
|
|
10
10
|
import os
|
|
11
11
|
|
|
12
|
-
from opencos import
|
|
13
|
-
from opencos.commands import sim, CommandSim
|
|
14
|
-
from opencos.tools.questa import ToolQuesta
|
|
15
|
-
from opencos.utils.str_helpers import sanitize_defines_for_sh
|
|
12
|
+
from opencos.tools.questa_common import CommonSimQuesta, CommonFListQuesta
|
|
16
13
|
|
|
17
|
-
class
|
|
18
|
-
'''
|
|
14
|
+
class CommandSimModelsimAse(CommonSimQuesta):
|
|
15
|
+
'''CommandSimModelsimAse is a command handler for: eda sim --tool=modelsim_ase'''
|
|
19
16
|
|
|
20
|
-
_TOOL = 'modelsim_ase'
|
|
17
|
+
_TOOL = 'modelsim_ase'
|
|
21
18
|
_EXE = 'vsim'
|
|
22
19
|
use_vopt = False
|
|
23
20
|
|
|
24
|
-
class CommandSimModelsimAse(CommandSim, ToolModelsimAse):
|
|
25
|
-
'''CommandSimModelsimAse is a command handler for: eda sim --tool=modelsim_ase'''
|
|
26
|
-
|
|
27
21
|
def __init__(self, config: dict):
|
|
28
|
-
|
|
29
|
-
|
|
22
|
+
CommonSimQuesta.__init__(self, config=config)
|
|
23
|
+
|
|
24
|
+
# repairs: override self._TOOL, and run get_versions() again.
|
|
25
|
+
self._TOOL = 'modelsim_ase'
|
|
26
|
+
|
|
30
27
|
self.shell_command = os.path.join(self.sim_exe_base_path, 'vsim')
|
|
31
28
|
self.starter_edition = True
|
|
32
29
|
self.args.update({
|
|
33
30
|
'tool': self._TOOL, # override
|
|
34
31
|
'gui': False,
|
|
35
|
-
'vopt': self.use_vopt,
|
|
36
32
|
})
|
|
33
|
+
|
|
34
|
+
|
|
37
35
|
self.args_help.update({
|
|
38
36
|
'vopt': (
|
|
39
37
|
'Boolean to enable/disable use of vopt step prior to vsim step'
|
|
@@ -53,371 +51,6 @@ class CommandSimModelsimAse(CommandSim, ToolModelsimAse):
|
|
|
53
51
|
)
|
|
54
52
|
)
|
|
55
53
|
|
|
56
|
-
def run_in_batch_mode(self) -> bool:
|
|
57
|
-
'''Returns bool if we should run in batch mode (-c) from command line'''
|
|
58
|
-
# TODO(drew): make CommandSimQuesta a parent and inherit this method instead.
|
|
59
|
-
if self.args['test-mode']:
|
|
60
|
-
return True
|
|
61
|
-
if self.args['gui']:
|
|
62
|
-
return False
|
|
63
|
-
return True
|
|
64
|
-
|
|
65
|
-
# We do override do_it() to avoid using CommandSimQuesta.do_it()
|
|
66
|
-
def do_it(self):
|
|
67
|
-
CommandSim.do_it(self)
|
|
68
|
-
# self.compile() # runs if stop-before-compile is False, stop-after-compile is True
|
|
69
|
-
# self.elaborate() # runs if stop-before-compile is False, stop-after-compile is False,
|
|
70
|
-
# stop-after-elaborate is True
|
|
71
|
-
# self.simulate() # runs if stop-* are all False (run the whole thing)
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
def prepare_compile(self):
|
|
75
|
-
self.set_tool_defines()
|
|
76
|
-
self.write_vlog_dot_f()
|
|
77
|
-
self.write_vsim_dot_do(dot_do_to_write='all')
|
|
78
|
-
|
|
79
|
-
vsim_command_lists = self.get_compile_command_lists()
|
|
80
|
-
util.write_shell_command_file(
|
|
81
|
-
dirpath=self.args['work-dir'],
|
|
82
|
-
filename='compile_only.sh',
|
|
83
|
-
command_lists=vsim_command_lists
|
|
84
|
-
)
|
|
85
|
-
|
|
86
|
-
vsim_command_lists = self.get_elaborate_command_lists()
|
|
87
|
-
util.write_shell_command_file(
|
|
88
|
-
dirpath=self.args['work-dir'],
|
|
89
|
-
filename='compile_elaborate_only.sh',
|
|
90
|
-
command_lists=vsim_command_lists
|
|
91
|
-
)
|
|
92
|
-
|
|
93
|
-
# Write simulate.sh and all.sh to work-dir:
|
|
94
|
-
vsim_command_lists = self.get_simulate_command_lists()
|
|
95
|
-
self.write_sh_scripts_to_work_dir(
|
|
96
|
-
compile_lists=[], elaborate_lists=[], simulate_lists=vsim_command_lists
|
|
97
|
-
)
|
|
98
|
-
|
|
99
|
-
def compile(self):
|
|
100
|
-
if self.args['stop-before-compile']:
|
|
101
|
-
# don't run anything, save everyting we've already run in _prep_compile()
|
|
102
|
-
return
|
|
103
|
-
if self.args['stop-after-compile']:
|
|
104
|
-
vsim_command_lists = self.get_compile_command_lists()
|
|
105
|
-
self.run_commands_check_logs(vsim_command_lists, log_filename='sim.log',
|
|
106
|
-
must_strings=['Errors: 0'], use_must_strings=False)
|
|
107
|
-
|
|
108
|
-
def elaborate(self):
|
|
109
|
-
if self.args['stop-before-compile']:
|
|
110
|
-
return
|
|
111
|
-
if self.args['stop-after-compile']:
|
|
112
|
-
return
|
|
113
|
-
if self.args['stop-after-elaborate']:
|
|
114
|
-
# only run this if we stop after elaborate (simulate run it all)
|
|
115
|
-
vsim_command_lists = self.get_elaborate_command_lists()
|
|
116
|
-
self.run_commands_check_logs(vsim_command_lists, log_filename='sim.log')
|
|
117
|
-
|
|
118
|
-
def simulate(self):
|
|
119
|
-
if self.args['stop-before-compile'] or self.args['stop-after-compile'] or \
|
|
120
|
-
self.args['stop-after-elaborate']:
|
|
121
|
-
# don't run this if we're stopping before/after compile/elab
|
|
122
|
-
return
|
|
123
|
-
vsim_command_lists = self.get_simulate_command_lists()
|
|
124
|
-
self.run_commands_check_logs(vsim_command_lists, log_filename='sim.log')
|
|
125
|
-
|
|
126
|
-
def get_compile_command_lists(self, **kwargs) -> list:
|
|
127
|
-
# This will also set up a compile.
|
|
128
|
-
vsim_command_list = [
|
|
129
|
-
self.sim_exe,
|
|
130
|
-
'-c' if self.run_in_batch_mode() else '',
|
|
131
|
-
'-do', 'vsim_vlogonly.do', '-logfile', 'sim.log',
|
|
132
|
-
]
|
|
133
|
-
return [vsim_command_list]
|
|
134
|
-
|
|
135
|
-
def get_elaborate_command_lists(self, **kwargs) -> list:
|
|
136
|
-
# This will also set up a compile, for vlog + vsim (0 time)
|
|
137
|
-
vsim_command_list = [
|
|
138
|
-
self.sim_exe,
|
|
139
|
-
'-c' if self.run_in_batch_mode() else '',
|
|
140
|
-
'-do', 'vsim_lintonly.do', '-logfile', 'sim.log',
|
|
141
|
-
]
|
|
142
|
-
return [vsim_command_list]
|
|
143
|
-
|
|
144
|
-
def get_simulate_command_lists(self, **kwargs) -> list:
|
|
145
|
-
# This will also set up a compile, for vlog + vsim (with run -a)
|
|
146
|
-
vsim_command_list = [
|
|
147
|
-
self.sim_exe,
|
|
148
|
-
'-c' if self.run_in_batch_mode() else '',
|
|
149
|
-
'-do', 'vsim.do', '-logfile', 'sim.log',
|
|
150
|
-
]
|
|
151
|
-
return [vsim_command_list]
|
|
152
|
-
|
|
153
|
-
def get_post_simulate_command_lists(self, **kwargs) -> list:
|
|
154
|
-
return []
|
|
155
|
-
|
|
156
|
-
def write_vlog_dot_f(self, filename='vlog.f') -> None:
|
|
157
|
-
'''Returns none, creates filename (str) for a vlog.f'''
|
|
158
|
-
vlog_dot_f_lines = []
|
|
159
|
-
|
|
160
|
-
# Add compile args from config.tool.modelsim_ase:
|
|
161
|
-
vlog_dot_f_lines += self.tool_config.get(
|
|
162
|
-
'compile-args',
|
|
163
|
-
'-sv -svinputport=net -lint').split()
|
|
164
|
-
# Add waivers from config.tool.modelsim_ase:
|
|
165
|
-
for waiver in self.tool_config.get(
|
|
166
|
-
'compile-waivers',
|
|
167
|
-
[ #defaults:
|
|
168
|
-
'2275', # 2275 - Existing package 'foo_pkg' will be overwritten.
|
|
169
|
-
]) + self.args['compile-waivers']:
|
|
170
|
-
vlog_dot_f_lines += ['-suppress', str(waiver)]
|
|
171
|
-
|
|
172
|
-
if self.args['gui'] or self.args['waves']:
|
|
173
|
-
vlog_dot_f_lines += self.tool_config.get('compile-waves-args', '').split()
|
|
174
|
-
|
|
175
|
-
vlog_dot_f_fname = filename
|
|
176
|
-
vlog_dot_f_fpath = os.path.join(self.args['work-dir'], vlog_dot_f_fname)
|
|
177
|
-
|
|
178
|
-
for value in self.incdirs:
|
|
179
|
-
vlog_dot_f_lines += [ f"+incdir+{value}" ]
|
|
180
|
-
|
|
181
|
-
for k,v in self.defines.items():
|
|
182
|
-
if v is None:
|
|
183
|
-
vlog_dot_f_lines += [ f'+define+{k}' ]
|
|
184
|
-
else:
|
|
185
|
-
|
|
186
|
-
# if the value v is a double-quoted string, such as v='"hi"', the
|
|
187
|
-
# entire +define+NAME="hi" needs to wrapped in double quotes with the
|
|
188
|
-
# value v double-quotes escaped: "+define+NAME=\"hi\""
|
|
189
|
-
if isinstance(v, str) and v.startswith('"') and v.endswith('"'):
|
|
190
|
-
str_v = v.replace('"', '\\"')
|
|
191
|
-
vlog_dot_f_lines += [ f'"+define+{k}={str_v}"' ]
|
|
192
|
-
else:
|
|
193
|
-
# Generally we should only support int and str python types passed as
|
|
194
|
-
# +define+{k}={v}, but also for SystemVerilog plusargs
|
|
195
|
-
vlog_dot_f_lines += [ f'+define+{k}={sanitize_defines_for_sh(v)}' ]
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
vlog_dot_f_lines += self.args['compile-args']
|
|
199
|
-
|
|
200
|
-
vlog_dot_f_lines += [
|
|
201
|
-
'-source',
|
|
202
|
-
] + list(self.files_sv) + list(self.files_v)
|
|
203
|
-
|
|
204
|
-
if not self.files_sv and not self.files_v:
|
|
205
|
-
if not self.args['stop-before-compile']:
|
|
206
|
-
self.error(f'{self.target=} {self.files_sv=} and {self.files_v=} are empty,',
|
|
207
|
-
'cannot create a valid vlog.f')
|
|
208
|
-
|
|
209
|
-
with open(vlog_dot_f_fpath, 'w', encoding='utf-8') as f:
|
|
210
|
-
f.writelines(line + "\n" for line in vlog_dot_f_lines)
|
|
211
|
-
|
|
212
|
-
def vopt_handle_parameters(self) -> (str, list):
|
|
213
|
-
'''Returns str for vopt or voptargs, and list of vopt tcl
|
|
214
|
-
|
|
215
|
-
Note this is used for self.use_vopt = True or False.
|
|
216
|
-
'''
|
|
217
|
-
|
|
218
|
-
voptargs_str = ''
|
|
219
|
-
vopt_do_lines = []
|
|
220
|
-
|
|
221
|
-
# Note that if self.use_vopt=True, we have to do some workarounds for how
|
|
222
|
-
# some questa-like tools behave for: tcl/.do + vopt arg processing
|
|
223
|
-
# This affects string based parameters that have spaces (vopt treats spaces unique args,
|
|
224
|
-
# vsim does not). Since we'd like to keep the vopt/vsim split into separate steps, we can
|
|
225
|
-
# work around this by setting tcl varaibles for each parameter.
|
|
226
|
-
if self.parameters:
|
|
227
|
-
if not self.use_vopt:
|
|
228
|
-
voptargs_str += ' ' + ' '.join(self.process_parameters_get_list(arg_prefix='-G'))
|
|
229
|
-
else:
|
|
230
|
-
for k,v in self.parameters.items():
|
|
231
|
-
s = sim.parameters_dict_get_command_list(params={k: v}, arg_prefix='')[0]
|
|
232
|
-
# At this point, s should be a str in form {k}={v}
|
|
233
|
-
if not s or '=' not in s:
|
|
234
|
-
continue
|
|
235
|
-
if ' ' in s:
|
|
236
|
-
# Instead of:
|
|
237
|
-
# vopt -GMyParam="hi bye"
|
|
238
|
-
# we'll do:
|
|
239
|
-
# set PARAMETERS(MyParam) "hi bye"
|
|
240
|
-
# vopt -GMyParam=$PARAMETERS(MyParam)
|
|
241
|
-
s = s.replace(f'{k}=', f'set PARAMETERS({k}) ')
|
|
242
|
-
vopt_do_lines.append(s)
|
|
243
|
-
voptargs_str += f' -G{k}=$PARAMETERS({k}) '
|
|
244
|
-
else:
|
|
245
|
-
voptargs_str += f' -G{s} '
|
|
246
|
-
|
|
247
|
-
return voptargs_str, vopt_do_lines
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
def write_vsim_dot_do( # pylint: disable=too-many-locals
|
|
251
|
-
self, dot_do_to_write: list
|
|
252
|
-
) -> None:
|
|
253
|
-
'''Writes files(s) based on dot_do_to_write(list of str)
|
|
254
|
-
|
|
255
|
-
list arg values can be empty (all) or have items 'all', 'sim', 'lint', 'vlog'.'''
|
|
256
|
-
|
|
257
|
-
vsim_dot_do_fpath = os.path.join(self.args['work-dir'], 'vsim.do')
|
|
258
|
-
vsim_lintonly_dot_do_fpath = os.path.join(self.args['work-dir'], 'vsim_lintonly.do')
|
|
259
|
-
vsim_vlogonly_dot_do_fpath = os.path.join(self.args['work-dir'], 'vsim_vlogonly.do')
|
|
260
|
-
|
|
261
|
-
sim_plusargs_str = self._get_sim_plusargs_str()
|
|
262
|
-
vsim_suppress_list_str = self._get_vsim_suppress_list_str()
|
|
263
|
-
vsim_ext_args = ' '.join(self.args.get('sim-args', []))
|
|
264
|
-
|
|
265
|
-
voptargs_str = self.tool_config.get('elab-args', '')
|
|
266
|
-
voptargs_str += ' '.join(self.args.get('elab-args', []))
|
|
267
|
-
if self.args['gui'] or self.args['waves']:
|
|
268
|
-
voptargs_str += ' ' + self.tool_config.get('simulate-waves-args', '+acc')
|
|
269
|
-
util.artifacts.add_extension(
|
|
270
|
-
search_paths=self.args['work-dir'], file_extension='wlf',
|
|
271
|
-
typ='waveform', description='Modelsim/Questa Waveform WLF (Wave Log Format) file'
|
|
272
|
-
)
|
|
273
|
-
|
|
274
|
-
# TODO(drew): support self.args['sim_libary'] (1 lists)
|
|
275
|
-
vlog_do_lines = []
|
|
276
|
-
vsim_do_lines = []
|
|
277
|
-
|
|
278
|
-
# parameters, use helper method to get voptargs_str and vopt_do_lines
|
|
279
|
-
more_voptargs_str, vopt_do_lines = self.vopt_handle_parameters()
|
|
280
|
-
voptargs_str += more_voptargs_str
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
vopt_one_liner = ""
|
|
284
|
-
if self.use_vopt:
|
|
285
|
-
vopt_one_liner = (
|
|
286
|
-
f"vopt {voptargs_str} work.{self.args['top']} -o opt__{self.args['top']}"
|
|
287
|
-
)
|
|
288
|
-
vopt_one_liner = vopt_one_liner.replace('\n', ' ') # needs to be a one-liner
|
|
289
|
-
# vopt doesn't need -voptargs=(value) like vsim does, simply use (value).
|
|
290
|
-
vopt_one_liner = vopt_one_liner.replace('-voptargs=', '')
|
|
291
|
-
|
|
292
|
-
vsim_one_liner = "vsim -onfinish stop" \
|
|
293
|
-
+ f" -sv_seed {self.args['seed']} {sim_plusargs_str} {vsim_suppress_list_str}" \
|
|
294
|
-
+ f" {vsim_ext_args} opt__{self.args['top']}"
|
|
295
|
-
else:
|
|
296
|
-
# vopt doesn't exist, use single vsim call after vlog call:
|
|
297
|
-
vsim_one_liner = "vsim -onfinish stop" \
|
|
298
|
-
+ f" -sv_seed {self.args['seed']} {sim_plusargs_str} {vsim_suppress_list_str}" \
|
|
299
|
-
+ f" {voptargs_str} {vsim_ext_args} work.{self.args['top']}"
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
vsim_one_liner = vsim_one_liner.replace('\n', ' ')
|
|
303
|
-
|
|
304
|
-
vlog_do_lines += [
|
|
305
|
-
"if {[file exists work]} { vdel -all work; }",
|
|
306
|
-
"vlib work;",
|
|
307
|
-
"quietly set qc 30;",
|
|
308
|
-
"if {[catch {vlog -f vlog.f} result]} {",
|
|
309
|
-
" echo \"Caught $result \";",
|
|
310
|
-
" if {[batch_mode]} {",
|
|
311
|
-
" quit -f -code 20;",
|
|
312
|
-
" }",
|
|
313
|
-
"}",
|
|
314
|
-
]
|
|
315
|
-
|
|
316
|
-
if self.use_vopt:
|
|
317
|
-
vopt_do_lines += [
|
|
318
|
-
"if {[catch { " + vopt_one_liner + " } result] } {",
|
|
319
|
-
" echo \"Caught $result\";",
|
|
320
|
-
" if {[batch_mode]} {",
|
|
321
|
-
" quit -f -code 19;",
|
|
322
|
-
" }",
|
|
323
|
-
"}",
|
|
324
|
-
]
|
|
325
|
-
|
|
326
|
-
vsim_do_lines += [
|
|
327
|
-
"if {[catch { " + vsim_one_liner + " } result] } {",
|
|
328
|
-
" echo \"Caught $result\";",
|
|
329
|
-
" if {[batch_mode]} {",
|
|
330
|
-
" quit -f -code 18;",
|
|
331
|
-
" }",
|
|
332
|
-
"}",
|
|
333
|
-
]
|
|
334
|
-
|
|
335
|
-
vsim_vlogonly_dot_do_lines = vlog_do_lines + [
|
|
336
|
-
"if {[batch_mode]} {",
|
|
337
|
-
" quit -f -code 0;",
|
|
338
|
-
"}",
|
|
339
|
-
]
|
|
340
|
-
|
|
341
|
-
final_check_teststatus_do_lines = [
|
|
342
|
-
"set TestStatus [coverage attribute -name SEED -name TESTSTATUS];",
|
|
343
|
-
"if {[regexp \"TESTSTATUS += 0\" $TestStatus]} {",
|
|
344
|
-
" quietly set qc 0;",
|
|
345
|
-
"} elseif {[regexp \"TESTSTATUS += 1\" $TestStatus]} {",
|
|
346
|
-
" quietly set qc 0;",
|
|
347
|
-
"} else {",
|
|
348
|
-
" quietly set qc 2;",
|
|
349
|
-
"}",
|
|
350
|
-
"if {[batch_mode]} {",
|
|
351
|
-
" quit -f -code $qc;",
|
|
352
|
-
"}",
|
|
353
|
-
]
|
|
354
|
-
|
|
355
|
-
# final vlog/vopt/vsim lint-only .do command (want to make sure it can completely
|
|
356
|
-
# build for 'elab' style eda job), runs for 0ns, logs nothing for a waveform, quits
|
|
357
|
-
vsim_lintonly_dot_do_lines = vlog_do_lines + vopt_do_lines + vsim_do_lines \
|
|
358
|
-
+ final_check_teststatus_do_lines
|
|
359
|
-
|
|
360
|
-
# final vlog/opt/vsim full simulation .do command.
|
|
361
|
-
vsim_dot_do_lines = vlog_do_lines + vopt_do_lines + vsim_do_lines + [
|
|
362
|
-
"onbreak { resume; };",
|
|
363
|
-
"catch {log -r *};",
|
|
364
|
-
"run -a;",
|
|
365
|
-
] + final_check_teststatus_do_lines
|
|
366
|
-
|
|
367
|
-
write_all = len(dot_do_to_write) == 0 or 'all' in dot_do_to_write
|
|
368
|
-
if write_all or 'sim' in dot_do_to_write:
|
|
369
|
-
with open(vsim_dot_do_fpath, 'w', encoding='utf-8') as f:
|
|
370
|
-
f.writelines(line + "\n" for line in vsim_dot_do_lines)
|
|
371
|
-
|
|
372
|
-
if write_all or 'lint' in dot_do_to_write:
|
|
373
|
-
with open(vsim_lintonly_dot_do_fpath, 'w', encoding='utf-8') as f:
|
|
374
|
-
f.writelines(line + "\n" for line in vsim_lintonly_dot_do_lines)
|
|
375
|
-
|
|
376
|
-
if write_all or 'vlog' in dot_do_to_write:
|
|
377
|
-
with open(vsim_vlogonly_dot_do_fpath, 'w', encoding='utf-8') as f:
|
|
378
|
-
f.writelines(line + "\n" for line in vsim_vlogonly_dot_do_lines)
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
def _get_sim_plusargs_str(self) -> str:
|
|
382
|
-
sim_plusargs = []
|
|
383
|
-
|
|
384
|
-
assert isinstance(self.args["sim-plusargs"], list), \
|
|
385
|
-
f'{self.target=} {type(self.args["sim-plusargs"])=} but must be list'
|
|
386
|
-
|
|
387
|
-
for x in self.args['sim-plusargs']:
|
|
388
|
-
# For vsim we need to add a +key=value if the + is missing
|
|
389
|
-
if x[0] != '+':
|
|
390
|
-
x = f'+{x}'
|
|
391
|
-
sim_plusargs.append(x)
|
|
392
|
-
|
|
393
|
-
return ' '.join(sim_plusargs)
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
def _get_vsim_suppress_list_str(self) -> str:
|
|
397
|
-
vsim_suppress_list = []
|
|
398
|
-
# Add waivers from config.tool.modelsim_ase:
|
|
399
|
-
for waiver in self.tool_config.get(
|
|
400
|
-
'simulate-waivers', [
|
|
401
|
-
#defaults:
|
|
402
|
-
'3009', # 3009: [TSCALE] - Module 'foo' does not have a timeunit/timeprecision
|
|
403
|
-
# specification in effect, but other modules do.
|
|
404
|
-
]) + self.args['sim-waivers']:
|
|
405
|
-
vsim_suppress_list += ['-suppress', str(waiver)]
|
|
406
|
-
|
|
407
|
-
return ' '.join(vsim_suppress_list)
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
def artifacts_add(self, name: str, typ: str, description: str) -> None:
|
|
411
|
-
'''Override from Command.artifacts_add, so we can catch known file
|
|
412
|
-
|
|
413
|
-
names to make their typ/description better, such as CommandSim using
|
|
414
|
-
sim.log
|
|
415
|
-
'''
|
|
416
|
-
_, leafname = os.path.split(name)
|
|
417
|
-
if leafname == 'sim.log':
|
|
418
|
-
description = 'Modelsim/Questa Transcript log file'
|
|
419
|
-
|
|
420
|
-
super().artifacts_add(name=name, typ=typ, description=description)
|
|
421
54
|
|
|
422
55
|
|
|
423
56
|
class CommandElabModelsimAse(CommandSimModelsimAse):
|
|
@@ -439,3 +72,11 @@ class CommandLintModelsimAse(CommandSimModelsimAse):
|
|
|
439
72
|
super().__init__(config)
|
|
440
73
|
self.args['stop-after-compile'] = True
|
|
441
74
|
self.args['stop-after-elaborate'] = True
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class CommandFListModelsimAse(CommonFListQuesta):
|
|
78
|
+
'''CommandFListModelsimAse is a command handler for: eda flist --tool=modelsim_ase'''
|
|
79
|
+
|
|
80
|
+
def __init__(self, config: dict):
|
|
81
|
+
CommonFListQuesta.__init__(self, config=config)
|
|
82
|
+
self._TOOL = 'questa_fse'
|