18from pathlib
import Path
26from typing
import Dict, List
28_thisdir = Path(__file__).parent
29CosimCollateralDir = _thisdir.parent /
"cosim"
33 """Check if a TCP port is open locally."""
34 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
35 result = sock.connect_ex((
'127.0.0.1', port))
37 return True if result == 0
else False
44 self.user: List[Path] = []
46 self.dpi_so: List[str] = [
"EsiCosimDpiServer"]
48 self.dpi_sv: List[Path] = [
49 CosimCollateralDir /
"Cosim_DpiPkg.sv",
50 CosimCollateralDir /
"Cosim_Endpoint.sv",
51 CosimCollateralDir /
"Cosim_Manifest.sv",
57 """Add all the RTL files in a directory to the source list."""
58 for file
in sorted(dir.iterdir()):
59 if file.is_file()
and (file.suffix ==
".sv" or file.suffix ==
".v"):
65 """Return a list of all the DPI shared object files."""
67 def find_so(name: str) -> Path:
68 for path
in Simulator.get_env().get(
"LD_LIBRARY_PATH",
"").split(
":"):
70 so = Path(path) / f
"{name}.dll"
72 so = Path(path) / f
"lib{name}.so"
75 raise FileNotFoundError(f
"Could not find {name}.so in LD_LIBRARY_PATH")
77 return [find_so(name)
for name
in self.dpi_so]
81 """Return a list of all the RTL source files."""
82 return self.dpi_sv + self.user
92 def __init__(self, sources: SourceFiles, run_dir: Path, debug: bool):
92 def __init__(self, sources: SourceFiles, run_dir: Path, debug: bool):
…
99 """Get the environment variables to locate shared objects."""
101 env = os.environ.copy()
102 env[
"LIBRARY_PATH"] = env.get(
"LIBRARY_PATH",
"") +
":" + str(
103 _thisdir.parent /
"lib")
104 env[
"LD_LIBRARY_PATH"] = env.get(
"LD_LIBRARY_PATH",
"") +
":" + str(
105 _thisdir.parent /
"lib")
109 """Compile the sources. Returns the exit code of the simulation compiler."""
110 assert False,
"Must be implemented by subclass"
114 self.
run_dir.mkdir(parents=
True, exist_ok=
True)
115 with (self.
run_dir /
"compile_stdout.log").open(
"w")
as stdout, (
116 self.
run_dir /
"compile_stderr.log").open(
"w")
as stderr:
118 stderr.write(
" ".join(cmd) +
"\n")
119 cp = subprocess.run(cmd,
120 env=Simulator.get_env(),
123 stdout.write(cp.stdout)
124 stderr.write(cp.stderr)
125 if cp.returncode != 0:
126 print(
"====== Compilation failure:")
135 """Return the command to run the simulation."""
136 assert False,
"Must be implemented by subclass"
138 def run(self, inner_command: str, gui: bool =
False) -> int:
139 """Start the simulation then run the command specified. Kill the simulation
140 when the command exits."""
147 self.
run_dir.mkdir(parents=
True, exist_ok=
True)
148 simStdout = open(self.
run_dir /
"sim_stdout.log",
"w")
149 simStderr = open(self.
run_dir /
"sim_stderr.log",
"w")
153 portFileName = self.
run_dir /
"cosim.cfg"
154 if os.path.exists(portFileName):
155 os.remove(portFileName)
158 simEnv = Simulator.get_env()
160 simEnv[
"COSIM_DEBUG_FILE"] =
"cosim_debug.log"
161 if "DEBUG_PERIOD" not in simEnv:
163 simEnv[
"DEBUG_PERIOD"] =
"1"
169 preexec_fn=os.setsid)
175 while (
not os.path.exists(portFileName))
and \
176 simProc.poll()
is None:
179 if checkCount > 200
and not gui:
180 raise Exception(f
"Cosim never wrote cfg file: {portFileName}")
183 portFile = open(portFileName,
"r")
184 for line
in portFile.readlines():
185 m = re.match(
"port: (\\d+)", line)
187 port = int(m.group(1))
195 raise Exception(f
"Cosim RPC port ({port}) never opened")
196 if simProc.poll()
is not None:
197 raise Exception(
"Simulation exited early")
201 testEnv = os.environ.copy()
202 testEnv[
"ESI_COSIM_PORT"] = str(port)
203 testEnv[
"ESI_COSIM_HOST"] =
"localhost"
204 return subprocess.run(inner_command, cwd=os.getcwd(),
205 env=testEnv).returncode
209 os.killpg(os.getpgid(simProc.pid), signal.SIGINT)
212 simProc.wait(timeout=1.0)
213 except subprocess.TimeoutExpired:
138 def run(self, inner_command: str, gui: bool =
False) -> int:
…
219 """Run and compile funcs for Verilator."""
221 DefaultDriver = CosimCollateralDir /
"driver.cpp"
223 def __init__(self, sources: SourceFiles, run_dir: Path, debug: bool):
224 super().
__init__(sources, run_dir, debug)
227 if "VERILATOR_PATH" in os.environ:
228 self.
verilator = os.environ[
"VERILATOR_PATH"]
223 def __init__(self, sources: SourceFiles, run_dir: Path, debug: bool):
…
243 str(Verilator.DefaultDriver),
246 "-DTOP_MODULE=" + self.
sources.top,
250 "--trace",
"--trace-params",
"--trace-structs",
"--trace-underscore"
252 cflags.append(
"-DTRACE")
254 cmd += [
"-CFLAGS",
" ".join(cflags)]
255 if len(self.
sources.dpi_so) > 0:
256 cmd += [
"-LDFLAGS",
" ".join([
"-l" + so
for so
in self.
sources.dpi_so])]
257 cmd += [str(p)
for p
in self.
sources.rtl_sources]
262 raise RuntimeError(
"Verilator does not support GUI mode.")
263 exe = Path.cwd() /
"obj_dir" / (
"V" + self.
sources.top)
268 """Run and compile funcs for Questasim."""
270 DefaultDriver = CosimCollateralDir /
"driver.sv"
277 "onerror { quit -f -code 1 }",
279 sources = self.
sources.rtl_sources
280 sources.append(Questa.DefaultDriver)
282 cmds.append(f
"vlog -incr +acc -sv +define+TOP_MODULE={self.sources.top}"
283 f
" +define+SIMULATION {str(src)}")
284 cmds.append(f
"vopt -incr driver -o driver_opt +acc")
288 with open(
"compile.do",
"w")
as f:
294 [
"vsim",
"-batch",
"-do",
"compile.do"],
314 for lib
in self.
sources.dpi_so_paths():
315 svLib = os.path.splitext(lib)[0]
316 cmd.append(
"-sv_lib")
320 def run(self, inner_command: str, gui: bool =
False) -> int:
321 """Override the Simulator.run() to add a soft link in the run directory (to
322 the work directory) before running vsim the usual way."""
325 workDir = self.
run_dir /
"work"
326 if not workDir.exists():
327 os.symlink(Path(os.getcwd()) /
"work", workDir)
330 return super().
run(inner_command, gui)
320 def run(self, inner_command: str, gui: bool =
False) -> int:
…
334 argparser = argparse.ArgumentParser(
335 description=
"Wrap a 'inner_cmd' in an ESI cosimulation environment.",
336 formatter_class=argparse.RawDescriptionHelpFormatter,
337 epilog=textwrap.dedent(
"""
339 - For Verilator, libEsiCosimDpiServer.so must be in the dynamic
340 library runtime search path (LD_LIBRARY_PATH) and link time path
341 (LIBRARY_PATH). If it is installed to a standard location (e.g.
342 /usr/lib), this should be handled automatically.
343 - This script needs to sit in the same directory as the ESI support
344 SystemVerilog (e.g. Cosim_DpiPkg.sv, Cosim_MMIO.sv, etc.). It can,
345 however, be soft linked to a different location.
346 - The simulator executable(s) must be in your PATH.
349 argparser.add_argument(
353 help=
"Name of the RTL simulator to use or path to an executable.")
354 argparser.add_argument(
"--rundir",
356 help=
"Directory in which simulation should be run.")
357 argparser.add_argument(
359 default=
"ESI_Cosim_Top",
360 help=
"Name of the 'top' module to use in the simulation.")
361 argparser.add_argument(
"--no-compile",
363 help=
"Do not run the compile.")
364 argparser.add_argument(
"--debug",
366 help=
"Enable debug output.")
367 argparser.add_argument(
"--gui",
369 help=
"Run the simulator in GUI mode (if supported).")
370 argparser.add_argument(
"--source",
371 help=
"Directories containing the source files.",
374 argparser.add_argument(
"inner_cmd",
375 nargs=argparse.REMAINDER,
376 help=
"Command to run in the simulation environment.")
379 argparser.print_help()
381 args = argparser.parse_args(args[1:])
384 sources.add_dir(Path(args.source))
386 if args.sim ==
"verilator":
387 sim =
Verilator(sources, Path(args.rundir), args.debug)
388 elif args.sim ==
"questa":
389 sim =
Questa(sources, Path(args.rundir), args.debug)
391 print(
"Unknown simulator: " + args.sim)
392 print(
"Supported simulators: ")
393 print(
" - verilator")
397 if not args.no_compile:
401 return sim.run(args.inner_cmd[1:], gui=args.gui)
404if __name__ ==
'__main__':
static void print(TypedAttr val, llvm::raw_ostream &os)
static StringAttr append(StringAttr base, const Twine &suffix)
Return a attribute with the specified suffix appended.
List[List[str]] compile_commands(self)
int run(self, str inner_command, bool gui=False)
List[str] internal_compile_commands(self)
List[str] run_command(self, bool gui)
List[str] run_command(self, bool gui)
int run(self, str inner_command, bool gui=False)
__init__(self, SourceFiles sources, Path run_dir, bool debug)
List[List[str]] compile_commands(self)
List[Path] rtl_sources(self)
List[Path] dpi_so_paths(self)
None __init__(self, str top)
run_command(self, bool gui)
List[List[str]] compile_commands(self)
__init__(self, SourceFiles sources, Path run_dir, bool debug)