build.dsl: allow assertions on subsignal widths.
authorwhitequark <cz@m-labs.hk>
Mon, 8 Jul 2019 10:32:41 +0000 (10:32 +0000)
committerwhitequark <cz@m-labs.hk>
Mon, 8 Jul 2019 10:42:06 +0000 (10:42 +0000)
This is useful when building abstractions around resources where
the pin names are user-specified.

Fixes #129.

nmigen/build/dsl.py
nmigen/test/test_build_dsl.py

index 6f76d0552c56a11b4bf6ef7b5058e732ccf7304f..90e09f8baa3f22bc2eb0d31cc3b66870fd01d1f0 100644 (file)
@@ -6,7 +6,7 @@ __all__ = ["Pins", "PinsN", "DiffPairs", "DiffPairsN",
 
 
 class Pins:
-    def __init__(self, names, *, dir="io", conn=None):
+    def __init__(self, names, *, dir="io", conn=None, assert_width=None):
         if not isinstance(names, str):
             raise TypeError("Names must be a whitespace-separated string, not {!r}"
                             .format(names))
@@ -23,6 +23,10 @@ class Pins:
             raise TypeError("Direction must be one of \"i\", \"o\", \"oe\", or \"io\", not {!r}"
                             .format(dir))
 
+        if assert_width is not None and len(names) != assert_width:
+            raise AssertionError("{} names are specified ({}), but {} names are expected"
+                                 .format(len(names), " ".join(names), assert_width))
+
         self.names  = names
         self.dir    = dir
         self.invert = False
@@ -56,9 +60,9 @@ def PinsN(*args, **kwargs):
 
 
 class DiffPairs:
-    def __init__(self, p, n, *, dir="io", conn=None):
-        self.p = Pins(p, dir=dir, conn=conn)
-        self.n = Pins(n, dir=dir, conn=conn)
+    def __init__(self, p, n, *, dir="io", conn=None, assert_width=None):
+        self.p = Pins(p, dir=dir, conn=conn, assert_width=assert_width)
+        self.n = Pins(n, dir=dir, conn=conn, assert_width=assert_width)
 
         if len(self.p.names) != len(self.n.names):
             raise TypeError("Positive and negative pins must have the same width, but {!r} "
index 158ef3549fe21466b3c66458418a3783fcc55688..d0843406e101c5d32e0aee61e12a7b7386160ebe 100644 (file)
@@ -59,6 +59,11 @@ class PinsTestCase(FHDLTestCase):
                     "connector pin pmod_0:1"):
             p.map_names(mapping, p)
 
+    def test_wrong_assert_width(self):
+        with self.assertRaises(AssertionError,
+                msg="3 names are specified (0 1 2), but 4 names are expected"):
+            Pins("0 1 2", assert_width=4)
+
 
 class DiffPairsTestCase(FHDLTestCase):
     def test_basic(self):
@@ -96,6 +101,11 @@ class DiffPairsTestCase(FHDLTestCase):
                     "and (pins io B0 B1) do not"):
             dp = DiffPairs("A0", "B0 B1")
 
+    def test_wrong_assert_width(self):
+        with self.assertRaises(AssertionError,
+                msg="3 names are specified (0 1 2), but 4 names are expected"):
+            DiffPairs("0 1 2", "3 4 5", assert_width=4)
+
 
 class AttrsTestCase(FHDLTestCase):
     def test_basic(self):