esiaccel 0.0.17.dev447__cp310-cp310-win_amd64.whl → 0.1.5.dev406__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 esiaccel might be problematic. Click here for more details.

Files changed (54) hide show
  1. esiaccel/CosimBackend.dll +0 -0
  2. esiaccel/CosimBackend.lib +0 -0
  3. esiaccel/ESICppRuntime.dll +0 -0
  4. esiaccel/ESICppRuntime.lib +0 -0
  5. esiaccel/EsiCosimDpiServer.dll +0 -0
  6. esiaccel/EsiCosimDpiServer.lib +0 -0
  7. esiaccel/MtiPli.dll +0 -0
  8. esiaccel/MtiPli.lib +0 -0
  9. esiaccel/__init__.py +10 -1
  10. esiaccel/abseil_dll.dll +0 -0
  11. esiaccel/accelerator.py +7 -0
  12. esiaccel/cares.dll +0 -0
  13. esiaccel/cmake/esiaccelConfig.cmake +1 -1
  14. esiaccel/cosim/Cosim_DpiPkg.sv +85 -0
  15. esiaccel/cosim/Cosim_Endpoint.sv +218 -0
  16. esiaccel/cosim/Cosim_Manifest.sv +32 -0
  17. esiaccel/cosim/driver.cpp +131 -0
  18. esiaccel/cosim/driver.sv +74 -0
  19. esiaccel/cosim/questa.py +141 -0
  20. esiaccel/cosim/simulator.py +382 -0
  21. esiaccel/cosim/verilator.py +92 -0
  22. esiaccel/esi-cosim.py +104 -0
  23. esiaccel/esiCppAccel.cp310-win_amd64.pyd +0 -0
  24. esiaccel/esiquery.exe +0 -0
  25. esiaccel/include/esi/Accelerator.h +31 -15
  26. esiaccel/include/esi/CLI.h +77 -0
  27. esiaccel/include/esi/Common.h +32 -3
  28. esiaccel/include/esi/Context.h +1 -1
  29. esiaccel/include/esi/Design.h +11 -4
  30. esiaccel/include/esi/Engines.h +124 -0
  31. esiaccel/include/esi/Logging.h +57 -7
  32. esiaccel/include/esi/Manifest.h +0 -2
  33. esiaccel/include/esi/Ports.h +47 -6
  34. esiaccel/include/esi/Services.h +144 -41
  35. esiaccel/include/esi/Types.h +103 -5
  36. esiaccel/include/esi/Values.h +313 -0
  37. esiaccel/include/esi/backends/Cosim.h +85 -0
  38. esiaccel/include/esi/backends/RpcServer.h +55 -0
  39. esiaccel/include/esi/backends/Trace.h +5 -6
  40. esiaccel/libcrypto-3-x64.dll +0 -0
  41. esiaccel/libprotobuf.dll +0 -0
  42. esiaccel/libssl-3-x64.dll +0 -0
  43. esiaccel/re2.dll +0 -0
  44. esiaccel/types.py +132 -26
  45. esiaccel/utils.py +21 -3
  46. esiaccel/zlib1.dll +0 -0
  47. {esiaccel-0.0.17.dev447.dist-info → esiaccel-0.1.5.dev406.dist-info}/METADATA +3 -3
  48. esiaccel-0.1.5.dev406.dist-info/RECORD +54 -0
  49. {esiaccel-0.0.17.dev447.dist-info → esiaccel-0.1.5.dev406.dist-info}/WHEEL +1 -1
  50. esiaccel/bin/esiquery.exe +0 -0
  51. esiaccel-0.0.17.dev447.dist-info/RECORD +0 -28
  52. {esiaccel-0.0.17.dev447.dist-info → esiaccel-0.1.5.dev406.dist-info}/entry_points.txt +0 -0
  53. {esiaccel-0.0.17.dev447.dist-info → esiaccel-0.1.5.dev406.dist-info/licenses}/LICENSE +0 -0
  54. {esiaccel-0.0.17.dev447.dist-info → esiaccel-0.1.5.dev406.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,141 @@
1
+ # Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
2
+ # See https://llvm.org/LICENSE.txt for license information.
3
+ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4
+
5
+ import os
6
+ from pathlib import Path
7
+ from typing import List, Optional, Callable, Dict
8
+
9
+ from .simulator import CosimCollateralDir, Simulator, SourceFiles
10
+
11
+
12
+ class Questa(Simulator):
13
+ """Run and compile funcs for Questasim."""
14
+
15
+ DefaultDriver = CosimCollateralDir / "driver.sv"
16
+
17
+ def __init__(
18
+ self,
19
+ sources: SourceFiles,
20
+ run_dir: Path,
21
+ debug: bool,
22
+ run_stdout_callback: Optional[Callable[[str], None]] = None,
23
+ run_stderr_callback: Optional[Callable[[str], None]] = None,
24
+ compile_stdout_callback: Optional[Callable[[str], None]] = None,
25
+ compile_stderr_callback: Optional[Callable[[str], None]] = None,
26
+ make_default_logs: bool = True,
27
+ macro_definitions: Optional[Dict[str, str]] = None,
28
+ # An optional list of questa error codes to suppress
29
+ suppressed_questa_errors: Optional[List[int]] = None):
30
+ super().__init__(
31
+ sources=sources,
32
+ run_dir=run_dir,
33
+ debug=debug,
34
+ run_stdout_callback=run_stdout_callback,
35
+ run_stderr_callback=run_stderr_callback,
36
+ compile_stdout_callback=compile_stdout_callback,
37
+ compile_stderr_callback=compile_stderr_callback,
38
+ make_default_logs=make_default_logs,
39
+ macro_definitions=macro_definitions,
40
+ )
41
+ self.suppressed_questa_errors = suppressed_questa_errors
42
+
43
+ # Questa doesn't use stderr for error messages. Everything goes to stdout.
44
+ UsesStderr = False
45
+
46
+ def internal_compile_commands(self) -> List[str]:
47
+ cmds = [
48
+ "onerror { quit -f -code 1 }",
49
+ ]
50
+ sources = self.sources.rtl_sources
51
+ sources.append(Questa.DefaultDriver)
52
+
53
+ # Format macro definition command
54
+ if self.macro_definitions:
55
+ macro_definitions_cmd = " ".join([
56
+ f"+define+{k}={v}" if v is not None else f"+define+{k}"
57
+ for k, v in self.macro_definitions.items()
58
+ ])
59
+ else:
60
+ macro_definitions_cmd = ""
61
+
62
+ # Format error suppression command
63
+ if self.suppressed_questa_errors:
64
+ suppressed_questa_errors_cmd = " ".join(
65
+ [f"-suppress {ec}" for ec in self.suppressed_questa_errors])
66
+ else:
67
+ suppressed_questa_errors_cmd = ""
68
+
69
+ for src in sources:
70
+ cmds.append(
71
+ f"vlog -incr +acc -sv {macro_definitions_cmd} {suppressed_questa_errors_cmd} +define+TOP_MODULE={self.sources.top}"
72
+ f" +define+SIMULATION {src.as_posix()}")
73
+ cmds.append(f"vopt -incr driver -o driver_opt +acc")
74
+ return cmds
75
+
76
+ def compile_commands(self) -> List[List[str]]:
77
+ with open("compile.do", "w") as f:
78
+ for cmd in self.internal_compile_commands():
79
+ f.write(cmd)
80
+ f.write("\n")
81
+ f.write("quit\n")
82
+ return [
83
+ ["vsim", "-batch", "-do", "compile.do"],
84
+ ]
85
+
86
+ def run_command(self, gui: bool) -> List[str]:
87
+ vsim = "vsim"
88
+ # Note: vsim exit codes say nothing about the test run's pass/fail even
89
+ # if $fatal is encountered in the simulation.
90
+ if gui:
91
+ cmd = [
92
+ vsim,
93
+ "driver_opt",
94
+ ]
95
+ else:
96
+ cmd = [
97
+ vsim,
98
+ "driver_opt",
99
+ "-batch",
100
+ ]
101
+
102
+ if self.debug:
103
+ # Create waveform dump .do file
104
+ wave_file = Path("wave.do")
105
+ with wave_file.open("w") as f:
106
+ f.write("log -r /*\n")
107
+ cmd += [
108
+ "-do",
109
+ str(wave_file.resolve()),
110
+ ]
111
+ # Questa will by default log to a vsim.wlf file in the current
112
+ # directory.
113
+ print(
114
+ f"Debug mode enabled - waveform will be in {wave_file.resolve().parent / 'vsim.wlf'}"
115
+ )
116
+
117
+ cmd += [
118
+ "-do",
119
+ "run -all",
120
+ ]
121
+
122
+ for lib in self.sources.dpi_so_paths():
123
+ svLib = os.path.splitext(lib)[0]
124
+ cmd.append("-sv_lib")
125
+ cmd.append(svLib)
126
+ return cmd
127
+
128
+ def run(self,
129
+ inner_command: str,
130
+ gui: bool = False,
131
+ server_only: bool = False) -> int:
132
+ """Override the Simulator.run() to add a soft link in the run directory (to
133
+ the work directory) before running vsim the usual way."""
134
+
135
+ # Create a soft link to the work directory.
136
+ workDir = self.run_dir / "work"
137
+ if not workDir.exists():
138
+ os.symlink(Path(os.getcwd()) / "work", workDir)
139
+
140
+ # Run the simulation.
141
+ return super().run(inner_command, gui, server_only=server_only)
@@ -0,0 +1,382 @@
1
+ # Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
2
+ # See https://llvm.org/LICENSE.txt for license information.
3
+ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4
+
5
+ import os
6
+ import re
7
+ import signal
8
+ import socket
9
+ import subprocess
10
+ import time
11
+ from pathlib import Path
12
+ from typing import Dict, List, Optional, Callable, IO
13
+ import threading
14
+
15
+ _thisdir = Path(__file__).parent
16
+ CosimCollateralDir = _thisdir
17
+
18
+
19
+ def is_port_open(port) -> bool:
20
+ """Check if a TCP port is open locally."""
21
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
22
+ result = sock.connect_ex(('127.0.0.1', port))
23
+ sock.close()
24
+ return True if result == 0 else False
25
+
26
+
27
+ class SourceFiles:
28
+
29
+ def __init__(self, top: str) -> None:
30
+ # User source files.
31
+ self.user: List[Path] = []
32
+ # DPI shared objects.
33
+ self.dpi_so: List[str] = ["EsiCosimDpiServer"]
34
+ # DPI SV files.
35
+ self.dpi_sv: List[Path] = [
36
+ CosimCollateralDir / "Cosim_DpiPkg.sv",
37
+ CosimCollateralDir / "Cosim_Endpoint.sv",
38
+ CosimCollateralDir / "Cosim_Manifest.sv",
39
+ ]
40
+ # Name of the top module.
41
+ self.top = top
42
+
43
+ def add_file(self, file: Path):
44
+ """Add a single RTL file to the source list."""
45
+ if file.is_file():
46
+ self.user.append(file)
47
+ else:
48
+ raise FileNotFoundError(f"File {file} does not exist")
49
+
50
+ def add_dir(self, dir: Path):
51
+ """Add all the RTL files in a directory to the source list."""
52
+ for file in sorted(dir.iterdir()):
53
+ if file.is_file() and (file.suffix == ".sv" or file.suffix == ".v"):
54
+ self.user.append(file)
55
+ elif file.is_dir():
56
+ self.add_dir(file)
57
+
58
+ def dpi_so_paths(self) -> List[Path]:
59
+ """Return a list of all the DPI shared object files."""
60
+
61
+ def find_so(name: str) -> Path:
62
+ for path in Simulator.get_env().get("LD_LIBRARY_PATH", "").split(":"):
63
+ if os.name == "nt":
64
+ so = Path(path) / f"{name}.dll"
65
+ else:
66
+ so = Path(path) / f"lib{name}.so"
67
+ if so.exists():
68
+ return so
69
+ raise FileNotFoundError(f"Could not find {name}.so in LD_LIBRARY_PATH")
70
+
71
+ return [find_so(name) for name in self.dpi_so]
72
+
73
+ @property
74
+ def rtl_sources(self) -> List[Path]:
75
+ """Return a list of all the RTL source files."""
76
+ return self.dpi_sv + self.user
77
+
78
+
79
+ class SimProcess:
80
+
81
+ def __init__(self,
82
+ proc: subprocess.Popen,
83
+ port: int,
84
+ threads: Optional[List[threading.Thread]] = None,
85
+ gui: bool = False):
86
+ self.proc = proc
87
+ self.port = port
88
+ self.threads: List[threading.Thread] = threads or []
89
+ self.gui = gui
90
+
91
+ def force_stop(self):
92
+ """Make sure to stop the simulation no matter what."""
93
+ if self.proc:
94
+ os.killpg(os.getpgid(self.proc.pid), signal.SIGINT)
95
+ # Allow the simulation time to flush its outputs.
96
+ try:
97
+ self.proc.wait(timeout=1.0)
98
+ except subprocess.TimeoutExpired:
99
+ # If the simulation doesn't exit of its own free will, kill it.
100
+ self.proc.kill()
101
+
102
+ # Join reader threads (they should exit once pipes are closed).
103
+ for t in self.threads:
104
+ t.join()
105
+
106
+
107
+ class Simulator:
108
+
109
+ # Some RTL simulators don't use stderr for error messages. Everything goes to
110
+ # stdout. Boo! They should feel bad about this. Also, they can specify that
111
+ # broken behavior by overriding this.
112
+ UsesStderr = True
113
+
114
+ def __init__(self,
115
+ sources: SourceFiles,
116
+ run_dir: Path,
117
+ debug: bool,
118
+ run_stdout_callback: Optional[Callable[[str], None]] = None,
119
+ run_stderr_callback: Optional[Callable[[str], None]] = None,
120
+ compile_stdout_callback: Optional[Callable[[str], None]] = None,
121
+ compile_stderr_callback: Optional[Callable[[str], None]] = None,
122
+ make_default_logs: bool = True,
123
+ macro_definitions: Optional[Dict[str, str]] = None):
124
+ """Simulator base class.
125
+
126
+ Optional sinks can be provided for capturing output. If not provided,
127
+ the simulator will write to log files in `run_dir`.
128
+
129
+ Args:
130
+ sources: SourceFiles describing RTL/DPI inputs.
131
+ run_dir: Directory where build/run artifacts are placed.
132
+ debug: Enable cosim debug mode.
133
+ run_stdout_callback: Line-based callback for runtime stdout.
134
+ run_stderr_callback: Line-based callback for runtime stderr.
135
+ compile_stdout_callback: Line-based callback for compile stdout.
136
+ compile_stderr_callback: Line-based callback for compile stderr.
137
+ make_default_logs: If True and corresponding callback is not supplied,
138
+ create log file and emit via internally-created callback.
139
+ macro_definitions: Optional dictionary of macro definitions to be defined
140
+ during compilation.
141
+ """
142
+ self.sources = sources
143
+ self.run_dir = run_dir
144
+ self.debug = debug
145
+ self.macro_definitions = macro_definitions
146
+
147
+ # Unified list of any log file handles we opened.
148
+ self._default_files: List[IO[str]] = []
149
+
150
+ def _ensure_default(cb: Optional[Callable[[str], None]], filename: str):
151
+ """Return (callback, file_handle_or_None) with optional file creation.
152
+
153
+ Behavior:
154
+ * If a callback is provided, return it unchanged with no file.
155
+ * If no callback and make_default_logs is False, return (None, None).
156
+ * If no callback and make_default_logs is True, create a log file and
157
+ return a writer callback plus the opened file handle.
158
+ """
159
+ if cb is not None:
160
+ return cb, None
161
+ if not make_default_logs:
162
+ return None, None
163
+ p = self.run_dir / filename
164
+ p.parent.mkdir(parents=True, exist_ok=True)
165
+ logf = p.open("w+")
166
+ self._default_files.append(logf)
167
+
168
+ def _writer(line: str, _lf=logf):
169
+ _lf.write(line + "\n")
170
+ _lf.flush()
171
+
172
+ return _writer, logf
173
+
174
+ # Initialize all four (compile/run stdout/stderr) uniformly.
175
+ self._compile_stdout_cb, self._compile_stdout_log = _ensure_default(
176
+ compile_stdout_callback, 'compile_stdout.log')
177
+ self._compile_stderr_cb, self._compile_stderr_log = _ensure_default(
178
+ compile_stderr_callback, 'compile_stderr.log')
179
+ self._run_stdout_cb, self._run_stdout_log = _ensure_default(
180
+ run_stdout_callback, 'sim_stdout.log')
181
+ self._run_stderr_cb, self._run_stderr_log = _ensure_default(
182
+ run_stderr_callback, 'sim_stderr.log')
183
+
184
+ @staticmethod
185
+ def get_env() -> Dict[str, str]:
186
+ """Get the environment variables to locate shared objects."""
187
+
188
+ env = os.environ.copy()
189
+ env["LIBRARY_PATH"] = env.get("LIBRARY_PATH", "") + ":" + str(
190
+ _thisdir.parent / "lib")
191
+ env["LD_LIBRARY_PATH"] = env.get("LD_LIBRARY_PATH", "") + ":" + str(
192
+ _thisdir.parent / "lib")
193
+ return env
194
+
195
+ def compile_commands(self) -> List[List[str]]:
196
+ """Compile the sources. Returns the exit code of the simulation compiler."""
197
+ assert False, "Must be implemented by subclass"
198
+
199
+ def compile(self) -> int:
200
+ cmds = self.compile_commands()
201
+ self.run_dir.mkdir(parents=True, exist_ok=True)
202
+ for cmd in cmds:
203
+ ret = self._start_process_with_callbacks(
204
+ cmd,
205
+ env=Simulator.get_env(),
206
+ cwd=None,
207
+ stdout_cb=self._compile_stdout_cb,
208
+ stderr_cb=self._compile_stderr_cb,
209
+ wait=True)
210
+ if isinstance(ret, int) and ret != 0:
211
+ print("====== Compilation failure")
212
+
213
+ # If we have the default file loggers, print the compilation logs to
214
+ # console. Else, assume that the user has already captured them.
215
+ if self.UsesStderr:
216
+ if self._compile_stderr_log is not None:
217
+ self._compile_stderr_log.seek(0)
218
+ print(self._compile_stderr_log.read())
219
+ else:
220
+ if self._compile_stdout_log is not None:
221
+ self._compile_stdout_log.seek(0)
222
+ print(self._compile_stdout_log.read())
223
+
224
+ return ret
225
+ return 0
226
+
227
+ def run_command(self, gui: bool) -> List[str]:
228
+ """Return the command to run the simulation."""
229
+ assert False, "Must be implemented by subclass"
230
+
231
+ def run_proc(self, gui: bool = False) -> SimProcess:
232
+ """Run the simulation process. Returns the Popen object and the port which
233
+ the simulation is listening on.
234
+
235
+ If user-provided stdout/stderr sinks were supplied in the constructor,
236
+ they are used. Otherwise, log files are created in `run_dir`.
237
+ """
238
+ self.run_dir.mkdir(parents=True, exist_ok=True)
239
+
240
+ env_gui = os.environ.get("COSIM_GUI", "0")
241
+ if env_gui != "0":
242
+ gui = True
243
+
244
+ # Erase the config file if it exists. We don't want to read
245
+ # an old config.
246
+ portFileName = self.run_dir / "cosim.cfg"
247
+ if os.path.exists(portFileName):
248
+ os.remove(portFileName)
249
+
250
+ # Run the simulation.
251
+ simEnv = Simulator.get_env()
252
+ if self.debug:
253
+ simEnv["COSIM_DEBUG_FILE"] = "cosim_debug.log"
254
+ if "DEBUG_PERIOD" not in simEnv:
255
+ # Slow the simulation down to one tick per millisecond.
256
+ simEnv["DEBUG_PERIOD"] = "1"
257
+ rcmd = self.run_command(gui)
258
+ # Start process with asynchronous output capture.
259
+ proc, threads = self._start_process_with_callbacks(
260
+ rcmd,
261
+ env=simEnv,
262
+ cwd=self.run_dir,
263
+ stdout_cb=self._run_stdout_cb,
264
+ stderr_cb=self._run_stderr_cb,
265
+ wait=False)
266
+
267
+ # Get the port which the simulation RPC selected.
268
+ checkCount = 0
269
+ while (not os.path.exists(portFileName)) and \
270
+ proc.poll() is None:
271
+ time.sleep(0.1)
272
+ checkCount += 1
273
+ if checkCount > 500 and not gui:
274
+ raise Exception(f"Cosim never wrote cfg file: {portFileName}")
275
+ port = -1
276
+ while port < 0:
277
+ portFile = open(portFileName, "r")
278
+ for line in portFile.readlines():
279
+ m = re.match("port: (\\d+)", line)
280
+ if m is not None:
281
+ port = int(m.group(1))
282
+ portFile.close()
283
+
284
+ # Wait for the simulation to start accepting RPC connections.
285
+ checkCount = 0
286
+ while not is_port_open(port):
287
+ checkCount += 1
288
+ if checkCount > 200:
289
+ raise Exception(f"Cosim RPC port ({port}) never opened")
290
+ if proc.poll() is not None:
291
+ raise Exception("Simulation exited early")
292
+ time.sleep(0.05)
293
+ return SimProcess(proc=proc, port=port, threads=threads, gui=gui)
294
+
295
+ def _start_process_with_callbacks(
296
+ self, cmd: List[str], env: Optional[Dict[str, str]], cwd: Optional[Path],
297
+ stdout_cb: Optional[Callable[[str],
298
+ None]], stderr_cb: Optional[Callable[[str],
299
+ None]],
300
+ wait: bool) -> int | tuple[subprocess.Popen, List[threading.Thread]]:
301
+ """Start a subprocess and stream its stdout/stderr to callbacks.
302
+
303
+ If wait is True, blocks until process completes and returns its exit code.
304
+ If wait is False, returns the Popen object (threads keep streaming).
305
+ """
306
+ if os.name == "posix":
307
+ proc = subprocess.Popen(cmd,
308
+ stdout=subprocess.PIPE,
309
+ stderr=subprocess.PIPE,
310
+ env=env,
311
+ cwd=cwd,
312
+ text=True,
313
+ preexec_fn=os.setsid)
314
+ else: # windows
315
+ proc = subprocess.Popen(cmd,
316
+ stdout=subprocess.PIPE,
317
+ stderr=subprocess.PIPE,
318
+ env=env,
319
+ cwd=cwd,
320
+ text=True,
321
+ creationflags=subprocess.CREATE_NEW_PROCESS_GROUP)
322
+
323
+ def _reader(pipe, cb):
324
+ if pipe is None:
325
+ return
326
+ for raw in pipe:
327
+ if raw.endswith('\n'):
328
+ raw = raw[:-1]
329
+ if cb:
330
+ try:
331
+ cb(raw)
332
+ except Exception as e:
333
+ print(f"Exception in simulator output callback: {e}")
334
+
335
+ threads: List[threading.Thread] = [
336
+ threading.Thread(target=_reader,
337
+ args=(proc.stdout, stdout_cb),
338
+ daemon=True),
339
+ threading.Thread(target=_reader,
340
+ args=(proc.stderr, stderr_cb),
341
+ daemon=True),
342
+ ]
343
+ for t in threads:
344
+ t.start()
345
+ if wait:
346
+ for t in threads:
347
+ t.join()
348
+ return proc.wait()
349
+ return proc, threads
350
+
351
+ def run(self,
352
+ inner_command: str,
353
+ gui: bool = False,
354
+ server_only: bool = False) -> int:
355
+ """Start the simulation then run the command specified. Kill the simulation
356
+ when the command exits."""
357
+
358
+ # 'simProc' is accessed in the finally block. Declare it here to avoid
359
+ # syntax errors in that block.
360
+ simProc = None
361
+ try:
362
+ simProc = self.run_proc(gui=gui)
363
+ if server_only:
364
+ # wait for user input to kill the server
365
+ input(
366
+ f"Running in server-only mode on port {simProc.port} - Press anything to kill the server..."
367
+ )
368
+ return 0
369
+ else:
370
+ # Run the inner command, passing the connection info via environment vars.
371
+ testEnv = os.environ.copy()
372
+ testEnv["ESI_COSIM_PORT"] = str(simProc.port)
373
+ testEnv["ESI_COSIM_HOST"] = "localhost"
374
+ ret = subprocess.run(inner_command, cwd=os.getcwd(),
375
+ env=testEnv).returncode
376
+ if simProc.gui:
377
+ print("GUI mode - waiting for simulator to exit...")
378
+ simProc.proc.wait()
379
+ return ret
380
+ finally:
381
+ if simProc and simProc.proc.poll() is None:
382
+ simProc.force_stop()
@@ -0,0 +1,92 @@
1
+ # Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
2
+ # See https://llvm.org/LICENSE.txt for license information.
3
+ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4
+
5
+ import os
6
+ from pathlib import Path
7
+ from typing import List, Optional, Callable, Dict
8
+
9
+ from .simulator import CosimCollateralDir, Simulator, SourceFiles
10
+
11
+
12
+ class Verilator(Simulator):
13
+ """Run and compile funcs for Verilator."""
14
+
15
+ DefaultDriver = CosimCollateralDir / "driver.cpp"
16
+
17
+ def __init__(
18
+ self,
19
+ sources: SourceFiles,
20
+ run_dir: Path,
21
+ debug: bool,
22
+ run_stdout_callback: Optional[Callable[[str], None]] = None,
23
+ run_stderr_callback: Optional[Callable[[str], None]] = None,
24
+ compile_stdout_callback: Optional[Callable[[str], None]] = None,
25
+ compile_stderr_callback: Optional[Callable[[str], None]] = None,
26
+ make_default_logs: bool = True,
27
+ macro_definitions: Optional[Dict[str, str]] = None,
28
+ ):
29
+ super().__init__(
30
+ sources=sources,
31
+ run_dir=run_dir,
32
+ debug=debug,
33
+ run_stdout_callback=run_stdout_callback,
34
+ run_stderr_callback=run_stderr_callback,
35
+ compile_stdout_callback=compile_stdout_callback,
36
+ compile_stderr_callback=compile_stderr_callback,
37
+ make_default_logs=make_default_logs,
38
+ macro_definitions=macro_definitions,
39
+ )
40
+ self.verilator = "verilator"
41
+ if "VERILATOR_PATH" in os.environ:
42
+ self.verilator = os.environ["VERILATOR_PATH"]
43
+
44
+ def compile_commands(self) -> List[List[str]]:
45
+ cmd: List[str] = [
46
+ self.verilator,
47
+ "--cc",
48
+ ]
49
+
50
+ if self.macro_definitions:
51
+ cmd += [
52
+ f"+define+{k}={v}" if v is not None else f"+define+{k}"
53
+ for k, v in self.macro_definitions.items()
54
+ ]
55
+
56
+ cmd += [
57
+ "--top-module",
58
+ self.sources.top,
59
+ "-DSIMULATION",
60
+ "-Wno-TIMESCALEMOD",
61
+ "-Wno-fatal",
62
+ "-sv",
63
+ "--exe",
64
+ "--build",
65
+ "-j",
66
+ "0",
67
+ "--output-split",
68
+ "--autoflush",
69
+ "--assert",
70
+ str(Verilator.DefaultDriver),
71
+ ]
72
+ cflags = [
73
+ "-DTOP_MODULE=" + self.sources.top,
74
+ ]
75
+ if self.debug:
76
+ cmd += [
77
+ "--trace-fst", "--trace-params", "--trace-structs",
78
+ "--trace-underscore"
79
+ ]
80
+ cflags.append("-DTRACE")
81
+ if len(cflags) > 0:
82
+ cmd += ["-CFLAGS", " ".join(cflags)]
83
+ if len(self.sources.dpi_so) > 0:
84
+ cmd += ["-LDFLAGS", " ".join(["-l" + so for so in self.sources.dpi_so])]
85
+ cmd += [str(p) for p in self.sources.rtl_sources]
86
+ return [cmd]
87
+
88
+ def run_command(self, gui: bool):
89
+ if gui:
90
+ raise RuntimeError("Verilator does not support GUI mode.")
91
+ exe = Path.cwd() / "obj_dir" / ("V" + self.sources.top)
92
+ return [str(exe)]