hdl._ir: raise an error when an elaboratable is duplicated in hierarchy.

Fixes #1194.
This commit is contained in:
Wanda 2024-04-03 12:02:32 +02:00 committed by Catherine
parent 2cf9bbf306
commit 466536efcf
3 changed files with 29 additions and 2 deletions

View file

@ -9,8 +9,8 @@ from . import _ast, _cd, _ir, _nir
__all__ = [
"UnusedElaboratable", "Elaboratable", "DriverConflict", "Fragment", "Instance",
"IOBufferInstance", "PortDirection", "Design", "build_netlist",
"UnusedElaboratable", "Elaboratable", "DuplicateElaboratable", "DriverConflict", "Fragment",
"Instance", "IOBufferInstance", "PortDirection", "Design", "build_netlist",
]
@ -30,6 +30,10 @@ class DriverConflict(UserWarning):
pass
class DuplicateElaboratable(Exception):
pass
class Fragment:
@staticmethod
def get(obj, platform):
@ -430,6 +434,7 @@ class Design:
self.hierarchy = hierarchy
self.fragments: dict[Fragment, DesignFragmentInfo] = {}
self.signal_lca = _ast.SignalDict()
self.elaboratables: dict[Elaboratable, Fragment] = {}
self._compute_fragment_depth_parent(fragment, None, 0)
self._collect_used_signals(fragment)
self._add_io_ports()
@ -598,6 +603,15 @@ class Design:
frag_info = self.fragments[fragment]
frag_info.name = hierarchy
if fragment.origins is not None:
for origin in fragment.origins:
if origin in self.elaboratables:
other_hierarchy = self.fragments[self.elaboratables[origin]].name
raise DuplicateElaboratable(f"Elaboratable {origin!r} is included twice "
f"in the hierarchy, as {'.'.join(other_hierarchy)} "
f"and {'.'.join(hierarchy)}")
self.elaboratables[origin] = fragment
if fragment is self.fragment:
# Reserve names for top-level ports. If equal to the signal name, let the signal share it.
for name, conn, _dir in self.ports:

View file

@ -318,6 +318,7 @@ class FragmentTransformer:
else:
new_fragment = Fragment(src_loc=fragment.src_loc)
new_fragment.attrs = OrderedDict(fragment.attrs)
new_fragment.origins = fragment.origins
self.map_subfragments(fragment, new_fragment)
self.map_domains(fragment, new_fragment)
self.map_statements(fragment, new_fragment)

View file

@ -77,6 +77,18 @@ class FragmentDriversTestCase(FHDLTestCase):
self.assertEqual(list(f.iter_sync()), [])
class DuplicateElaboratableTestCase(FHDLTestCase):
def test_duplicate(self):
sub = Module()
m = Module()
m.submodules.a = sub
m.submodules.b = sub
with self.assertRaisesRegex(DuplicateElaboratable,
r"^Elaboratable .* is included twice in the hierarchy, as "
r"top\.a and top\.b$"):
Fragment.get(m, None).prepare()
class FragmentPortsTestCase(FHDLTestCase):
def setUp(self):
self.s1 = Signal()