Skip to content

Commit 3c52547

Browse files
committed
lib.io: Implement *Port from RFC 55.
1 parent 7445760 commit 3c52547

File tree

3 files changed

+125
-21
lines changed

3 files changed

+125
-21
lines changed

amaranth/build/res.py

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,6 @@ class ResourceError(Exception):
1414
pass
1515

1616

17-
class SingleEndedPort:
18-
def __init__(self, io):
19-
self.io = io
20-
21-
22-
class DifferentialPort:
23-
def __init__(self, p, n):
24-
self.p = p
25-
self.n = n
26-
27-
2817
class PortGroup:
2918
pass
3019

@@ -144,20 +133,16 @@ def resolve(resource, dir, xdr, path, attrs):
144133
if isinstance(phys, Pins):
145134
phys_names = phys.names
146135
io = IOPort(len(phys), name="__".join(path) + "__io")
147-
port = SingleEndedPort(io)
136+
port = SingleEndedPort(io, invert=phys.invert, direction=phys.dir)
148137
if isinstance(phys, DiffPairs):
149138
phys_names = []
139+
p = IOPort(len(phys), name="__".join(path) + "__p")
140+
n = IOPort(len(phys), name="__".join(path) + "__n")
150141
if not self.should_skip_port_component(None, attrs, "p"):
151-
p = IOPort(len(phys), name="__".join(path) + "__p")
152142
phys_names += phys.p.names
153-
else:
154-
p = None
155143
if not self.should_skip_port_component(None, attrs, "n"):
156-
n = IOPort(len(phys), name="__".join(path) + "__n")
157144
phys_names += phys.n.names
158-
else:
159-
n = None
160-
port = DifferentialPort(p, n)
145+
port = DifferentialPort(p, n, invert=phys.invert, direction=phys.dir)
161146
if dir == "-":
162147
pin = None
163148
else:

amaranth/lib/io.py

Lines changed: 119 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,127 @@
1-
from .. import *
1+
import enum
2+
3+
from ..hdl import *
24
from ..lib import wiring
35
from ..lib.wiring import In, Out
46
from .. import tracer
57

68

7-
__all__ = ["Pin"]
9+
__all__ = ["Direction", "SingleEndedPort", "DifferentialPort", "Pin"]
10+
11+
12+
class Direction(enum.Enum):
13+
Input = "i"
14+
Output = "o"
15+
Bidir = "io"
16+
17+
def __or__(self, other):
18+
if not isinstance(other, Direction):
19+
return NotImplemented
20+
if self == other:
21+
return self
22+
else:
23+
return Direction.Bidir
24+
25+
26+
class SingleEndedPort:
27+
"""TODO
28+
"""
29+
def __init__(self, io, *, invert=False, direction=Direction.Bidir):
30+
self._io = IOValue.cast(io)
31+
if isinstance(invert, bool):
32+
self._invert = (invert,) * len(self._io)
33+
else:
34+
self._invert = tuple(invert)
35+
if len(self._invert) != len(self._io):
36+
raise ValueError(f"Length of 'invert' ({len(self._invert)}) must match "
37+
f"length of 'io' ({len(self._io)}).")
38+
if not all(isinstance(item, bool) for item in self._invert):
39+
raise ValueError(f"'invert' must be a bool or iterable of bool, not {invert!r}")
40+
self._direction = Direction(direction)
41+
42+
@property
43+
def io(self):
44+
return self._io
45+
46+
@property
47+
def invert(self):
48+
return self._invert
49+
50+
@property
51+
def direction(self):
52+
return self._direction
53+
54+
def __len__(self):
55+
return len(self._io)
56+
57+
def __invert__(self):
58+
return SingleEndedPort(self._io, invert=tuple(~inv for inv in self._invert),
59+
direction=self._direction)
60+
61+
def __getitem__(self, index):
62+
return SingleEndedPort(self._io[index], invert=self._invert[index],
63+
direction=self._direction)
64+
65+
def __add__(self, other):
66+
if not isinstance(other, SingleEndedPort):
67+
return NotImplemented
68+
return SingleEndedPort(Cat(self._io, other._io), invert=self._invert + other._invert,
69+
direction=self._direction | other._direction)
70+
71+
72+
class DifferentialPort:
73+
"""TODO
74+
"""
75+
def __init__(self, p, n, *, invert=False, direction=Direction.Bidir):
76+
self._p = IOValue.cast(p)
77+
self._n = IOValue.cast(n)
78+
if len(self._p) != len(self._n):
79+
raise ValueError(f"Length of 'p' ({len(self._p)}) must match length of 'n' "
80+
f"({len(self._n)})")
81+
if isinstance(invert, bool):
82+
self._invert = (invert,) * len(self._p)
83+
else:
84+
self._invert = tuple(invert)
85+
if len(self._invert) != len(self._p):
86+
raise ValueError(f"Length of 'invert' ({len(self._invert)}) must match "
87+
f"length of 'p' ({len(self._p)}).")
88+
if not all(isinstance(item, bool) for item in self._invert):
89+
raise ValueError(f"'invert' must be a bool or iterable of bool, not {invert!r}")
90+
self._direction = Direction(direction)
91+
92+
@property
93+
def p(self):
94+
return self._p
95+
96+
@property
97+
def n(self):
98+
return self._n
99+
100+
@property
101+
def invert(self):
102+
return self._invert
103+
104+
@property
105+
def direction(self):
106+
return self._direction
107+
108+
def __len__(self):
109+
return len(self._p)
110+
111+
def __invert__(self):
112+
return DifferentialPort(self._p, self._n, invert=tuple(~inv for inv in self._invert),
113+
direction=self._direction)
114+
115+
def __getitem__(self, index):
116+
return DifferentialPort(self._p[index], self._n[index], invert=self._invert[index],
117+
direction=self._direction)
118+
119+
def __add__(self, other):
120+
if not isinstance(other, DifferentialPort):
121+
return NotImplemented
122+
return DifferentialPort(Cat(self._p, other._p), Cat(self._n, other._n),
123+
invert=self._invert + other._invert,
124+
direction=self._direction | other._direction)
8125

9126

10127
class Pin(wiring.PureInterface):

docs/changes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ Implemented RFCs
5050
.. _RFC 46: https://amaranth-lang.org/rfcs/0046-shape-range-1.html
5151
.. _RFC 50: https://amaranth-lang.org/rfcs/0050-print.html
5252
.. _RFC 53: https://amaranth-lang.org/rfcs/0053-ioport.html
53+
.. _RFC 55: https://amaranth-lang.org/rfcs/0055-lib-io.html
5354

5455
* `RFC 17`_: Remove ``log2_int``
5556
* `RFC 27`_: Testbench processes for the simulator
@@ -93,6 +94,7 @@ Standard library changes
9394
.. currentmodule:: amaranth.lib
9495

9596
* Added: :mod:`amaranth.lib.memory`. (`RFC 45`_)
97+
* Added: :class:`amaranth.lib.io.SingleEndedPort`, :class:`amaranth.lib.io.DifferentialPort`. (`RFC 55`_)
9698
* Removed: (deprecated in 0.4) :mod:`amaranth.lib.scheduler`. (`RFC 19`_)
9799
* Removed: (deprecated in 0.4) :class:`amaranth.lib.fifo.FIFOInterface` with ``fwft=False``. (`RFC 20`_)
98100
* Removed: (deprecated in 0.4) :class:`amaranth.lib.fifo.SyncFIFO` with ``fwft=False``. (`RFC 20`_)

0 commit comments

Comments
 (0)