hdl.xfrm: implement SwitchCleaner, for pruning empty switches.
authorwhitequark <whitequark@whitequark.org>
Mon, 24 Dec 2018 02:02:59 +0000 (02:02 +0000)
committerwhitequark <whitequark@whitequark.org>
Mon, 24 Dec 2018 02:02:59 +0000 (02:02 +0000)
nmigen/back/rtlil.py
nmigen/hdl/xfrm.py
nmigen/test/test_hdl_xfrm.py

index 91bd1c1ffed4dce4df9eb46ca0a367b3c68578ee..aca7ff28fee515d1b38e08084cfdc6adfebd9fac 100644 (file)
@@ -620,6 +620,7 @@ def convert_fragment(builder, fragment, name, top):
         rhs_compiler   = _RHSValueCompiler(compiler_state)
         lhs_compiler   = _LHSValueCompiler(compiler_state)
         stmt_compiler  = _StatementCompiler(compiler_state, rhs_compiler, lhs_compiler)
+        switch_cleaner = xfrm.SwitchCleaner()
 
         verilog_trigger = None
         verilog_trigger_sync_emitted = False
@@ -720,7 +721,7 @@ def convert_fragment(builder, fragment, name, top):
                     stmt_compiler._group = group_signals
                     stmt_compiler._case = case
                     stmt_compiler._has_rhs = False
-                    stmt_compiler(fragment.statements)
+                    stmt_compiler(switch_cleaner(fragment.statements))
 
                     # Verilog `always @*` blocks will not run if `*` does not match anythng, i.e.
                     # if the implicit sensitivity list is empty. We check this while translating,
index 06e5c284314c7ed606954b3e7ae2c1620b31cdcd..2b219b82a311b302028ee8d075a41c4fedc03411 100644 (file)
@@ -13,7 +13,7 @@ __all__ = ["ValueVisitor", "ValueTransformer",
            "StatementVisitor", "StatementTransformer",
            "FragmentTransformer",
            "DomainRenamer", "DomainLowerer",
-           "LHSGroupAnalyzer",
+           "SwitchCleaner", "LHSGroupAnalyzer",
            "ResetInserter", "CEInserter"]
 
 
@@ -165,7 +165,7 @@ class StatementTransformer(StatementVisitor):
         return Assign(self.on_value(stmt.lhs), self.on_value(stmt.rhs))
 
     def on_Switch(self, stmt):
-        cases = OrderedDict((k, self.on_statement(v)) for k, v in stmt.cases.items())
+        cases = OrderedDict((k, self.on_statement(s)) for k, s in stmt.cases.items())
         return Switch(self.on_value(stmt.test), cases)
 
     def on_statements(self, stmts):
@@ -280,6 +280,20 @@ class DomainLowerer(FragmentTransformer, ValueTransformer, StatementTransformer)
         return cd.rst
 
 
+class SwitchCleaner(StatementVisitor):
+    def on_Assign(self, stmt):
+        return stmt
+
+    def on_Switch(self, stmt):
+        cases = OrderedDict((k, self.on_statement(s)) for k, s in stmt.cases.items())
+        if any(len(s) for s in stmt.cases.values()):
+            return Switch(stmt.test, cases)
+
+    def on_statements(self, stmts):
+        stmts = flatten(self.on_statement(stmt) for stmt in stmts)
+        return _StatementList(stmt for stmt in stmts if stmt is not None)
+
+
 class LHSGroupAnalyzer(StatementVisitor):
     def __init__(self):
         self.signals = SignalDict()
index d89db073dd18aa37ba996a4e579980d065c36823..1c6d6c0603afce2b0342464d85d5666ef557b5f9 100644 (file)
@@ -158,6 +158,33 @@ class DomainLowererTestCase(FHDLTestCase):
             DomainLowerer({"sync": sync})(f)
 
 
+class SwitchCleanerTestCase(FHDLTestCase):
+    def test_clean(self):
+        a = Signal()
+        b = Signal()
+        c = Signal()
+        stmts = [
+            Switch(a, {
+                1: a.eq(0),
+                0: [
+                    b.eq(1),
+                    Switch(b, {1: []})
+                ]
+            })
+        ]
+
+        self.assertRepr(SwitchCleaner()(stmts), """
+        (
+            (switch (sig a)
+                (case 1
+                    (eq (sig a) (const 1'd0)))
+                (case 0
+                    (eq (sig b) (const 1'd1)))
+            )
+        )
+        """)
+
+
 class LHSGroupAnalyzerTestCase(FHDLTestCase):
     def test_no_group_unrelated(self):
         a = Signal()