litex/soc/cores/gpio: support external tristate buffer

Support exposing tristate GPIOs with tristate pads, by avoiding
instantiation of tristate buffers directly in the module. This gives
the developers more flexibility in how they want to implement their
tristate IOs (for example with level shifters behind the IOs), and
allows to use the GPIOTristate core in the Verilated simulation as
Verilator does not support top-level inout signals.

Signed-off-by: Leon Schuermann <leon@is.currently.online>
This commit is contained in:
Leon Schuermann 2021-09-13 11:17:54 +02:00
parent e0e9311ceb
commit af8459301c
1 changed files with 26 additions and 11 deletions

View File

@ -73,20 +73,35 @@ class GPIOInOut(Module):
class GPIOTristate(_GPIOIRQ, Module, AutoCSR):
def __init__(self, pads, with_irq=False):
assert isinstance(pads, Signal)
nbits = len(pads)
self._oe = CSRStorage(nbits, description="GPIO Tristate(s) Control.")
self._in = CSRStatus(nbits, description="GPIO Input(s) Status.")
self._out = CSRStorage(nbits, description="GPIO Ouptut(s) Control.")
assert isinstance(pads, Signal) or isinstance(pads, Record)
# # #
for i in range(nbits):
t = TSTriple()
self.specials += t.get_tristate(pads[i])
self.comb += t.oe.eq(self._oe.storage[i])
self.comb += t.o.eq(self._out.storage[i])
self.specials += MultiReg(t.i, self._in.status[i])
if isinstance(pads, Signal):
# Proper inout IOs
nbits = len(pads)
self._oe = CSRStorage(nbits, description="GPIO Tristate(s) Control.")
self._in = CSRStatus(nbits, description="GPIO Input(s) Status.")
self._out = CSRStorage(nbits, description="GPIO Ouptut(s) Control.")
for i in range(nbits):
t = TSTriple()
self.specials += t.get_tristate(pads[i])
self.comb += t.oe.eq(self._oe.storage[i])
self.comb += t.o.eq(self._out.storage[i])
self.specials += MultiReg(t.i, self._in.status[i])
else:
# Tristate record, for external tristate IO chips or simulation
nbits = len(pads.oe)
self._oe = CSRStorage(nbits, description="GPIO Tristate(s) Control.")
self._in = CSRStatus(nbits, description="GPIO Input(s) Status.")
self._out = CSRStorage(nbits, description="GPIO Ouptut(s) Control.")
clocked_inputs = Signal.like(pads.i)
for i in range(nbits):
self.comb += pads.oe[i].eq(self._oe.storage[i])
self.comb += pads.o[i].eq(self._out.storage[i])
self.specials += MultiReg(pads.i[i], self._in.status[i])
if with_irq:
self.add_irq(self._in.status)