Skip to content

Commit 0542dd1

Browse files
committed
Bring out all _oe/_oeb/_dm lines so easy for backend to wire up
1 parent c316237 commit 0542dd1

File tree

1 file changed

+39
-16
lines changed

1 file changed

+39
-16
lines changed

chipflow_lib/platforms/silicon.py

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,10 @@
1010
from pprint import pformat
1111
from typing import TYPE_CHECKING, List
1212

13-
from amaranth import Module, Signal, ClockDomain, ClockSignal, ResetSignal
14-
15-
from amaranth.lib import wiring, io
13+
from amaranth import Module, Signal, ClockDomain, ClockSignal, ResetSignal, unsigned
14+
from amaranth.lib import wiring, io, data
1615
from amaranth.lib.cdc import FFSynchronizer
1716
from amaranth.lib.wiring import Component, In, PureInterface
18-
1917
from amaranth.back import rtlil #type: ignore[reportAttributeAccessIssue]
2018
from amaranth.hdl import Fragment
2119
from amaranth.hdl._ir import PortDirection
@@ -91,10 +89,17 @@ def __init__(self,
9189
if self.direction in (io.Direction.Output, io.Direction.Bidir):
9290
self._o = Signal(self._port_desc.width, name=f"{self._name}__o")
9391
if self.direction is io.Direction.Bidir:
94-
if "individual_oe" in self.iomodel and self.iomodel["individual_oe"]:
95-
self._oe = Signal(self._port_desc.width, name=f"{self._name}__oe", init=-1)
96-
else:
92+
# the signals that get wired out to iocells. Always one per io.
93+
init_oe = -1
94+
if 'init_oe' in port_desc.iomodel and port_desc.iomodel['init_oe']:
95+
init_oe = port_desc.iomodel['init_oe']
96+
self._oes = Signal(self._port_desc.width, name=f"{self._name}__oe", init=init_oe)
97+
# the oe on the user side.
98+
if "individual_oe" not in self.iomodel or not self.iomodel["individual_oe"]:
9799
self._oe = Signal(1, name=f"{self._name}__oe", init=-1)
100+
else:
101+
self._oe = self._oes
102+
98103
elif self.direction is io.Direction.Output:
99104
# Always create an _oe for output ports
100105
self._oe = Signal(1, name=f"{self._name}__oe", init=-1)
@@ -103,11 +108,15 @@ def __init__(self,
103108

104109
def wire(self, m: Module, interface: PureInterface):
105110
assert self.direction == interface.signature.direction #type: ignore
106-
if hasattr(interface, 'i'):
111+
if hasattr(interface, '_i'):
107112
m.d.comb += interface.i.eq(self.i) # type: ignore
108-
for d in ['o', 'oe']:
113+
for d in ['_o', '_oe']:
109114
if hasattr(interface, d):
110115
m.d.comb += getattr(self, d).eq(getattr(interface, d))
116+
if self._oe is not None \
117+
and "individual_oe" in self.iomodel \
118+
and self.iomodel["individual_oe"]:
119+
m.d.comb += self._oe.eq(self._oes)
111120

112121
def instantiate_toplevel(self):
113122
ports = []
@@ -250,6 +259,8 @@ def __init__(self,
250259
# Port Configuration
251260
# Input voltage trip level
252261
if self.direction in (io.Direction.Input, io.Direction.Bidir):
262+
assert self._i is not None
263+
253264
if 'trip_point' in port_desc.iomodel:
254265
trip_point = port_desc.iomodel['trip_point']
255266
if trip_point not in __class__._VTrip_map:
@@ -258,21 +269,23 @@ def __init__(self,
258269
else:
259270
ib_mode_init = vtrip_init = 0
260271

261-
self._gpio_ib_mode_sel = Signal(1, name=f"{self._name}$ib_mode_sel", init=ib_mode_init)
262-
self._signals.append((self._gpio_ib_mode_sel, PortDirection.Output))
263-
self._gpio_vtrip_sel = Signal(1, name=f"{self._name}$vtrip_sel", init=vtrip_init)
264-
self._signals.append((self._gpio_vtrip_sel, PortDirection.Output))
272+
self._ib_mode_sel = Signal(self._i.shape().width, name=f"{self._name}$ib_mode_sel", init=ib_mode_init)
273+
self._signals.append((self._ib_mode_sel, PortDirection.Output))
274+
self._vtrip_sel = Signal(self._i.shape().width, name=f"{self._name}$vtrip_sel", init=vtrip_init)
275+
self._signals.append((self._vtrip_sel, PortDirection.Output))
265276

266277
# Drive mode
267278
if self.direction in (io.Direction.Output, io.Direction.Bidir):
279+
if self._o is None:
280+
raise ChipFlowError(f"Cannot set drive modes on a port with no outputs for {name}")
268281
if 'drive_mode' in port_desc.iomodel:
269282
dm = Sky130DriveMode(port_desc.iomodel['drive_mode'])
270283
else:
271284
dm = Sky130DriveMode.STRONG_UP_STRONG_DOWN
272285
dm_init = __class__._DriveMode_map[dm]
273-
self._gpio_dm = Signal(3, name=f"{self._name}$dm", init=dm_init)
274-
self._signals.append((self._gpio_dm, PortDirection.Output))
275-
286+
dms_shape = data.ArrayLayout(unsigned(3), self._o.shape().width)
287+
self._dms = Signal(dms_shape, name=f"{self._name}$dm", init=[dm_init]*self._o.shape().width)
288+
self._signals.append((self._dms.as_value(), PortDirection.Output)) #type: ignore
276289
# Not enabled yet:
277290
self._gpio_slow_sel = None # Select slew rate
278291
self._gpio_holdover = None # Hold mode
@@ -295,6 +308,7 @@ def wire(self, m: Module, interface: PureInterface):
295308
def instantiate_toplevel(self):
296309
ports = super().instantiate_toplevel()
297310
for s, d in self._signals:
311+
logger.debug(f"Instantiating port for signal {repr(s)}")
298312
logger.debug(f"Instantiating io${s.name} top level port")
299313
ports.append((f"io${s.name}", s, d))
300314
return ports
@@ -306,6 +320,15 @@ def ie(self):
306320
"input enable signal")
307321
return self._ie
308322

323+
@property
324+
def drive_mode(self):
325+
if self._dms is None:
326+
raise AttributeError("SiliconPlatformPort with input direction does not have an "
327+
"input enable signal")
328+
return self._dms
329+
330+
#TODO: trip selection
331+
309332
def __invert__(self):
310333
result = Sky130Port(self._name, self._port_desc, invert=not self.invert)
311334
return result

0 commit comments

Comments
 (0)