Skip to content

Commit

Permalink
Fixes due to mistake and Aldec integration (#53)
Browse files Browse the repository at this point in the history
  • Loading branch information
themperek authored Sep 23, 2019
1 parent 6ccb1d5 commit c8a64d2
Show file tree
Hide file tree
Showing 8 changed files with 324 additions and 81 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -156,3 +156,5 @@ waves.shm/
/.dvt

/cocotb_test/libs
.cocotb-results

2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,5 +54,5 @@ For cocotb tests/examples install cocotb in editable mode
```bash
git clone https://github.com/potentialventures/cocotb.git
pip install -e cocotb
SIM=icarus pytest -s --junitxml=test-results.xml tests
SIM=icarus pytest -s --junitxml=test-results.xml --cocotbxml=test-cocotb.xml tests
```
2 changes: 1 addition & 1 deletion azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ jobs:
- script: |
set SIM=icarus
pytest -s --junitxml=test-results.xml tests
pytest -s --junitxml=test-results.xml --cocotbxml=test-cocotb.xml tests
displayName: 'Test with pytest'
- script: |
Expand Down
91 changes: 64 additions & 27 deletions cocotb_test/build_libs.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,14 @@ def _rename_safe(target, link_name):

if sys.platform == "darwin": # On Mac there is an issue with rename? Workaround!
try:
os.symlink(target, link_name)
os.symlink(target, link_name)
except OSError as e:
if e.errno == errno.EEXIST:
os.remove(link_name)
os.symlink(target, link_name)
else:
raise e
return
return

if os.name == "nt": # On Windows there is an issue with symlink and rename? !Workaround!
shutil.copy2(target, link_name)
Expand Down Expand Up @@ -82,9 +82,7 @@ def _build_lib(lib, dist, build_dir):

target = os.path.join(os.path.abspath(dir_name), lib_name + "." + ext_name)
if target != lib_path:
_rename_safe(
lib_path, os.path.join(os.path.abspath(dir_name), lib_name + "." + ext_name)
)
_rename_safe(lib_path, os.path.join(os.path.abspath(dir_name), lib_name + "." + ext_name))

return dir_name, ext_name

Expand All @@ -109,16 +107,19 @@ def build_libs(build_dir="cocotb_build"):

ext_modules = []

ld_library = sysconfig.get_config_var("LDLIBRARY")
if ld_library:
python_lib_link = os.path.splitext(ld_library)[0][3:]
else:
python_version = sysconfig.get_python_version().replace(".", "")
python_lib_link = "python" + python_version

if os.name == "nt":
ext_name = "dll"
python_version = distutils.sysconfig.get_python_version()
python_version.replace(".", "")
python_lib = "python" + python_version + ".dll"
python_lib_link = python_lib.split(".")[0]
python_lib = python_lib_link + "." + ext_name
else:
python_lib = sysconfig.get_config_var("LDLIBRARY")
python_lib_link = os.path.splitext(python_lib)[0][3:]
ext_name = "so"
python_lib = "lib" + python_lib_link + "." + ext_name

include_dir = os.path.join(share_dir, "include")

Expand Down Expand Up @@ -207,9 +208,7 @@ def build_libs_common(build_dir_abs):
if os.name == "nt":
iverilog_path = find_executable("iverilog")
if iverilog_path is None:
logger.warning(
"Icarus Verilog executable not found. VPI interface will not be avaliable."
)
logger.warning("Icarus Verilog executable not found. VPI interface will not be avaliable.")
icarus_compile = False
else:
icarus_path = os.path.dirname(os.path.dirname(iverilog_path))
Expand All @@ -230,24 +229,19 @@ def build_libs_common(build_dir_abs):

_build_lib(libvpi_icarus, dist, icarus_build_dir)

_rename_safe(
os.path.join(icarus_build_dir, "libvpi." + ext_name),
os.path.join(icarus_build_dir, "libvpi.vpl"),
)
_rename_safe(os.path.join(icarus_build_dir, "libvpi." + ext_name), os.path.join(icarus_build_dir, "libvpi.vpl"))

# For Questa
questa_extra_lib = []
questa_extra_lib_path = []
questa_compile = True
vsim_path = find_executable("vsim")
vsim_path = find_executable("vopt")
questa_build_dir = os.path.join(build_dir_abs, "questa")
libvpi_library_dirs = [questa_build_dir]

if os.name == "nt":
if vsim_path is None:
logger.warning(
"Questa (vsim) executable not found. VPI interface will not be avaliable."
)
logger.warning("Questa executable not found. VPI interface will not be avaliable.")
questa_compile = False
else:
questa_path = os.path.dirname(vsim_path)
Expand All @@ -269,9 +263,7 @@ def build_libs_common(build_dir_abs):
_build_lib(libvpi_questa, dist, questa_build_dir)

if vsim_path is None:
logger.warning(
"Questa (vsim) executable not found. FLI interface will not be avaliable."
)
logger.warning("Questa (vsim) executable not found. FLI interface will not be avaliable.")
else:
questa_path = os.path.dirname(os.path.dirname(vsim_path))
libfli = Extension(
Expand All @@ -287,7 +279,10 @@ def build_libs_common(build_dir_abs):
extra_link_args=["-Wl,-rpath,$ORIGIN"],
)

_build_lib(libfli, dist, questa_build_dir)
try:
_build_lib(libfli, dist, questa_build_dir)
except:
logger.warning("Building FLI intercae for Questa faild!") # some Modelsim version doesn not include FLI?

# For GHDL
if os.name == "posix":
Expand All @@ -303,7 +298,7 @@ def build_libs_common(build_dir_abs):
sources=libvpi_sources,
extra_link_args=libvpi_extra_link_args,
)

_build_lib(libvpi_ghdl, dist, ghdl_build_dir)

# For ius
Expand Down Expand Up @@ -355,6 +350,48 @@ def build_libs_common(build_dir_abs):

_build_lib(libvpi_vcs, dist, vcs_build_dir)

# For Aldec
vsimsa_path = find_executable("vsimsa")

if vsimsa_path is None:
logger.warning("Riviera executable not found. No Vpi/Vhpi interface will not be avaliable.")
else:
aldec_extra_lib = []
aldec_extra_lib_path = []
aldec_build_dir = os.path.join(build_dir_abs, "aldec")
libvpi_library_dirs = [aldec_build_dir]
aldec_path = os.path.dirname(vsimsa_path)
aldec_extra_lib = ["aldecpli"]
aldec_extra_lib_path = [aldec_path]

build_libs_common(aldec_build_dir)
libvpi_aldec = Extension(
"libvpi",
define_macros=libvpi_define_macros + [("ALDEC", 1)],
include_dirs=libvpi_include_dirs,
libraries=libvpi_libraries + aldec_extra_lib,
library_dirs=libvpi_library_dirs + aldec_extra_lib_path,
sources=libvpi_sources,
extra_link_args=libvpi_extra_link_args,
)

_build_lib(libvpi_aldec, dist, aldec_build_dir)

libvhpi_aldec = Extension(
"libvhpi",
include_dirs=[include_dir],
define_macros=[("VHPI_CHECKING", 1), ("ALDEC", 1)],
libraries=["gpi", "gpilog", "stdc++"] + aldec_extra_lib,
library_dirs=libvpi_library_dirs + aldec_extra_lib_path,
sources=[
os.path.join(share_lib_dir, "vhpi", "VhpiImpl.cpp"),
os.path.join(share_lib_dir, "vhpi", "VhpiCbHdl.cpp"),
],
extra_link_args=["-Wl,-rpath,$ORIGIN"],
)

_build_lib(libvhpi_aldec, dist, aldec_build_dir)

return build_dir_abs, ext_name


Expand Down
87 changes: 87 additions & 0 deletions cocotb_test/plugin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import os
import shutil
from xml.etree import cElementTree as ET


class ResultsCocotb(object):
def __init__(self, results_xml_output):
self.results_xml_output = results_xml_output
self.names = []
self.results_xml_dir = os.path.abspath(".cocotb-results")

def get_results_xml_file(self, nodeid):
return os.path.join(self.results_xml_dir, nodeid.replace(os.sep, "_").replace("/", "_").replace(":", "-") + ".xml")

def pytest_runtest_logreport(self, report):
if report.when == "call" and report.outcome != "skipped":
self.names.append(report.nodeid)

def pytest_sessionstart(self, session):

if os.path.exists(self.results_xml_dir):
shutil.rmtree(self.results_xml_dir)

os.makedirs(self.results_xml_dir)

def pytest_runtest_setup(self, item):

os.environ["COCOTB_RESULTS_FILE"] = self.get_results_xml_file(item._nodeid)
os.environ["RESULT_TESTPACKAGE"] = item._nodeid

def pytest_sessionfinish(self, session):

result = ET.Element("testsuites", name="results")

for nodeid in self.names:
fname = self.get_results_xml_file(nodeid)

if os.path.isfile(fname):
tree = ET.parse(fname)
for testsuite in tree.getiterator("testsuite"):
use_element = None

for testcase in testsuite.getiterator("testcase"):
testcase.set("classname", "cocotb." + testcase.get("classname")) # add cocotb. for easeir selection

for existing in result:
if existing.get("name") == testsuite.get("name") and (existing.get("package") == testsuite.get("package")):
use_element = existing
break
if use_element is None:
result.append(testsuite)
else:
use_element.extend(list(testsuite))

ET.ElementTree(result).write(self.results_xml_output, encoding="UTF-8")

def pytest_runtest_teardown(self, item, nextitem):
results_xml_file = self.get_results_xml_file(item._nodeid)
results_xml_file_defulat = os.path.join("sim_build", "results.xml")

if os.path.isfile(results_xml_file_defulat):
os.rename(results_xml_file_defulat, results_xml_file)


def pytest_unconfigure(config):
cocotb = getattr(config, "_cocotb", None)
if cocotb:
config.pluginmanager.unregister(cocotb)


def pytest_configure(config):
if config.option.cocotb_xml:
config._cocotb = ResultsCocotb(config.option.cocotb_xml)
config.pluginmanager.register(config._cocotb)


def pytest_addoption(parser):
group = parser.getgroup("terminal reporting")
group.addoption(
"--cocotbxml",
"--cocotb-xml",
action="store",
dest="cocotb_xml",
default=None,
metavar="path",
help="create junit-xml style report file for cocotb reports at given path.",
)
25 changes: 16 additions & 9 deletions cocotb_test/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,29 +7,34 @@
from xml.etree import cElementTree as ET


def run(simulator=None, sim=os.getenv("SIM", "icarus"), **kwargs):
def run(simulator=None, **kwargs):

supported_sim = ["icarus", "questa", "ius", "vcs", "ghdl"]
if (sim in supported_sim) or simulator:
sim_env = os.getenv("SIM", "icarus")

supported_sim = ["icarus", "questa", "ius", "vcs", "ghdl", "aldec"]
if (sim_env in supported_sim) or simulator:
pass
else:
raise NotImplementedError("Set SIM/sim variable. Supported: " + ", ".join(supported_sim))

run_filename = inspect.getframeinfo(inspect.currentframe().f_back)[0]
kwargs["run_filename"] = run_filename
kwargs["sim_name"] = sim_env

if simulator:
sim = simulator(**kwargs)
elif os.getenv("SIM") == "icarus":
elif sim_env == "icarus":
sim = cocotb_test.simulator.Icarus(**kwargs)
elif os.getenv("SIM") == "questa":
elif sim_env == "questa":
sim = cocotb_test.simulator.Questa(**kwargs)
elif os.getenv("SIM") == "ius":
elif sim_env == "ius":
sim = cocotb_test.simulator.Ius(**kwargs)
elif os.getenv("SIM") == "vcs":
elif sim_env == "vcs":
sim = cocotb_test.simulator.Vcs(**kwargs)
elif os.getenv("SIM") == "ghdl":
elif sim_env == "ghdl":
sim = cocotb_test.simulator.Ghdl(**kwargs)
elif sim_env == "aldec":
sim = cocotb_test.simulator.Aldec(**kwargs)

results_xml_file = sim.run()

Expand All @@ -39,7 +44,9 @@ def run(simulator=None, sim=os.getenv("SIM", "icarus"), **kwargs):
for ts in tree.iter("testsuite"):
for tc in ts.iter("testcase"):
for failure in tc.iter("failure"):
assert False, '{} class="{}" test="{}" error={}'.format(failure.get("message"), tc.get("classname"), tc.get("name"), failure.get("stdout"))
assert False, '{} class="{}" test="{}" error={}'.format(
failure.get("message"), tc.get("classname"), tc.get("name"), failure.get("stdout")
)

return results_xml_file

Expand Down
Loading

0 comments on commit c8a64d2

Please sign in to comment.