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:
parent
9ba2efd86b
commit
1eee7cd76f
|
@ -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
|
||||
|
|
|
@ -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, {
|
||||
|
|
Loading…
Reference in a new issue