ir: allow non-Signals in Instance ports.
authorwhitequark <cz@m-labs.hk>
Thu, 20 Dec 2018 23:38:01 +0000 (23:38 +0000)
committerwhitequark <cz@m-labs.hk>
Thu, 20 Dec 2018 23:40:40 +0000 (23:40 +0000)
examples/inst.py
nmigen/back/rtlil.py
nmigen/hdl/ir.py
nmigen/hdl/xfrm.py
nmigen/test/test_hdl_ir.py

index 9b011d20d8155e84086a14705e169a76b822dcd8..5bfdaaa552a5b5549ec0b44ed034fa910e325ec9 100644 (file)
@@ -16,6 +16,7 @@ class System:
             i_d_adr  =self.adr,
             i_d_dat_r=self.dat_r,
             o_d_dat_w=self.dat_w,
+            i_d_we   =self.we,
         )
         return m.lower(platform)
 
index e46d9292c099c531a276eb503392b115fc04af4a..a4c8a61bfdfe84f4b7f9f2da5954f3169ce5b62f 100644 (file)
@@ -567,15 +567,12 @@ class _StatementCompiler(xfrm.AbstractStatementTransformer):
 
 
 def convert_fragment(builder, fragment, name, top):
-    if fragment.black_box is not None:
+    if isinstance(fragment, ir.Instance):
         port_map = OrderedDict()
-        for signal in fragment.ports:
-            port_map["\\{}".format(fragment.port_names[signal])] = signal
+        for port_name, value in fragment.named_ports.items():
+            port_map["\\{}".format(port_name)] = value
 
-        return "\\{}".format(fragment.black_box), port_map
-    else:
-        assert not fragment.port_names
-        assert not fragment.parameters
+        return "\\{}".format(fragment.type), port_map
 
     with builder.module(name or "anonymous", attrs={"top": 1} if top else {}) as module:
         compiler_state = _ValueCompilerState(module)
index adc5bc417a78fe995aacab65607973bca18e8e04..3d90f6bf398c9aeaf83314598dbc62aad26a6a4f 100644 (file)
@@ -15,10 +15,6 @@ class DriverConflict(UserWarning):
 
 class Fragment:
     def __init__(self):
-        self.black_box = None
-        self.port_names = SignalDict()
-        self.parameters = OrderedDict()
-
         self.ports = SignalDict()
         self.drivers = OrderedDict()
         self.statements = []
@@ -241,8 +237,11 @@ class Fragment:
     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).
-        self_driven = union(s._lhs_signals() for s in self.statements) or SignalSet()
-        self_used   = union(s._rhs_signals() for s in self.statements) or SignalSet()
+        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)
@@ -296,18 +295,24 @@ class Fragment:
 class Instance(Fragment):
     def __init__(self, type, **kwargs):
         super().__init__()
-        self.black_box = type
+
+        self.type = type
+        self.parameters = OrderedDict()
+        self.named_ports = OrderedDict()
+
         for kw, arg in kwargs.items():
             if kw.startswith("p_"):
                 self.parameters[kw[2:]] = arg
             elif kw.startswith("i_"):
-                self.port_names[arg] = kw[2:]
-                self.add_ports(arg, dir="i")
+                self.named_ports[kw[2:]] = arg
+                # Unlike with "o_" and "io_", "i_" ports can be assigned an arbitrary value;
+                # this includes unresolved ClockSignals etc. We rely on Fragment.prepare to
+                # populate fragment ports for these named ports.
             elif kw.startswith("o_"):
-                self.port_names[arg] = kw[2:]
+                self.named_ports[kw[2:]] = arg
                 self.add_ports(arg, dir="o")
             elif kw.startswith("io_"):
-                self.port_names[arg] = kw[3:]
+                self.named_ports[kw[3:]] = arg
                 self.add_ports(arg, dir="io")
             else:
                 raise NameError("Instance argument '{}' does not start with p_, i_, o_, or io_"
index 9dc0e06ecf75fd1202e3a9a4149bb8fa63b3f8c4..3aa10cbc92892abda7cf5d32c1ddb89d5fe4a04e 100644 (file)
@@ -179,6 +179,13 @@ class FragmentTransformer:
         for port, dir in fragment.ports.items():
             new_fragment.add_ports(port, dir=dir)
 
+    def map_named_ports(self, fragment, new_fragment):
+        if hasattr(self, "on_value"):
+            for name, value in fragment.named_ports.items():
+                new_fragment.named_ports[name] = self.on_value(value)
+        else:
+            new_fragment.named_ports = OrderedDict(fragment.named_ports.items())
+
     def map_domains(self, fragment, new_fragment):
         for domain in fragment.iter_domains():
             new_fragment.add_domains(fragment.domains[domain])
@@ -194,10 +201,12 @@ class FragmentTransformer:
             new_fragment.add_driver(signal, domain)
 
     def on_fragment(self, fragment):
-        new_fragment = Fragment()
-        new_fragment.black_box = fragment.black_box
-        new_fragment.parameters = OrderedDict(fragment.parameters)
-        new_fragment.port_names = SignalDict(fragment.port_names.items())
+        if isinstance(fragment, Instance):
+            new_fragment = Instance(fragment.type)
+            new_fragment.parameters = OrderedDict(fragment.parameters)
+            self.map_named_ports(fragment, new_fragment)
+        else:
+            new_fragment = Fragment()
         self.map_ports(fragment, new_fragment)
         self.map_subfragments(fragment, new_fragment)
         self.map_domains(fragment, new_fragment)
index a90aac0a04d7363fee3c2b9d2e6b330ab5c68a2a..5f5081d214afeb7596da84f244ab2bef4945df31 100644 (file)
@@ -412,11 +412,17 @@ class InstanceTestCase(FHDLTestCase):
         rst = Signal()
         stb = Signal()
         pins = Signal(8)
-        inst = Instance("cpu", p_RESET=0x1234, i_rst=rst, o_stb=stb, io_pins=pins)
-        self.assertEqual(inst.black_box, "cpu")
+        inst = Instance("cpu",
+            p_RESET=0x1234,
+            i_clk=ClockSignal(),
+            i_rst=rst,
+            o_stb=stb,
+            io_pins=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([
-            (rst, "i"),
             (stb, "o"),
             (pins, "io"),
         ]))