hdl.ir: allow explicitly requesting flattening.
authorwhitequark <whitequark@whitequark.org>
Mon, 14 Jan 2019 17:04:23 +0000 (17:04 +0000)
committerwhitequark <whitequark@whitequark.org>
Mon, 14 Jan 2019 17:04:23 +0000 (17:04 +0000)
nmigen/hdl/ir.py
nmigen/hdl/xfrm.py
nmigen/lib/io.py
nmigen/test/test_hdl_ir.py

index a4889b169c9d70c7071ee44e8286efedb35d6074..bf66135a6d898b11341e194fed41ac066ba375d4 100644 (file)
@@ -21,6 +21,7 @@ class Fragment:
         self.domains = OrderedDict()
         self.subfragments = []
         self.generated = OrderedDict()
+        self.flatten = False
 
     def add_ports(self, *ports, dir):
         assert dir in ("i", "o", "io")
@@ -141,7 +142,16 @@ class Fragment:
         for domain, signal in self.iter_drivers():
             add_subfrag(driver_subfrags, signal, (None, hierarchy))
 
+        flatten_subfrags = set()
         for i, (subfrag, name) in enumerate(self.subfragments):
+            if name is None:
+                name = "<unnamed #{}>".format(i)
+            subfrag_hierarchy = hierarchy + (name,)
+
+            if subfrag.flatten:
+                # Always flatten subfragments that explicitly request it.
+                flatten_subfrags.add((subfrag, subfrag_hierarchy))
+
             if isinstance(subfrag, Instance):
                 # For memories (which are subfragments, but semantically a part of superfragment),
                 # record that this fragment is driving it.
@@ -153,9 +163,6 @@ class Fragment:
                 continue
 
             # First, recurse into subfragments and let them detect driver conflicts as well.
-            if name is None:
-                name = "<unnamed #{}>".format(i)
-            subfrag_hierarchy = hierarchy + (name,)
             subfrag_drivers, subfrag_memories = \
                 subfrag._resolve_hierarchy_conflicts(subfrag_hierarchy, mode)
 
@@ -167,7 +174,6 @@ class Fragment:
 
         # Find out the set of subfragments that needs to be flattened into this fragment
         # to resolve driver-driver conflicts.
-        flatten_subfrags = set()
         def flatten_subfrags_if_needed(subfrags):
             if len(subfrags) == 1:
                 return []
index 20a325ce5fe830be2e127e2b58b8743c14858916..33c534ec3a318909a02b261c19a668f56c8b0160 100644 (file)
@@ -237,6 +237,7 @@ class FragmentTransformer:
             self.map_named_ports(fragment, new_fragment)
         else:
             new_fragment = Fragment()
+            new_fragment.flatten = fragment.flatten
         self.map_ports(fragment, new_fragment)
         self.map_subfragments(fragment, new_fragment)
         self.map_domains(fragment, new_fragment)
index 1801f5f5157df93c8e9ff9ef2f2d45445e4dfd45..313c8b753b75d4dc6b3d6975a159667f4e6ff17e 100644 (file)
@@ -41,4 +41,7 @@ class Tristate:
             i_A=self.triple.o,
             o_Y=self.io,
         )
-        return m.lower(platform)
+
+        f = m.lower(platform)
+        f.flatten = True
+        return f
index 25956d4ee60e572c2fc57b08e09c7c307a1f101b..ffe1f63e18b9fd2f2fd5e21387184f25db05e4a7 100644 (file)
@@ -509,6 +509,15 @@ class FragmentHierarchyConflictTestCase(FHDLTestCase):
                     "top.<unnamed #1>; hierarchy will be flattened"):
             self.f1._resolve_hierarchy_conflicts(mode="warn")
 
+    def test_explicit_flatten(self):
+        self.f1 = Fragment()
+        self.f2 = Fragment()
+        self.f2.flatten = True
+        self.f1.add_subfragment(self.f2)
+
+        self.f1._resolve_hierarchy_conflicts(mode="silent")
+        self.assertEqual(self.f1.subfragments, [])
+
 
 class InstanceTestCase(FHDLTestCase):
     def setUp_cpu(self):