lib.io: allow Pin(xdr=0), representing a combinatorial I/O buffer.

This commit is contained in:
whitequark 2019-06-03 03:29:27 +00:00
parent 3327deae92
commit c30617fc05
2 changed files with 49 additions and 9 deletions

View file

@ -18,19 +18,19 @@ def pin_layout(width, dir, xdr=1):
if dir not in ("i", "o", "io"): if dir not in ("i", "o", "io"):
raise TypeError("Direction must be one of \"i\", \"o\" or \"io\", not '{!r}'""" raise TypeError("Direction must be one of \"i\", \"o\" or \"io\", not '{!r}'"""
.format(dir)) .format(dir))
if not isinstance(xdr, int) or xdr < 1: if not isinstance(xdr, int) or xdr < 0:
raise TypeError("Gearing ratio must be a positive integer, not '{!r}'" raise TypeError("Gearing ratio must be a non-negative integer, not '{!r}'"
.format(xdr)) .format(xdr))
fields = [] fields = []
if dir in ("i", "io"): if dir in ("i", "io"):
if xdr == 1: if xdr in (0, 1):
fields.append(("i", width)) fields.append(("i", width))
else: else:
for n in range(xdr): for n in range(xdr):
fields.append(("i{}".format(n), width)) fields.append(("i{}".format(n), width))
if dir in ("o", "io"): if dir in ("o", "io"):
if xdr == 1: if xdr in (0, 1):
fields.append(("o", width)) fields.append(("o", width))
else: else:
for n in range(xdr): 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`` is specified, both the ``i``/``iN`` and ``o``/``oN`` signals are present, and an ``oe``
signal is present. signal is present.
xdr : int 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 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 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`` 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 : Signal, out
I/O buffer input, without gearing. Present if ``dir="i"`` or ``dir="io"``, and ``xdr`` is 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 i0, i1, ... : Signal, out
I/O buffer inputs, with gearing. Present if ``dir="i"`` or ``dir="io"``, and ``xdr`` is I/O buffer inputs, with gearing. Present if ``dir="i"`` or ``dir="io"``, and ``xdr`` is
greater than 1. greater than 1.
o : Signal, in o : Signal, in
I/O buffer output, without gearing. Present if ``dir="o"`` or ``dir="io"``, and ``xdr`` is 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 o0, o1, ... : Signal, in
I/O buffer outputs, with gearing. Present if ``dir="o"`` or ``dir="io"``, and ``xdr`` is I/O buffer outputs, with gearing. Present if ``dir="o"`` or ``dir="io"``, and ``xdr`` is
greater than 1. greater than 1.
@ -86,7 +87,7 @@ class Pin(Record):
I/O buffer output enable. Present if ``dir="io"``. Buffers generally cannot change 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. 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.width = width
self.dir = dir self.dir = dir
self.xdr = xdr self.xdr = xdr

View file

@ -4,7 +4,7 @@ from ..hdl.rec import *
from ..lib.io import * from ..lib.io import *
class PinLayoutSDRTestCase(FHDLTestCase): class PinLayoutCombTestCase(FHDLTestCase):
def test_pin_layout_i(self): def test_pin_layout_i(self):
layout_1 = pin_layout(1, dir="i") layout_1 = pin_layout(1, dir="i")
self.assertEqual(layout_1.fields, { 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): class PinLayoutDDRTestCase(FHDLTestCase):
def test_pin_layout_i(self): def test_pin_layout_i(self):
layout_1 = pin_layout(1, dir="i", xdr=2) layout_1 = pin_layout(1, dir="i", xdr=2)