cocotb 1.8.1__cp36-cp36m-win_amd64.whl → 1.9.0rc1__cp36-cp36m-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.

Files changed (79) hide show
  1. cocotb/_version.py +1 -1
  2. cocotb/binary.py +45 -14
  3. cocotb/config.py +10 -16
  4. cocotb/decorators.py +7 -1
  5. cocotb/handle.py +1 -1
  6. cocotb/libs/cocotb.dll +0 -0
  7. cocotb/libs/cocotb.exp +0 -0
  8. cocotb/libs/cocotb.lib +0 -0
  9. cocotb/libs/cocotbfli_modelsim.dll +0 -0
  10. cocotb/libs/cocotbfli_modelsim.exp +0 -0
  11. cocotb/libs/cocotbfli_modelsim.lib +0 -0
  12. cocotb/libs/cocotbutils.dll +0 -0
  13. cocotb/libs/cocotbutils.exp +0 -0
  14. cocotb/libs/cocotbutils.lib +0 -0
  15. cocotb/libs/cocotbvhpi_aldec.dll +0 -0
  16. cocotb/libs/cocotbvhpi_aldec.exp +0 -0
  17. cocotb/libs/cocotbvhpi_aldec.lib +0 -0
  18. cocotb/libs/cocotbvhpi_modelsim.dll +0 -0
  19. cocotb/libs/cocotbvhpi_modelsim.exp +0 -0
  20. cocotb/libs/cocotbvhpi_modelsim.lib +0 -0
  21. cocotb/libs/cocotbvpi_aldec.dll +0 -0
  22. cocotb/libs/cocotbvpi_aldec.exp +0 -0
  23. cocotb/libs/cocotbvpi_aldec.lib +0 -0
  24. cocotb/libs/cocotbvpi_ghdl.dll +0 -0
  25. cocotb/libs/cocotbvpi_ghdl.exp +0 -0
  26. cocotb/libs/cocotbvpi_ghdl.lib +0 -0
  27. cocotb/libs/cocotbvpi_icarus.exp +0 -0
  28. cocotb/libs/cocotbvpi_icarus.lib +0 -0
  29. cocotb/libs/cocotbvpi_icarus.vpl +0 -0
  30. cocotb/libs/cocotbvpi_modelsim.dll +0 -0
  31. cocotb/libs/cocotbvpi_modelsim.exp +0 -0
  32. cocotb/libs/cocotbvpi_modelsim.lib +0 -0
  33. cocotb/libs/embed.dll +0 -0
  34. cocotb/libs/embed.exp +0 -0
  35. cocotb/libs/embed.lib +0 -0
  36. cocotb/libs/gpi.dll +0 -0
  37. cocotb/libs/gpi.exp +0 -0
  38. cocotb/libs/gpi.lib +0 -0
  39. cocotb/libs/gpilog.dll +0 -0
  40. cocotb/libs/gpilog.exp +0 -0
  41. cocotb/libs/gpilog.lib +0 -0
  42. cocotb/libs/pygpilog.dll +0 -0
  43. cocotb/libs/pygpilog.exp +0 -0
  44. cocotb/libs/pygpilog.lib +0 -0
  45. cocotb/runner.py +487 -120
  46. cocotb/scheduler.py +4 -8
  47. cocotb/share/def/aldec.exp +0 -0
  48. cocotb/share/def/aldec.lib +0 -0
  49. cocotb/share/def/ghdl.exp +0 -0
  50. cocotb/share/def/ghdl.lib +0 -0
  51. cocotb/share/def/icarus.exp +0 -0
  52. cocotb/share/def/icarus.lib +0 -0
  53. cocotb/share/def/modelsim.exp +0 -0
  54. cocotb/share/def/modelsim.lib +0 -0
  55. cocotb/share/lib/verilator/verilator.cpp +50 -8
  56. cocotb/share/makefiles/Makefile.inc +4 -10
  57. cocotb/share/makefiles/Makefile.sim +5 -5
  58. cocotb/share/makefiles/simulators/Makefile.activehdl +3 -3
  59. cocotb/share/makefiles/simulators/Makefile.cvc +1 -1
  60. cocotb/share/makefiles/simulators/Makefile.ghdl +29 -1
  61. cocotb/share/makefiles/simulators/Makefile.icarus +4 -4
  62. cocotb/share/makefiles/simulators/Makefile.ius +1 -1
  63. cocotb/share/makefiles/simulators/Makefile.nvc +64 -0
  64. cocotb/share/makefiles/simulators/Makefile.questa +1 -1
  65. cocotb/share/makefiles/simulators/Makefile.riviera +28 -12
  66. cocotb/share/makefiles/simulators/Makefile.vcs +2 -2
  67. cocotb/share/makefiles/simulators/Makefile.verilator +11 -5
  68. cocotb/share/makefiles/simulators/Makefile.xcelium +6 -1
  69. cocotb/simulator.cp36-win_amd64.exp +0 -0
  70. cocotb/simulator.cp36-win_amd64.lib +0 -0
  71. cocotb/simulator.cp36-win_amd64.pyd +0 -0
  72. cocotb/triggers.py +102 -29
  73. {cocotb-1.8.1.dist-info → cocotb-1.9.0rc1.dist-info}/METADATA +3 -3
  74. cocotb-1.9.0rc1.dist-info/RECORD +121 -0
  75. cocotb-1.8.1.dist-info/RECORD +0 -120
  76. {cocotb-1.8.1.dist-info → cocotb-1.9.0rc1.dist-info}/LICENSE +0 -0
  77. {cocotb-1.8.1.dist-info → cocotb-1.9.0rc1.dist-info}/WHEEL +0 -0
  78. {cocotb-1.8.1.dist-info → cocotb-1.9.0rc1.dist-info}/entry_points.txt +0 -0
  79. {cocotb-1.8.1.dist-info → cocotb-1.9.0rc1.dist-info}/top_level.txt +0 -0
cocotb/runner.py CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
7
  # TODO: maybe do globbing and expanduser/expandvars in --include, --vhdl-sources, --verilog-sources
8
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
9
+ # TODO: support timescale on all simulators
10
10
  # TODO: support custom dependencies
11
11
 
12
12
  import abc
@@ -20,8 +20,8 @@ import tempfile
20
20
  import warnings
21
21
  from contextlib import suppress
22
22
  from pathlib import Path
23
- from typing import Dict, List, Mapping, Optional, Sequence, Tuple, Type, Union
24
- from xml.etree import cElementTree as ET
23
+ from typing import Dict, List, Mapping, Optional, Sequence, TextIO, Tuple, Type, Union
24
+ from xml.etree import ElementTree as ET
25
25
 
26
26
  import find_libpython
27
27
 
@@ -29,6 +29,7 @@ import cocotb.config
29
29
 
30
30
  PathLike = Union["os.PathLike[str]", str]
31
31
  Command = List[str]
32
+ Timescale = Tuple[str, str]
32
33
 
33
34
  warnings.warn(
34
35
  "Python runners and associated APIs are an experimental feature and subject to change.",
@@ -59,6 +60,14 @@ def shlex_join(split_command):
59
60
  return " ".join(shlex.quote(arg) for arg in split_command)
60
61
 
61
62
 
63
+ class VHDL(str):
64
+ """Tags source files and build arguments to :meth:`~cocotb.runner.Simulator.build` as VHDL-specific."""
65
+
66
+
67
+ class Verilog(str):
68
+ """Tags source files and build arguments to :meth:`~cocotb.runner.Simulator.build` as Verilog-specific."""
69
+
70
+
62
71
  class Simulator(abc.ABC):
63
72
 
64
73
  supported_gpi_interfaces: Dict[str, List[str]] = {}
@@ -93,10 +102,17 @@ class Simulator(abc.ABC):
93
102
  ValueError: *hdl_toplevel_lang* is not supported by the simulator.
94
103
  """
95
104
  if hdl_toplevel_lang is None:
96
- if self.vhdl_sources and not self.verilog_sources:
105
+ if self.vhdl_sources and not self.verilog_sources and not self.sources:
97
106
  lang = "vhdl"
98
- elif self.verilog_sources and not self.vhdl_sources:
107
+ elif self.verilog_sources and not self.vhdl_sources and not self.sources:
99
108
  lang = "verilog"
109
+ elif self.sources and not self.vhdl_sources and not self.verilog_sources:
110
+ if is_vhdl_source(self.sources[-1]):
111
+ lang = "vhdl"
112
+ elif is_verilog_source(self.sources[-1]):
113
+ lang = "verilog"
114
+ else:
115
+ raise UnknownFileExtension(self.sources[-1])
100
116
  else:
101
117
  raise ValueError(
102
118
  f"{type(self).__qualname__}: Must specify a hdl_toplevel_lang in a mixed-language design"
@@ -119,7 +135,12 @@ class Simulator(abc.ABC):
119
135
  self.env[e] = os.environ[e]
120
136
 
121
137
  if "LIBPYTHON_LOC" not in self.env:
122
- self.env["LIBPYTHON_LOC"] = find_libpython.find_libpython()
138
+ libpython_path = find_libpython.find_libpython()
139
+ if not libpython_path:
140
+ raise ValueError(
141
+ "Unable to find libpython, please make sure the appropriate libpython is installed"
142
+ )
143
+ self.env["LIBPYTHON_LOC"] = libpython_path
123
144
 
124
145
  self.env["PATH"] += os.pathsep + cocotb.config.libs_dir
125
146
  self.env["PYTHONPATH"] = os.pathsep.join(sys.path)
@@ -144,21 +165,58 @@ class Simulator(abc.ABC):
144
165
  hdl_library: str = "top",
145
166
  verilog_sources: Sequence[PathLike] = [],
146
167
  vhdl_sources: Sequence[PathLike] = [],
168
+ sources: Sequence[Union[PathLike, VHDL, Verilog]] = [],
147
169
  includes: Sequence[PathLike] = [],
148
170
  defines: Mapping[str, object] = {},
149
171
  parameters: Mapping[str, object] = {},
150
- build_args: Sequence[str] = [],
172
+ build_args: Sequence[Union[str, VHDL, Verilog]] = [],
151
173
  hdl_toplevel: Optional[str] = None,
152
174
  always: bool = False,
153
175
  build_dir: PathLike = "sim_build",
176
+ clean: bool = False,
154
177
  verbose: bool = False,
178
+ timescale: Optional[Timescale] = None,
179
+ waves: Optional[bool] = None,
180
+ log_file: Optional[PathLike] = None,
155
181
  ) -> None:
156
182
  """Build the HDL sources.
157
183
 
184
+ With mixed language simulators, *sources* will be built,
185
+ followed by *vhdl_sources*, then *verilog_sources*.
186
+ With simulators that only support either VHDL or Verilog, *sources* will be built,
187
+ followed by *vhdl_sources* and *verilog_sources*, respectively.
188
+
189
+ If your source files use an atypical file extension,
190
+ use :class:`VHDL` and :class:`Verilog` to tag the path as a VHDL or Verilog source file, respectively.
191
+ If the filepaths aren't tagged, the extension is used to determine if they are VHDL or Verilog files.
192
+
193
+ +----------+------------------------------------+
194
+ | Language | File Extensions |
195
+ +==========+====================================+
196
+ | VHDL | ``.vhd``, ``.vhdl`` |
197
+ +----------+------------------------------------+
198
+ | Verilog | ``.v``, ``.sv``, ``.vh``, ``.svh`` |
199
+ +----------+------------------------------------+
200
+
201
+
202
+ .. code-block:: python3
203
+
204
+ runner.build(
205
+ sources=[
206
+ VHDL("/my/file.is_actually_vhdl"),
207
+ Verilog("/other/file.verilog"),
208
+ ],
209
+ )
210
+
211
+ The same tagging works for *build_args*.
212
+ Tagged *build_args* only supply that option to the compiler when building the source file for the tagged language.
213
+ Non-tagged *build_args* are supplied when compiling any language.
214
+
158
215
  Args:
159
216
  hdl_library: The library name to compile into.
160
217
  verilog_sources: Verilog source files to build.
161
218
  vhdl_sources: VHDL source files to build.
219
+ sources: Language-agnostic list of source files to build.
162
220
  includes: Verilog include directories.
163
221
  defines: Defines to set.
164
222
  parameters: Verilog parameters or VHDL generics.
@@ -166,10 +224,17 @@ class Simulator(abc.ABC):
166
224
  hdl_toplevel: The name of the HDL toplevel module.
167
225
  always: Always run the build step.
168
226
  build_dir: Directory to run the build step in.
227
+ clean: Delete build_dir before building
169
228
  verbose: Enable verbose messages.
229
+ timescale: Tuple containing time unit and time precision for simulation.
230
+ waves: Record signal traces.
231
+ log_file: File to write the build log to.
170
232
  """
171
233
 
234
+ self.clean: bool = clean
172
235
  self.build_dir = get_abs_path(build_dir)
236
+ if self.clean:
237
+ self.rm_build_folder(self.build_dir)
173
238
  os.makedirs(self.build_dir, exist_ok=True)
174
239
 
175
240
  # note: to avoid mutating argument defaults, we ensure that no value
@@ -179,6 +244,7 @@ class Simulator(abc.ABC):
179
244
  self.hdl_library: str = hdl_library
180
245
  self.verilog_sources: List[Path] = get_abs_paths(verilog_sources)
181
246
  self.vhdl_sources: List[Path] = get_abs_paths(vhdl_sources)
247
+ self.sources: List[Path] = get_abs_paths(sources)
182
248
  self.includes: List[Path] = get_abs_paths(includes)
183
249
  self.defines = dict(defines)
184
250
  self.parameters = dict(parameters)
@@ -186,6 +252,10 @@ class Simulator(abc.ABC):
186
252
  self.always: bool = always
187
253
  self.hdl_toplevel: Optional[str] = hdl_toplevel
188
254
  self.verbose: bool = verbose
255
+ self.timescale: Optional[Timescale] = timescale
256
+ self.log_file: Optional[PathLike] = log_file
257
+
258
+ self.waves = bool(waves)
189
259
 
190
260
  for e in os.environ:
191
261
  self.env[e] = os.environ[e]
@@ -210,8 +280,11 @@ class Simulator(abc.ABC):
210
280
  parameters: Mapping[str, object] = None,
211
281
  build_dir: Optional[PathLike] = None,
212
282
  test_dir: Optional[PathLike] = None,
213
- results_xml: str = "results.xml",
283
+ results_xml: Optional[str] = None,
284
+ pre_cmd: List[str] = [],
214
285
  verbose: bool = False,
286
+ timescale: Optional[Timescale] = None,
287
+ log_file: Optional[PathLike] = None,
215
288
  ) -> Path:
216
289
  """Run the tests.
217
290
 
@@ -235,15 +308,17 @@ class Simulator(abc.ABC):
235
308
  build_dir: Directory the build step has been run in.
236
309
  test_dir: Directory to run the tests in.
237
310
  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.
311
+ If an absolute path is provided it will be used as-is,
312
+ ``{build_dir}/results.xml`` otherwise.
313
+ This argument should not be set when run with ``pytest``.
239
314
  verbose: Enable verbose messages.
315
+ pre_cmd: Commands to run before simulation begins.
316
+ timescale: Tuple containing time unit and time precision for simulation.
317
+ log_file: File to write the test log to.
240
318
 
241
319
  Returns:
242
320
  The absolute location of the results XML file which can be
243
321
  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
322
  """
248
323
 
249
324
  __tracebackhide__ = True # Hide the traceback when using pytest
@@ -279,6 +354,8 @@ class Simulator(abc.ABC):
279
354
  for gpi_if in self.supported_gpi_interfaces.values():
280
355
  self.gpi_interfaces.append(gpi_if[0])
281
356
 
357
+ self.pre_cmd = pre_cmd
358
+
282
359
  self.test_args = list(test_args)
283
360
  self.plusargs = list(plusargs)
284
361
  self.env = dict(extra_env)
@@ -292,22 +369,31 @@ class Simulator(abc.ABC):
292
369
  if seed is not None:
293
370
  self.env["RANDOM_SEED"] = str(seed)
294
371
 
372
+ self.log_file = log_file
295
373
  self.waves = bool(waves)
296
374
  self.gui = bool(gui)
375
+ self.timescale: Optional[Timescale] = timescale
297
376
 
298
377
  if verbose is not None:
299
378
  self.verbose = verbose
300
379
 
301
380
  # When using pytest, use test name as result file name
302
- pytest_current_test = os.getenv("PYTEST_CURRENT_TEST", "")
303
- if pytest_current_test:
381
+ pytest_current_test = os.getenv("PYTEST_CURRENT_TEST", None)
382
+ test_dir_path = Path(self.test_dir)
383
+ self.current_test_name = "test"
384
+ if results_xml is not None:
385
+ # PYTEST_CURRENT_TEST only allowed when results_xml is not set
386
+ assert not pytest_current_test
387
+ results_xml_path = Path(results_xml)
388
+ if results_xml_path.is_absolute():
389
+ results_xml_file = results_xml_path
390
+ else:
391
+ results_xml_file = test_dir_path / results_xml_path
392
+ elif pytest_current_test is not None:
304
393
  self.current_test_name = pytest_current_test.split(":")[-1].split(" ")[0]
305
- results_xml_name = f"{self.current_test_name}.{results_xml}"
394
+ results_xml_file = test_dir_path / f"{self.current_test_name}.{results_xml}"
306
395
  else:
307
- self.current_test_name = "test"
308
- results_xml_name = results_xml
309
-
310
- results_xml_file = Path(self.test_dir) / results_xml_name
396
+ results_xml_file = test_dir_path / "results.xml"
311
397
 
312
398
  with suppress(OSError):
313
399
  os.remove(results_xml_file)
@@ -350,19 +436,38 @@ class Simulator(abc.ABC):
350
436
 
351
437
  __tracebackhide__ = True # Hide the traceback when using PyTest.
352
438
 
439
+ if self.log_file is None:
440
+ self._execute_cmds(cmds, cwd)
441
+ else:
442
+ with open(self.log_file, "w") as f:
443
+ self._execute_cmds(cmds, cwd, f)
444
+
445
+ def _execute_cmds(
446
+ self, cmds: Sequence[Command], cwd: PathLike, stdout: Optional[TextIO] = None
447
+ ) -> None:
448
+ __tracebackhide__ = True # Hide the traceback when using PyTest.
449
+
353
450
  for cmd in cmds:
354
451
  print(f"INFO: Running command {shlex_join(cmd)} in directory {cwd}")
355
452
 
356
453
  # TODO: create a thread to handle stderr and log as error?
357
454
  # TODO: log forwarding
358
455
 
359
- process = subprocess.run(cmd, cwd=cwd, env=self.env)
456
+ stderr = None if stdout is None else subprocess.STDOUT
457
+ process = subprocess.run(
458
+ cmd, cwd=cwd, env=self.env, stdout=stdout, stderr=stderr
459
+ )
360
460
 
361
461
  if process.returncode != 0:
362
462
  raise SystemExit(
363
463
  f"Process {process.args[0]!r} terminated with error {process.returncode}"
364
464
  )
365
465
 
466
+ def rm_build_folder(self, build_dir: Path):
467
+ if os.path.isdir(build_dir):
468
+ print("Removing:", build_dir)
469
+ shutil.rmtree(build_dir, ignore_errors=True)
470
+
366
471
 
367
472
  def get_results(results_xml_file: Path) -> Tuple[int, int]:
368
473
  """Return number of tests and fails in *results_xml_file*.
@@ -446,6 +551,40 @@ def get_abs_paths(paths: Sequence[PathLike]) -> List[Path]:
446
551
  return [get_abs_path(path) for path in paths]
447
552
 
448
553
 
554
+ _verilog_extensions = (".v", ".sv", ".vh", ".svh")
555
+ _vhdl_extensions = (".vhd", ".vhdl")
556
+
557
+ _vhdl_extensions_s = ", ".join(f"`{c}`" for c in _vhdl_extensions)
558
+ _verilog_extensions_s = ", ".join(f"`{c}`" for c in _verilog_extensions)
559
+
560
+
561
+ class UnknownFileExtension(ValueError):
562
+ def __init__(self, source: PathLike) -> None:
563
+ super().__init__(
564
+ f"Can't determine if {source} is a VHDL or Verilog file. "
565
+ f"Use a standard file extension ({_vhdl_extensions_s} for VHDL files and {_verilog_extensions_s} for Verilog files) "
566
+ "or tag the source with `VHDL(source)` or `Verilog(source)`."
567
+ )
568
+
569
+
570
+ def is_vhdl_source(source: PathLike) -> bool:
571
+ if isinstance(source, VHDL):
572
+ return True
573
+ source_as_path = Path(source)
574
+ if source_as_path.suffix in _vhdl_extensions:
575
+ return True
576
+ return False
577
+
578
+
579
+ def is_verilog_source(source: PathLike) -> bool:
580
+ if isinstance(source, Verilog):
581
+ return True
582
+ source_as_path = Path(source)
583
+ if source_as_path.suffix in _verilog_extensions:
584
+ return True
585
+ return False
586
+
587
+
449
588
  class Icarus(Simulator):
450
589
  supported_gpi_interfaces = {"verilog": ["vpi"]}
451
590
 
@@ -469,11 +608,39 @@ class Icarus(Simulator):
469
608
  for name, value in parameters.items()
470
609
  ]
471
610
 
611
+ def _create_cmd_file(self) -> None:
612
+ with open(self.cmds_file, "w") as f:
613
+ f.write("+timescale+{}/{}\n".format(*self.timescale))
614
+
615
+ def _create_iverilog_dump_file(self) -> None:
616
+ dumpfile_path = Path(self.build_dir, f"{self.hdl_toplevel}.fst").as_posix()
617
+ with open(self.iverilog_dump_file, "w") as f:
618
+ f.write("module cocotb_iverilog_dump();\n")
619
+ f.write("initial begin\n")
620
+ f.write(f' $dumpfile("{dumpfile_path}");\n')
621
+ f.write(f" $dumpvars(0, {self.hdl_toplevel});\n")
622
+ f.write("end\n")
623
+ f.write("endmodule\n")
624
+
472
625
  @property
473
626
  def sim_file(self) -> Path:
474
627
  return self.build_dir / "sim.vvp"
475
628
 
629
+ @property
630
+ def iverilog_dump_file(self) -> Path:
631
+ return self.build_dir / "cocotb_iverilog_dump.v"
632
+
633
+ @property
634
+ def cmds_file(self) -> Path:
635
+ return self.build_dir / "cmds.f"
636
+
476
637
  def _test_command(self) -> List[Command]:
638
+ plusargs = self.plusargs
639
+ if self.waves:
640
+ plusargs += ["-fst"]
641
+
642
+ if self.pre_cmd:
643
+ print("WARNING: pre_cmd is not implemented for Icarus Verilog.")
477
644
 
478
645
  return [
479
646
  [
@@ -485,26 +652,56 @@ class Icarus(Simulator):
485
652
  ]
486
653
  + self.test_args
487
654
  + [str(self.sim_file)]
488
- + self.plusargs
655
+ + plusargs
489
656
  ]
490
657
 
491
658
  def _build_command(self) -> List[Command]:
659
+ for source in self.sources:
660
+ if not is_verilog_source(source):
661
+ raise ValueError(
662
+ f"{type(self).__qualname__} only supports Verilog. {str(source)!r} cannot be compiled."
663
+ )
664
+ for arg in self.build_args:
665
+ if type(arg) not in (str, Verilog):
666
+ print(
667
+ f"WARNING: {type(self).__qualname__} only supports Verilog. build_args {arg!r} will not be applied."
668
+ )
492
669
 
493
- if self.vhdl_sources:
494
- raise ValueError(
495
- f"{type(self).__qualname__}: Simulator does not support VHDL"
496
- )
670
+ build_args = list(self.build_args)
671
+ if self.waves:
672
+ self._create_iverilog_dump_file()
673
+ build_args += ["-s", "cocotb_iverilog_dump"]
497
674
 
498
- cmds = []
499
- if outdated(self.sim_file, self.verilog_sources) or self.always:
675
+ if self.timescale is not None:
676
+ self._create_cmd_file()
677
+ build_args += ["-f", str(self.cmds_file)]
500
678
 
679
+ cmds = []
680
+ sources = [
681
+ source for source in self.sources if is_verilog_source(source)
682
+ ] + self.verilog_sources
683
+ if outdated(self.sim_file, sources) or self.always:
501
684
  cmds = [
502
- ["iverilog", "-o", str(self.sim_file), "-D", "COCOTB_SIM=1", "-g2012"]
685
+ [
686
+ "iverilog",
687
+ "-o",
688
+ str(self.sim_file),
689
+ "-D",
690
+ "COCOTB_SIM=1",
691
+ "-s",
692
+ self.hdl_toplevel,
693
+ "-g2012",
694
+ ]
503
695
  + self._get_define_options(self.defines)
504
696
  + self._get_include_options(self.includes)
505
697
  + self._get_parameter_options(self.parameters)
506
- + self.build_args
507
- + [str(source_file) for source_file in self.verilog_sources]
698
+ + [arg for arg in build_args if type(arg) in (str, Verilog)]
699
+ + [str(source_file) for source_file in sources]
700
+ + [
701
+ str(source_file)
702
+ for source_file in [self.iverilog_dump_file]
703
+ if self.waves
704
+ ]
508
705
  ]
509
706
 
510
707
  else:
@@ -540,35 +737,48 @@ class Questa(Simulator):
540
737
 
541
738
  cmds = []
542
739
 
543
- if 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]
550
- )
551
-
552
- if self.verilog_sources:
553
- cmds.append(["vlib", as_tcl_value(self.hdl_library)])
554
- cmds.append(
555
- ["vlog"]
556
- + ([] if self.always else ["-incr"])
557
- + ["-work", as_tcl_value(self.hdl_library)]
558
- + ["+define+COCOTB_SIM"]
559
- + ["-sv"]
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]
564
- )
740
+ cmds.append(["vlib", as_tcl_value(self.hdl_library)])
741
+ for source in self.sources:
742
+ if is_vhdl_source(source):
743
+ cmds.append(self._build_vhdl_command(source))
744
+ elif is_verilog_source(source):
745
+ cmds.append(self._build_verilog_command(source))
746
+ else:
747
+ raise UnknownFileExtension(source)
748
+ for source in self.vhdl_sources:
749
+ cmds.append(self._build_vhdl_command(source))
750
+ for source in self.verilog_sources:
751
+ cmds.append(self._build_verilog_command(source))
565
752
 
566
753
  return cmds
567
754
 
755
+ def _build_vhdl_command(self, source: PathLike) -> Command:
756
+ return (
757
+ ["vcom"]
758
+ + ["-work", as_tcl_value(self.hdl_library)]
759
+ + [as_tcl_value(v) for v in self.build_args if type(v) in (str, VHDL)]
760
+ + [as_tcl_value(str(source))]
761
+ )
762
+
763
+ def _build_verilog_command(self, source: PathLike) -> Command:
764
+ return (
765
+ ["vlog"]
766
+ + ([] if self.always else ["-incr"])
767
+ + ["-work", as_tcl_value(self.hdl_library)]
768
+ + ["-sv"]
769
+ + self._get_define_options(self.defines)
770
+ + self._get_include_options(self.includes)
771
+ + [as_tcl_value(v) for v in self.build_args if type(v) in (str, Verilog)]
772
+ + [as_tcl_value(str(source))]
773
+ )
774
+
568
775
  def _test_command(self) -> List[Command]:
569
776
 
570
777
  cmds = []
571
778
 
779
+ if self.pre_cmd:
780
+ self.pre_cmd = ["-do"] + self.pre_cmd
781
+
572
782
  do_script = ""
573
783
  if self.waves:
574
784
  do_script += "log -recursive /*;"
@@ -577,8 +787,6 @@ class Questa(Simulator):
577
787
  do_script += "run -all; quit"
578
788
 
579
789
  gpi_if_entry = self.gpi_interfaces[0]
580
- gpi_if_entry_lib_path = cocotb.config.lib_name_path(gpi_if_entry, "questa")
581
-
582
790
  if gpi_if_entry == "fli":
583
791
  lib_opts = [
584
792
  "-foreign",
@@ -598,11 +806,6 @@ class Questa(Simulator):
598
806
  as_tcl_value(cocotb.config.lib_name_path("vpi", "questa")),
599
807
  ]
600
808
 
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."
604
- )
605
-
606
809
  cmds.append(
607
810
  ["vsim"]
608
811
  + ["-gui" if self.gui else "-c"]
@@ -612,6 +815,7 @@ class Questa(Simulator):
612
815
  + [as_tcl_value(v) for v in self._get_parameter_options(self.parameters)]
613
816
  + [as_tcl_value(f"{self.hdl_toplevel_library}.{self.sim_hdl_toplevel}")]
614
817
  + [as_tcl_value(v) for v in self.plusargs]
818
+ + self.pre_cmd
615
819
  + ["-do", do_script]
616
820
  )
617
821
 
@@ -638,22 +842,39 @@ class Ghdl(Simulator):
638
842
  if shutil.which("ghdl") is None:
639
843
  raise SystemExit("ERROR: ghdl executable not found!")
640
844
 
845
+ def _is_mcode_backend(self) -> bool:
846
+ """Is GHDL using the mcode backend?"""
847
+ result = subprocess.run(
848
+ ["ghdl", "--version"],
849
+ check=True,
850
+ text=True,
851
+ stdout=subprocess.PIPE,
852
+ stderr=subprocess.STDOUT,
853
+ )
854
+ return "mcode" in result.stdout
855
+
641
856
  @staticmethod
642
857
  def _get_parameter_options(parameters: Mapping[str, object]) -> Command:
643
858
  return [f"-g{name}={value}" for name, value in parameters.items()]
644
859
 
645
860
  def _build_command(self) -> List[Command]:
646
-
647
- if self.verilog_sources:
648
- raise ValueError(
649
- f"{type(self).__qualname__}: Simulator does not support Verilog"
650
- )
861
+ for source in self.sources:
862
+ if not is_vhdl_source(source):
863
+ raise ValueError(
864
+ f"{type(self).__qualname__} only supports VHDL. {str(source)!r} cannot be compiled."
865
+ )
866
+ for arg in self.build_args:
867
+ if type(arg) not in (str, VHDL):
868
+ print(
869
+ f"WARNING: {type(self).__qualname__} only supports VHDL. build_args {arg!r} will not be applied."
870
+ )
651
871
 
652
872
  cmds = [
653
873
  ["ghdl", "-i"]
654
874
  + [f"--work={self.hdl_library}"]
655
- + self.build_args
656
- + [str(source_file) for source_file in self.vhdl_sources]
875
+ + [arg for arg in self.build_args if type(arg) in (str, VHDL)]
876
+ + [str(source) for source in self.sources if is_vhdl_source(source)]
877
+ + [str(source) for source in self.vhdl_sources]
657
878
  ]
658
879
 
659
880
  if self.hdl_toplevel is not None:
@@ -667,11 +888,42 @@ class Ghdl(Simulator):
667
888
  return cmds
668
889
 
669
890
  def _test_command(self) -> List[Command]:
891
+ if self.pre_cmd:
892
+ print("WARNING: pre_cmd is not implemented for GHDL.")
893
+
894
+ ghdl_run_args = self.test_args
895
+
896
+ if self._is_mcode_backend() and self.timescale:
897
+ _, precision = self.timescale
898
+ # Convert the time precision to a format string supported by GHDL,
899
+ # if possible.
900
+ # GHDL only supports setting the time precision if the mcode backend
901
+ # is used, using the --time-resolution argument causes GHDL to error
902
+ # out otherwise.
903
+ # https://ghdl.github.io/ghdl/using/InvokingGHDL.html#cmdoption-ghdl-time-resolution
904
+ if precision == "1fs":
905
+ ghdl_time_resolution = "fs"
906
+ elif precision == "1ps":
907
+ ghdl_time_resolution = "ps"
908
+ elif precision == "1ns":
909
+ ghdl_time_resolution = "ns"
910
+ elif precision == "1us":
911
+ ghdl_time_resolution = "us"
912
+ elif precision == "1ms":
913
+ ghdl_time_resolution = "ms"
914
+ elif precision == "1s":
915
+ ghdl_time_resolution = "sec"
916
+ else:
917
+ raise ValueError(
918
+ "GHDL only supports the following precisions in timescale: 1fs, 1ps, 1us, 1ms, 1s"
919
+ )
920
+
921
+ ghdl_run_args.append(f"--time-resolution={ghdl_time_resolution}")
670
922
 
671
923
  cmds = [
672
924
  ["ghdl", "-r"]
673
925
  + [f"--work={self.hdl_toplevel_library}"]
674
- + self.test_args
926
+ + ghdl_run_args
675
927
  + [self.sim_hdl_toplevel]
676
928
  + ["--vpi=" + cocotb.config.lib_name_path("vpi", "ghdl")]
677
929
  + self.plusargs
@@ -681,6 +933,55 @@ class Ghdl(Simulator):
681
933
  return cmds
682
934
 
683
935
 
936
+ class Nvc(Simulator):
937
+ supported_gpi_interfaces = {"vhdl": ["vhpi"]}
938
+
939
+ @staticmethod
940
+ def _simulator_in_path() -> None:
941
+ if shutil.which("nvc") is None:
942
+ raise SystemExit("ERROR: nvc executable not found!")
943
+
944
+ @staticmethod
945
+ def _get_parameter_options(parameters: Mapping[str, object]) -> Command:
946
+ return [f"-g{name}={value}" for name, value in parameters.items()]
947
+
948
+ def _build_command(self) -> List[Command]:
949
+ for source in self.sources:
950
+ if not is_vhdl_source(source):
951
+ raise ValueError(
952
+ f"{type(self).__qualname__} only supports VHDL. {str(source)!r} cannot be compiled."
953
+ )
954
+ for arg in self.build_args:
955
+ if type(arg) not in (str, VHDL):
956
+ print(
957
+ f"WARNING: {type(self).__qualname__} only supports VHDL. build_args {arg!r} will not be applied."
958
+ )
959
+
960
+ cmds = [
961
+ ["nvc", f"--work={self.hdl_library}"]
962
+ + [arg for arg in self.build_args if type(arg) in (str, VHDL)]
963
+ + ["-a"]
964
+ + [str(source) for source in self.sources if is_vhdl_source(source)]
965
+ + [str(source) for source in self.vhdl_sources]
966
+ ]
967
+
968
+ return cmds
969
+
970
+ def _test_command(self) -> List[Command]:
971
+ cmds = [
972
+ ["nvc", f"--work={self.hdl_toplevel_library}"]
973
+ + self.build_args
974
+ + ["-e", self.sim_hdl_toplevel, "--no-save", "--jit"]
975
+ + self._get_parameter_options(self.parameters)
976
+ + ["-r"]
977
+ + self.test_args
978
+ + ["--load=" + cocotb.config.lib_name_path("vhpi", "nvc")]
979
+ + self.plusargs
980
+ ]
981
+
982
+ return cmds
983
+
984
+
684
985
  class Riviera(Simulator):
685
986
  supported_gpi_interfaces = {"verilog": ["vpi"], "vhdl": ["vhpi"]}
686
987
 
@@ -705,53 +1006,67 @@ class Riviera(Simulator):
705
1006
  return [f"-g{name}={value}" for name, value in parameters.items()]
706
1007
 
707
1008
  def _build_command(self) -> List[Command]:
708
-
709
- do_script = "\nonerror {\n quit -code 1 \n} \n"
1009
+ do_script: List[str] = ["onerror {\n quit -code 1 \n}"]
710
1010
 
711
1011
  out_file = self.build_dir / self.hdl_library / f"{self.hdl_library}.lib"
712
1012
 
713
1013
  if outdated(out_file, self.verilog_sources + self.vhdl_sources) or self.always:
714
-
715
- do_script += "alib {RTL_LIBRARY} \n".format(
716
- RTL_LIBRARY=as_tcl_value(self.hdl_library)
717
- )
718
-
719
- if self.vhdl_sources:
720
- do_script += (
721
- "acom -work {RTL_LIBRARY} {EXTRA_ARGS} {VHDL_SOURCES}\n".format(
722
- RTL_LIBRARY=as_tcl_value(self.hdl_library),
723
- VHDL_SOURCES=" ".join(
724
- as_tcl_value(str(v)) for v in self.vhdl_sources
725
- ),
726
- EXTRA_ARGS=" ".join(as_tcl_value(v) for v in self.build_args),
727
- )
728
- )
729
-
730
- if self.verilog_sources:
731
- do_script += "alog -work {RTL_LIBRARY} +define+COCOTB_SIM -sv {DEFINES} {INCDIR} {EXTRA_ARGS} {VERILOG_SOURCES} \n".format(
732
- RTL_LIBRARY=as_tcl_value(self.hdl_library),
733
- VERILOG_SOURCES=" ".join(
734
- as_tcl_value(str(v)) for v in self.verilog_sources
735
- ),
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),
739
- )
740
- else:
741
- print("WARNING: Skipping compilation of", out_file)
1014
+ do_script.append(f"alib {as_tcl_value(self.hdl_library)}")
1015
+
1016
+ for source in self.sources:
1017
+ if is_verilog_source(source):
1018
+ do_script.append(self._build_verilog_source(source))
1019
+ elif is_vhdl_source(source):
1020
+ do_script.append(self._build_vhdl_source(source))
1021
+ else:
1022
+ raise UnknownFileExtension(source)
1023
+ for source in self.vhdl_sources:
1024
+ do_script.append(self._build_vhdl_source(source))
1025
+ for source in self.verilog_sources:
1026
+ do_script.append(self._build_verilog_source(source))
1027
+
1028
+ # Explicitly exit the script at the end. In batch mode, which is invoked
1029
+ # implicitly by redirecting STDOUT/STDERR of the alog/acom commands,
1030
+ # the tool exits by itself even without this 'exit' command -- but not
1031
+ # when running from an interactive terminal. Be explicit for predictable
1032
+ # behavior.
1033
+ do_script.append("exit")
742
1034
 
743
1035
  do_file = tempfile.NamedTemporaryFile(delete=False)
744
- do_file.write(do_script.encode())
1036
+ do_file.write("\n".join(do_script).encode())
745
1037
  do_file.close()
746
1038
 
747
1039
  return [["vsimsa"] + ["-do"] + ["do"] + [do_file.name]]
748
1040
 
1041
+ def _build_vhdl_source(self, source: PathLike) -> str:
1042
+ return "acom -work {RTL_LIBRARY} {EXTRA_ARGS} {VHDL_SOURCES}".format(
1043
+ RTL_LIBRARY=as_tcl_value(self.hdl_library),
1044
+ VHDL_SOURCES=as_tcl_value(str(source)),
1045
+ EXTRA_ARGS=" ".join(
1046
+ as_tcl_value(v) for v in self.build_args if type(v) in (str, VHDL)
1047
+ ),
1048
+ )
1049
+
1050
+ def _build_verilog_source(self, source: PathLike) -> str:
1051
+ return "alog -work {RTL_LIBRARY} -pli {EXT_NAME} -sv {DEFINES} {INCDIR} {EXTRA_ARGS} {VERILOG_SOURCES}".format(
1052
+ RTL_LIBRARY=as_tcl_value(self.hdl_library),
1053
+ EXT_NAME=as_tcl_value(cocotb.config.lib_name_path("vpi", "riviera")),
1054
+ VERILOG_SOURCES=as_tcl_value(str(source)),
1055
+ DEFINES=" ".join(self._get_define_options(self.defines)),
1056
+ INCDIR=" ".join(self._get_include_options(self.includes)),
1057
+ EXTRA_ARGS=" ".join(
1058
+ as_tcl_value(v) for v in self.build_args if type(v) in (str, Verilog)
1059
+ ),
1060
+ )
1061
+
749
1062
  def _test_command(self) -> List[Command]:
1063
+ if self.pre_cmd:
1064
+ print("WARNING: pre_cmd is not implemented for Riviera.")
750
1065
 
751
- do_script = "\nonerror {\n quit -code 1 \n} \n"
1066
+ do_script: str = "\nonerror {\n quit -code 1 \n} \n"
752
1067
 
753
1068
  if self.hdl_toplevel_lang == "vhdl":
754
- do_script += "asim +access +w -interceptcoutput -O2 -loadvhpi {EXT_NAME} {EXTRA_ARGS} {TOPLEVEL} {PLUSARGS}\n".format(
1069
+ do_script += "asim +access +w_nets -interceptcoutput -loadvhpi {EXT_NAME} {EXTRA_ARGS} {TOPLEVEL} {PLUSARGS}\n".format(
755
1070
  TOPLEVEL=as_tcl_value(
756
1071
  f"{self.hdl_toplevel_library}.{self.sim_hdl_toplevel}"
757
1072
  ),
@@ -769,7 +1084,7 @@ class Riviera(Simulator):
769
1084
  cocotb.config.lib_name_path("vpi", "riviera") + ":cocotbvpi_entry_point"
770
1085
  )
771
1086
  else:
772
- do_script += "asim +access +w -interceptcoutput -O2 -pli {EXT_NAME} {EXTRA_ARGS} {TOPLEVEL} {PLUSARGS} \n".format(
1087
+ do_script += "asim +access +w_nets -interceptcoutput -pli {EXT_NAME} {EXTRA_ARGS} {TOPLEVEL} {PLUSARGS} \n".format(
773
1088
  TOPLEVEL=as_tcl_value(
774
1089
  f"{self.hdl_toplevel_library}.{self.sim_hdl_toplevel}"
775
1090
  ),
@@ -804,6 +1119,10 @@ class Verilator(Simulator):
804
1119
  supported_gpi_interfaces = {"verilog": ["vpi"]}
805
1120
 
806
1121
  def _simulator_in_path(self) -> None:
1122
+ # the verilator binary is only needed for building
1123
+ return
1124
+
1125
+ def _simulator_in_path_build_only(self) -> None:
807
1126
  executable = shutil.which("verilator")
808
1127
  if executable is None:
809
1128
  raise SystemExit("ERROR: verilator executable not found!")
@@ -822,15 +1141,22 @@ class Verilator(Simulator):
822
1141
  return [f"-G{name}={value}" for name, value in parameters.items()]
823
1142
 
824
1143
  def _build_command(self) -> List[Command]:
1144
+ self._simulator_in_path_build_only()
825
1145
 
826
- if self.vhdl_sources:
827
- raise ValueError(
828
- f"{type(self).__qualname__}: Simulator does not support VHDL"
829
- )
1146
+ for source in self.sources:
1147
+ if not is_verilog_source(source):
1148
+ raise ValueError(
1149
+ f"{type(self).__qualname__} only supports Verilog. {str(source)!r} cannot be compiled."
1150
+ )
1151
+ for arg in self.build_args:
1152
+ if type(arg) not in (str, Verilog):
1153
+ print(
1154
+ f"WARNING: {type(self).__qualname__} only supports Verilog. build_args {arg!r} will not be applied."
1155
+ )
830
1156
 
831
1157
  if self.hdl_toplevel is None:
832
1158
  raise ValueError(
833
- f"{type(self).__qualname__}: Simulator requires the hdl_toplevel parameter to be specified"
1159
+ f"{type(self).__qualname__} requires the hdl_toplevel parameter to be specified"
834
1160
  )
835
1161
 
836
1162
  # TODO: set "--debug" if self.verbose
@@ -867,21 +1193,40 @@ class Verilator(Simulator):
867
1193
  LIB_DIR=cocotb.config.libs_dir
868
1194
  ),
869
1195
  ]
870
- + self.build_args
1196
+ + (["--trace"] if self.waves else [])
1197
+ + [arg for arg in self.build_args if type(arg) in (str, Verilog)]
871
1198
  + self._get_define_options(self.defines)
872
1199
  + self._get_include_options(self.includes)
873
1200
  + self._get_parameter_options(self.parameters)
874
1201
  + [verilator_cpp]
875
- + [str(source_file) for source_file in self.verilog_sources]
1202
+ + [str(source) for source in self.sources if is_verilog_source(source)]
1203
+ + [str(source) for source in self.verilog_sources]
876
1204
  )
877
1205
 
878
- cmds.append(["make", "-C", str(self.build_dir), "-f", "Vtop.mk"])
1206
+ cmds.append(
1207
+ [
1208
+ "make",
1209
+ "-C",
1210
+ str(self.build_dir),
1211
+ "-f",
1212
+ "Vtop.mk",
1213
+ f"VM_TRACE={int(self.waves)}",
1214
+ ]
1215
+ )
879
1216
 
880
1217
  return cmds
881
1218
 
882
1219
  def _test_command(self) -> List[Command]:
1220
+ if self.pre_cmd:
1221
+ print("WARNING: pre_cmd is not implemented for Verilator.")
1222
+
883
1223
  out_file = self.build_dir / self.sim_hdl_toplevel
884
- return [[str(out_file)] + self.plusargs]
1224
+ return [
1225
+ [str(out_file)]
1226
+ + (["--trace"] if self.waves else [])
1227
+ + self.test_args
1228
+ + self.plusargs
1229
+ ]
885
1230
 
886
1231
 
887
1232
  class Xcelium(Simulator):
@@ -907,6 +1252,8 @@ class Xcelium(Simulator):
907
1252
  def _build_command(self) -> List[Command]:
908
1253
  self.env["CDS_AUTO_64BIT"] = "all"
909
1254
 
1255
+ assert self.hdl_toplevel, "A HDL toplevel is required in all Xcelium compiles."
1256
+
910
1257
  verbosity_opts = []
911
1258
  if self.verbose:
912
1259
  verbosity_opts += ["-messages"]
@@ -922,6 +1269,11 @@ class Xcelium(Simulator):
922
1269
  verbosity_opts += ["-quiet"]
923
1270
  verbosity_opts += ["-plinowarn"]
924
1271
 
1272
+ vhpi_opts = []
1273
+ # Xcelium 23.09.004 fixes cocotb issue #1076 as long as the
1274
+ # following define is set.
1275
+ vhpi_opts.append("-NEW_VHPI_PROPAGATE_DELAY")
1276
+
925
1277
  cmds = [
926
1278
  ["xrun"]
927
1279
  + ["-logfile"]
@@ -940,6 +1292,7 @@ class Xcelium(Simulator):
940
1292
  cocotb.config.lib_name_path("vpi", "xcelium")
941
1293
  + ":vlog_startup_routines_bootstrap"
942
1294
  ]
1295
+ + vhpi_opts
943
1296
  + [f"-work {self.hdl_library}"]
944
1297
  + self.build_args
945
1298
  + ["-define COCOTB_SIM"]
@@ -949,13 +1302,18 @@ class Xcelium(Simulator):
949
1302
  + [f"-top {self.hdl_toplevel}"]
950
1303
  + [
951
1304
  str(source_file)
952
- for source_file in self.vhdl_sources + self.verilog_sources
1305
+ for source_file in (
1306
+ self.sources + self.vhdl_sources + self.verilog_sources
1307
+ )
953
1308
  ]
954
1309
  ]
955
1310
 
956
1311
  return cmds
957
1312
 
958
1313
  def _test_command(self) -> List[Command]:
1314
+ if self.pre_cmd:
1315
+ print("WARNING: pre_cmd is not implemented for Xcelium.")
1316
+
959
1317
  self.env["CDS_AUTO_64BIT"] = "all"
960
1318
 
961
1319
  verbosity_opts = []
@@ -980,6 +1338,21 @@ class Xcelium(Simulator):
980
1338
  else:
981
1339
  xrun_top = self.sim_hdl_toplevel
982
1340
 
1341
+ if self.waves:
1342
+ input_tcl = [
1343
+ f'-input "@database -open cocotb_waves -default" '
1344
+ f'-input "@probe -database cocotb_waves -create {xrun_top} -all -depth all" '
1345
+ f'-input "@run" '
1346
+ f'-input "@exit" '
1347
+ ]
1348
+ else:
1349
+ input_tcl = ["-input", "@run; exit;"]
1350
+
1351
+ vhpi_opts = []
1352
+ # Xcelium 23.09.004 fixes cocotb issue #1076 as long as the
1353
+ # following define is set.
1354
+ vhpi_opts.append("-NEW_VHPI_PROPAGATE_DELAY")
1355
+
983
1356
  cmds = [["mkdir", "-p", tmpdir]]
984
1357
  cmds += [
985
1358
  ["xrun"]
@@ -990,20 +1363,13 @@ class Xcelium(Simulator):
990
1363
  + ["-cds_implicit_tmpdir"]
991
1364
  + [tmpdir]
992
1365
  + ["-licqueue"]
1366
+ + vhpi_opts
993
1367
  + verbosity_opts
994
1368
  + ["-R"]
995
1369
  + self.test_args
996
1370
  + self.plusargs
997
1371
  + ["-gui" if self.gui else ""]
998
- + ["-input"]
999
- + [
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" '
1004
- if self.waves
1005
- else "@run; exit;"
1006
- ]
1372
+ + input_tcl
1007
1373
  ]
1008
1374
  self.env["GPI_EXTRA"] = (
1009
1375
  cocotb.config.lib_name_path("vhpi", "xcelium") + ":cocotbvhpi_entry_point"
@@ -1022,6 +1388,7 @@ def get_runner(simulator_name: str) -> Simulator:
1022
1388
  "riviera": Riviera,
1023
1389
  "verilator": Verilator,
1024
1390
  "xcelium": Xcelium,
1391
+ "nvc": Nvc,
1025
1392
  # TODO: "vcs": Vcs,
1026
1393
  # TODO: "activehdl": ActiveHdl,
1027
1394
  }