9
9
10
10
11
11
__all__ = [
12
- "UnusedElaboratable" , "Elaboratable" , "DriverConflict " , "Fragment " , "Instance " ,
13
- "IOBufferInstance" , "PortDirection" , "Design" , "build_netlist" ,
12
+ "UnusedElaboratable" , "Elaboratable" , "DuplicateElaboratable " , "DriverConflict " , "Fragment " ,
13
+ "Instance" , " IOBufferInstance" , "PortDirection" , "Design" , "build_netlist" ,
14
14
]
15
15
16
16
@@ -30,6 +30,10 @@ class DriverConflict(UserWarning):
30
30
pass
31
31
32
32
33
+ class DuplicateElaboratable (Exception ):
34
+ pass
35
+
36
+
33
37
class Fragment :
34
38
@staticmethod
35
39
def get (obj , platform ):
@@ -430,6 +434,7 @@ def __init__(self, fragment: Fragment, ports, *, hierarchy):
430
434
self .hierarchy = hierarchy
431
435
self .fragments : dict [Fragment , DesignFragmentInfo ] = {}
432
436
self .signal_lca = _ast .SignalDict ()
437
+ self .elaboratables : dict [Elaboratable , Fragment ] = {}
433
438
self ._compute_fragment_depth_parent (fragment , None , 0 )
434
439
self ._collect_used_signals (fragment )
435
440
self ._add_io_ports ()
@@ -598,6 +603,15 @@ def _assign_names(self, fragment: Fragment, hierarchy: "tuple[str]"):
598
603
frag_info = self .fragments [fragment ]
599
604
frag_info .name = hierarchy
600
605
606
+ if fragment .origins is not None :
607
+ for origin in fragment .origins :
608
+ if origin in self .elaboratables :
609
+ other_hierarchy = self .fragments [self .elaboratables [origin ]].name
610
+ raise DuplicateElaboratable (f"Elaboratable { origin !r} is included twice "
611
+ f"in the hierarchy, as { '.' .join (other_hierarchy )} "
612
+ f"and { '.' .join (hierarchy )} " )
613
+ self .elaboratables [origin ] = fragment
614
+
601
615
if fragment is self .fragment :
602
616
# Reserve names for top-level ports. If equal to the signal name, let the signal share it.
603
617
for name , conn , _dir in self .ports :
0 commit comments