cocotb 1.7.2__cp310-cp310-win_amd64.whl → 1.8.0rc1__cp310-cp310-win_amd64.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.
Potentially problematic release.
This version of cocotb might be problematic. Click here for more details.
- cocotb/__init__.py +7 -18
- cocotb/_sim_versions.py +16 -1
- cocotb/_version.py +1 -1
- cocotb/clock.py +8 -3
- cocotb/decorators.py +40 -318
- cocotb/ipython_support.py +3 -1
- cocotb/libs/cocotb.dll +0 -0
- cocotb/libs/cocotb.exp +0 -0
- cocotb/libs/cocotb.lib +0 -0
- cocotb/libs/cocotbfli_modelsim.dll +0 -0
- cocotb/libs/cocotbfli_modelsim.exp +0 -0
- cocotb/libs/cocotbfli_modelsim.lib +0 -0
- cocotb/libs/cocotbutils.dll +0 -0
- cocotb/libs/cocotbutils.exp +0 -0
- cocotb/libs/cocotbutils.lib +0 -0
- cocotb/libs/cocotbvhpi_aldec.dll +0 -0
- cocotb/libs/cocotbvhpi_aldec.exp +0 -0
- cocotb/libs/cocotbvhpi_aldec.lib +0 -0
- cocotb/libs/cocotbvhpi_modelsim.dll +0 -0
- cocotb/libs/cocotbvhpi_modelsim.exp +0 -0
- cocotb/libs/cocotbvhpi_modelsim.lib +0 -0
- cocotb/libs/cocotbvpi_aldec.dll +0 -0
- cocotb/libs/cocotbvpi_aldec.exp +0 -0
- cocotb/libs/cocotbvpi_aldec.lib +0 -0
- cocotb/libs/cocotbvpi_ghdl.dll +0 -0
- cocotb/libs/cocotbvpi_ghdl.exp +0 -0
- cocotb/libs/cocotbvpi_ghdl.lib +0 -0
- cocotb/libs/cocotbvpi_icarus.exp +0 -0
- cocotb/libs/cocotbvpi_icarus.lib +0 -0
- cocotb/libs/cocotbvpi_icarus.vpl +0 -0
- cocotb/libs/cocotbvpi_modelsim.dll +0 -0
- cocotb/libs/cocotbvpi_modelsim.exp +0 -0
- cocotb/libs/cocotbvpi_modelsim.lib +0 -0
- cocotb/libs/embed.dll +0 -0
- cocotb/libs/embed.exp +0 -0
- cocotb/libs/embed.lib +0 -0
- cocotb/libs/gpi.dll +0 -0
- cocotb/libs/gpi.exp +0 -0
- cocotb/libs/gpi.lib +0 -0
- cocotb/libs/gpilog.dll +0 -0
- cocotb/libs/gpilog.exp +0 -0
- cocotb/libs/gpilog.lib +0 -0
- cocotb/libs/pygpilog.dll +0 -0
- cocotb/libs/pygpilog.exp +0 -0
- cocotb/libs/pygpilog.lib +0 -0
- cocotb/regression.py +32 -14
- cocotb/runner.py +538 -453
- cocotb/scheduler.py +35 -18
- cocotb/share/def/aldec.exp +0 -0
- cocotb/share/def/aldec.lib +0 -0
- cocotb/share/def/ghdl.exp +0 -0
- cocotb/share/def/ghdl.lib +0 -0
- cocotb/share/def/icarus.exp +0 -0
- cocotb/share/def/icarus.lib +0 -0
- cocotb/share/def/modelsim.def +2 -0
- cocotb/share/def/modelsim.exp +0 -0
- cocotb/share/def/modelsim.lib +0 -0
- cocotb/share/include/embed.h +1 -2
- cocotb/share/include/gpi.h +10 -15
- cocotb/share/include/vpi_user_ext.h +3 -0
- cocotb/share/lib/verilator/verilator.cpp +8 -4
- cocotb/share/makefiles/Makefile.inc +16 -4
- cocotb/share/makefiles/Makefile.sim +2 -2
- cocotb/share/makefiles/simulators/Makefile.icarus +19 -0
- cocotb/share/makefiles/simulators/Makefile.ius +12 -1
- cocotb/share/makefiles/simulators/Makefile.questa +2 -1
- cocotb/share/makefiles/simulators/Makefile.riviera +4 -0
- cocotb/share/makefiles/simulators/Makefile.vcs +4 -0
- cocotb/share/makefiles/simulators/Makefile.verilator +5 -1
- cocotb/share/makefiles/simulators/Makefile.xcelium +5 -1
- cocotb/simulator.cp310-win_amd64.exp +0 -0
- cocotb/simulator.cp310-win_amd64.lib +0 -0
- cocotb/simulator.cp310-win_amd64.pyd +0 -0
- cocotb/task.py +325 -0
- cocotb/triggers.py +23 -7
- cocotb/types/logic_array.py +34 -3
- {cocotb-1.7.2.dist-info → cocotb-1.8.0rc1.dist-info}/METADATA +24 -9
- cocotb-1.8.0rc1.dist-info/RECORD +120 -0
- {cocotb-1.7.2.dist-info → cocotb-1.8.0rc1.dist-info}/WHEEL +1 -1
- cocotb-1.7.2.dist-info/RECORD +0 -119
- {cocotb-1.7.2.dist-info → cocotb-1.8.0rc1.dist-info}/LICENSE +0 -0
- {cocotb-1.7.2.dist-info → cocotb-1.8.0rc1.dist-info}/entry_points.txt +0 -0
- {cocotb-1.7.2.dist-info → cocotb-1.8.0rc1.dist-info}/top_level.txt +0 -0
cocotb/runner.py
CHANGED
|
@@ -2,16 +2,25 @@
|
|
|
2
2
|
# Licensed under the Revised BSD License, see LICENSE for details.
|
|
3
3
|
# SPDX-License-Identifier: BSD-3-Clause
|
|
4
4
|
|
|
5
|
+
"""Build HDL and run cocotb tests."""
|
|
6
|
+
|
|
7
|
+
# TODO: maybe do globbing and expanduser/expandvars in --include, --vhdl-sources, --verilog-sources
|
|
8
|
+
# TODO: create a short README and a .gitignore (content: "*") in both build_dir and test_dir? (Some other tools do this.)
|
|
9
|
+
# TODO: support timescale
|
|
10
|
+
# TODO: support custom dependencies
|
|
11
|
+
|
|
5
12
|
import abc
|
|
6
13
|
import os
|
|
7
14
|
import re
|
|
15
|
+
import shlex
|
|
8
16
|
import shutil
|
|
9
17
|
import subprocess
|
|
10
18
|
import sys
|
|
11
19
|
import tempfile
|
|
12
20
|
import warnings
|
|
13
21
|
from contextlib import suppress
|
|
14
|
-
from
|
|
22
|
+
from pathlib import Path
|
|
23
|
+
from typing import Dict, List, Mapping, Optional, Sequence, Tuple, Type, Union
|
|
15
24
|
from xml.etree import cElementTree as ET
|
|
16
25
|
|
|
17
26
|
import find_libpython
|
|
@@ -42,30 +51,68 @@ def as_tcl_value(value: str) -> str:
|
|
|
42
51
|
return value
|
|
43
52
|
|
|
44
53
|
|
|
54
|
+
def shlex_join(split_command):
|
|
55
|
+
"""
|
|
56
|
+
Return a shell-escaped string from *split_command*
|
|
57
|
+
This is here more for compatibility purposes
|
|
58
|
+
"""
|
|
59
|
+
return " ".join(shlex.quote(arg) for arg in split_command)
|
|
60
|
+
|
|
61
|
+
|
|
45
62
|
class Simulator(abc.ABC):
|
|
63
|
+
|
|
64
|
+
supported_gpi_interfaces: Dict[str, List[str]] = {}
|
|
65
|
+
|
|
46
66
|
def __init__(self) -> None:
|
|
47
67
|
|
|
48
|
-
self.
|
|
68
|
+
self._simulator_in_path()
|
|
49
69
|
|
|
50
70
|
self.env: Dict[str, str] = {}
|
|
51
71
|
|
|
52
72
|
# for running test() independently of build()
|
|
53
|
-
self.build_dir = "sim_build"
|
|
54
|
-
self.parameters = {}
|
|
73
|
+
self.build_dir: Path = get_abs_path("sim_build")
|
|
74
|
+
self.parameters: Mapping[str, object] = {}
|
|
55
75
|
|
|
56
76
|
@abc.abstractmethod
|
|
57
|
-
def
|
|
58
|
-
"""
|
|
77
|
+
def _simulator_in_path(self) -> None:
|
|
78
|
+
"""Raise exception if the simulator executable does not exist in :envvar:`PATH`.
|
|
79
|
+
|
|
80
|
+
Raises:
|
|
81
|
+
SystemExit: Simulator executable does not exist in :envvar:`PATH`.
|
|
82
|
+
"""
|
|
59
83
|
|
|
60
84
|
raise NotImplementedError()
|
|
61
85
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
"""Return *toplevel_lang* if supported by simulator, raise exception otherwise."""
|
|
86
|
+
def _check_hdl_toplevel_lang(self, hdl_toplevel_lang: Optional[str]) -> str:
|
|
87
|
+
"""Return *hdl_toplevel_lang* if supported by simulator, raise exception otherwise.
|
|
65
88
|
|
|
66
|
-
|
|
89
|
+
Returns:
|
|
90
|
+
*hdl_toplevel_lang* if supported by the simulator.
|
|
91
|
+
|
|
92
|
+
Raises:
|
|
93
|
+
ValueError: *hdl_toplevel_lang* is not supported by the simulator.
|
|
94
|
+
"""
|
|
95
|
+
if hdl_toplevel_lang is None:
|
|
96
|
+
if self.vhdl_sources and not self.verilog_sources:
|
|
97
|
+
lang = "vhdl"
|
|
98
|
+
elif self.verilog_sources and not self.vhdl_sources:
|
|
99
|
+
lang = "verilog"
|
|
100
|
+
else:
|
|
101
|
+
raise ValueError(
|
|
102
|
+
f"{type(self).__qualname__}: Must specify a hdl_toplevel_lang in a mixed-language design"
|
|
103
|
+
)
|
|
104
|
+
else:
|
|
105
|
+
lang = hdl_toplevel_lang
|
|
106
|
+
|
|
107
|
+
if lang in self.supported_gpi_interfaces.keys():
|
|
108
|
+
return lang
|
|
109
|
+
else:
|
|
110
|
+
raise ValueError(
|
|
111
|
+
f"{type(self).__qualname__}: hdl_toplevel_lang {hdl_toplevel_lang!r} is not "
|
|
112
|
+
f"in supported list: {', '.join(self.supported_gpi_interfaces.keys())}"
|
|
113
|
+
)
|
|
67
114
|
|
|
68
|
-
def
|
|
115
|
+
def _set_env(self) -> None:
|
|
69
116
|
"""Set environment variables for sub-processes."""
|
|
70
117
|
|
|
71
118
|
for e in os.environ:
|
|
@@ -75,187 +122,236 @@ class Simulator(abc.ABC):
|
|
|
75
122
|
self.env["LIBPYTHON_LOC"] = find_libpython.find_libpython()
|
|
76
123
|
|
|
77
124
|
self.env["PATH"] += os.pathsep + cocotb.config.libs_dir
|
|
78
|
-
|
|
79
125
|
self.env["PYTHONPATH"] = os.pathsep.join(sys.path)
|
|
80
|
-
for path in self.python_search:
|
|
81
|
-
self.env["PYTHONPATH"] += os.pathsep + str(path)
|
|
82
|
-
|
|
83
126
|
self.env["PYTHONHOME"] = sys.prefix
|
|
84
|
-
|
|
85
|
-
self.env["
|
|
86
|
-
self.env["MODULE"] = self.module
|
|
127
|
+
self.env["TOPLEVEL"] = self.sim_hdl_toplevel
|
|
128
|
+
self.env["MODULE"] = self.test_module
|
|
87
129
|
|
|
88
130
|
@abc.abstractmethod
|
|
89
|
-
def
|
|
131
|
+
def _build_command(self) -> Sequence[Command]:
|
|
90
132
|
"""Return command to build the HDL sources."""
|
|
91
133
|
|
|
92
134
|
raise NotImplementedError()
|
|
93
135
|
|
|
94
136
|
@abc.abstractmethod
|
|
95
|
-
def
|
|
137
|
+
def _test_command(self) -> Sequence[Command]:
|
|
96
138
|
"""Return command to run a test."""
|
|
97
139
|
|
|
98
140
|
raise NotImplementedError()
|
|
99
141
|
|
|
100
142
|
def build(
|
|
101
143
|
self,
|
|
102
|
-
|
|
144
|
+
hdl_library: str = "top",
|
|
103
145
|
verilog_sources: Sequence[PathLike] = [],
|
|
104
146
|
vhdl_sources: Sequence[PathLike] = [],
|
|
105
147
|
includes: Sequence[PathLike] = [],
|
|
106
|
-
defines:
|
|
148
|
+
defines: Mapping[str, object] = {},
|
|
107
149
|
parameters: Mapping[str, object] = {},
|
|
108
|
-
|
|
109
|
-
|
|
150
|
+
build_args: Sequence[str] = [],
|
|
151
|
+
hdl_toplevel: Optional[str] = None,
|
|
110
152
|
always: bool = False,
|
|
111
153
|
build_dir: PathLike = "sim_build",
|
|
154
|
+
verbose: bool = False,
|
|
112
155
|
) -> None:
|
|
113
|
-
"""Build the HDL sources.
|
|
114
|
-
|
|
115
|
-
|
|
156
|
+
"""Build the HDL sources.
|
|
157
|
+
|
|
158
|
+
Args:
|
|
159
|
+
hdl_library: The library name to compile into.
|
|
160
|
+
verilog_sources: Verilog source files to build.
|
|
161
|
+
vhdl_sources: VHDL source files to build.
|
|
162
|
+
includes: Verilog include directories.
|
|
163
|
+
defines: Defines to set.
|
|
164
|
+
parameters: Verilog parameters or VHDL generics.
|
|
165
|
+
build_args: Extra build arguments for the simulator.
|
|
166
|
+
hdl_toplevel: The name of the HDL toplevel module.
|
|
167
|
+
always: Always run the build step.
|
|
168
|
+
build_dir: Directory to run the build step in.
|
|
169
|
+
verbose: Enable verbose messages.
|
|
170
|
+
"""
|
|
171
|
+
|
|
172
|
+
self.build_dir = get_abs_path(build_dir)
|
|
116
173
|
os.makedirs(self.build_dir, exist_ok=True)
|
|
117
174
|
|
|
118
175
|
# note: to avoid mutating argument defaults, we ensure that no value
|
|
119
176
|
# is written without a copy. This is much more concise and leads to
|
|
120
177
|
# a better docstring than using `None` as a default in the parameters
|
|
121
178
|
# list.
|
|
122
|
-
self.
|
|
123
|
-
self.verilog_sources = get_abs_paths(verilog_sources)
|
|
124
|
-
self.vhdl_sources = get_abs_paths(vhdl_sources)
|
|
125
|
-
self.includes = get_abs_paths(includes)
|
|
126
|
-
self.defines =
|
|
179
|
+
self.hdl_library: str = hdl_library
|
|
180
|
+
self.verilog_sources: List[Path] = get_abs_paths(verilog_sources)
|
|
181
|
+
self.vhdl_sources: List[Path] = get_abs_paths(vhdl_sources)
|
|
182
|
+
self.includes: List[Path] = get_abs_paths(includes)
|
|
183
|
+
self.defines = dict(defines)
|
|
127
184
|
self.parameters = dict(parameters)
|
|
128
|
-
self.
|
|
129
|
-
self.always = always
|
|
130
|
-
self.hdl_toplevel =
|
|
185
|
+
self.build_args = list(build_args)
|
|
186
|
+
self.always: bool = always
|
|
187
|
+
self.hdl_toplevel: Optional[str] = hdl_toplevel
|
|
188
|
+
self.verbose: bool = verbose
|
|
131
189
|
|
|
132
190
|
for e in os.environ:
|
|
133
191
|
self.env[e] = os.environ[e]
|
|
134
192
|
|
|
135
|
-
cmds = self.
|
|
136
|
-
self.
|
|
193
|
+
cmds: Sequence[Command] = self._build_command()
|
|
194
|
+
self._execute(cmds, cwd=self.build_dir)
|
|
137
195
|
|
|
138
196
|
def test(
|
|
139
197
|
self,
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
198
|
+
test_module: Union[str, Sequence[str]],
|
|
199
|
+
hdl_toplevel: str,
|
|
200
|
+
hdl_toplevel_library: str = "top",
|
|
201
|
+
hdl_toplevel_lang: Optional[str] = None,
|
|
202
|
+
gpi_interfaces: Optional[List[str]] = None,
|
|
203
|
+
testcase: Optional[Union[str, Sequence[str]]] = None,
|
|
144
204
|
seed: Optional[Union[str, int]] = None,
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
plus_args: Sequence[str] = [],
|
|
205
|
+
test_args: Sequence[str] = [],
|
|
206
|
+
plusargs: Sequence[str] = [],
|
|
148
207
|
extra_env: Mapping[str, str] = {},
|
|
149
208
|
waves: Optional[bool] = None,
|
|
150
209
|
gui: Optional[bool] = None,
|
|
151
210
|
parameters: Mapping[str, object] = None,
|
|
152
211
|
build_dir: Optional[PathLike] = None,
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
212
|
+
test_dir: Optional[PathLike] = None,
|
|
213
|
+
results_xml: str = "results.xml",
|
|
214
|
+
verbose: bool = False,
|
|
215
|
+
) -> Path:
|
|
216
|
+
"""Run the tests.
|
|
217
|
+
|
|
218
|
+
Args:
|
|
219
|
+
test_module: Name(s) of the Python module(s) containing the tests to run.
|
|
220
|
+
Can be a comma-separated list.
|
|
221
|
+
hdl_toplevel: Name of the HDL toplevel module.
|
|
222
|
+
hdl_toplevel_library: The library name for HDL toplevel module.
|
|
223
|
+
hdl_toplevel_lang: Language of the HDL toplevel module.
|
|
224
|
+
gpi_interfaces: List of GPI interfaces to use, with the first one being the entry point.
|
|
225
|
+
testcase: Name(s) of a specific testcase(s) to run.
|
|
226
|
+
If not set, run all testcases found in *test_module*.
|
|
227
|
+
Can be a comma-separated list.
|
|
228
|
+
seed: A specific random seed to use.
|
|
229
|
+
test_args: Extra arguments for the simulator.
|
|
230
|
+
plusargs: 'plusargs' to set for the simulator.
|
|
231
|
+
extra_env: Extra environment variables to set.
|
|
232
|
+
waves: Record signal traces.
|
|
233
|
+
gui: Run with simulator GUI.
|
|
234
|
+
parameters: Verilog parameters or VHDL generics.
|
|
235
|
+
build_dir: Directory the build step has been run in.
|
|
236
|
+
test_dir: Directory to run the tests in.
|
|
237
|
+
results_xml: Name of xUnit XML file to store test results in.
|
|
238
|
+
When running with pytest, the testcase name is prefixed to this name.
|
|
239
|
+
verbose: Enable verbose messages.
|
|
240
|
+
|
|
241
|
+
Returns:
|
|
242
|
+
The absolute location of the results XML file which can be
|
|
243
|
+
defined by the *results_xml* argument.
|
|
244
|
+
The default is :file:`{build_dir}/{pytest_test_name}.results.xml`
|
|
245
|
+
when run with ``pytest``,
|
|
246
|
+
:file:`{build_dir}/results.xml` otherwise.
|
|
247
|
+
"""
|
|
156
248
|
|
|
157
249
|
__tracebackhide__ = True # Hide the traceback when using pytest
|
|
158
250
|
|
|
159
251
|
if build_dir is not None:
|
|
160
|
-
self.build_dir = build_dir
|
|
252
|
+
self.build_dir = get_abs_path(build_dir)
|
|
161
253
|
|
|
162
254
|
if parameters is not None:
|
|
163
255
|
self.parameters = dict(parameters)
|
|
164
256
|
|
|
165
|
-
if
|
|
166
|
-
self.
|
|
257
|
+
if test_dir is None:
|
|
258
|
+
self.test_dir = self.build_dir
|
|
167
259
|
else:
|
|
168
|
-
self.
|
|
260
|
+
self.test_dir = get_abs_path(test_dir)
|
|
261
|
+
os.makedirs(self.test_dir, exist_ok=True)
|
|
169
262
|
|
|
170
|
-
if isinstance(
|
|
171
|
-
self.
|
|
263
|
+
if isinstance(test_module, str):
|
|
264
|
+
self.test_module = test_module
|
|
172
265
|
else:
|
|
173
|
-
self.
|
|
266
|
+
self.test_module = ",".join(test_module)
|
|
174
267
|
|
|
175
268
|
# note: to avoid mutating argument defaults, we ensure that no value
|
|
176
269
|
# is written without a copy. This is much more concise and leads to
|
|
177
270
|
# a better docstring than using `None` as a default in the parameters
|
|
178
271
|
# list.
|
|
179
|
-
self.
|
|
180
|
-
self.
|
|
181
|
-
self.
|
|
182
|
-
|
|
183
|
-
|
|
272
|
+
self.sim_hdl_toplevel = hdl_toplevel
|
|
273
|
+
self.hdl_toplevel_library: str = hdl_toplevel_library
|
|
274
|
+
self.hdl_toplevel_lang = self._check_hdl_toplevel_lang(hdl_toplevel_lang)
|
|
275
|
+
if gpi_interfaces:
|
|
276
|
+
self.gpi_interfaces = gpi_interfaces
|
|
277
|
+
else:
|
|
278
|
+
self.gpi_interfaces = []
|
|
279
|
+
for gpi_if in self.supported_gpi_interfaces.values():
|
|
280
|
+
self.gpi_interfaces.append(gpi_if[0])
|
|
281
|
+
|
|
282
|
+
self.test_args = list(test_args)
|
|
283
|
+
self.plusargs = list(plusargs)
|
|
184
284
|
self.env = dict(extra_env)
|
|
185
285
|
|
|
186
286
|
if testcase is not None:
|
|
187
|
-
|
|
287
|
+
if isinstance(testcase, str):
|
|
288
|
+
self.env["TESTCASE"] = testcase
|
|
289
|
+
else:
|
|
290
|
+
self.env["TESTCASE"] = ",".join(testcase)
|
|
188
291
|
|
|
189
292
|
if seed is not None:
|
|
190
293
|
self.env["RANDOM_SEED"] = str(seed)
|
|
191
294
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
else:
|
|
195
|
-
self.waves = bool(waves)
|
|
295
|
+
self.waves = bool(waves)
|
|
296
|
+
self.gui = bool(gui)
|
|
196
297
|
|
|
197
|
-
if
|
|
198
|
-
self.
|
|
199
|
-
else:
|
|
200
|
-
self.gui = bool(gui)
|
|
298
|
+
if verbose is not None:
|
|
299
|
+
self.verbose = verbose
|
|
201
300
|
|
|
202
301
|
# When using pytest, use test name as result file name
|
|
203
302
|
pytest_current_test = os.getenv("PYTEST_CURRENT_TEST", "")
|
|
204
303
|
if pytest_current_test:
|
|
205
304
|
self.current_test_name = pytest_current_test.split(":")[-1].split(" ")[0]
|
|
206
|
-
results_xml_name = f"{self.current_test_name}.
|
|
305
|
+
results_xml_name = f"{self.current_test_name}.{results_xml}"
|
|
207
306
|
else:
|
|
208
307
|
self.current_test_name = "test"
|
|
209
|
-
results_xml_name =
|
|
308
|
+
results_xml_name = results_xml
|
|
210
309
|
|
|
211
|
-
results_xml_file =
|
|
212
|
-
"COCOTB_RESULTS_FILE", os.path.join(self.build_dir, results_xml_name)
|
|
213
|
-
)
|
|
214
|
-
|
|
215
|
-
self.env["COCOTB_RESULTS_FILE"] = results_xml_file
|
|
310
|
+
results_xml_file = Path(self.test_dir) / results_xml_name
|
|
216
311
|
|
|
217
312
|
with suppress(OSError):
|
|
218
313
|
os.remove(results_xml_file)
|
|
219
314
|
|
|
220
|
-
|
|
221
|
-
self.
|
|
222
|
-
self.
|
|
315
|
+
# transport the settings to cocotb via environment variables
|
|
316
|
+
self._set_env()
|
|
317
|
+
self.env["COCOTB_RESULTS_FILE"] = str(results_xml_file)
|
|
223
318
|
|
|
224
|
-
|
|
319
|
+
cmds: Sequence[Command] = self._test_command()
|
|
320
|
+
self._execute(cmds, cwd=self.test_dir)
|
|
321
|
+
|
|
322
|
+
# Only when running under pytest, check the results file here,
|
|
323
|
+
# potentially raising an exception with failing testcases,
|
|
324
|
+
# otherwise return the results file for later analysis.
|
|
325
|
+
if pytest_current_test:
|
|
326
|
+
check_results_file(results_xml_file)
|
|
225
327
|
|
|
226
328
|
print(f"INFO: Results file: {results_xml_file}")
|
|
227
329
|
return results_xml_file
|
|
228
330
|
|
|
229
|
-
@
|
|
230
|
-
def
|
|
231
|
-
"""Return simulator
|
|
331
|
+
@staticmethod
|
|
332
|
+
def _get_include_options(self, includes: Sequence[PathLike]) -> Command:
|
|
333
|
+
"""Return simulator-specific formatted option strings with *includes* directories."""
|
|
232
334
|
|
|
233
335
|
raise NotImplementedError()
|
|
234
336
|
|
|
235
|
-
@
|
|
236
|
-
def
|
|
237
|
-
"""Return simulator
|
|
337
|
+
@staticmethod
|
|
338
|
+
def _get_define_options(self, defines: Mapping[str, object]) -> Command:
|
|
339
|
+
"""Return simulator-specific formatted option strings with *defines* macros."""
|
|
238
340
|
|
|
239
341
|
raise NotImplementedError()
|
|
240
342
|
|
|
241
343
|
@abc.abstractmethod
|
|
242
|
-
def
|
|
243
|
-
"""Return simulator
|
|
344
|
+
def _get_parameter_options(self, parameters: Mapping[str, object]) -> Command:
|
|
345
|
+
"""Return simulator-specific formatted option strings with *parameters*/generics."""
|
|
244
346
|
|
|
245
347
|
raise NotImplementedError()
|
|
246
348
|
|
|
247
|
-
def
|
|
349
|
+
def _execute(self, cmds: Sequence[Command], cwd: PathLike) -> None:
|
|
248
350
|
|
|
249
351
|
__tracebackhide__ = True # Hide the traceback when using PyTest.
|
|
250
352
|
|
|
251
353
|
for cmd in cmds:
|
|
252
|
-
print(
|
|
253
|
-
"INFO: Running command: "
|
|
254
|
-
+ ' "'.join(cmd)
|
|
255
|
-
+ '" in directory:"'
|
|
256
|
-
+ str(cwd)
|
|
257
|
-
+ '"'
|
|
258
|
-
)
|
|
354
|
+
print(f"INFO: Running command {shlex_join(cmd)} in directory {cwd}")
|
|
259
355
|
|
|
260
356
|
# TODO: create a thread to handle stderr and log as error?
|
|
261
357
|
# TODO: log forwarding
|
|
@@ -268,86 +364,105 @@ class Simulator(abc.ABC):
|
|
|
268
364
|
)
|
|
269
365
|
|
|
270
366
|
|
|
271
|
-
def
|
|
272
|
-
"""
|
|
367
|
+
def get_results(results_xml_file: Path) -> Tuple[int, int]:
|
|
368
|
+
"""Return number of tests and fails in *results_xml_file*.
|
|
369
|
+
|
|
370
|
+
Returns:
|
|
371
|
+
Tuple of number of tests and number of fails.
|
|
372
|
+
|
|
373
|
+
Raises:
|
|
374
|
+
SystemExit: *results_xml_file* is non-existent.
|
|
375
|
+
"""
|
|
273
376
|
|
|
274
377
|
__tracebackhide__ = True # Hide the traceback when using PyTest.
|
|
275
378
|
|
|
276
|
-
|
|
277
|
-
if not results_file_exist:
|
|
379
|
+
if not results_xml_file.is_file():
|
|
278
380
|
raise SystemExit(
|
|
279
|
-
"ERROR: Simulation terminated abnormally. Results file not found."
|
|
381
|
+
f"ERROR: Simulation terminated abnormally. Results file {results_xml_file} not found."
|
|
280
382
|
)
|
|
281
383
|
|
|
282
|
-
|
|
384
|
+
num_tests = 0
|
|
385
|
+
num_failed = 0
|
|
283
386
|
|
|
284
387
|
tree = ET.parse(results_xml_file)
|
|
285
388
|
for ts in tree.iter("testsuite"):
|
|
286
389
|
for tc in ts.iter("testcase"):
|
|
390
|
+
num_tests += 1
|
|
287
391
|
for _ in tc.iter("failure"):
|
|
288
|
-
|
|
392
|
+
num_failed += 1
|
|
393
|
+
|
|
394
|
+
return (num_tests, num_failed)
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
def check_results_file(results_xml_file: Path) -> None:
|
|
398
|
+
"""Raise exception if *results_xml_file* does not exist or contains failed tests.
|
|
399
|
+
|
|
400
|
+
Raises:
|
|
401
|
+
SystemExit: *results_xml_file* is non-existent or contains fails.
|
|
402
|
+
"""
|
|
403
|
+
|
|
404
|
+
__tracebackhide__ = True # Hide the traceback when using PyTest.
|
|
405
|
+
|
|
406
|
+
(num_tests, num_failed) = get_results(results_xml_file)
|
|
407
|
+
|
|
408
|
+
if num_failed:
|
|
409
|
+
raise SystemExit(f"ERROR: Failed {num_failed} of {num_tests} tests.")
|
|
289
410
|
|
|
290
|
-
if failed:
|
|
291
|
-
raise SystemExit(f"ERROR: Failed {failed} tests.")
|
|
292
411
|
|
|
412
|
+
def outdated(output: Path, dependencies: Sequence[Path]) -> bool:
|
|
413
|
+
"""Return ``True`` if any source files in *dependencies* are newer than the *output* directory.
|
|
293
414
|
|
|
294
|
-
|
|
295
|
-
|
|
415
|
+
Returns:
|
|
416
|
+
``True`` if any source files are newer, ``False`` otherwise.
|
|
417
|
+
"""
|
|
296
418
|
|
|
297
|
-
if not
|
|
419
|
+
if not output.is_file():
|
|
298
420
|
return True
|
|
299
421
|
|
|
300
|
-
output_mtime =
|
|
422
|
+
output_mtime = output.stat().st_mtime
|
|
301
423
|
|
|
302
424
|
dep_mtime = 0.0
|
|
303
|
-
for
|
|
304
|
-
mtime =
|
|
425
|
+
for dependency in dependencies:
|
|
426
|
+
mtime = dependency.stat().st_mtime
|
|
305
427
|
if mtime > dep_mtime:
|
|
306
428
|
dep_mtime = mtime
|
|
307
429
|
|
|
308
|
-
|
|
309
|
-
return True
|
|
430
|
+
return dep_mtime > output_mtime
|
|
310
431
|
|
|
311
|
-
return False
|
|
312
432
|
|
|
433
|
+
def get_abs_path(path: PathLike) -> Path:
|
|
434
|
+
"""Return *path* in absolute form."""
|
|
313
435
|
|
|
314
|
-
|
|
315
|
-
|
|
436
|
+
path = Path(path)
|
|
437
|
+
if path.is_absolute():
|
|
438
|
+
return path.resolve()
|
|
439
|
+
else:
|
|
440
|
+
return Path(Path.cwd() / path).resolve()
|
|
316
441
|
|
|
317
|
-
paths_abs: List[str] = []
|
|
318
|
-
for path in paths:
|
|
319
|
-
if os.path.isabs(path):
|
|
320
|
-
paths_abs.append(os.path.abspath(path))
|
|
321
|
-
else:
|
|
322
|
-
paths_abs.append(os.path.abspath(os.path.join(os.getcwd(), path)))
|
|
323
442
|
|
|
324
|
-
|
|
443
|
+
def get_abs_paths(paths: Sequence[PathLike]) -> List[Path]:
|
|
444
|
+
"""Return list of *paths* in absolute form."""
|
|
445
|
+
|
|
446
|
+
return [get_abs_path(path) for path in paths]
|
|
325
447
|
|
|
326
448
|
|
|
327
449
|
class Icarus(Simulator):
|
|
328
|
-
|
|
329
|
-
def simulator_in_path() -> None:
|
|
330
|
-
if shutil.which("iverilog") is None:
|
|
331
|
-
raise SystemExit("ERROR: iverilog exacutable not found!")
|
|
450
|
+
supported_gpi_interfaces = {"verilog": ["vpi"]}
|
|
332
451
|
|
|
333
452
|
@staticmethod
|
|
334
|
-
def
|
|
335
|
-
if
|
|
336
|
-
|
|
337
|
-
else:
|
|
338
|
-
raise ValueError(
|
|
339
|
-
f"iverilog does not support {toplevel_lang!r} as a toplevel_lang"
|
|
340
|
-
)
|
|
453
|
+
def _simulator_in_path() -> None:
|
|
454
|
+
if shutil.which("iverilog") is None:
|
|
455
|
+
raise SystemExit("ERROR: iverilog executable not found!")
|
|
341
456
|
|
|
342
457
|
@staticmethod
|
|
343
|
-
def
|
|
344
|
-
return ["-I"
|
|
458
|
+
def _get_include_options(includes: Sequence[PathLike]) -> Command:
|
|
459
|
+
return [f"-I{include}" for include in includes]
|
|
345
460
|
|
|
346
461
|
@staticmethod
|
|
347
|
-
def
|
|
348
|
-
return ["-D"
|
|
462
|
+
def _get_define_options(defines: Mapping[str, object]) -> Command:
|
|
463
|
+
return [f"-D{name}={value}" for name, value in defines.items()]
|
|
349
464
|
|
|
350
|
-
def
|
|
465
|
+
def _get_parameter_options(self, parameters: Mapping[str, object]) -> Command:
|
|
351
466
|
assert self.hdl_toplevel is not None
|
|
352
467
|
return [
|
|
353
468
|
f"-P{self.hdl_toplevel}.{name}={value}"
|
|
@@ -355,10 +470,10 @@ class Icarus(Simulator):
|
|
|
355
470
|
]
|
|
356
471
|
|
|
357
472
|
@property
|
|
358
|
-
def sim_file(self) ->
|
|
359
|
-
return
|
|
473
|
+
def sim_file(self) -> Path:
|
|
474
|
+
return self.build_dir / "sim.vvp"
|
|
360
475
|
|
|
361
|
-
def
|
|
476
|
+
def _test_command(self) -> List[Command]:
|
|
362
477
|
|
|
363
478
|
return [
|
|
364
479
|
[
|
|
@@ -368,99 +483,91 @@ class Icarus(Simulator):
|
|
|
368
483
|
"-m",
|
|
369
484
|
cocotb.config.lib_name("vpi", "icarus"),
|
|
370
485
|
]
|
|
371
|
-
+ self.
|
|
372
|
-
+ [self.sim_file]
|
|
373
|
-
+ self.
|
|
486
|
+
+ self.test_args
|
|
487
|
+
+ [str(self.sim_file)]
|
|
488
|
+
+ self.plusargs
|
|
374
489
|
]
|
|
375
490
|
|
|
376
|
-
def
|
|
491
|
+
def _build_command(self) -> List[Command]:
|
|
377
492
|
|
|
378
493
|
if self.vhdl_sources:
|
|
379
|
-
raise ValueError(
|
|
494
|
+
raise ValueError(
|
|
495
|
+
f"{type(self).__qualname__}: Simulator does not support VHDL"
|
|
496
|
+
)
|
|
380
497
|
|
|
381
|
-
|
|
498
|
+
cmds = []
|
|
382
499
|
if outdated(self.sim_file, self.verilog_sources) or self.always:
|
|
383
500
|
|
|
384
|
-
|
|
385
|
-
["iverilog", "-o", self.sim_file, "-D", "COCOTB_SIM=1", "-g2012"]
|
|
386
|
-
+ self.
|
|
387
|
-
+ self.
|
|
388
|
-
+ self.
|
|
389
|
-
+ self.
|
|
390
|
-
+ self.verilog_sources
|
|
501
|
+
cmds = [
|
|
502
|
+
["iverilog", "-o", str(self.sim_file), "-D", "COCOTB_SIM=1", "-g2012"]
|
|
503
|
+
+ self._get_define_options(self.defines)
|
|
504
|
+
+ self._get_include_options(self.includes)
|
|
505
|
+
+ self._get_parameter_options(self.parameters)
|
|
506
|
+
+ self.build_args
|
|
507
|
+
+ [str(source_file) for source_file in self.verilog_sources]
|
|
391
508
|
]
|
|
392
509
|
|
|
393
510
|
else:
|
|
394
|
-
print("WARNING: Skipping compilation
|
|
511
|
+
print("WARNING: Skipping compilation of", self.sim_file)
|
|
395
512
|
|
|
396
|
-
return
|
|
513
|
+
return cmds
|
|
397
514
|
|
|
398
515
|
|
|
399
516
|
class Questa(Simulator):
|
|
517
|
+
supported_gpi_interfaces = {"verilog": ["vpi"], "vhdl": ["fli", "vhpi"]}
|
|
518
|
+
|
|
400
519
|
@staticmethod
|
|
401
|
-
def
|
|
520
|
+
def _simulator_in_path() -> None:
|
|
402
521
|
if shutil.which("vsim") is None:
|
|
403
522
|
raise SystemExit("ERROR: vsim executable not found!")
|
|
404
523
|
|
|
405
|
-
def check_toplevel_lang(self, toplevel_lang: Optional[str]) -> str:
|
|
406
|
-
if toplevel_lang is None:
|
|
407
|
-
if self.vhdl_sources and not self.verilog_sources:
|
|
408
|
-
return "vhdl"
|
|
409
|
-
elif self.verilog_sources and not self.vhdl_sources:
|
|
410
|
-
return "verilog"
|
|
411
|
-
else:
|
|
412
|
-
raise ValueError("Must specify a toplevel_lang in a mixed design")
|
|
413
|
-
elif toplevel_lang in ("verilog", "vhdl"):
|
|
414
|
-
return toplevel_lang
|
|
415
|
-
else:
|
|
416
|
-
raise ValueError(
|
|
417
|
-
f"Questa does not support {toplevel_lang!r} as a toplevel_lang"
|
|
418
|
-
)
|
|
419
|
-
|
|
420
524
|
@staticmethod
|
|
421
|
-
def
|
|
422
|
-
return ["+incdir+
|
|
525
|
+
def _get_include_options(includes: Sequence[PathLike]) -> Command:
|
|
526
|
+
return [f"+incdir+{as_tcl_value(str(include))}" for include in includes]
|
|
423
527
|
|
|
424
528
|
@staticmethod
|
|
425
|
-
def
|
|
426
|
-
return [
|
|
529
|
+
def _get_define_options(defines: Mapping[str, object]) -> Command:
|
|
530
|
+
return [
|
|
531
|
+
f"+define+{as_tcl_value(name)}={as_tcl_value(str(value))}"
|
|
532
|
+
for name, value in defines.items()
|
|
533
|
+
]
|
|
427
534
|
|
|
428
535
|
@staticmethod
|
|
429
|
-
def
|
|
430
|
-
return ["-g
|
|
536
|
+
def _get_parameter_options(parameters: Mapping[str, object]) -> Command:
|
|
537
|
+
return [f"-g{name}={value}" for name, value in parameters.items()]
|
|
431
538
|
|
|
432
|
-
def
|
|
539
|
+
def _build_command(self) -> List[Command]:
|
|
433
540
|
|
|
434
|
-
|
|
541
|
+
cmds = []
|
|
435
542
|
|
|
436
543
|
if self.vhdl_sources:
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
["vcom"
|
|
440
|
-
+ ["-work", as_tcl_value(self.
|
|
441
|
-
+ [as_tcl_value(v) for v in self.
|
|
442
|
-
+ [as_tcl_value(v) for v in self.vhdl_sources]
|
|
544
|
+
cmds.append(["vlib", as_tcl_value(self.hdl_library)])
|
|
545
|
+
cmds.append(
|
|
546
|
+
["vcom"]
|
|
547
|
+
+ ["-work", as_tcl_value(self.hdl_library)]
|
|
548
|
+
+ [as_tcl_value(v) for v in self.build_args]
|
|
549
|
+
+ [as_tcl_value(str(v)) for v in self.vhdl_sources]
|
|
443
550
|
)
|
|
444
551
|
|
|
445
552
|
if self.verilog_sources:
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
["vlog"
|
|
553
|
+
cmds.append(["vlib", as_tcl_value(self.hdl_library)])
|
|
554
|
+
cmds.append(
|
|
555
|
+
["vlog"]
|
|
449
556
|
+ ([] if self.always else ["-incr"])
|
|
450
|
-
+ ["-work", as_tcl_value(self.
|
|
557
|
+
+ ["-work", as_tcl_value(self.hdl_library)]
|
|
451
558
|
+ ["+define+COCOTB_SIM"]
|
|
452
559
|
+ ["-sv"]
|
|
453
|
-
+ self.
|
|
454
|
-
+ self.
|
|
455
|
-
+ [as_tcl_value(v) for v in self.
|
|
456
|
-
+ [as_tcl_value(v) for v in self.verilog_sources]
|
|
560
|
+
+ self._get_define_options(self.defines)
|
|
561
|
+
+ self._get_include_options(self.includes)
|
|
562
|
+
+ [as_tcl_value(v) for v in self.build_args]
|
|
563
|
+
+ [as_tcl_value(str(v)) for v in self.verilog_sources]
|
|
457
564
|
)
|
|
458
565
|
|
|
459
|
-
return
|
|
566
|
+
return cmds
|
|
460
567
|
|
|
461
|
-
def
|
|
568
|
+
def _test_command(self) -> List[Command]:
|
|
462
569
|
|
|
463
|
-
|
|
570
|
+
cmds = []
|
|
464
571
|
|
|
465
572
|
do_script = ""
|
|
466
573
|
if self.waves:
|
|
@@ -469,200 +576,169 @@ class Questa(Simulator):
|
|
|
469
576
|
if not self.gui:
|
|
470
577
|
do_script += "run -all; quit"
|
|
471
578
|
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
if self.toplevel_lang == "vhdl":
|
|
475
|
-
|
|
476
|
-
if not os.path.isfile(fli_lib_path):
|
|
477
|
-
raise SystemExit(
|
|
478
|
-
"ERROR: cocotb was not installed with an FLI library, as the mti.h header could not be located.\n\
|
|
479
|
-
If you installed an FLI-capable simulator after cocotb, you will need to reinstall cocotb.\n\
|
|
480
|
-
Please check the cocotb documentation on ModelSim support."
|
|
481
|
-
)
|
|
579
|
+
gpi_if_entry = self.gpi_interfaces[0]
|
|
580
|
+
gpi_if_entry_lib_path = cocotb.config.lib_name_path(gpi_if_entry, "questa")
|
|
482
581
|
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
+
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
+
|
|
495
|
-
|
|
496
|
-
|
|
582
|
+
if gpi_if_entry == "fli":
|
|
583
|
+
lib_opts = [
|
|
584
|
+
"-foreign",
|
|
585
|
+
"cocotb_init "
|
|
586
|
+
+ as_tcl_value(cocotb.config.lib_name_path("fli", "questa")),
|
|
587
|
+
]
|
|
588
|
+
elif gpi_if_entry == "vhpi":
|
|
589
|
+
lib_opts = ["-voptargs=-access=rw+/."]
|
|
590
|
+
lib_opts += [
|
|
591
|
+
"-foreign",
|
|
592
|
+
"vhpi_startup_routines_bootstrap "
|
|
593
|
+
+ as_tcl_value(cocotb.config.lib_name_path("vhpi", "questa")),
|
|
594
|
+
]
|
|
595
|
+
else:
|
|
596
|
+
lib_opts = [
|
|
597
|
+
"-pli",
|
|
598
|
+
as_tcl_value(cocotb.config.lib_name_path("vpi", "questa")),
|
|
599
|
+
]
|
|
497
600
|
|
|
498
|
-
|
|
499
|
-
|
|
601
|
+
if not Path(gpi_if_entry_lib_path).is_file():
|
|
602
|
+
raise SystemExit(
|
|
603
|
+
"ERROR: cocotb was not installed with a {gpi_if_entry} library."
|
|
500
604
|
)
|
|
501
605
|
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
)
|
|
606
|
+
cmds.append(
|
|
607
|
+
["vsim"]
|
|
608
|
+
+ ["-gui" if self.gui else "-c"]
|
|
609
|
+
+ ["-onfinish", "stop" if self.gui else "exit"]
|
|
610
|
+
+ lib_opts
|
|
611
|
+
+ [as_tcl_value(v) for v in self.test_args]
|
|
612
|
+
+ [as_tcl_value(v) for v in self._get_parameter_options(self.parameters)]
|
|
613
|
+
+ [as_tcl_value(f"{self.hdl_toplevel_library}.{self.sim_hdl_toplevel}")]
|
|
614
|
+
+ [as_tcl_value(v) for v in self.plusargs]
|
|
615
|
+
+ ["-do", do_script]
|
|
616
|
+
)
|
|
514
617
|
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
618
|
+
gpi_extra_list = []
|
|
619
|
+
for gpi_if in self.gpi_interfaces[1:]:
|
|
620
|
+
gpi_if_lib_path = cocotb.config.lib_name_path(gpi_if, "questa")
|
|
621
|
+
if Path(gpi_if_lib_path).is_file():
|
|
622
|
+
gpi_extra_list.append(
|
|
623
|
+
cocotb.config.lib_name_path(gpi_if, "questa")
|
|
624
|
+
+ f":cocotb{gpi_if}_entry_point"
|
|
519
625
|
)
|
|
520
626
|
else:
|
|
521
|
-
print(
|
|
522
|
-
|
|
523
|
-
)
|
|
627
|
+
print("WARNING: {gpi_if_lib_path} library not found.")
|
|
628
|
+
self.env["GPI_EXTRA"] = ",".join(gpi_extra_list)
|
|
524
629
|
|
|
525
|
-
return
|
|
630
|
+
return cmds
|
|
526
631
|
|
|
527
632
|
|
|
528
633
|
class Ghdl(Simulator):
|
|
634
|
+
supported_gpi_interfaces = {"vhdl": ["vpi"]}
|
|
635
|
+
|
|
529
636
|
@staticmethod
|
|
530
|
-
def
|
|
637
|
+
def _simulator_in_path() -> None:
|
|
531
638
|
if shutil.which("ghdl") is None:
|
|
532
639
|
raise SystemExit("ERROR: ghdl executable not found!")
|
|
533
640
|
|
|
534
|
-
def check_toplevel_lang(self, toplevel_lang: Optional[str]) -> str:
|
|
535
|
-
if toplevel_lang is None or toplevel_lang == "vhdl":
|
|
536
|
-
return "vhdl"
|
|
537
|
-
else:
|
|
538
|
-
raise ValueError(
|
|
539
|
-
f"GHDL does not support {toplevel_lang!r} as a toplevel_lang"
|
|
540
|
-
)
|
|
541
|
-
|
|
542
|
-
@staticmethod
|
|
543
|
-
def get_include_options(includes: Sequence[str]) -> List[str]:
|
|
544
|
-
return [f"-I{dir}" for dir in includes]
|
|
545
|
-
|
|
546
|
-
@staticmethod
|
|
547
|
-
def get_define_options(defines: Sequence[str]) -> List[str]:
|
|
548
|
-
return [f"-D{define}" for define in defines]
|
|
549
|
-
|
|
550
641
|
@staticmethod
|
|
551
|
-
def
|
|
552
|
-
return ["-g
|
|
642
|
+
def _get_parameter_options(parameters: Mapping[str, object]) -> Command:
|
|
643
|
+
return [f"-g{name}={value}" for name, value in parameters.items()]
|
|
553
644
|
|
|
554
|
-
def
|
|
645
|
+
def _build_command(self) -> List[Command]:
|
|
555
646
|
|
|
556
647
|
if self.verilog_sources:
|
|
557
|
-
raise ValueError("This simulator does not support Verilog")
|
|
558
|
-
|
|
559
|
-
if self.hdl_toplevel is None:
|
|
560
648
|
raise ValueError(
|
|
561
|
-
"
|
|
649
|
+
f"{type(self).__qualname__}: Simulator does not support Verilog"
|
|
562
650
|
)
|
|
563
651
|
|
|
564
|
-
|
|
652
|
+
cmds = [
|
|
565
653
|
["ghdl", "-i"]
|
|
566
|
-
+ [f"--work={self.
|
|
567
|
-
+ self.
|
|
568
|
-
+ [source_file]
|
|
569
|
-
for source_file in self.vhdl_sources
|
|
654
|
+
+ [f"--work={self.hdl_library}"]
|
|
655
|
+
+ self.build_args
|
|
656
|
+
+ [str(source_file) for source_file in self.vhdl_sources]
|
|
570
657
|
]
|
|
571
658
|
|
|
572
|
-
|
|
573
|
-
[
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
659
|
+
if self.hdl_toplevel is not None:
|
|
660
|
+
cmds += [
|
|
661
|
+
["ghdl", "-m"]
|
|
662
|
+
+ [f"--work={self.hdl_library}"]
|
|
663
|
+
+ self.build_args
|
|
664
|
+
+ [self.hdl_toplevel]
|
|
665
|
+
]
|
|
578
666
|
|
|
579
|
-
return
|
|
667
|
+
return cmds
|
|
580
668
|
|
|
581
|
-
def
|
|
669
|
+
def _test_command(self) -> List[Command]:
|
|
582
670
|
|
|
583
|
-
|
|
671
|
+
cmds = [
|
|
584
672
|
["ghdl", "-r"]
|
|
585
|
-
+ [self.
|
|
673
|
+
+ [f"--work={self.hdl_toplevel_library}"]
|
|
674
|
+
+ self.test_args
|
|
675
|
+
+ [self.sim_hdl_toplevel]
|
|
586
676
|
+ ["--vpi=" + cocotb.config.lib_name_path("vpi", "ghdl")]
|
|
587
|
-
+ self.
|
|
588
|
-
+ self.
|
|
677
|
+
+ self.plusargs
|
|
678
|
+
+ self._get_parameter_options(self.parameters)
|
|
589
679
|
]
|
|
590
680
|
|
|
591
|
-
return
|
|
681
|
+
return cmds
|
|
592
682
|
|
|
593
683
|
|
|
594
684
|
class Riviera(Simulator):
|
|
685
|
+
supported_gpi_interfaces = {"verilog": ["vpi"], "vhdl": ["vhpi"]}
|
|
686
|
+
|
|
595
687
|
@staticmethod
|
|
596
|
-
def
|
|
688
|
+
def _simulator_in_path() -> None:
|
|
597
689
|
if shutil.which("vsimsa") is None:
|
|
598
690
|
raise SystemExit("ERROR: vsimsa executable not found!")
|
|
599
691
|
|
|
600
|
-
def check_toplevel_lang(self, toplevel_lang: Optional[str]) -> str:
|
|
601
|
-
if toplevel_lang is None:
|
|
602
|
-
if self.vhdl_sources and not self.verilog_sources:
|
|
603
|
-
return "vhdl"
|
|
604
|
-
elif self.verilog_sources and not self.vhdl_sources:
|
|
605
|
-
return "verilog"
|
|
606
|
-
else:
|
|
607
|
-
raise ValueError(
|
|
608
|
-
"Must specify a toplevel_lang in a mixed-language design"
|
|
609
|
-
)
|
|
610
|
-
elif toplevel_lang in ("verilog", "vhdl"):
|
|
611
|
-
return toplevel_lang
|
|
612
|
-
else:
|
|
613
|
-
raise ValueError(
|
|
614
|
-
f"Riviera does not support {toplevel_lang!r} as a toplevel_lang"
|
|
615
|
-
)
|
|
616
|
-
|
|
617
692
|
@staticmethod
|
|
618
|
-
def
|
|
619
|
-
return ["+incdir+
|
|
693
|
+
def _get_include_options(includes: Sequence[PathLike]) -> Command:
|
|
694
|
+
return [f"+incdir+{as_tcl_value(str(include))}" for include in includes]
|
|
620
695
|
|
|
621
696
|
@staticmethod
|
|
622
|
-
def
|
|
623
|
-
return [
|
|
697
|
+
def _get_define_options(defines: Mapping[str, object]) -> Command:
|
|
698
|
+
return [
|
|
699
|
+
f"+define+{as_tcl_value(name)}={as_tcl_value(str(value))}"
|
|
700
|
+
for name, value in defines.items()
|
|
701
|
+
]
|
|
624
702
|
|
|
625
703
|
@staticmethod
|
|
626
|
-
def
|
|
627
|
-
return ["-g
|
|
704
|
+
def _get_parameter_options(parameters: Mapping[str, object]) -> Command:
|
|
705
|
+
return [f"-g{name}={value}" for name, value in parameters.items()]
|
|
628
706
|
|
|
629
|
-
def
|
|
707
|
+
def _build_command(self) -> List[Command]:
|
|
630
708
|
|
|
631
709
|
do_script = "\nonerror {\n quit -code 1 \n} \n"
|
|
632
710
|
|
|
633
|
-
out_file =
|
|
634
|
-
self.build_dir, self.library_name, self.library_name + ".lib"
|
|
635
|
-
)
|
|
711
|
+
out_file = self.build_dir / self.hdl_library / f"{self.hdl_library}.lib"
|
|
636
712
|
|
|
637
713
|
if outdated(out_file, self.verilog_sources + self.vhdl_sources) or self.always:
|
|
638
714
|
|
|
639
715
|
do_script += "alib {RTL_LIBRARY} \n".format(
|
|
640
|
-
RTL_LIBRARY=as_tcl_value(self.
|
|
716
|
+
RTL_LIBRARY=as_tcl_value(self.hdl_library)
|
|
641
717
|
)
|
|
642
718
|
|
|
643
719
|
if self.vhdl_sources:
|
|
644
720
|
do_script += (
|
|
645
721
|
"acom -work {RTL_LIBRARY} {EXTRA_ARGS} {VHDL_SOURCES}\n".format(
|
|
646
|
-
RTL_LIBRARY=as_tcl_value(self.
|
|
722
|
+
RTL_LIBRARY=as_tcl_value(self.hdl_library),
|
|
647
723
|
VHDL_SOURCES=" ".join(
|
|
648
|
-
as_tcl_value(v) for v in self.vhdl_sources
|
|
724
|
+
as_tcl_value(str(v)) for v in self.vhdl_sources
|
|
649
725
|
),
|
|
650
|
-
EXTRA_ARGS=" ".join(as_tcl_value(v) for v in self.
|
|
726
|
+
EXTRA_ARGS=" ".join(as_tcl_value(v) for v in self.build_args),
|
|
651
727
|
)
|
|
652
728
|
)
|
|
653
729
|
|
|
654
730
|
if self.verilog_sources:
|
|
655
731
|
do_script += "alog -work {RTL_LIBRARY} +define+COCOTB_SIM -sv {DEFINES} {INCDIR} {EXTRA_ARGS} {VERILOG_SOURCES} \n".format(
|
|
656
|
-
RTL_LIBRARY=as_tcl_value(self.
|
|
732
|
+
RTL_LIBRARY=as_tcl_value(self.hdl_library),
|
|
657
733
|
VERILOG_SOURCES=" ".join(
|
|
658
|
-
as_tcl_value(v) for v in self.verilog_sources
|
|
734
|
+
as_tcl_value(str(v)) for v in self.verilog_sources
|
|
659
735
|
),
|
|
660
|
-
DEFINES=" ".join(self.
|
|
661
|
-
INCDIR=" ".join(self.
|
|
662
|
-
EXTRA_ARGS=" ".join(as_tcl_value(v) for v in self.
|
|
736
|
+
DEFINES=" ".join(self._get_define_options(self.defines)),
|
|
737
|
+
INCDIR=" ".join(self._get_include_options(self.includes)),
|
|
738
|
+
EXTRA_ARGS=" ".join(as_tcl_value(v) for v in self.build_args),
|
|
663
739
|
)
|
|
664
740
|
else:
|
|
665
|
-
print("WARNING: Skipping compilation
|
|
741
|
+
print("WARNING: Skipping compilation of", out_file)
|
|
666
742
|
|
|
667
743
|
do_file = tempfile.NamedTemporaryFile(delete=False)
|
|
668
744
|
do_file.write(do_script.encode())
|
|
@@ -670,36 +746,41 @@ class Riviera(Simulator):
|
|
|
670
746
|
|
|
671
747
|
return [["vsimsa"] + ["-do"] + ["do"] + [do_file.name]]
|
|
672
748
|
|
|
673
|
-
def
|
|
749
|
+
def _test_command(self) -> List[Command]:
|
|
674
750
|
|
|
675
751
|
do_script = "\nonerror {\n quit -code 1 \n} \n"
|
|
676
752
|
|
|
677
|
-
if self.
|
|
678
|
-
do_script += "asim +access +w -interceptcoutput -O2 -loadvhpi {EXT_NAME} {EXTRA_ARGS} {TOPLEVEL} \n".format(
|
|
679
|
-
TOPLEVEL=as_tcl_value(
|
|
753
|
+
if self.hdl_toplevel_lang == "vhdl":
|
|
754
|
+
do_script += "asim +access +w -interceptcoutput -O2 -loadvhpi {EXT_NAME} {EXTRA_ARGS} {TOPLEVEL} {PLUSARGS}\n".format(
|
|
755
|
+
TOPLEVEL=as_tcl_value(
|
|
756
|
+
f"{self.hdl_toplevel_library}.{self.sim_hdl_toplevel}"
|
|
757
|
+
),
|
|
680
758
|
EXT_NAME=as_tcl_value(cocotb.config.lib_name_path("vhpi", "riviera")),
|
|
681
759
|
EXTRA_ARGS=" ".join(
|
|
682
760
|
as_tcl_value(v)
|
|
683
761
|
for v in (
|
|
684
|
-
self.
|
|
762
|
+
self.test_args + self._get_parameter_options(self.parameters)
|
|
685
763
|
)
|
|
686
764
|
),
|
|
765
|
+
PLUSARGS=" ".join(as_tcl_value(v) for v in self.plusargs),
|
|
687
766
|
)
|
|
688
767
|
|
|
689
768
|
self.env["GPI_EXTRA"] = (
|
|
690
769
|
cocotb.config.lib_name_path("vpi", "riviera") + ":cocotbvpi_entry_point"
|
|
691
770
|
)
|
|
692
771
|
else:
|
|
693
|
-
do_script += "asim +access +w -interceptcoutput -O2 -pli {EXT_NAME} {EXTRA_ARGS} {TOPLEVEL} {
|
|
694
|
-
TOPLEVEL=as_tcl_value(
|
|
772
|
+
do_script += "asim +access +w -interceptcoutput -O2 -pli {EXT_NAME} {EXTRA_ARGS} {TOPLEVEL} {PLUSARGS} \n".format(
|
|
773
|
+
TOPLEVEL=as_tcl_value(
|
|
774
|
+
f"{self.hdl_toplevel_library}.{self.sim_hdl_toplevel}"
|
|
775
|
+
),
|
|
695
776
|
EXT_NAME=as_tcl_value(cocotb.config.lib_name_path("vpi", "riviera")),
|
|
696
777
|
EXTRA_ARGS=" ".join(
|
|
697
778
|
as_tcl_value(v)
|
|
698
779
|
for v in (
|
|
699
|
-
self.
|
|
780
|
+
self.test_args + self._get_parameter_options(self.parameters)
|
|
700
781
|
)
|
|
701
782
|
),
|
|
702
|
-
|
|
783
|
+
PLUSARGS=" ".join(as_tcl_value(v) for v in self.plusargs),
|
|
703
784
|
)
|
|
704
785
|
|
|
705
786
|
self.env["GPI_EXTRA"] = (
|
|
@@ -720,61 +801,58 @@ class Riviera(Simulator):
|
|
|
720
801
|
|
|
721
802
|
|
|
722
803
|
class Verilator(Simulator):
|
|
723
|
-
|
|
804
|
+
supported_gpi_interfaces = {"verilog": ["vpi"]}
|
|
805
|
+
|
|
806
|
+
def _simulator_in_path(self) -> None:
|
|
724
807
|
executable = shutil.which("verilator")
|
|
725
808
|
if executable is None:
|
|
726
809
|
raise SystemExit("ERROR: verilator executable not found!")
|
|
727
|
-
self.executable = executable
|
|
728
|
-
|
|
729
|
-
@staticmethod
|
|
730
|
-
def check_toplevel_lang(toplevel_lang: Optional[str]) -> str:
|
|
731
|
-
if toplevel_lang is None or toplevel_lang == "verilog":
|
|
732
|
-
return "verilog"
|
|
733
|
-
else:
|
|
734
|
-
raise ValueError(
|
|
735
|
-
f"Verilator does not support {toplevel_lang!r} as a toplevel_lang"
|
|
736
|
-
)
|
|
810
|
+
self.executable: str = executable
|
|
737
811
|
|
|
738
812
|
@staticmethod
|
|
739
|
-
def
|
|
740
|
-
return ["-I"
|
|
813
|
+
def _get_include_options(includes: Sequence[PathLike]) -> Command:
|
|
814
|
+
return [f"-I{include}" for include in includes]
|
|
741
815
|
|
|
742
816
|
@staticmethod
|
|
743
|
-
def
|
|
744
|
-
return ["-D"
|
|
817
|
+
def _get_define_options(defines: Mapping[str, object]) -> Command:
|
|
818
|
+
return [f"-D{name}={value}" for name, value in defines.items()]
|
|
745
819
|
|
|
746
820
|
@staticmethod
|
|
747
|
-
def
|
|
748
|
-
return ["-G
|
|
821
|
+
def _get_parameter_options(parameters: Mapping[str, object]) -> Command:
|
|
822
|
+
return [f"-G{name}={value}" for name, value in parameters.items()]
|
|
749
823
|
|
|
750
|
-
def
|
|
824
|
+
def _build_command(self) -> List[Command]:
|
|
751
825
|
|
|
752
826
|
if self.vhdl_sources:
|
|
753
|
-
raise ValueError(
|
|
827
|
+
raise ValueError(
|
|
828
|
+
f"{type(self).__qualname__}: Simulator does not support VHDL"
|
|
829
|
+
)
|
|
754
830
|
|
|
755
831
|
if self.hdl_toplevel is None:
|
|
756
832
|
raise ValueError(
|
|
757
|
-
"
|
|
833
|
+
f"{type(self).__qualname__}: Simulator requires the hdl_toplevel parameter to be specified"
|
|
758
834
|
)
|
|
759
835
|
|
|
760
|
-
|
|
836
|
+
# TODO: set "--debug" if self.verbose
|
|
837
|
+
# TODO: support "--always"
|
|
761
838
|
|
|
762
|
-
verilator_cpp =
|
|
763
|
-
|
|
764
|
-
"share"
|
|
765
|
-
"lib"
|
|
766
|
-
"verilator"
|
|
767
|
-
"verilator.cpp"
|
|
839
|
+
verilator_cpp = str(
|
|
840
|
+
Path(cocotb.__file__).parent
|
|
841
|
+
/ "share"
|
|
842
|
+
/ "lib"
|
|
843
|
+
/ "verilator"
|
|
844
|
+
/ "verilator.cpp"
|
|
768
845
|
)
|
|
769
846
|
|
|
770
|
-
|
|
847
|
+
cmds = []
|
|
848
|
+
cmds.append(
|
|
771
849
|
[
|
|
772
850
|
"perl",
|
|
773
851
|
self.executable,
|
|
774
852
|
"-cc",
|
|
775
853
|
"--exe",
|
|
776
854
|
"-Mdir",
|
|
777
|
-
self.build_dir,
|
|
855
|
+
str(self.build_dir),
|
|
778
856
|
"-DCOCOTB_SIM=1",
|
|
779
857
|
"--top-module",
|
|
780
858
|
self.hdl_toplevel,
|
|
@@ -789,132 +867,154 @@ class Verilator(Simulator):
|
|
|
789
867
|
LIB_DIR=cocotb.config.libs_dir
|
|
790
868
|
),
|
|
791
869
|
]
|
|
792
|
-
+ self.
|
|
793
|
-
+ self.
|
|
794
|
-
+ self.
|
|
795
|
-
+ self.
|
|
870
|
+
+ self.build_args
|
|
871
|
+
+ self._get_define_options(self.defines)
|
|
872
|
+
+ self._get_include_options(self.includes)
|
|
873
|
+
+ self._get_parameter_options(self.parameters)
|
|
796
874
|
+ [verilator_cpp]
|
|
797
|
-
+ self.verilog_sources
|
|
875
|
+
+ [str(source_file) for source_file in self.verilog_sources]
|
|
798
876
|
)
|
|
799
877
|
|
|
800
|
-
|
|
878
|
+
cmds.append(["make", "-C", str(self.build_dir), "-f", "Vtop.mk"])
|
|
801
879
|
|
|
802
|
-
return
|
|
880
|
+
return cmds
|
|
803
881
|
|
|
804
|
-
def
|
|
805
|
-
out_file =
|
|
806
|
-
return [[out_file] + self.
|
|
882
|
+
def _test_command(self) -> List[Command]:
|
|
883
|
+
out_file = self.build_dir / self.sim_hdl_toplevel
|
|
884
|
+
return [[str(out_file)] + self.plusargs]
|
|
807
885
|
|
|
808
886
|
|
|
809
887
|
class Xcelium(Simulator):
|
|
888
|
+
supported_gpi_interfaces = {"verilog": ["vpi"], "vhdl": ["vhpi"]}
|
|
889
|
+
|
|
810
890
|
@staticmethod
|
|
811
|
-
def
|
|
891
|
+
def _simulator_in_path() -> None:
|
|
812
892
|
if shutil.which("xrun") is None:
|
|
813
893
|
raise SystemExit("ERROR: xrun executable not found!")
|
|
814
894
|
|
|
815
|
-
def check_toplevel_lang(self, toplevel_lang: Optional[str]) -> str:
|
|
816
|
-
if toplevel_lang is None:
|
|
817
|
-
if self.vhdl_sources and not self.verilog_sources:
|
|
818
|
-
return "vhdl"
|
|
819
|
-
elif self.verilog_sources and not self.vhdl_sources:
|
|
820
|
-
return "verilog"
|
|
821
|
-
else:
|
|
822
|
-
raise ValueError("Must specify a toplevel_lang in a mixed design")
|
|
823
|
-
elif toplevel_lang in ("verilog", "vhdl"):
|
|
824
|
-
return toplevel_lang
|
|
825
|
-
else:
|
|
826
|
-
raise ValueError(
|
|
827
|
-
f"Xcelium does not support {toplevel_lang!r} as a toplevel_lang"
|
|
828
|
-
)
|
|
829
|
-
|
|
830
895
|
@staticmethod
|
|
831
|
-
def
|
|
896
|
+
def _get_include_options(includes: Sequence[PathLike]) -> Command:
|
|
832
897
|
return [f"-incdir {include}" for include in includes]
|
|
833
898
|
|
|
834
899
|
@staticmethod
|
|
835
|
-
def
|
|
836
|
-
return [f"-define {
|
|
900
|
+
def _get_define_options(defines: Mapping[str, object]) -> Command:
|
|
901
|
+
return [f"-define {name}={value}" for name, value in defines.items()]
|
|
837
902
|
|
|
838
903
|
@staticmethod
|
|
839
|
-
def
|
|
904
|
+
def _get_parameter_options(parameters: Mapping[str, object]) -> Command:
|
|
840
905
|
return [f'-gpg "{name} => {value}"' for name, value in parameters.items()]
|
|
841
906
|
|
|
842
|
-
def
|
|
843
|
-
|
|
907
|
+
def _build_command(self) -> List[Command]:
|
|
844
908
|
self.env["CDS_AUTO_64BIT"] = "all"
|
|
845
|
-
|
|
909
|
+
|
|
910
|
+
verbosity_opts = []
|
|
911
|
+
if self.verbose:
|
|
912
|
+
verbosity_opts += ["-messages"]
|
|
913
|
+
verbosity_opts += ["-status"]
|
|
914
|
+
verbosity_opts += ["-gverbose"] # print assigned generics/parameters
|
|
915
|
+
verbosity_opts += ["-pliverbose"]
|
|
916
|
+
verbosity_opts += ["-plidebug"] # Enhance the profile output with PLI info
|
|
917
|
+
verbosity_opts += [
|
|
918
|
+
"-plierr_verbose"
|
|
919
|
+
] # Expand handle info in PLI/VPI/VHPI messages
|
|
920
|
+
|
|
921
|
+
else:
|
|
922
|
+
verbosity_opts += ["-quiet"]
|
|
923
|
+
verbosity_opts += ["-plinowarn"]
|
|
924
|
+
|
|
925
|
+
cmds = [
|
|
846
926
|
["xrun"]
|
|
847
|
-
+ ["-logfile
|
|
927
|
+
+ ["-logfile"]
|
|
928
|
+
+ ["xrun_build.log"]
|
|
848
929
|
+ ["-elaborate"]
|
|
849
|
-
+ [
|
|
930
|
+
+ ["-xmlibdirname"]
|
|
931
|
+
+ [f"{self.build_dir}/xrun_snapshot"]
|
|
850
932
|
+ ["-licqueue"]
|
|
851
|
-
|
|
852
|
-
+
|
|
853
|
-
+ ["-gverbose"] # print assigned generics/parameters
|
|
854
|
-
+ ["-plinowarn"]
|
|
855
|
-
# + ["-pliverbose"]
|
|
856
|
-
# + ["-plidebug"] # Enhance the profile output with PLI info
|
|
857
|
-
# + ["-plierr_verbose"] # Expand handle info in PLI/VPI/VHPI messages
|
|
933
|
+
+ (["-clean"] if self.always else [])
|
|
934
|
+
+ verbosity_opts
|
|
858
935
|
# + ["-vpicompat 1800v2005"] # <1364v1995|1364v2001|1364v2005|1800v2005> Specify the IEEE VPI
|
|
859
936
|
+ ["-access +rwc"]
|
|
937
|
+
+ ["-loadvpi"]
|
|
938
|
+
# always start with VPI on Xcelium
|
|
860
939
|
+ [
|
|
861
|
-
"
|
|
862
|
-
+ cocotb.config.lib_name_path("vpi", "xcelium")
|
|
940
|
+
cocotb.config.lib_name_path("vpi", "xcelium")
|
|
863
941
|
+ ":vlog_startup_routines_bootstrap"
|
|
864
942
|
]
|
|
865
|
-
+ [f"-work {self.
|
|
866
|
-
+ self.
|
|
943
|
+
+ [f"-work {self.hdl_library}"]
|
|
944
|
+
+ self.build_args
|
|
867
945
|
+ ["-define COCOTB_SIM"]
|
|
868
|
-
+ self.
|
|
869
|
-
+ self.
|
|
870
|
-
+ self.
|
|
946
|
+
+ self._get_include_options(self.includes)
|
|
947
|
+
+ self._get_define_options(self.defines)
|
|
948
|
+
+ self._get_parameter_options(self.parameters)
|
|
871
949
|
+ [f"-top {self.hdl_toplevel}"]
|
|
872
|
-
+
|
|
873
|
-
|
|
950
|
+
+ [
|
|
951
|
+
str(source_file)
|
|
952
|
+
for source_file in self.vhdl_sources + self.verilog_sources
|
|
953
|
+
]
|
|
874
954
|
]
|
|
875
955
|
|
|
876
|
-
return
|
|
956
|
+
return cmds
|
|
877
957
|
|
|
878
|
-
def
|
|
958
|
+
def _test_command(self) -> List[Command]:
|
|
879
959
|
self.env["CDS_AUTO_64BIT"] = "all"
|
|
880
960
|
|
|
961
|
+
verbosity_opts = []
|
|
962
|
+
if self.verbose:
|
|
963
|
+
verbosity_opts += ["-messages"]
|
|
964
|
+
verbosity_opts += ["-status"]
|
|
965
|
+
verbosity_opts += ["-gverbose"] # print assigned generics/parameters
|
|
966
|
+
verbosity_opts += ["-pliverbose"]
|
|
967
|
+
verbosity_opts += ["-plidebug"] # Enhance the profile output with PLI info
|
|
968
|
+
verbosity_opts += [
|
|
969
|
+
"-plierr_verbose"
|
|
970
|
+
] # Expand handle info in PLI/VPI/VHPI messages
|
|
971
|
+
|
|
972
|
+
else:
|
|
973
|
+
verbosity_opts += ["-quiet"]
|
|
974
|
+
verbosity_opts += ["-plinowarn"]
|
|
975
|
+
|
|
881
976
|
tmpdir = f"implicit_tmpdir_{self.current_test_name}"
|
|
882
|
-
cmd = [["mkdir", "-p", tmpdir]]
|
|
883
977
|
|
|
884
|
-
|
|
978
|
+
if self.hdl_toplevel_lang == "vhdl":
|
|
979
|
+
xrun_top = ":"
|
|
980
|
+
else:
|
|
981
|
+
xrun_top = self.sim_hdl_toplevel
|
|
982
|
+
|
|
983
|
+
cmds = [["mkdir", "-p", tmpdir]]
|
|
984
|
+
cmds += [
|
|
885
985
|
["xrun"]
|
|
886
|
-
+ [
|
|
887
|
-
+ [
|
|
888
|
-
|
|
889
|
-
]
|
|
986
|
+
+ ["-logfile"]
|
|
987
|
+
+ [f"xrun_{self.current_test_name}.log"]
|
|
988
|
+
+ ["-xmlibdirname"]
|
|
989
|
+
+ [f"{self.build_dir}/xrun_snapshot"]
|
|
990
|
+
+ ["-cds_implicit_tmpdir"]
|
|
991
|
+
+ [tmpdir]
|
|
890
992
|
+ ["-licqueue"]
|
|
891
|
-
|
|
892
|
-
+ ["-messages"]
|
|
893
|
-
+ ["-plinowarn"]
|
|
894
|
-
# + ["-pliverbose"]
|
|
895
|
-
# + ["-plidebug"] # Enhance the profile output with PLI info
|
|
896
|
-
# + ["-plierr_verbose"] # Expand handle info in PLI/VPI/VHPI messages
|
|
897
|
-
# + ["-vpicompat 1800v2005"] # <1364v1995|1364v2001|1364v2005|1800v2005> Specify the IEEE VPI
|
|
993
|
+
+ verbosity_opts
|
|
898
994
|
+ ["-R"]
|
|
899
|
-
+ self.
|
|
900
|
-
+ self.
|
|
995
|
+
+ self.test_args
|
|
996
|
+
+ self.plusargs
|
|
901
997
|
+ ["-gui" if self.gui else ""]
|
|
998
|
+
+ ["-input"]
|
|
902
999
|
+ [
|
|
903
|
-
'-input "@
|
|
1000
|
+
f'-input "@database -open cocotb_waves -default" '
|
|
1001
|
+
f'-input "@probe -database cocotb_waves -create {xrun_top} -all -depth all" '
|
|
1002
|
+
f'-input "@run" '
|
|
1003
|
+
f'-input "@exit" '
|
|
904
1004
|
if self.waves
|
|
905
|
-
else ""
|
|
1005
|
+
else "@run; exit;"
|
|
906
1006
|
]
|
|
907
1007
|
]
|
|
908
1008
|
self.env["GPI_EXTRA"] = (
|
|
909
1009
|
cocotb.config.lib_name_path("vhpi", "xcelium") + ":cocotbvhpi_entry_point"
|
|
910
1010
|
)
|
|
911
1011
|
|
|
912
|
-
return
|
|
1012
|
+
return cmds
|
|
913
1013
|
|
|
914
1014
|
|
|
915
|
-
def get_runner(simulator_name: str) ->
|
|
1015
|
+
def get_runner(simulator_name: str) -> Simulator:
|
|
1016
|
+
"""Return the *simulator_name* instance."""
|
|
916
1017
|
|
|
917
|
-
sim_name = simulator_name.lower()
|
|
918
1018
|
supported_sims: Dict[str, Type[Simulator]] = {
|
|
919
1019
|
"icarus": Icarus,
|
|
920
1020
|
"questa": Questa,
|
|
@@ -923,26 +1023,11 @@ def get_runner(simulator_name: str) -> Type[Simulator]:
|
|
|
923
1023
|
"verilator": Verilator,
|
|
924
1024
|
"xcelium": Xcelium,
|
|
925
1025
|
# TODO: "vcs": Vcs,
|
|
1026
|
+
# TODO: "activehdl": ActiveHdl,
|
|
926
1027
|
}
|
|
927
1028
|
try:
|
|
928
|
-
return supported_sims[
|
|
1029
|
+
return supported_sims[simulator_name]()
|
|
929
1030
|
except KeyError:
|
|
930
|
-
raise
|
|
931
|
-
"
|
|
1031
|
+
raise ValueError(
|
|
1032
|
+
f"Simulator {simulator_name!r} is not in supported list: {', '.join(supported_sims)}"
|
|
932
1033
|
) from None
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
def clean(recursive: bool = False) -> None:
|
|
936
|
-
dir = os.getcwd()
|
|
937
|
-
|
|
938
|
-
def rm_clean() -> None:
|
|
939
|
-
build_dir = os.path.join(dir, "sim_build")
|
|
940
|
-
if os.path.isdir(build_dir):
|
|
941
|
-
print("INFO: Removing:", build_dir)
|
|
942
|
-
shutil.rmtree(build_dir, ignore_errors=True)
|
|
943
|
-
|
|
944
|
-
rm_clean()
|
|
945
|
-
|
|
946
|
-
if recursive:
|
|
947
|
-
for dir, _, _ in os.walk(dir):
|
|
948
|
-
rm_clean()
|