Skip to content

Commit

Permalink
Implement warning for non-deterministic selection of virtual cores
Browse files Browse the repository at this point in the history
  • Loading branch information
blueluna committed Dec 19, 2024
1 parent 6528646 commit 7a1e1f4
Show file tree
Hide file tree
Showing 4 changed files with 150 additions and 0 deletions.
22 changes: 22 additions & 0 deletions fusesoc/coremanager.py
Original file line number Diff line number Diff line change
Expand Up @@ -225,14 +225,36 @@ def eq_vln(this, that):
except NoPackageFound as e:
raise DependencyError(top_core.name)

virtual_selection = {}
objdict = {}
if len(transaction.operations) > 1:
for op in transaction.operations:
package_name = self._package_name(op.package.core.name)
virtuals = op.package.core.get_virtuals(_flags)
for p in op.package.provides:
for virtual in virtuals:
if p[0] == self._package_name(virtual):
# Add virtual core selection to dictionary
virtual_selection[package_name] = (
op.package.core.name,
virtual,
)
objdict[p[0]] = str(op.package.core.name)
for p in op.package.install_requires:
if p[0] in virtual_selection:
# If package that implements a virtual core is required, remove from the dictionary
del virtual_selection[p[0]]
op.package.core.direct_deps = [
objdict[n[0]] for n in op.package.install_requires
]
# Print a warning for all virtual selections that has no concrete requirement selection
for virtual in virtual_selection.values():
logger.warning(
"Non-deterministic selection of virtual core {} selected {}".format(
virtual[1], virtual[0]
)
)

result = [op.package.core for op in transaction.operations]

# Cache the solution for further lookups
Expand Down
22 changes: 22 additions & 0 deletions tests/capi2_cores/virtual/top_conflict.core
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
CAPI=2:
# Copyright FuseSoC contributors
# Licensed under the 2-Clause BSD License, see LICENSE for details.
# SPDX-License-Identifier: BSD-2-Clause

name: ::top_conflict:0
filesets:
rtl:
depend:
- ::user:0
- ::impl1:0
- ::impl2:0
files:
- top_conflict.sv
file_type: systemVerilogSource


targets:
default:
filesets:
- rtl
toplevel: top_impl2
19 changes: 19 additions & 0 deletions tests/capi2_cores/virtual/top_non_deterministic.core
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
CAPI=2:
# Copyright FuseSoC contributors
# Licensed under the 2-Clause BSD License, see LICENSE for details.
# SPDX-License-Identifier: BSD-2-Clause

name: ::top_non_deterministic:0
filesets:
rtl:
depend:
- ::user:0
files:
- top_impl1.sv
file_type: systemVerilogSource

targets:
default:
filesets:
- rtl
toplevel: top_impl1
87 changes: 87 additions & 0 deletions tests/test_coremanager.py
Original file line number Diff line number Diff line change
Expand Up @@ -278,3 +278,90 @@ def test_virtual():
deps_names = [str(c) for c in deps]

assert deps_names == expected_deps


def test_virtual_conflict():
"""
Test virtual core selection when there are more than one selected implementation.
This shall result in a conflict of cores.
"""
import os
import tempfile

from fusesoc.config import Config
from fusesoc.coremanager import CoreManager, DependencyError
from fusesoc.edalizer import Edalizer
from fusesoc.librarymanager import Library
from fusesoc.vlnv import Vlnv

flags = {"tool": "icarus"}

build_root = tempfile.mkdtemp(prefix="export_")
work_root = os.path.join(build_root, "work")

core_dir = os.path.join(os.path.dirname(__file__), "capi2_cores", "virtual")

cm = CoreManager(Config())
cm.add_library(Library("virtual", core_dir), [])

root_core = cm.get_core(Vlnv("::top_conflict"))

edalizer = Edalizer(
toplevel=root_core.name,
flags=flags,
core_manager=cm,
work_root=work_root,
)
with pytest.raises(DependencyError) as _:
edalizer.run()


def test_virtual_non_deterministic_virtual(caplog):
"""
Test virtual core selection when there are no selected implementations.
This shall result in a warning that the virtual core selection is non-deteministic.
"""
import logging
import os
import tempfile

from fusesoc.config import Config
from fusesoc.coremanager import CoreManager
from fusesoc.edalizer import Edalizer
from fusesoc.librarymanager import Library
from fusesoc.vlnv import Vlnv

flags = {"tool": "icarus"}

build_root = tempfile.mkdtemp(prefix="export_")
work_root = os.path.join(build_root, "work")

core_dir = os.path.join(os.path.dirname(__file__), "capi2_cores", "virtual")

cm = CoreManager(Config())
cm.add_library(Library("virtual", core_dir), [])

root_core = cm.get_core(Vlnv("::top_non_deterministic"))

edalizer = Edalizer(
toplevel=root_core.name,
flags=flags,
core_manager=cm,
work_root=work_root,
)
edalizer.run()

with caplog.at_level(logging.WARNING):
edalizer.run()
assert "Non-deterministic selection of virtual core" in caplog.text

deps = cm.get_depends(root_core.name, {})
deps_names = [str(c) for c in deps]

for dependency in deps_names:
assert dependency in [
"::impl1:0",
"::impl2:0",
"::user:0",
"::top_non_deterministic:0",
]

0 comments on commit 7a1e1f4

Please sign in to comment.