[circt-cocotb] Refactor slightly and add Questa support

This commit is contained in:
John Demme 2024-12-17 18:14:27 +00:00
parent 134617d702
commit 50e3f9faff
1 changed files with 67 additions and 25 deletions

View File

@ -5,7 +5,7 @@ import os
import subprocess
import sys
import re
from cocotb_test.simulator import run
import cocotb_test.simulator as csim
def parseArgs(args):
@ -22,7 +22,7 @@ def parseArgs(args):
help="Name of the top level verilog module.")
argparser.add_argument("--simulator",
choices=['icarus'],
choices=['icarus', 'questa'],
default="icarus",
help="Name of the simulator to use.")
@ -31,10 +31,16 @@ def parseArgs(args):
required=True,
help="Name of the python module.")
argparser.add_argument("--pythonFolders",
type=str,
default="",
help="The folders where cocotb should include from, separated by commas.")
argparser.add_argument(
"--pythonFolders",
type=str,
default="",
help="The folders where cocotb should include from, separated by commas.")
argparser.add_argument(
"--gui",
action="store_true",
help="Run the simulator with a GUI. Only supported by Questa.")
argparser.add_argument(
"sources",
@ -44,10 +50,12 @@ def parseArgs(args):
return argparser.parse_args(args[1:])
class _IVerilogHandler:
class Icarus(csim.Icarus):
""" Class for handling icarus-verilog specific commands and patching."""
def __init__(self):
def __init__(self, **kwargs):
super().__init__(**kwargs)
# Ensure that iverilog is available in path and it is at least iverilog v11
try:
out = subprocess.check_output(["iverilog", "-V"])
@ -64,7 +72,10 @@ class _IVerilogHandler:
if float(ver) < 11:
raise Exception(f"Icarus Verilog version must be >= 11, got {ver}")
def extra_compile_args(self, objDir):
def run(self, objDir, gui=False):
if gui:
raise Exception("GUI is not supported by Icarus Verilog")
# If no timescale is defined in the source code, icarus assumes a
# timescale of '1'. This prevents cocotb from creating small timescale clocks.
# Since a timescale is not emitted by default from export-verilog, make our
@ -73,7 +84,41 @@ class _IVerilogHandler:
with open(cmd_file, "w+") as f:
f.write("+timescale+1ns/1ps")
return [f"-f{cmd_file}"]
self.compile_args.append(f"-f{cmd_file}")
return super().run()
class Questa(csim.Questa):
""" Class for handling icarus-verilog specific commands and patching."""
def __init__(self, **kwargs):
super().__init__(**kwargs)
# Ensure that iverilog is available in path and it is at least iverilog v11
try:
out = subprocess.check_output(["vlog", "-version"])
except subprocess.CalledProcessError:
raise Exception("vlog not found in path")
# find the 'Icarus Verilog version #' string and extract the version number
# using a regex
ver_re = r"QuestaSim-64 vlog (\d+\.\d+)"
ver_match = re.search(ver_re, out.decode("utf-8"))
if ver_match is None:
raise Exception("Could not find Questa version")
def run(self, objDir, gui=False):
# If no timescale is defined in the source code, icarus assumes a
# timescale of '1'. This prevents cocotb from creating small timescale clocks.
# Since a timescale is not emitted by default from export-verilog, make our
# lives easier and create a minimum timescale through the command-line.
cmd_file = os.path.join(objDir, "cmds.f")
with open(cmd_file, "w+") as f:
f.write("+timescale+1ns/1ps")
self.gui = gui
self.extra_compile_args = ["-f", f"{cmd_file}"]
return super().run()
def main():
@ -96,28 +141,25 @@ def main():
except subprocess.CalledProcessError:
raise Exception(
"'make' is not available, and is required to run cocotb tests.")
kwargs = {
"module": args.pythonModule,
"toplevel": args.topLevel,
"toplevel_lang": "verilog",
"verilog_sources": sources,
"python_search": [f.strip() for f in args.pythonFolders.split(",")],
"work_dir": objDir,
}
try:
if args.simulator == "icarus":
simhandler = _IVerilogHandler()
sim = Icarus(**kwargs)
elif args.simulator == "questa":
sim = Questa(**kwargs)
else:
raise Exception(f"Unknown simulator: {args.simulator}")
except Exception as e:
raise Exception(f"Failed to initialize simulator handler: {e}")
# Simulator-specific extra compile args.
compileArgs = []
if simhandler:
compileArgs += simhandler.extra_compile_args(objDir)
run(simulator=args.simulator,
module=args.pythonModule,
toplevel=args.topLevel,
toplevel_lang="verilog",
verilog_sources=sources,
python_search=[f.strip() for f in args.pythonFolders.split(",")],
work_dir=objDir,
compile_args=compileArgs)
sim.run(objDir, gui=args.gui)
if __name__ == "__main__":