hdl.ir: correctly handle named output and inout ports.
authorwhitequark <cz@m-labs.hk>
Fri, 21 Dec 2018 04:03:03 +0000 (04:03 +0000)
committerwhitequark <cz@m-labs.hk>
Fri, 21 Dec 2018 04:03:03 +0000 (04:03 +0000)
nmigen/hdl/ir.py
nmigen/test/test_hdl_ir.py

index 3d90f6bf398c9aeaf83314598dbc62aad26a6a4f..0f6a9ec5998deddc218b909e91b530d1041de519 100644 (file)
@@ -239,14 +239,20 @@ class Fragment:
         # (on RHS of statements, or in clock domains).
         self_driven = union((s._lhs_signals() for s in self.statements), start=SignalSet())
         self_used   = union((s._rhs_signals() for s in self.statements), start=SignalSet())
-        if isinstance(self, Instance):
-            self_used |= union((p._rhs_signals() for p in self.named_ports.values()),
-                               start=SignalSet())
         for domain, _ in self.iter_sync():
             cd = self.domains[domain]
             self_used.add(cd.clk)
             if cd.rst is not None:
                 self_used.add(cd.rst)
+        if isinstance(self, Instance):
+            # Named ports contain signals for input, output and bidirectional ports. Output
+            # and bidirectional ports are already added to the main port dict, however, for
+            # input ports this has to be done lazily as any expression is valid there, including
+            # ones with deferred resolution to signals, such as ClockSignal().
+            for named_port_used in union((p._rhs_signals() for p in self.named_ports.values()),
+                                         start=SignalSet()):
+                if named_port_used not in self.ports:
+                    self_used.add(named_port_used)
 
         # Our input ports are all the signals we're using but not driving. This is an over-
         # approximation: some of these signals may be driven by our subfragments.
index 5f5081d214afeb7596da84f244ab2bef4945df31..bd71ecabbe6cabe63013b7686fde93d7ac2ae19b 100644 (file)
@@ -408,21 +408,39 @@ class FragmentDriverConflictTestCase(FHDLTestCase):
 
 
 class InstanceTestCase(FHDLTestCase):
-    def test_init(self):
-        rst = Signal()
-        stb = Signal()
-        pins = Signal(8)
-        inst = Instance("cpu",
+    def setUp_cpu(self):
+        self.rst = Signal()
+        self.stb = Signal()
+        self.pins = Signal(8)
+        self.inst = Instance("cpu",
             p_RESET=0x1234,
             i_clk=ClockSignal(),
-            i_rst=rst,
-            o_stb=stb,
-            io_pins=pins
+            i_rst=self.rst,
+            o_stb=self.stb,
+            io_pins=self.pins
         )
-        self.assertEqual(inst.type, "cpu")
-        self.assertEqual(inst.parameters, OrderedDict([("RESET", 0x1234)]))
-        self.assertEqual(list(inst.named_ports.keys()), ["clk", "rst", "stb", "pins"])
-        self.assertEqual(inst.ports, SignalDict([
-            (stb, "o"),
-            (pins, "io"),
+
+    def test_init(self):
+        self.setUp_cpu()
+        f = self.inst
+        self.assertEqual(f.type, "cpu")
+        self.assertEqual(f.parameters, OrderedDict([("RESET", 0x1234)]))
+        self.assertEqual(list(f.named_ports.keys()), ["clk", "rst", "stb", "pins"])
+        self.assertEqual(f.ports, SignalDict([
+            (self.stb, "o"),
+            (self.pins, "io"),
+        ]))
+
+    def test_prepare(self):
+        self.setUp_cpu()
+        f = self.inst.prepare()
+        clk = f.domains["sync"].clk
+        self.assertEqual(f.type, "cpu")
+        self.assertEqual(f.parameters, OrderedDict([("RESET", 0x1234)]))
+        self.assertEqual(list(f.named_ports.keys()), ["clk", "rst", "stb", "pins"])
+        self.assertEqual(f.ports, SignalDict([
+            (clk, "i"),
+            (self.rst, "i"),
+            (self.stb, "o"),
+            (self.pins, "io"),
         ]))