fhdl.ir: move Fragment prepare logic from back.rtlil.
authorwhitequark <cz@m-labs.hk>
Thu, 13 Dec 2018 14:33:39 +0000 (14:33 +0000)
committerwhitequark <cz@m-labs.hk>
Thu, 13 Dec 2018 14:34:07 +0000 (14:34 +0000)
nmigen/back/rtlil.py
nmigen/fhdl/ast.py
nmigen/fhdl/ir.py
nmigen/test/test_fhdl_ir.py

index d1c7c7a95043f533702ee95e5bbe3700e5af7fae..a8dd7d39d7b4b2bb8c9f92a7af31e00cf5524e72 100644 (file)
@@ -518,17 +518,8 @@ def convert_fragment(builder, fragment, name, top):
     return module.name, port_map
 
 
-def convert(fragment, ports=[]):
-    fragment._propagate_domains(ensure_sync_exists=True)
-
-    # Clock domain reset always takes priority over all other logic. To ensure this, insert
-    # decision trees for clock domain reset as the very last step before synthesis.
-    fragment = xfrm.ResetInserter({
-        cd.name: cd.rst for cd in fragment.domains.values() if cd.rst is not None
-    })(fragment)
-
-    ins, outs = fragment._propagate_ports(ports)
-
+def convert(fragment, name="top", **kwargs):
+    fragment = fragment.prepare(**kwargs)
     builder = _Builder()
-    convert_fragment(builder, fragment, name="top", top=True)
+    convert_fragment(builder, fragment, name=name, top=True)
     return str(builder)
index c74a69bf2be6bc15cba708ffa9c17ae5ef8584e7..15f67e397c10031996df8f046b7eb5aea9bcdb27 100644 (file)
@@ -728,6 +728,9 @@ class ValueKey:
         else:
             raise TypeError
 
+    def __repr__(self):
+        return "<{}.ValueKey {!r}>".format(__name__, self.value)
+
 
 class ValueDict(MutableMapping):
     def __init__(self, pairs=()):
index 383ef74164acfb663eae0540fb16b69645068d15..8f4efee00c07dbb3d706c69903d84ff7c8b4bf69 100644 (file)
@@ -48,6 +48,13 @@ class Fragment:
             for signal in signals:
                 yield domain, signal
 
+    def iter_signals(self):
+        signals = ValueSet()
+        signals |= self.ports.keys()
+        for domain, domain_signals in self.drivers.items():
+            signals |= domain_signals
+        return signals
+
     def add_domains(self, *domains):
         for domain in domains:
             assert isinstance(domain, ClockDomain)
@@ -124,12 +131,19 @@ class Fragment:
 
             subfrag._propagate_domains_down()
 
-    def _propagate_domains(self, ensure_sync_exists=False):
+    def _propagate_domains(self, ensure_sync_exists):
         self._propagate_domains_up()
         if ensure_sync_exists and not self.domains:
             self.add_domains(ClockDomain("sync"))
         self._propagate_domains_down()
 
+    def _insert_domain_resets(self):
+        from .xfrm import ResetInserter
+
+        return ResetInserter({
+            cd.name: cd.rst for cd in self.domains.values() if cd.rst is not None
+        })(self)
+
     def _propagate_ports(self, ports):
         # Collect all signals we're driving (on LHS of statements), and signals we're using
         # (on RHS of statements, or in clock domains).
@@ -167,3 +181,12 @@ class Fragment:
         self.add_ports(outs, kind="o")
 
         return ins, outs
+
+    def prepare(self, ports=(), ensure_sync_exists=True):
+        from .xfrm import FragmentTransformer
+
+        fragment = FragmentTransformer()(self)
+        fragment._propagate_domains(ensure_sync_exists)
+        fragment = fragment._insert_domain_resets()
+        fragment._propagate_ports(ports)
+        return fragment
index decfa3c08819492d56ba9c49054f19991b497d18..ddd182195306c5860074e90dcd4fcfb1cf3c7123 100644 (file)
@@ -232,11 +232,11 @@ class FragmentDomainsTestCase(FHDLTestCase):
         f1.add_domains(cd)
         f1.add_subfragment(f2)
 
-        f1._propagate_domains()
+        f1._propagate_domains(ensure_sync_exists=False)
         self.assertEqual(f1.domains, {"cd": cd})
         self.assertEqual(f2.domains, {"cd": cd})
 
-    def test_propagate_default(self):
+    def test_propagate_ensure_sync(self):
         f1 = Fragment()
         f2 = Fragment()
         f1.add_subfragment(f2)