Skip to content

Commit 8f285e3

Browse files
committed
Enable a a bidir port to have either one output enable, or one for each wire
1 parent 1110b59 commit 8f285e3

File tree

4 files changed

+35
-12
lines changed

4 files changed

+35
-12
lines changed

chipflow_lib/pin_lock.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,11 @@ def allocate_pins(name: str, member: Dict[str, Any], pins: List[str]) -> Tuple[D
4545
name = name
4646
sig = member['annotations'][PIN_ANNOTATION_SCHEMA]
4747
width = sig['width']
48+
options = sig['options']
4849
pin_map[name] = {'pins': pins[0:width],
4950
'direction': sig['direction'],
50-
'type': 'io'}
51+
'type': 'io',
52+
'options': options}
5153
logger.debug(f"added '{name}':{pin_map[name]} to pin_map")
5254
return pin_map, pins[width:]
5355
elif member['type'] == 'interface':

chipflow_lib/platforms/silicon.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,13 +70,19 @@ def __init__(self,
7070
invert: bool = False):
7171
self._direction = io.Direction(port.direction)
7272
self._invert = invert
73+
self._options = port.options
7374

7475
self._i = self._o = self._oe = Signal(1)
7576
if self._direction in (io.Direction.Input, io.Direction.Bidir):
7677
self._i = Signal(port.width, name=f"{component}_{name}__i")
7778
if self._direction in (io.Direction.Output, io.Direction.Bidir):
7879
self._o = Signal(port.width, name=f"{component}_{name}__o")
79-
self._oe = Signal(1, name=f"{component}_{name}__oe")
80+
if self._direction is io.Direction.Bidir:
81+
if "all_have_oe" in self._options and self._options["all_have_oe"]:
82+
self._oe = Signal(port.width, name=f"{component}_{name}__oe")
83+
else:
84+
self._oe = Signal(1, name=f"{component}_{name}__oe")
85+
8086
self._pins = port.pins
8187
logger.debug(f"Created SiliconPlatformPort {name}, width={len(port.pins)},dir{self._direction}")
8288

@@ -120,7 +126,11 @@ def __len__(self):
120126
assert len(self._o) == len(self._oe)
121127
return len(self._o)
122128
if self._direction is io.Direction.Bidir:
123-
assert len(self._i) == len(self._o) == len(self._oe)
129+
assert len(self._i) == len(self._o)
130+
if self._options["all_have_oe"]:
131+
assert len(self.o) == len(self._oe)
132+
else:
133+
assert len(self._oe) == 1
124134
return len(self._i)
125135
assert False # :nocov:
126136

chipflow_lib/platforms/utils.py

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ class _PinAnnotationModel(BaseModel):
3333
model_config = ConfigDict(use_enum_values=True)
3434
direction: io.Direction
3535
width: int
36+
options: dict = {}
3637

3738
@classmethod
3839
def _annotation_schema(cls):
@@ -65,18 +66,23 @@ def as_json(self): # type: ignore
6566

6667
class PinSignature(wiring.Signature):
6768
"""Amaranth Signtaure used to decorate wires that would
68-
usually be brought out onto a pin on the package.
69+
usually be brought out onto a port on the package.
70+
71+
direction: Input, Output or Bidir
72+
width: width of port
73+
all_have_oe: For Bidir ports, should Output Enable be per wire or for the whole port
74+
init: a :ref:`const-castable object <lang-constcasting>` for the initial values of the port
6975
"""
7076

71-
def __init__(self, direction, width=1, init=None):
77+
def __init__(self, direction: io.Direction, width: int = 1, all_have_oe: bool = False, init = None):
7278
self._direction = direction
7379
self._width = width
7480
self._init = init
7581
match direction:
7682
case io.Direction.Bidir:
7783
sig = {
7884
"o": Out(width),
79-
"oe": Out(1),
85+
"oe": Out(width if all_have_oe else 1),
8086
"i": In(width)
8187
}
8288
case io.Direction.Input:
@@ -85,16 +91,21 @@ def __init__(self, direction, width=1, init=None):
8591
sig = {"o": Out(width)}
8692
case _:
8793
assert False
94+
self._options = {
95+
"all_have_oe": all_have_oe,
96+
"init": init,
97+
}
8898

8999
super().__init__(sig)
90100

91101
def annotations(self, *args):
92102
annotations = wiring.Signature.annotations(self, *args)
93-
pin_annotation = _PinAnnotation(direction=self._direction, width=self._width)
103+
pin_annotation = _PinAnnotation(direction=self._direction, width=self._width, options=self._options)
94104
return annotations + (pin_annotation,)
95105

96106
def __repr__(self):
97-
return f"PinSignature({self._direction}, {self._width})"
107+
opts = ', '.join(f"{k}={v}" for k, v in self._options.items())
108+
return f"PinSignature({self._direction}, {self._width}, {opts})"
98109

99110

100111
def OutputPinSignature(width, **kwargs):
@@ -297,6 +308,7 @@ class Port(pydantic.BaseModel):
297308
type: str
298309
pins: List[str]
299310
direction: Optional[str] = None
311+
options: Optional[dict] = None
300312

301313
@property
302314
def width(self):

chipflow_lib/steps/silicon.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
import time
1313

1414
import dotenv
15-
1615
from amaranth import *
1716

1817
from .. import ChipFlowError
@@ -124,13 +123,13 @@ def submit(self, rtlil_path, *, dry_run=False):
124123
pads = {}
125124
for iface, port in self.platform._ports.items():
126125
width = len(port.pins)
127-
print(f"iface={iface}, port={port}, dir={port.direction}, width={width}")
126+
logger.debug(f"iface={iface}, port={port}, dir={port.direction}, width={width}")
128127
if width > 1:
129128
for i in range(width):
130129
padname = f"{iface}{i}"
131-
print(f"padname={padname}, port={port}, loc={port.pins[i:i+1]}, "
130+
logger.debug(f"padname={padname}, port={port}, loc={port.pins[i]}, "
132131
f"dir={port.direction}, width={width}")
133-
pads[padname] = {'loc': port.pins[i:i+1], 'dir': port.direction}
132+
pads[padname] = {'loc': port.pins[i], 'dir': port.direction.value}
134133

135134
config = {
136135
"dependency_versions": dep_versions,

0 commit comments

Comments
 (0)