From af8459301c3cf96c4389faf398c9617772696568 Mon Sep 17 00:00:00 2001 From: Leon Schuermann Date: Mon, 13 Sep 2021 11:17:54 +0200 Subject: [PATCH] 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 --- litex/soc/cores/gpio.py | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/litex/soc/cores/gpio.py b/litex/soc/cores/gpio.py index daaf9c453..649669753 100644 --- a/litex/soc/cores/gpio.py +++ b/litex/soc/cores/gpio.py @@ -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)