lib.io: allow Pin(xdr=0), representing a combinatorial I/O buffer.
authorwhitequark <whitequark@whitequark.org>
Mon, 3 Jun 2019 03:29:27 +0000 (03:29 +0000)
committerwhitequark <whitequark@whitequark.org>
Mon, 3 Jun 2019 03:36:32 +0000 (03:36 +0000)
nmigen/lib/io.py
nmigen/test/test_lib_io.py

index f77dde6f11e090a7aaa4fd41a7573a5d34f9f7a3..3b65f07c0d7fb687ea9159aedc48fe8e5903b243 100644 (file)
@@ -18,19 +18,19 @@ def pin_layout(width, dir, xdr=1):
     if dir not in ("i", "o", "io"):
         raise TypeError("Direction must be one of \"i\", \"o\" or \"io\", not '{!r}'"""
                         .format(dir))
-    if not isinstance(xdr, int) or xdr < 1:
-        raise TypeError("Gearing ratio must be a positive integer, not '{!r}'"
+    if not isinstance(xdr, int) or xdr < 0:
+        raise TypeError("Gearing ratio must be a non-negative integer, not '{!r}'"
                         .format(xdr))
 
     fields = []
     if dir in ("i", "io"):
-        if xdr == 1:
+        if xdr in (0, 1):
             fields.append(("i", width))
         else:
             for n in range(xdr):
                 fields.append(("i{}".format(n), width))
     if dir in ("o", "io"):
-        if xdr == 1:
+        if xdr in (0, 1):
             fields.append(("o", width))
         else:
             for n in range(xdr):
@@ -60,7 +60,8 @@ class Pin(Record):
         is specified, both the ``i``/``iN`` and ``o``/``oN`` signals are present, and an ``oe``
         signal is present.
     xdr : int
-        Gearbox ratio. If equal to 1, the I/O buffer is SDR, and only ``i``/``o`` signals are
+        Gearbox ratio. If equal to 0, the I/O buffer is combinatorial, and only ``i``/``o``
+        signals are present. If equal to 1, the I/O buffer is SDR, and only ``i``/``o`` signals are
         present. If greater than 1, the I/O buffer includes a gearbox, and ``iN``/``oN`` signals
         are present instead, where ``N in range(0, N)``. For example, if ``xdr=2``, the I/O buffer
         is DDR; the signal ``i0`` reflects the value at the rising edge, and the signal ``i1``
@@ -72,13 +73,13 @@ class Pin(Record):
     ----------
     i : Signal, out
         I/O buffer input, without gearing. Present if ``dir="i"`` or ``dir="io"``, and ``xdr`` is
-        equal to 1.
+        equal to 0 or 1.
     i0, i1, ... : Signal, out
         I/O buffer inputs, with gearing. Present if ``dir="i"`` or ``dir="io"``, and ``xdr`` is
         greater than 1.
     o : Signal, in
         I/O buffer output, without gearing. Present if ``dir="o"`` or ``dir="io"``, and ``xdr`` is
-        equal to 1.
+        equal to 0 or 1.
     o0, o1, ... : Signal, in
         I/O buffer outputs, with gearing. Present if ``dir="o"`` or ``dir="io"``, and ``xdr`` is
         greater than 1.
@@ -86,7 +87,7 @@ class Pin(Record):
         I/O buffer output enable. Present if ``dir="io"``. Buffers generally cannot change
         direction more than once per cycle, so at most one output enable signal is present.
     """
-    def __init__(self, width, dir, xdr=1, name=None):
+    def __init__(self, width, dir, xdr=0, name=None):
         self.width = width
         self.dir   = dir
         self.xdr   = xdr
index f2cfdeff29999394fdb34abd1831f64ce59ab352..1a91a29435c8fad6f7da461d5b9e62b27ad39622 100644 (file)
@@ -4,7 +4,7 @@ from ..hdl.rec import *
 from ..lib.io import *
 
 
-class PinLayoutSDRTestCase(FHDLTestCase):
+class PinLayoutCombTestCase(FHDLTestCase):
     def test_pin_layout_i(self):
         layout_1 = pin_layout(1, dir="i")
         self.assertEqual(layout_1.fields, {
@@ -43,6 +43,45 @@ class PinLayoutSDRTestCase(FHDLTestCase):
         })
 
 
+class PinLayoutSDRTestCase(FHDLTestCase):
+    def test_pin_layout_i(self):
+        layout_1 = pin_layout(1, dir="i", xdr=1)
+        self.assertEqual(layout_1.fields, {
+            "i": ((1, False), DIR_NONE),
+        })
+
+        layout_2 = pin_layout(2, dir="i", xdr=1)
+        self.assertEqual(layout_2.fields, {
+            "i": ((2, False), DIR_NONE),
+        })
+
+    def test_pin_layout_o(self):
+        layout_1 = pin_layout(1, dir="o", xdr=1)
+        self.assertEqual(layout_1.fields, {
+            "o": ((1, False), DIR_NONE),
+        })
+
+        layout_2 = pin_layout(2, dir="o", xdr=1)
+        self.assertEqual(layout_2.fields, {
+            "o": ((2, False), DIR_NONE),
+        })
+
+    def test_pin_layout_io(self):
+        layout_1 = pin_layout(1, dir="io", xdr=1)
+        self.assertEqual(layout_1.fields, {
+            "i":  ((1, False), DIR_NONE),
+            "o":  ((1, False), DIR_NONE),
+            "oe": ((1, False), DIR_NONE),
+        })
+
+        layout_2 = pin_layout(2, dir="io", xdr=1)
+        self.assertEqual(layout_2.fields, {
+            "i":  ((2, False), DIR_NONE),
+            "o":  ((2, False), DIR_NONE),
+            "oe": ((1, False), DIR_NONE),
+        })
+
+
 class PinLayoutDDRTestCase(FHDLTestCase):
     def test_pin_layout_i(self):
         layout_1 = pin_layout(1, dir="i", xdr=2)