Initial Commit - Forked from PeakRDL-regblock @ a440cc19769069be831d267505da4f3789a26695

This commit is contained in:
Arnav Sacheti
2025-10-10 22:28:36 -07:00
commit 9bf5cd1e68
308 changed files with 19414 additions and 0 deletions

View File

@@ -0,0 +1,39 @@
from typing import Type, Optional, List
import functools
from .base import Simulator
from .questa import Questa
from .xilinx import XilinxXSIM
from .xcelium import Xcelium
from .stub import StubSimulator
ALL_SIMULATORS: List[Simulator]
ALL_SIMULATORS = [
Questa,
XilinxXSIM,
Xcelium,
StubSimulator,
]
@functools.lru_cache()
def get_simulator_cls(name: str) -> Optional[Type[Simulator]]:
if name == "skip":
return None
if name == "auto":
# Find the first simulator that is installed
for sim_cls in ALL_SIMULATORS:
if sim_cls is StubSimulator:
# Never offer the stub as an automatic option
continue
if sim_cls.is_installed():
return sim_cls
raise ValueError("Could not find any installed simulators")
# Look up which explicit simulator name was specified
for sim_cls in ALL_SIMULATORS:
if sim_cls.name == name:
if not sim_cls.is_installed():
raise ValueError("Simulator '%s' is not installed" % sim_cls.name)
return sim_cls
raise RuntimeError

View File

@@ -0,0 +1,35 @@
from typing import TYPE_CHECKING, List
if TYPE_CHECKING:
from ..sim_testcase import SimTestCase
class Simulator:
name = ""
@classmethod
def is_installed(cls) -> bool:
raise NotImplementedError
def __init__(self, testcase: 'SimTestCase' = None) -> None:
self.testcase = testcase
@property
def gui_mode(self) -> bool:
return self.testcase.request.config.getoption("--gui")
@property
def tb_files(self) -> List[str]:
files = []
files.extend(self.testcase.cpuif.get_sim_files())
files.extend(self.testcase.get_extra_tb_files())
files.append("regblock_pkg.sv")
files.append("regblock.sv")
files.append("tb.sv")
return files
def compile(self) -> None:
raise NotImplementedError
def run(self, plusargs:List[str] = None) -> None:
raise NotImplementedError

View File

@@ -0,0 +1,84 @@
from typing import List
import subprocess
import os
import shutil
from .base import Simulator
class Questa(Simulator):
name = "questa"
@classmethod
def is_installed(cls) -> bool:
return (
shutil.which("vlog") is not None
and shutil.which("vsim") is not None
)
def compile(self) -> None:
cmd = [
"vlog", "-sv", "-quiet", "-l", "build.log",
"+incdir+%s" % os.path.join(os.path.dirname(__file__), ".."),
# Use strict LRM conformance
"-svinputport=net",
# all warnings are errors
"-warning", "error",
# Ignore noisy warning about vopt-time checking of always_comb/always_latch
"-suppress", "2583",
# Suppress "error" about use of the `line directive
"-suppress", "13465",
]
# Add source files
cmd.extend(self.tb_files)
# Run command!
subprocess.run(cmd, check=True)
def run(self, plusargs:List[str] = None) -> None:
plusargs = plusargs or []
test_name = self.testcase.request.node.name
# call vsim
cmd = [
"vsim", "-quiet",
"-voptargs=+acc",
"-msgmode", "both",
"-l", "%s.log" % test_name,
"-wlf", "%s.wlf" % test_name,
"tb",
"-do", "set WildcardFilter [lsearch -not -all -inline $WildcardFilter Memory]",
"-do", "log -r /*;",
]
if self.gui_mode:
cmd.append("-i")
else:
cmd.extend([
"-do", "run -all; exit;",
"-c",
])
for plusarg in plusargs:
cmd.append("+" + plusarg)
subprocess.run(cmd, check=True)
self.assertSimLogPass("%s.log" % test_name)
def assertSimLogPass(self, path: str):
self.testcase.assertTrue(os.path.isfile(path))
with open(path, encoding="utf-8") as f:
for line in f:
if line.startswith("# ** Error"):
self.testcase.fail(line)
elif line.startswith("# ** Fatal"):
self.testcase.fail(line)

View File

@@ -0,0 +1,17 @@
from typing import List
from .base import Simulator
class StubSimulator(Simulator):
name = "stub"
@classmethod
def is_installed(cls) -> bool:
# Always available!
return True
def compile(self) -> None:
pass
def run(self, plusargs: List[str] = None) -> None:
pass

View File

@@ -0,0 +1,86 @@
from typing import List
import subprocess
import os
import shutil
from .base import Simulator
class Xcelium(Simulator):
"""
Don't use the Xcelium simulator, it is unable to compile & run any testcases.
As observed in 25.03.006:
- Using unpacked structs with more than 2 levels of nesting in clocking blocks is not
supported.
"""
name = "xcelium"
@classmethod
def is_installed(cls) -> bool:
return (
shutil.which("xrun") is not None
)
def compile(self) -> None:
# Compile and elaborate into a snapshot
cmd = [
"xrun",
"-64bit",
"-elaborate",
"-sv",
"-log build.log",
"-timescale 10ps/1ps",
"-ENABLE_DS_UNPS", # Allow ".*" DUT connection with unpacked structs
"-nowarn LNDER6", # Suppress warning about the `line 2 "lib/tb_base.sv" 0 file location
"-nowarn SPDUSD", # Suppress warning about unused include directory
"-incdir %s" % os.path.join(os.path.dirname(__file__), "..")
]
if self.gui_mode:
cmd.append("-access +rwc")
# Add source files
cmd.extend(self.tb_files)
# Run command!
subprocess.run(cmd, check=True)
def run(self, plusargs:List[str] = None) -> None:
plusargs = plusargs or []
test_name = self.testcase.request.node.name
# Call xrun on the elaborated snapshot
cmd = [
"xrun",
"-64bit",
"-log %s.log" % test_name,
"-r worklib.tb:sv"
]
if self.gui_mode:
cmd.append("-gui")
cmd.append('-input "@database -open waves -into waves.shm -shm -default -event"')
cmd.append('-input "@probe -create tb -depth all -tasks -functions -all -packed 4k \
-unpacked 16k -memories -dynamic -variables -database waves"')
else:
cmd.extend([
"-input", "@run",
])
for plusarg in plusargs:
cmd.append("+" + plusarg)
subprocess.run(cmd, check=True)
self.assertSimLogPass("%s.log" % test_name)
def assertSimLogPass(self, path: str):
self.testcase.assertTrue(os.path.isfile(path))
with open(path, encoding="utf-8") as f:
for line in f:
if line.startswith("xmsim: *E"):
self.testcase.fail(line)
elif line.startswith("xmsim: *F"):
self.testcase.fail(line)

View File

@@ -0,0 +1,74 @@
from typing import List
import subprocess
import os
import shutil
from .base import Simulator
class XilinxXSIM(Simulator):
name = "xsim"
@classmethod
def is_installed(cls) -> bool:
return (
shutil.which("xvlog") is not None
and shutil.which("xelab") is not None
and shutil.which("xsim") is not None
)
def compile(self) -> None:
cmd = [
"xvlog", "--sv",
"--log", "compile.log",
"--include", os.path.join(os.path.dirname(__file__), ".."),
"--define", "XILINX_XSIM",
]
cmd.extend(self.tb_files)
subprocess.run(cmd, check=True)
cmd = [
"xelab",
"--log", "elaborate.log",
"--timescale", "1ps/1ps",
"--debug", "all",
"tb",
]
subprocess.run(cmd, check=True)
def run(self, plusargs:List[str] = None) -> None:
plusargs = plusargs or []
test_name = self.testcase.request.node.name
# call xsim
cmd = ["xsim"]
if self.gui_mode:
cmd.append("--gui")
else:
cmd.append("-R")
cmd.extend([
"--log", "%s.log" % test_name,
"tb",
])
for plusarg in plusargs:
cmd.append("--testplusarg")
cmd.append(plusarg)
subprocess.run(cmd, check=True)
self.assertSimLogPass("%s.log" % test_name)
def assertSimLogPass(self, path: str):
self.testcase.assertTrue(os.path.isfile(path))
with open(path, encoding="utf-8") as f:
for line in f:
if line.startswith("Error:"):
self.testcase.fail(line)
elif line.startswith("Fatal:"):
self.testcase.fail(line)
elif line.startswith("FATAL_ERROR:"):
self.testcase.fail(line)