hdl.ir: accept expanded (kind, name, value) tuples in Instance.
authorwhitequark <cz@m-labs.hk>
Mon, 3 Jun 2019 02:12:01 +0000 (02:12 +0000)
committerwhitequark <cz@m-labs.hk>
Mon, 3 Jun 2019 02:12:01 +0000 (02:12 +0000)
This is useful for e.g. programmatically generating parameters
without having to mess with kwargs dicts.

nmigen/hdl/ir.py
nmigen/test/test_hdl_ir.py

index 8836b25cc53c87b88b2b6fe61abdb15876c89c36..eb322820239d07cfa707fe05285c28f64d3b5ad2 100644 (file)
@@ -517,13 +517,23 @@ class Fragment:
 
 
 class Instance(Fragment):
-    def __init__(self, type, **kwargs):
+    def __init__(self, type, *args, **kwargs):
         super().__init__()
 
         self.type        = type
         self.parameters  = OrderedDict()
         self.named_ports = OrderedDict()
 
+        for (kind, name, value) in args:
+            if kind == "p":
+                self.parameters[name] = value
+            elif kind in ("i", "o", "io"):
+                self.named_ports[name] = (value, kind)
+            else:
+                raise NameError("Instance argument {!r} should be a tuple (kind, name, value) "
+                                "where kind is one of \"p\", \"i\", \"o\", or \"io\""
+                                .format((kind, name, value)))
+
         for kw, arg in kwargs.items():
             if kw.startswith("p_"):
                 self.parameters[kw[2:]] = arg
@@ -534,5 +544,6 @@ class Instance(Fragment):
             elif kw.startswith("io_"):
                 self.named_ports[kw[3:]] = (arg, "io")
             else:
-                raise NameError("Instance argument '{}' does not start with p_, i_, o_, or io_"
-                                .format(arg))
+                raise NameError("Instance keyword argument {}={!r} does not start with one of "
+                                "\"p_\", \"i_\", \"o_\", or \"io_\""
+                                .format(kw, arg))
index e2426cf052bcd06e2451d468da81a8fad89871a0..850e5f46510510cc4579a659e81a4a9db892206e 100644 (file)
@@ -547,6 +547,50 @@ class FragmentHierarchyConflictTestCase(FHDLTestCase):
 
 
 class InstanceTestCase(FHDLTestCase):
+    def test_construct(self):
+        s1 = Signal()
+        s2 = Signal()
+        s3 = Signal()
+        s4 = Signal()
+        s5 = Signal()
+        s6 = Signal()
+        inst = Instance("foo",
+            ("p", "PARAM1", 0x1234),
+            ("i", "s1", s1),
+            ("o", "s2", s2),
+            ("io", "s3", s3),
+            p_PARAM2=0x5678,
+            i_s4=s4,
+            o_s5=s5,
+            io_s6=s6,
+        )
+        self.assertEqual(inst.parameters, OrderedDict([
+            ("PARAM1", 0x1234),
+            ("PARAM2", 0x5678),
+        ]))
+        self.assertEqual(inst.named_ports, OrderedDict([
+            ("s1", (s1, "i")),
+            ("s2", (s2, "o")),
+            ("s3", (s3, "io")),
+            ("s4", (s4, "i")),
+            ("s5", (s5, "o")),
+            ("s6", (s6, "io")),
+        ]))
+
+    def test_wrong_construct_arg(self):
+        s = Signal()
+        with self.assertRaises(NameError,
+                msg="Instance argument ('', 's1', (sig s)) should be a tuple "
+                    "(kind, name, value) where kind is one of \"p\", \"i\", \"o\", or \"io\""):
+            Instance("foo", ("", "s1", s))
+
+    def test_wrong_construct_kwarg(self):
+        s = Signal()
+        with self.assertRaises(NameError,
+                msg="Instance keyword argument x_s1=(sig s) does not start with one of "
+                    "\"p_\", \"i_\", \"o_\", or \"io_\""):
+            Instance("foo", x_s1=s)
+
     def setUp_cpu(self):
         self.rst = Signal()
         self.stb = Signal()