lib.io: allow dir="oe".

Although a dir="oe" pin is generally equivalent to dir="io" pin with
the i* signal(s) disconnected, they are not equivalent, because some
pins may not be able to support input buffers at all, either because
there are no input buffers, or because the input buffers are consumed
by some other resource.

E.g. this can happen on iCE40 when the input buffer is consumed by
a PLL.
This commit is contained in:
whitequark 2019-06-03 04:28:53 +00:00
parent 9ba2efd86b
commit 1eee7cd76f
2 changed files with 53 additions and 10 deletions

View file

@ -15,8 +15,8 @@ def pin_layout(width, dir, xdr=1):
if not isinstance(width, int) or width < 1:
raise TypeError("Width must be a positive integer, not '{!r}'"
.format(width))
if dir not in ("i", "o", "io"):
raise TypeError("Direction must be one of \"i\", \"o\" or \"io\", not '{!r}'"""
if dir not in ("i", "o", "oe", "io"):
raise TypeError("Direction must be one of \"i\", \"o\", \"io\", or \"oe\", not '{!r}'"""
.format(dir))
if not isinstance(xdr, int) or xdr < 0:
raise TypeError("Gearing ratio must be a non-negative integer, not '{!r}'"
@ -29,13 +29,13 @@ def pin_layout(width, dir, xdr=1):
else:
for n in range(xdr):
fields.append(("i{}".format(n), width))
if dir in ("o", "io"):
if dir in ("o", "oe", "io"):
if xdr in (0, 1):
fields.append(("o", width))
else:
for n in range(xdr):
fields.append(("o{}".format(n), width))
if dir == "io":
if dir in ("oe", "io"):
fields.append(("oe", 1))
return Layout(fields)
@ -54,11 +54,12 @@ class Pin(Record):
----------
width : int
Width of the ``i``/``iN`` and ``o``/``oN`` signals.
dir : ``"i"``, ``"o"``, ``"io"``
dir : ``"i"``, ``"o"``, ``"io"``, ``"oe"``
Direction of the buffers. If ``"i"`` is specified, only the ``i``/``iN`` signals are
present. If ``"o"`` is specified, only the ``o``/``oN`` signals are present. If ``"io"``
is specified, both the ``i``/``iN`` and ``o``/``oN`` signals are present, and an ``oe``
signal is present.
present. If ``"o"`` is specified, only the ``o``/``oN`` signals are present. If ``"oe"`` is
specified, the ``o``/``oN`` signals are present, and an ``oe`` signal is present.
If ``"io"`` 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 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
@ -84,8 +85,9 @@ class Pin(Record):
I/O buffer outputs, with gearing. Present if ``dir="o"`` or ``dir="io"``, and ``xdr`` is
greater than 1.
oe : Signal, in
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.
I/O buffer output enable. Present if ``dir="io"`` or ``dir="oe"``. 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=0, name=None):
self.width = width

View file

@ -27,6 +27,19 @@ class PinLayoutCombTestCase(FHDLTestCase):
"o": ((2, False), DIR_NONE),
})
def test_pin_layout_oe(self):
layout_1 = pin_layout(1, dir="oe")
self.assertEqual(layout_1.fields, {
"o": ((1, False), DIR_NONE),
"oe": ((1, False), DIR_NONE),
})
layout_2 = pin_layout(2, dir="oe")
self.assertEqual(layout_2.fields, {
"o": ((2, False), DIR_NONE),
"oe": ((1, False), DIR_NONE),
})
def test_pin_layout_io(self):
layout_1 = pin_layout(1, dir="io")
self.assertEqual(layout_1.fields, {
@ -66,6 +79,19 @@ class PinLayoutSDRTestCase(FHDLTestCase):
"o": ((2, False), DIR_NONE),
})
def test_pin_layout_oe(self):
layout_1 = pin_layout(1, dir="oe", xdr=1)
self.assertEqual(layout_1.fields, {
"o": ((1, False), DIR_NONE),
"oe": ((1, False), DIR_NONE),
})
layout_2 = pin_layout(2, dir="oe", xdr=1)
self.assertEqual(layout_2.fields, {
"o": ((2, False), DIR_NONE),
"oe": ((1, False), DIR_NONE),
})
def test_pin_layout_io(self):
layout_1 = pin_layout(1, dir="io", xdr=1)
self.assertEqual(layout_1.fields, {
@ -109,6 +135,21 @@ class PinLayoutDDRTestCase(FHDLTestCase):
"o1": ((2, False), DIR_NONE),
})
def test_pin_layout_oe(self):
layout_1 = pin_layout(1, dir="oe", xdr=2)
self.assertEqual(layout_1.fields, {
"o0": ((1, False), DIR_NONE),
"o1": ((1, False), DIR_NONE),
"oe": ((1, False), DIR_NONE),
})
layout_2 = pin_layout(2, dir="oe", xdr=2)
self.assertEqual(layout_2.fields, {
"o0": ((2, False), DIR_NONE),
"o1": ((2, False), DIR_NONE),
"oe": ((1, False), DIR_NONE),
})
def test_pin_layout_io(self):
layout_1 = pin_layout(1, dir="io", xdr=2)
self.assertEqual(layout_1.fields, {