lib.io, build.res: Make Pin and related objects interfaces.

Fixes #1040.
This commit is contained in:
Wanda 2024-02-27 10:42:57 +01:00 committed by Catherine
parent c30585b47b
commit f524dd041a
4 changed files with 249 additions and 266 deletions

View file

@ -1,10 +1,6 @@
from collections import OrderedDict from collections import OrderedDict
import warnings
from ..hdl._ast import * from ..hdl._ast import *
with warnings.catch_warnings():
warnings.filterwarnings(action="ignore", category=DeprecationWarning)
from ..hdl.rec import *
from ..lib.io import * from ..lib.io import *
from ..lib import wiring from ..lib import wiring
@ -106,7 +102,7 @@ class ResourceManager:
.format(subsignal.ios[0], xdr)) .format(subsignal.ios[0], xdr))
return dir, xdr return dir, xdr
def resolve(resource, dir, xdr, name, attrs): def resolve(resource, dir, xdr, path, attrs):
for attr_key, attr_value in attrs.items(): for attr_key, attr_value in attrs.items():
if hasattr(attr_value, "__call__"): if hasattr(attr_value, "__call__"):
attr_value = attr_value(self) attr_value = attr_value(self)
@ -117,18 +113,21 @@ class ResourceManager:
attrs[attr_key] = attr_value attrs[attr_key] = attr_value
if isinstance(resource.ios[0], Subsignal): if isinstance(resource.ios[0], Subsignal):
fields = OrderedDict() members = OrderedDict()
sig_members = OrderedDict()
for sub in resource.ios: for sub in resource.ios:
fields[sub.name] = resolve(sub, dir[sub.name], xdr[sub.name], member = resolve(sub, dir[sub.name], xdr[sub.name],
name=f"{name}__{sub.name}", path=path + (sub.name,),
attrs={**attrs, **sub.attrs}) attrs={**attrs, **sub.attrs})
rec = Record([ members[sub.name] = member
(f_name, f.layout) for (f_name, f) in fields.items() sig_members[sub.name] = wiring.Out(member.signature)
], fields=fields, name=name) signature = wiring.Signature(sig_members)
rec.signature = wiring.Signature({ # Provide members ourselves instead of having the constructor
f_name: wiring.Out(f.signature) for (f_name, f) in fields.items() # create ones for us.
}) intf = object.__new__(wiring.PureInterface)
return rec intf.signature = signature
intf.__dict__.update(members)
return intf
elif isinstance(resource.ios[0], (Pins, DiffPairs)): elif isinstance(resource.ios[0], (Pins, DiffPairs)):
phys = resource.ios[0] phys = resource.ios[0]
@ -137,34 +136,30 @@ class ResourceManager:
# ignore it as well. # ignore it as well.
if isinstance(phys, Pins): if isinstance(phys, Pins):
phys_names = phys.names phys_names = phys.names
port = Record([("io", len(phys))], name=name) port = wiring.Signature({"io": wiring.In(len(phys))}).create(path=path)
port.signature = wiring.Signature({"io": wiring.In(len(phys))})
if isinstance(phys, DiffPairs): if isinstance(phys, DiffPairs):
phys_names = [] phys_names = []
rec_members = []
sig_members = {} sig_members = {}
if not self.should_skip_port_component(None, attrs, "p"): if not self.should_skip_port_component(None, attrs, "p"):
phys_names += phys.p.names phys_names += phys.p.names
rec_members.append(("p", len(phys)))
sig_members["p"] = wiring.In(len(phys)) sig_members["p"] = wiring.In(len(phys))
if not self.should_skip_port_component(None, attrs, "n"): if not self.should_skip_port_component(None, attrs, "n"):
phys_names += phys.n.names phys_names += phys.n.names
rec_members.append(("n", len(phys)))
sig_members["n"] = wiring.In(len(phys)) sig_members["n"] = wiring.In(len(phys))
port = Record(rec_members, name=name) port = wiring.Signature(sig_members).create(path=path)
port.signature = wiring.Signature(sig_members)
if dir == "-": if dir == "-":
pin = None pin = None
else: else:
pin = wiring.flipped(Pin(len(phys), dir, xdr=xdr, name=name)) pin = wiring.flipped(Pin(len(phys), dir, xdr=xdr, path=path))
for phys_name in phys_names: for phys_name in phys_names:
if phys_name in self._phys_reqd: if phys_name in self._phys_reqd:
raise ResourceError("Resource component {} uses physical pin {}, but it " raise ResourceError("Resource component {} uses physical pin {}, but it "
"is already used by resource component {} that was " "is already used by resource component {} that was "
"requested earlier" "requested earlier"
.format(name, phys_name, self._phys_reqd[phys_name])) .format(".".join(path), phys_name,
self._phys_reqd[phys_name] = name ".".join(self._phys_reqd[phys_name])))
self._phys_reqd[phys_name] = path
self._ports.append((resource, pin, port, attrs)) self._ports.append((resource, pin, port, attrs))
@ -178,7 +173,7 @@ class ResourceManager:
value = resolve(resource, value = resolve(resource,
*merge_options(resource, dir, xdr), *merge_options(resource, dir, xdr),
name=f"{resource.name}_{resource.number}", path=(f"{resource.name}_{resource.number}",),
attrs=resource.attrs) attrs=resource.attrs)
self._requested[resource.name, resource.number] = value self._requested[resource.name, resource.number] = value
return value return value

View file

@ -1,74 +1,18 @@
import warnings
from .. import * from .. import *
with warnings.catch_warnings(): from ..lib import wiring
warnings.filterwarnings(action="ignore", category=DeprecationWarning) from ..lib.wiring import In, Out
from ..hdl.rec import *
from ..lib.wiring import In, Out, Signature, flipped, FlippedInterface
__all__ = ["pin_layout", "Pin"] __all__ = ["Pin"]
def _pin_signature(width, dir, xdr=0): class Pin(wiring.PureInterface):
if not isinstance(width, int) or width < 0:
raise TypeError("Width must be a non-negative integer, not {!r}"
.format(width))
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}"
.format(xdr))
members = {}
if dir in ("i", "io"):
if xdr > 0:
members["i_clk"] = In(1)
if xdr > 2:
members["i_fclk"] = In(1)
if xdr in (0, 1):
members["i"] = In(width)
else:
for n in range(xdr):
members[f"i{n}"] = In(width)
if dir in ("o", "oe", "io"):
if xdr > 0:
members["o_clk"] = Out(1)
if xdr > 2:
members["o_fclk"] = Out(1)
if xdr in (0, 1):
members["o"] = Out(width)
else:
for n in range(xdr):
members[f"o{n}"] = Out(width)
if dir in ("oe", "io"):
members["oe"] = Out(1)
return Signature(members)
def pin_layout(width, dir, xdr=0):
"""
Layout of the platform interface of a pin or several pins, which may be used inside
user-defined records.
See :class:`Pin` for details.
"""
fields = []
for name, member in _pin_signature(width, dir, xdr).members.items():
fields.append((name, member.shape))
return Layout(fields)
class Pin(Record):
""" """
An interface to an I/O buffer or a group of them that provides uniform access to input, output, An interface to an I/O buffer or a group of them that provides uniform access to input, output,
or tristate buffers that may include a 1:n gearbox. (A 1:2 gearbox is typically called "DDR".) or tristate buffers that may include a 1:n gearbox. (A 1:2 gearbox is typically called "DDR".)
A :class:`Pin` is identical to a :class:`Record` that uses the corresponding :meth:`pin_layout` This is an interface object using :class:`Pin.Signature` as its signature. The signature flows
except that it allows accessing the parameters like ``width`` as attributes. It is legal to use are defined from the point of view of a component that drives the I/O buffer.
a plain :class:`Record` anywhere a :class:`Pin` is used, provided that these attributes are
not necessary.
Parameters Parameters
---------- ----------
@ -87,8 +31,8 @@ class Pin(Record):
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``
reflects the value at the falling edge. reflects the value at the falling edge.
name : str path : tuple of str
Name of the underlying record. As in :class:`PureInterface`, used to name the created signals.
Attributes Attributes
---------- ----------
@ -119,23 +63,76 @@ class Pin(Record):
cannot change direction more than once per cycle, so at most one output enable signal cannot change direction more than once per cycle, so at most one output enable signal
is present. is present.
""" """
def __init__(self, width, dir, *, xdr=0, name=None, src_loc_at=0):
self.width = width
self.dir = dir
self.xdr = xdr
super().__init__(pin_layout(self.width, self.dir, self.xdr), class Signature(wiring.Signature):
name=name, src_loc_at=src_loc_at + 1) """A signature for :class:`Pin`. The parameters are as defined on the ``Pin`` class,
and are accessible as attributes.
"""
def __init__(self, width, dir, *, xdr=0):
if not isinstance(width, int) or width < 0:
raise TypeError("Width must be a non-negative integer, not {!r}"
.format(width))
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}"
.format(xdr))
self.width = width
self.dir = dir
self.xdr = xdr
members = {}
if dir in ("i", "io"):
if xdr > 0:
members["i_clk"] = Out(1)
if xdr > 2:
members["i_fclk"] = Out(1)
if xdr in (0, 1):
members["i"] = In(width)
else:
for n in range(xdr):
members[f"i{n}"] = In(width)
if dir in ("o", "oe", "io"):
if xdr > 0:
members["o_clk"] = Out(1)
if xdr > 2:
members["o_fclk"] = Out(1)
if xdr in (0, 1):
members["o"] = Out(width)
else:
for n in range(xdr):
members[f"o{n}"] = Out(width)
if dir in ("oe", "io"):
members["oe"] = Out(1)
super().__init__(members)
def __eq__(self, other):
return (type(self) is type(other) and
self.width == other.width and
self.dir == other.dir and
self.xdr == other.xdr)
def create(self, *, path=None, src_loc_at=0):
return Pin(self.width, self.dir, xdr=self.xdr, path=path, src_loc_at=1 + src_loc_at)
def __init__(self, width, dir, *, xdr=0, name=None, path=None, src_loc_at=0):
if name is not None:
if path is None:
raise ValueError("Cannot pass both name and path")
path = (name,)
signature = Pin.Signature(width, dir, xdr=xdr)
super().__init__(signature, path=path, src_loc_at=src_loc_at + 1)
@property @property
def signature(self): def width(self):
return _pin_signature(self.width, self.dir, self.xdr) return self.signature.width
def eq(self, other): @property
first_field, _, _ = next(iter(Pin(1, dir="o").layout)) def dir(self):
warnings.warn(f"`pin.eq(...)` is deprecated; use `pin.{first_field}.eq(...)` here", return self.signature.dir
DeprecationWarning, stacklevel=2)
if isinstance(self, FlippedInterface): @property
return Record.eq(flipped(self), other) def xdr(self):
else: return self.signature.xdr
return Record.eq(self, other)

View file

@ -64,7 +64,7 @@ class ResourceManagerTestCase(FHDLTestCase):
user_led = self.cm.request("user_led", 0) user_led = self.cm.request("user_led", 0)
self.assertIsInstance(flipped(user_led), Pin) self.assertIsInstance(flipped(user_led), Pin)
self.assertEqual(user_led.name, "user_led_0") self.assertEqual(user_led.o.name, "user_led_0__o")
self.assertEqual(user_led.width, 1) self.assertEqual(user_led.width, 1)
self.assertEqual(user_led.dir, "o") self.assertEqual(user_led.dir, "o")
@ -77,12 +77,14 @@ class ResourceManagerTestCase(FHDLTestCase):
def test_request_with_dir(self): def test_request_with_dir(self):
i2c = self.cm.request("i2c", 0, dir={"sda": "o"}) i2c = self.cm.request("i2c", 0, dir={"sda": "o"})
self.assertIsInstance(i2c, Record) self.assertIsInstance(i2c, PureInterface)
self.assertIsInstance(i2c.sda, Pin) self.assertTrue(i2c.signature.is_compliant(i2c))
self.assertIsInstance(flipped(i2c.sda), Pin)
self.assertEqual(i2c.sda.dir, "o") self.assertEqual(i2c.sda.dir, "o")
def test_request_tristate(self): def test_request_tristate(self):
i2c = self.cm.request("i2c", 0) i2c = self.cm.request("i2c", 0)
self.assertTrue(i2c.signature.is_compliant(i2c))
self.assertEqual(i2c.sda.dir, "io") self.assertEqual(i2c.sda.dir, "io")
ports = list(self.cm.iter_ports()) ports = list(self.cm.iter_ports())
@ -92,11 +94,11 @@ class ResourceManagerTestCase(FHDLTestCase):
self.assertEqual(ports[1].width, 1) self.assertEqual(ports[1].width, 1)
scl_info, sda_info = self.cm.iter_single_ended_pins() scl_info, sda_info = self.cm.iter_single_ended_pins()
self.assertIs(flipped(scl_info[0]), i2c.scl) self.assertIs(scl_info[0], i2c.scl)
self.assertIs(scl_info[1].io, scl) self.assertIs(scl_info[1].io, scl)
self.assertEqual(scl_info[2], {}) self.assertEqual(scl_info[2], {})
self.assertEqual(scl_info[3], False) self.assertEqual(scl_info[3], False)
self.assertIs(flipped(sda_info[0]), i2c.sda) self.assertIs(sda_info[0], i2c.sda)
self.assertIs(sda_info[1].io, sda) self.assertIs(sda_info[1].io, sda)
self.assertEqual(list(self.cm.iter_port_constraints()), [ self.assertEqual(list(self.cm.iter_port_constraints()), [
@ -315,12 +317,3 @@ class ResourceManagerTestCase(FHDLTestCase):
(r"^Cannot add clock constraint on \(sig clk100_0__i\), which is already " (r"^Cannot add clock constraint on \(sig clk100_0__i\), which is already "
r"constrained to 100000000\.0 Hz$")): r"constrained to 100000000\.0 Hz$")):
self.cm.add_clock_constraint(clk100.i, 1e6) self.cm.add_clock_constraint(clk100.i, 1e6)
def test_eq_deprecation(self):
user_led = self.cm.request("user_led", 0)
m = Module()
with self.assertWarns(DeprecationWarning):
m.d.sync += user_led.eq(1)
p = Pin(4, "o")
with self.assertWarns(DeprecationWarning):
m.d.sync += p.eq(1)

View file

@ -1,207 +1,201 @@
import warnings import warnings
from amaranth.hdl import * from amaranth.hdl import *
with warnings.catch_warnings():
warnings.filterwarnings(action="ignore", category=DeprecationWarning)
from amaranth.hdl.rec import *
from amaranth.sim import * from amaranth.sim import *
from amaranth.lib.io import * from amaranth.lib.io import *
from amaranth.lib.wiring import *
from .utils import * from .utils import *
class PinLayoutTestCase(FHDLTestCase): class PinSignatureTestCase(FHDLTestCase):
def assertLayoutEqual(self, layout, expected): def assertSignatureEqual(self, signature, expected):
casted_layout = {} self.assertEqual(signature.members, Signature(expected).members)
for name, (shape, dir) in layout.items():
casted_layout[name] = (Shape.cast(shape), dir)
self.assertEqual(casted_layout, expected)
class PinLayoutCombTestCase(PinLayoutTestCase): class PinSignatureCombTestCase(PinSignatureTestCase):
def test_pin_layout_i(self): def test_signature_i(self):
layout_1 = pin_layout(1, dir="i") sig_1 = Pin.Signature(1, dir="i")
self.assertLayoutEqual(layout_1.fields, { self.assertSignatureEqual(sig_1, {
"i": (unsigned(1), DIR_NONE), "i": In(1),
}) })
layout_2 = pin_layout(2, dir="i") sig_2 = Pin.Signature(2, dir="i")
self.assertLayoutEqual(layout_2.fields, { self.assertSignatureEqual(sig_2, {
"i": (unsigned(2), DIR_NONE), "i": In(2),
}) })
def test_pin_layout_o(self): def test_signature_o(self):
layout_1 = pin_layout(1, dir="o") sig_1 = Pin.Signature(1, dir="o")
self.assertLayoutEqual(layout_1.fields, { self.assertSignatureEqual(sig_1, {
"o": (unsigned(1), DIR_NONE), "o": Out(1),
}) })
layout_2 = pin_layout(2, dir="o") sig_2 = Pin.Signature(2, dir="o")
self.assertLayoutEqual(layout_2.fields, { self.assertSignatureEqual(sig_2, {
"o": (unsigned(2), DIR_NONE), "o": Out(2),
}) })
def test_pin_layout_oe(self): def test_signature_oe(self):
layout_1 = pin_layout(1, dir="oe") sig_1 = Pin.Signature(1, dir="oe")
self.assertLayoutEqual(layout_1.fields, { self.assertSignatureEqual(sig_1, {
"o": (unsigned(1), DIR_NONE), "o": Out(1),
"oe": (unsigned(1), DIR_NONE), "oe": Out(1),
}) })
layout_2 = pin_layout(2, dir="oe") sig_2 = Pin.Signature(2, dir="oe")
self.assertLayoutEqual(layout_2.fields, { self.assertSignatureEqual(sig_2, {
"o": (unsigned(2), DIR_NONE), "o": Out(2),
"oe": (unsigned(1), DIR_NONE), "oe": Out(1),
}) })
def test_pin_layout_io(self): def test_signature_io(self):
layout_1 = pin_layout(1, dir="io") sig_1 = Pin.Signature(1, dir="io")
self.assertLayoutEqual(layout_1.fields, { self.assertSignatureEqual(sig_1, {
"i": (unsigned(1), DIR_NONE), "i": In(1),
"o": (unsigned(1), DIR_NONE), "o": Out(1),
"oe": (unsigned(1), DIR_NONE), "oe": Out(1),
}) })
layout_2 = pin_layout(2, dir="io") sig_2 = Pin.Signature(2, dir="io")
self.assertLayoutEqual(layout_2.fields, { self.assertSignatureEqual(sig_2, {
"i": (unsigned(2), DIR_NONE), "i": In(2),
"o": (unsigned(2), DIR_NONE), "o": Out(2),
"oe": (unsigned(1), DIR_NONE), "oe": Out(1),
}) })
class PinLayoutSDRTestCase(PinLayoutTestCase): class PinSignatureSDRTestCase(PinSignatureTestCase):
def test_pin_layout_i(self): def test_signature_i(self):
layout_1 = pin_layout(1, dir="i", xdr=1) sig_1 = Pin.Signature(1, dir="i", xdr=1)
self.assertLayoutEqual(layout_1.fields, { self.assertSignatureEqual(sig_1, {
"i_clk": (unsigned(1), DIR_NONE), "i_clk": Out(1),
"i": (unsigned(1), DIR_NONE), "i": In(1),
}) })
layout_2 = pin_layout(2, dir="i", xdr=1) sig_2 = Pin.Signature(2, dir="i", xdr=1)
self.assertLayoutEqual(layout_2.fields, { self.assertSignatureEqual(sig_2, {
"i_clk": (unsigned(1), DIR_NONE), "i_clk": Out(1),
"i": (unsigned(2), DIR_NONE), "i": In(2),
}) })
def test_pin_layout_o(self): def test_signature_o(self):
layout_1 = pin_layout(1, dir="o", xdr=1) sig_1 = Pin.Signature(1, dir="o", xdr=1)
self.assertLayoutEqual(layout_1.fields, { self.assertSignatureEqual(sig_1, {
"o_clk": (unsigned(1), DIR_NONE), "o_clk": Out(1),
"o": (unsigned(1), DIR_NONE), "o": Out(1),
}) })
layout_2 = pin_layout(2, dir="o", xdr=1) sig_2 = Pin.Signature(2, dir="o", xdr=1)
self.assertLayoutEqual(layout_2.fields, { self.assertSignatureEqual(sig_2, {
"o_clk": (unsigned(1), DIR_NONE), "o_clk": Out(1),
"o": (unsigned(2), DIR_NONE), "o": Out(2),
}) })
def test_pin_layout_oe(self): def test_signature_oe(self):
layout_1 = pin_layout(1, dir="oe", xdr=1) sig_1 = Pin.Signature(1, dir="oe", xdr=1)
self.assertLayoutEqual(layout_1.fields, { self.assertSignatureEqual(sig_1, {
"o_clk": (unsigned(1), DIR_NONE), "o_clk": Out(1),
"o": (unsigned(1), DIR_NONE), "o": Out(1),
"oe": (unsigned(1), DIR_NONE), "oe": Out(1),
}) })
layout_2 = pin_layout(2, dir="oe", xdr=1) sig_2 = Pin.Signature(2, dir="oe", xdr=1)
self.assertLayoutEqual(layout_2.fields, { self.assertSignatureEqual(sig_2, {
"o_clk": (unsigned(1), DIR_NONE), "o_clk": Out(1),
"o": (unsigned(2), DIR_NONE), "o": Out(2),
"oe": (unsigned(1), DIR_NONE), "oe": Out(1),
}) })
def test_pin_layout_io(self): def test_signature_io(self):
layout_1 = pin_layout(1, dir="io", xdr=1) sig_1 = Pin.Signature(1, dir="io", xdr=1)
self.assertLayoutEqual(layout_1.fields, { self.assertSignatureEqual(sig_1, {
"i_clk": (unsigned(1), DIR_NONE), "i_clk": Out(1),
"i": (unsigned(1), DIR_NONE), "i": In(1),
"o_clk": (unsigned(1), DIR_NONE), "o_clk": Out(1),
"o": (unsigned(1), DIR_NONE), "o": Out(1),
"oe": (unsigned(1), DIR_NONE), "oe": Out(1),
}) })
layout_2 = pin_layout(2, dir="io", xdr=1) sig_2 = Pin.Signature(2, dir="io", xdr=1)
self.assertLayoutEqual(layout_2.fields, { self.assertSignatureEqual(sig_2, {
"i_clk": (unsigned(1), DIR_NONE), "i_clk": Out(1),
"i": (unsigned(2), DIR_NONE), "i": In(2),
"o_clk": (unsigned(1), DIR_NONE), "o_clk": Out(1),
"o": (unsigned(2), DIR_NONE), "o": Out(2),
"oe": (unsigned(1), DIR_NONE), "oe": Out(1),
}) })
class PinLayoutDDRTestCase(PinLayoutTestCase): class PinSignatureDDRTestCase(PinSignatureTestCase):
def test_pin_layout_i(self): def test_signature_i(self):
layout_1 = pin_layout(1, dir="i", xdr=2) sig_1 = Pin.Signature(1, dir="i", xdr=2)
self.assertLayoutEqual(layout_1.fields, { self.assertSignatureEqual(sig_1, {
"i_clk": (unsigned(1), DIR_NONE), "i_clk": Out(1),
"i0": (unsigned(1), DIR_NONE), "i0": In(1),
"i1": (unsigned(1), DIR_NONE), "i1": In(1),
}) })
layout_2 = pin_layout(2, dir="i", xdr=2) sig_2 = Pin.Signature(2, dir="i", xdr=2)
self.assertLayoutEqual(layout_2.fields, { self.assertSignatureEqual(sig_2, {
"i_clk": (unsigned(1), DIR_NONE), "i_clk": Out(1),
"i0": (unsigned(2), DIR_NONE), "i0": In(2),
"i1": (unsigned(2), DIR_NONE), "i1": In(2),
}) })
def test_pin_layout_o(self): def test_signature_o(self):
layout_1 = pin_layout(1, dir="o", xdr=2) sig_1 = Pin.Signature(1, dir="o", xdr=2)
self.assertLayoutEqual(layout_1.fields, { self.assertSignatureEqual(sig_1, {
"o_clk": (unsigned(1), DIR_NONE), "o_clk": Out(1),
"o0": (unsigned(1), DIR_NONE), "o0": Out(1),
"o1": (unsigned(1), DIR_NONE), "o1": Out(1),
}) })
layout_2 = pin_layout(2, dir="o", xdr=2) sig_2 = Pin.Signature(2, dir="o", xdr=2)
self.assertLayoutEqual(layout_2.fields, { self.assertSignatureEqual(sig_2, {
"o_clk": (unsigned(1), DIR_NONE), "o_clk": Out(1),
"o0": (unsigned(2), DIR_NONE), "o0": Out(2),
"o1": (unsigned(2), DIR_NONE), "o1": Out(2),
}) })
def test_pin_layout_oe(self): def test_signature_oe(self):
layout_1 = pin_layout(1, dir="oe", xdr=2) sig_1 = Pin.Signature(1, dir="oe", xdr=2)
self.assertLayoutEqual(layout_1.fields, { self.assertSignatureEqual(sig_1, {
"o_clk": (unsigned(1), DIR_NONE), "o_clk": Out(1),
"o0": (unsigned(1), DIR_NONE), "o0": Out(1),
"o1": (unsigned(1), DIR_NONE), "o1": Out(1),
"oe": (unsigned(1), DIR_NONE), "oe": Out(1),
}) })
layout_2 = pin_layout(2, dir="oe", xdr=2) sig_2 = Pin.Signature(2, dir="oe", xdr=2)
self.assertLayoutEqual(layout_2.fields, { self.assertSignatureEqual(sig_2, {
"o_clk": (unsigned(1), DIR_NONE), "o_clk": Out(1),
"o0": (unsigned(2), DIR_NONE), "o0": Out(2),
"o1": (unsigned(2), DIR_NONE), "o1": Out(2),
"oe": (unsigned(1), DIR_NONE), "oe": Out(1),
}) })
def test_pin_layout_io(self): def test_signature_io(self):
layout_1 = pin_layout(1, dir="io", xdr=2) sig_1 = Pin.Signature(1, dir="io", xdr=2)
self.assertLayoutEqual(layout_1.fields, { self.assertSignatureEqual(sig_1, {
"i_clk": (unsigned(1), DIR_NONE), "i_clk": Out(1),
"i0": (unsigned(1), DIR_NONE), "i0": In(1),
"i1": (unsigned(1), DIR_NONE), "i1": In(1),
"o_clk": (unsigned(1), DIR_NONE), "o_clk": Out(1),
"o0": (unsigned(1), DIR_NONE), "o0": Out(1),
"o1": (unsigned(1), DIR_NONE), "o1": Out(1),
"oe": (unsigned(1), DIR_NONE), "oe": Out(1),
}) })
layout_2 = pin_layout(2, dir="io", xdr=2) sig_2 = Pin.Signature(2, dir="io", xdr=2)
self.assertLayoutEqual(layout_2.fields, { self.assertSignatureEqual(sig_2, {
"i_clk": (unsigned(1), DIR_NONE), "i_clk": Out(1),
"i0": (unsigned(2), DIR_NONE), "i0": In(2),
"i1": (unsigned(2), DIR_NONE), "i1": In(2),
"o_clk": (unsigned(1), DIR_NONE), "o_clk": Out(1),
"o0": (unsigned(2), DIR_NONE), "o0": Out(2),
"o1": (unsigned(2), DIR_NONE), "o1": Out(2),
"oe": (unsigned(1), DIR_NONE), "oe": Out(1),
}) })
@ -211,3 +205,7 @@ class PinTestCase(FHDLTestCase):
self.assertEqual(pin.width, 2) self.assertEqual(pin.width, 2)
self.assertEqual(pin.dir, "io") self.assertEqual(pin.dir, "io")
self.assertEqual(pin.xdr, 2) self.assertEqual(pin.xdr, 2)
self.assertEqual(pin.signature.width, 2)
self.assertEqual(pin.signature.dir, "io")
self.assertEqual(pin.signature.xdr, 2)