From ca6e768dd8cd3799442bf027f215c139a01c764a Mon Sep 17 00:00:00 2001 From: whitequark Date: Fri, 21 Dec 2018 04:03:03 +0000 Subject: [PATCH] hdl.ir: correctly handle named output and inout ports. --- nmigen/hdl/ir.py | 12 +++++++--- nmigen/test/test_hdl_ir.py | 46 ++++++++++++++++++++++++++------------ 2 files changed, 41 insertions(+), 17 deletions(-) diff --git a/nmigen/hdl/ir.py b/nmigen/hdl/ir.py index 3d90f6b..0f6a9ec 100644 --- a/nmigen/hdl/ir.py +++ b/nmigen/hdl/ir.py @@ -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. diff --git a/nmigen/test/test_hdl_ir.py b/nmigen/test/test_hdl_ir.py index 5f5081d..bd71eca 100644 --- a/nmigen/test/test_hdl_ir.py +++ b/nmigen/test/test_hdl_ir.py @@ -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"), ])) -- 2.30.2