From d689bb70774be68d426552c81719a722d47659ce Mon Sep 17 00:00:00 2001 From: Alex Mykyta Date: Sun, 22 Oct 2023 11:04:43 -0700 Subject: [PATCH] Reorganize how tb infrstructure selects toolchains --- .github/workflows/build.yml | 4 +- .gitignore | 1 + tests/README.md | 12 +-- tests/conftest.py | 25 ++++++ tests/lib/base_testcase.py | 76 ++++++++----------- tests/lib/cpuifs/base.py | 4 +- tests/lib/sim_testcase.py | 63 ++++++++------- tests/lib/simulators/__init__.py | 71 ++++++++--------- tests/lib/simulators/base.py | 31 ++++++++ tests/lib/simulators/questa.py | 20 +++-- tests/lib/simulators/stub.py | 17 +++++ tests/lib/simulators/xilinx.py | 27 +++++-- tests/lib/synth_testcase.py | 37 ++++----- tests/lib/synthesizers/__init__.py | 30 ++++++++ tests/lib/synthesizers/base.py | 17 +++++ tests/lib/synthesizers/vivado.py | 29 +++++++ .../vivado_scripts}/constr.xdc | 0 .../vivado_scripts}/run.tcl | 0 tests/lib/tb_base.sv | 12 +-- tests/run.sh | 5 +- tests/test_buffered_swacc_swmod/testcase.py | 1 + tests/test_counter_basics/testcase.py | 1 + tests/test_read_fanin/tb_template.sv | 4 +- tests/test_structural_sw_rw/testcase.py | 29 ------- 24 files changed, 330 insertions(+), 186 deletions(-) create mode 100644 tests/conftest.py create mode 100644 tests/lib/simulators/base.py create mode 100644 tests/lib/simulators/stub.py create mode 100644 tests/lib/synthesizers/__init__.py create mode 100644 tests/lib/synthesizers/base.py create mode 100644 tests/lib/synthesizers/vivado.py rename tests/lib/{synthesis/vivado => synthesizers/vivado_scripts}/constr.xdc (100%) rename tests/lib/{synthesis/vivado => synthesizers/vivado_scripts}/run.tcl (100%) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e4c5392..18242f6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -52,9 +52,7 @@ jobs: - name: Test run: | cd tests - export SKIP_SYNTH_TESTS=1 - export STUB_SIMULATOR=1 - pytest --cov=peakrdl_regblock + pytest --cov=peakrdl_regblock --synth-tool skip --sim-tool stub - name: Coveralls env: diff --git a/.gitignore b/.gitignore index 7278eb0..ac5e70c 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ **/_build **/*.out **/transcript +**/htmlcov **/*.log **/*.pb **/.Xil diff --git a/tests/README.md b/tests/README.md index 6ccc99b..528d0b7 100644 --- a/tests/README.md +++ b/tests/README.md @@ -30,11 +30,6 @@ To run synthesis tests, Vivado needs to be installed and visible via the PATH en Vivado can be downloaded for free from: https://www.xilinx.com/support/download.html -To skip synthesis tests, export the following environment variable: -```bash -export SKIP_SYNTH_TESTS=1 -``` - ## Python Packages @@ -62,6 +57,13 @@ You can also run a specific testcase. For example: pytest tests/test_hw_access ``` +Command-line arguments can be used to explicitly select which simulator/synthesis tools are used +If unspecified, the tool will be selected automatically based on what you have installed. +```bash +pytest --sim-tool questa --synth-tool vivado +``` + + Alternatively, launch tests using the helper script. This handles installing dependencies into a virtual environment automatically. ```bash diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..26a0575 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,25 @@ +def pytest_addoption(parser): + parser.addoption( + "--sim-tool", + choices=["questa", "xilinx", "stub", "skip", "auto"], + default="auto", + help=""" + Select the simulator to use. + + stub: run the testcase using a no-op simulator stub + skip: skip all the simulation tests + auto: choose the best simulator based on what is installed + """ + ) + + parser.addoption( + "--synth-tool", + choices=["vivado", "skip", "auto"], + default="auto", + help=""" + Select the synthesis tool to use. + + skip: skip all the simulation tests + auto: choose the best tool based on what is installed + """ + ) diff --git a/tests/lib/base_testcase.py b/tests/lib/base_testcase.py index ca016d0..e69f7f3 100644 --- a/tests/lib/base_testcase.py +++ b/tests/lib/base_testcase.py @@ -1,4 +1,4 @@ -from typing import Optional, List +from typing import Optional import unittest import os import glob @@ -49,41 +49,37 @@ class BaseTestCase(unittest.TestCase): def _load_request(self, request): self.request = request - @classmethod - def get_testcase_dir(cls) -> str: - class_dir = os.path.dirname(inspect.getfile(cls)) + def get_testcase_dir(self) -> str: + class_dir = os.path.dirname(inspect.getfile(self.__class__)) return class_dir - @classmethod - def get_run_dir(cls) -> str: - this_dir = cls.get_testcase_dir() - run_dir = os.path.join(this_dir, "run.out", cls.__name__) + def get_run_dir(self) -> str: + this_dir = self.get_testcase_dir() + run_dir = os.path.join(this_dir, "run.out", self.__class__.__name__) return run_dir - @classmethod - def _write_params(cls) -> None: + def _write_params(self) -> None: """ Write out the class parameters to a file so that it is easier to debug how a testcase was parameterized """ - path = os.path.join(cls.get_run_dir(), "params.txt") + path = os.path.join(self.get_run_dir(), "params.txt") with open(path, 'w') as f: - for k, v in cls.__dict__.items(): + for k, v in self.__class__.__dict__.items(): if k.startswith("_") or callable(v): continue f.write(f"{k}: {repr(v)}\n") - @classmethod - def _export_regblock(cls): + def _export_regblock(self): """ Call the peakrdl_regblock exporter to generate the DUT """ - this_dir = cls.get_testcase_dir() + this_dir = self.get_testcase_dir() - if cls.rdl_file: - rdl_file = cls.rdl_file + if self.rdl_file: + rdl_file = self.rdl_file else: # Find any *.rdl file in testcase dir rdl_file = glob.glob(os.path.join(this_dir, "*.rdl"))[0] @@ -98,45 +94,33 @@ def _export_regblock(cls): rdlc.compile_file(udp_file) rdlc.compile_file(rdl_file) - root = rdlc.elaborate(cls.rdl_elab_target, "regblock", cls.rdl_elab_params) + root = rdlc.elaborate(self.rdl_elab_target, "regblock", self.rdl_elab_params) - cls.exporter.export( + self.exporter.export( root, - cls.get_run_dir(), + self.get_run_dir(), module_name="regblock", package_name="regblock_pkg", - cpuif_cls=cls.cpuif.cpuif_cls, - retime_read_fanin=cls.retime_read_fanin, - retime_read_response=cls.retime_read_response, - reuse_hwif_typedefs=cls.reuse_hwif_typedefs, - retime_external_reg=cls.retime_external, - retime_external_regfile=cls.retime_external, - retime_external_mem=cls.retime_external, - retime_external_addrmap=cls.retime_external, - default_reset_activelow=cls.default_reset_activelow, - default_reset_async=cls.default_reset_async, + cpuif_cls=self.cpuif.cpuif_cls, + retime_read_fanin=self.retime_read_fanin, + retime_read_response=self.retime_read_response, + reuse_hwif_typedefs=self.reuse_hwif_typedefs, + retime_external_reg=self.retime_external, + retime_external_regfile=self.retime_external, + retime_external_mem=self.retime_external, + retime_external_addrmap=self.retime_external, + default_reset_activelow=self.default_reset_activelow, + default_reset_async=self.default_reset_async, ) - @classmethod - def setUpClass(cls): + def setUp(self) -> None: # Create fresh build dir - run_dir = cls.get_run_dir() + run_dir = self.get_run_dir() if os.path.exists(run_dir): shutil.rmtree(run_dir) pathlib.Path(run_dir).mkdir(parents=True, exist_ok=True) - cls._write_params() + self._write_params() # Convert testcase RDL file --> SV - cls._export_regblock() - - - def setUp(self) -> None: - # cd into the run directory - self.original_cwd = os.getcwd() - os.chdir(self.get_run_dir()) - - - def run_test(self, plusargs:List[str] = None) -> None: - simulator = self.simulator_cls(testcase_cls_inst=self) - simulator.run(plusargs) + self._export_regblock() diff --git a/tests/lib/cpuifs/base.py b/tests/lib/cpuifs/base.py index 3f2b6f5..c53358f 100644 --- a/tests/lib/cpuifs/base.py +++ b/tests/lib/cpuifs/base.py @@ -66,7 +66,7 @@ def get_synth_files(self) -> List[str]: return self._get_file_paths("rtl_files") - def get_tb_inst(self, tb_cls: 'SimTestCase', exporter: 'RegblockExporter') -> str: + def get_tb_inst(self, testcase: 'SimTestCase', exporter: 'RegblockExporter') -> str: class_dir = self._get_class_dir_of_variable("tb_template") loader = jj.FileSystemLoader(class_dir) jj_env = jj.Environment( @@ -77,7 +77,7 @@ def get_tb_inst(self, tb_cls: 'SimTestCase', exporter: 'RegblockExporter') -> st context = { "cpuif": self, - "cls": tb_cls, + "testcase": testcase, "exporter": exporter, "type": type, } diff --git a/tests/lib/sim_testcase.py b/tests/lib/sim_testcase.py index dd5fdb4..631061e 100644 --- a/tests/lib/sim_testcase.py +++ b/tests/lib/sim_testcase.py @@ -1,24 +1,21 @@ from typing import List import os + import jinja2 as jj +import pytest from .sv_line_anchor import SVLineAnchor -from .simulators.questa import Questa -from .simulators import StubSimulator +from .simulators import get_simulator_cls from .base_testcase import BaseTestCase -SIM_CLS = Questa -if os.environ.get("STUB_SIMULATOR", False): - SIM_CLS = StubSimulator - class SimTestCase(BaseTestCase): #: Abort test if it exceeds this number of clock cycles timeout_clk_cycles = 5000 - simulator_cls = SIM_CLS + incompatible_sim_tools = set() tb_template_file = "tb_template.sv" @@ -32,17 +29,14 @@ class SimTestCase(BaseTestCase): clocking_hwif_in = True clocking_hwif_out = True - - @classmethod - def get_extra_tb_files(cls) -> List[str]: + def get_extra_tb_files(self) -> List[str]: paths = [] - for path in cls.extra_tb_files: - path = os.path.join(cls.get_testcase_dir(), path) + for path in self.extra_tb_files: + path = os.path.join(self.get_testcase_dir(), path) paths.append(path) return paths - @classmethod - def _generate_tb(cls): + def _generate_tb(self): """ Render the testbench template into actual tb.sv """ @@ -57,32 +51,38 @@ def _generate_tb(cls): ) context = { - "cls": cls, - "exporter": cls.exporter, + "testcase": self, + "exporter": self.exporter, } # template path needs to be relative to the Jinja loader root - template_path = os.path.join(cls.get_testcase_dir(), cls.tb_template_file) + template_path = os.path.join(self.get_testcase_dir(), self.tb_template_file) template_path = os.path.relpath(template_path, template_root_path) template = jj_env.get_template(template_path) - output_path = os.path.join(cls.get_run_dir(), "tb.sv") + output_path = os.path.join(self.get_run_dir(), "tb.sv") stream = template.stream(context) stream.dump(output_path) - @classmethod - def setUpClass(cls): - super().setUpClass() + def setUp(self): + name = self.request.config.getoption("--sim-tool") + if name in self.incompatible_sim_tools: + pytest.skip() + simulator_cls = get_simulator_cls(name) + if simulator_cls is None: + pytest.skip() + + super().setUp() # Create testbench from template - cls._generate_tb() + self._generate_tb() - simulator = cls.simulator_cls(testcase_cls=cls) + simulator = simulator_cls(self) # cd into the build directory cwd = os.getcwd() - os.chdir(cls.get_run_dir()) + os.chdir(self.get_run_dir()) try: simulator.compile() finally: @@ -91,5 +91,16 @@ def setUpClass(cls): def run_test(self, plusargs:List[str] = None) -> None: - simulator = self.simulator_cls(testcase_cls_inst=self) - simulator.run(plusargs) + name = self.request.config.getoption("--sim-tool") + simulator_cls = get_simulator_cls(name) + simulator = simulator_cls(self) + + # cd into the build directory + cwd = os.getcwd() + os.chdir(self.get_run_dir()) + + try: + simulator.run(plusargs) + finally: + # cd back + os.chdir(cwd) diff --git a/tests/lib/simulators/__init__.py b/tests/lib/simulators/__init__.py index b0079e9..f8eef84 100644 --- a/tests/lib/simulators/__init__.py +++ b/tests/lib/simulators/__init__.py @@ -1,34 +1,37 @@ -from typing import Type, TYPE_CHECKING, List - -if TYPE_CHECKING: - from ..sim_testcase import SimTestCase - -class Simulator: - - def __init__(self, testcase_cls: 'Type[SimTestCase]' = None, testcase_cls_inst: 'SimTestCase' = None) -> None: - self.testcase_cls = testcase_cls - self.testcase_cls_inst = testcase_cls_inst - - @property - def tb_files(self) -> List[str]: - files = [] - files.extend(self.testcase_cls.cpuif.get_sim_files()) - files.extend(self.testcase_cls.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 - -class StubSimulator(Simulator): - def compile(self) -> None: - pass - - def run(self, plusargs:List[str] = None) -> None: - pass +from typing import Type, Optional, List +import functools + +from .base import Simulator +from .questa import Questa +from .xilinx import Xilinx +from .stub import StubSimulator + +ALL_SIMULATORS: List[Simulator] +ALL_SIMULATORS = [ + Questa, + Xilinx, + 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 diff --git a/tests/lib/simulators/base.py b/tests/lib/simulators/base.py new file mode 100644 index 0000000..2897666 --- /dev/null +++ b/tests/lib/simulators/base.py @@ -0,0 +1,31 @@ +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 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 diff --git a/tests/lib/simulators/questa.py b/tests/lib/simulators/questa.py index ed896f5..defe138 100644 --- a/tests/lib/simulators/questa.py +++ b/tests/lib/simulators/questa.py @@ -1,10 +1,20 @@ from typing import List import subprocess import os +import shutil -from . import Simulator +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", @@ -31,7 +41,7 @@ def compile(self) -> None: def run(self, plusargs:List[str] = None) -> None: plusargs = plusargs or [] - test_name = self.testcase_cls_inst.request.node.name + test_name = self.testcase.request.node.name # call vsim cmd = [ @@ -54,11 +64,11 @@ def run(self, plusargs:List[str] = None) -> None: def assertSimLogPass(self, path: str): - self.testcase_cls_inst.assertTrue(os.path.isfile(path)) + 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_cls_inst.fail(line) + self.testcase.fail(line) elif line.startswith("# ** Fatal"): - self.testcase_cls_inst.fail(line) + self.testcase.fail(line) diff --git a/tests/lib/simulators/stub.py b/tests/lib/simulators/stub.py new file mode 100644 index 0000000..6e54425 --- /dev/null +++ b/tests/lib/simulators/stub.py @@ -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 diff --git a/tests/lib/simulators/xilinx.py b/tests/lib/simulators/xilinx.py index b6e4440..13c8c46 100644 --- a/tests/lib/simulators/xilinx.py +++ b/tests/lib/simulators/xilinx.py @@ -1,22 +1,34 @@ from typing import List import subprocess import os +import shutil -from . import Simulator +from .base import Simulator class Xilinx(Simulator): """ Don't bother using the Xilinx simulator... Its buggy and extraordinarily slow. - As observed in v2021.1: + As observed in v2023.2: - clocking block assignments do not seem to actually simulate correctly. assignment statements get ignored or the values get mangled. - Streaming operators have all sorts of limitations. Keeping this here in case someday it works better... """ + name = "xilinx" + + @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", "XSIM", ] @@ -25,6 +37,7 @@ def compile(self) -> None: cmd = [ "xelab", + "--log", "elaborate.log", "--timescale", "1ns/1ps", "--debug", "all", "tb", @@ -35,7 +48,7 @@ def compile(self) -> None: def run(self, plusargs:List[str] = None) -> None: plusargs = plusargs or [] - test_name = self.testcase_cls_inst.request.node.name + test_name = self.testcase.request.node.name # call vsim cmd = [ @@ -54,13 +67,13 @@ def run(self, plusargs:List[str] = None) -> None: def assertSimLogPass(self, path: str): - self.testcase_cls_inst.assertTrue(os.path.isfile(path)) + 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_cls_inst.fail(line) + self.testcase.fail(line) elif line.startswith("Fatal:"): - self.testcase_cls_inst.fail(line) + self.testcase.fail(line) elif line.startswith("FATAL_ERROR:"): - self.testcase_cls_inst.fail(line) + self.testcase.fail(line) diff --git a/tests/lib/synth_testcase.py b/tests/lib/synth_testcase.py index cc56f0d..552902d 100644 --- a/tests/lib/synth_testcase.py +++ b/tests/lib/synth_testcase.py @@ -1,12 +1,11 @@ from typing import List -import subprocess import os import pytest from .base_testcase import BaseTestCase +from .synthesizers import get_synthesizer_cls -@pytest.mark.skipif(os.environ.get("SKIP_SYNTH_TESTS", False), reason="user skipped") class SynthTestCase(BaseTestCase): def _get_synth_files(self) -> List[str]: @@ -17,20 +16,24 @@ def _get_synth_files(self) -> List[str]: return files + def setUp(self) -> None: + name = self.request.config.getoption("--synth-tool") + synth_cls = get_synthesizer_cls(name) + if synth_cls is None: + pytest.skip() + super().setUp() def run_synth(self) -> None: - script = os.path.join( - os.path.dirname(__file__), - "synthesis/vivado/run.tcl" - ) - - cmd = [ - "vivado", "-nojournal", "-notrace", - "-mode", "batch", - "-log", "out.log", - "-source", script, - "-tclargs" - ] - cmd.extend(self._get_synth_files()) - - subprocess.run(cmd, check=True) + name = self.request.config.getoption("--synth-tool") + synth_cls = get_synthesizer_cls(name) + synth = synth_cls(self) + + # cd into the build directory + cwd = os.getcwd() + os.chdir(self.get_run_dir()) + + try: + synth.run() + finally: + # cd back + os.chdir(cwd) diff --git a/tests/lib/synthesizers/__init__.py b/tests/lib/synthesizers/__init__.py new file mode 100644 index 0000000..58d1c7e --- /dev/null +++ b/tests/lib/synthesizers/__init__.py @@ -0,0 +1,30 @@ +from typing import List, Optional, Type +import functools + +from .base import Synthesizer +from .vivado import Vivado + +ALL_SYNTHESIZERS: List[Synthesizer] +ALL_SYNTHESIZERS = [ + Vivado, +] + +@functools.lru_cache() +def get_synthesizer_cls(name: str) -> Optional[Type[Synthesizer]]: + if name == "skip": + return None + + if name == "auto": + # Find the first tool that is installed + for synth_cls in ALL_SYNTHESIZERS: + if synth_cls.is_installed(): + return synth_cls + raise ValueError("Could not find any installed synthesis tools") + + # Look up which explicit synth tool name was specified + for synth_cls in ALL_SYNTHESIZERS: + if synth_cls.name == name: + if not synth_cls.is_installed(): + raise ValueError("Synthesis tool '%s' is not installed" % synth_cls.name) + return synth_cls + raise RuntimeError diff --git a/tests/lib/synthesizers/base.py b/tests/lib/synthesizers/base.py new file mode 100644 index 0000000..5a3e36e --- /dev/null +++ b/tests/lib/synthesizers/base.py @@ -0,0 +1,17 @@ +from typing import TYPE_CHECKING, List + +if TYPE_CHECKING: + from ..synth_testcase import SynthTestCase + +class Synthesizer: + name = "" + + @classmethod + def is_installed(cls) -> bool: + raise NotImplementedError + + def __init__(self, testcase: 'SynthTestCase' = None) -> None: + self.testcase = testcase + + def run(self) -> None: + raise NotImplementedError diff --git a/tests/lib/synthesizers/vivado.py b/tests/lib/synthesizers/vivado.py new file mode 100644 index 0000000..857fac0 --- /dev/null +++ b/tests/lib/synthesizers/vivado.py @@ -0,0 +1,29 @@ +import os +import subprocess +import shutil + +from .base import Synthesizer + +class Vivado(Synthesizer): + name = "vivado" + + @classmethod + def is_installed(cls) -> bool: + return shutil.which("vivado") is not None + + def run(self) -> None: + script = os.path.join( + os.path.dirname(__file__), + "vivado_scripts/run.tcl" + ) + + cmd = [ + "vivado", "-nojournal", "-notrace", + "-mode", "batch", + "-log", "out.log", + "-source", script, + "-tclargs" + ] + cmd.extend(self.testcase._get_synth_files()) + + subprocess.run(cmd, check=True) diff --git a/tests/lib/synthesis/vivado/constr.xdc b/tests/lib/synthesizers/vivado_scripts/constr.xdc similarity index 100% rename from tests/lib/synthesis/vivado/constr.xdc rename to tests/lib/synthesizers/vivado_scripts/constr.xdc diff --git a/tests/lib/synthesis/vivado/run.tcl b/tests/lib/synthesizers/vivado_scripts/run.tcl similarity index 100% rename from tests/lib/synthesis/vivado/run.tcl rename to tests/lib/synthesizers/vivado_scripts/run.tcl diff --git a/tests/lib/tb_base.sv b/tests/lib/tb_base.sv index 7d7363e..9c6ea55 100644 --- a/tests/lib/tb_base.sv +++ b/tests/lib/tb_base.sv @@ -40,11 +40,11 @@ module tb; default clocking cb @(posedge clk); default input #1step output #1; output rst; -{%- if exporter.hwif.has_input_struct and cls.clocking_hwif_in %} +{%- if exporter.hwif.has_input_struct and testcase.clocking_hwif_in %} output hwif_in; {%- endif %} -{%- if exporter.hwif.has_output_struct and cls.clocking_hwif_out %} +{%- if exporter.hwif.has_output_struct and testcase.clocking_hwif_out %} input hwif_out; {%- endif %} @@ -61,7 +61,7 @@ module tb; //-------------------------------------------------------------------------- // CPUIF //-------------------------------------------------------------------------- - {{cls.cpuif.get_tb_inst(cls, exporter)|indent}} + {{testcase.cpuif.get_tb_inst(testcase, exporter)|indent}} //-------------------------------------------------------------------------- // DUT @@ -93,7 +93,7 @@ module tb; //-------------------------------------------------------------------------- initial begin cb.rst <= '1; - {%- if exporter.hwif.has_input_struct and cls.init_hwif_in %} + {%- if exporter.hwif.has_input_struct and testcase.init_hwif_in %} cb.hwif_in <= '{default: '0}; {%- endif %} @@ -112,8 +112,8 @@ module tb; // Monitor for timeout //-------------------------------------------------------------------------- initial begin - ##{{cls.timeout_clk_cycles}}; - $fatal(1, "Test timed out after {{cls.timeout_clk_cycles}} clock cycles"); + ##{{testcase.timeout_clk_cycles}}; + $fatal(1, "Test timed out after {{testcase.timeout_clk_cycles}} clock cycles"); end endmodule diff --git a/tests/run.sh b/tests/run.sh index b6f5612..ea1b0d8 100755 --- a/tests/run.sh +++ b/tests/run.sh @@ -19,10 +19,7 @@ pip install -U . cd $this_dir # Run unit tests -export SKIP_SYNTH_TESTS=1 -#export STUB_SIMULATOR=1 -export NO_XSIM=1 -pytest --workers auto --cov=peakrdl_regblock +pytest --workers auto --cov=peakrdl_regblock --synth-tool skip # Generate coverage report coverage html -i -d $this_dir/htmlcov diff --git a/tests/test_buffered_swacc_swmod/testcase.py b/tests/test_buffered_swacc_swmod/testcase.py index 835b5ef..41b42d2 100644 --- a/tests/test_buffered_swacc_swmod/testcase.py +++ b/tests/test_buffered_swacc_swmod/testcase.py @@ -1,5 +1,6 @@ from ..lib.sim_testcase import SimTestCase class Test(SimTestCase): + incompatible_sim_tools = {"xilinx"} def test_dut(self): self.run_test() diff --git a/tests/test_counter_basics/testcase.py b/tests/test_counter_basics/testcase.py index 835b5ef..41b42d2 100644 --- a/tests/test_counter_basics/testcase.py +++ b/tests/test_counter_basics/testcase.py @@ -1,5 +1,6 @@ from ..lib.sim_testcase import SimTestCase class Test(SimTestCase): + incompatible_sim_tools = {"xilinx"} def test_dut(self): self.run_test() diff --git a/tests/test_read_fanin/tb_template.sv b/tests/test_read_fanin/tb_template.sv index 519a1e5..1154c3f 100644 --- a/tests/test_read_fanin/tb_template.sv +++ b/tests/test_read_fanin/tb_template.sv @@ -2,9 +2,9 @@ {%- block declarations %} {% sv_line_anchor %} - localparam REGWIDTH = {{cls.regwidth}}; + localparam REGWIDTH = {{testcase.regwidth}}; localparam STRIDE = REGWIDTH/8; - localparam N_REGS = {{cls.n_regs}}; + localparam N_REGS = {{testcase.n_regs}}; {%- endblock %} diff --git a/tests/test_structural_sw_rw/testcase.py b/tests/test_structural_sw_rw/testcase.py index 9c947c4..afb1d82 100644 --- a/tests/test_structural_sw_rw/testcase.py +++ b/tests/test_structural_sw_rw/testcase.py @@ -1,13 +1,11 @@ import os from parameterized import parameterized_class -import pytest from ..lib.sim_testcase import SimTestCase from ..lib.synth_testcase import SynthTestCase from ..lib.test_params import get_permutations from ..lib.cpuifs import ALL_CPUIF -from ..lib.simulators.xilinx import Xilinx @@ -51,30 +49,3 @@ def test_dut(self): class TestSynth(SynthTestCase): def test_dut(self): self.run_synth() - - - -@pytest.mark.skipif(os.environ.get("STUB_SIMULATOR", False) or os.environ.get("NO_XSIM", False), reason="user skipped") -@parameterized_class(get_permutations({ - "cpuif": ALL_CPUIF, - "retime_read_fanin": [True, False], - "retime_read_response": [True, False], - "reuse_hwif_typedefs": [True, False], -})) -class TestVivado(SimTestCase): - """ - Vivado XSIM's implementation of clocking blocks is broken, which is heavily used - by the testbench infrastructure in most testcases. - Since this group of tests does not rely on writing HWIF values, the bugs in - xsim are avoided. - - Run this testcase using xsim to get some cross-simulator coverage. - Goal is to validate the generated RTL doesn't use constructs that offend xsim. - - This is skipped in CI stub tests as it doesn't add value - """ - - simulator_cls = Xilinx - - def test_dut(self): - self.run_test()