From af8459301c3cf96c4389faf398c9617772696568 Mon Sep 17 00:00:00 2001 From: Leon Schuermann Date: Mon, 13 Sep 2021 11:17:54 +0200 Subject: [PATCH 1/2] 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) From 8670ac4902c85d59682f159d8744892d91c81020 Mon Sep 17 00:00:00 2001 From: Leon Schuermann Date: Mon, 13 Sep 2021 11:28:02 +0200 Subject: [PATCH 2/2] litex_sim: add optional GPIOTristate core Adds a switch `--with-gpio`, which will add a 32 pin GPIOTristate core, with the GPIOTristate signals exposed on the top-level module. This can be used to add a custom GPIO module in the Verilated simulation. Signed-off-by: Leon Schuermann --- litex/tools/litex_sim.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/litex/tools/litex_sim.py b/litex/tools/litex_sim.py index 961c3635e..8a4e4cebc 100755 --- a/litex/tools/litex_sim.py +++ b/litex/tools/litex_sim.py @@ -22,6 +22,7 @@ from litex.soc.integration.soc_core import * from litex.soc.integration.builder import * from litex.soc.integration.soc import * from litex.soc.cores.bitbang import * +from litex.soc.cores.gpio import GPIOTristate from litex.soc.cores.cpu import CPUS @@ -87,6 +88,13 @@ _io = [ Subsignal("clk", Pins(1)), Subsignal("dq", Pins(4)), ), + # Simulated tristate IO (Verilator does not support top-level + # tristate signals) + ("gpio", 0, + Subsignal("oe", Pins(32)), + Subsignal("o", Pins(32)), + Subsignal("i", Pins(32)), + ) ] # Platform ----------------------------------------------------------------------------------------- @@ -117,6 +125,7 @@ class SimSoC(SoCCore): with_sdcard = False, with_spi_flash = False, spi_flash_init = [], + with_gpio = False, sim_debug = False, trace_reset_on = False, **kwargs): @@ -262,6 +271,11 @@ class SimSoC(SoCCore): self.submodules.spiflash_phy = LiteSPIPHYModel(spiflash_module, init=spi_flash_init) self.add_spi_flash(phy=self.spiflash_phy, mode="4x", module=spiflash_module, with_master=True) + # GPIO -------------------------------------------------------------------------------------- + if with_gpio: + self.submodules.gpio = GPIOTristate(platform.request("gpio"), with_irq=True) + self.irq.add("gpio", use_loc_if_exists=True) + # Simulation debugging ---------------------------------------------------------------------- if sim_debug: platform.add_debug(self, reset=1 if trace_reset_on else 0) @@ -327,6 +341,7 @@ def sim_args(parser): parser.add_argument("--with-sdcard", action="store_true", help="Enable SDCard support") parser.add_argument("--with-spi-flash", action="store_true", help="Enable SPI Flash (MMAPed)") parser.add_argument("--spi_flash-init", default=None, help="SPI Flash init file") + parser.add_argument("--with-gpio", action="store_true", help="Enable Tristate GPIO (32 pins)") parser.add_argument("--trace", action="store_true", help="Enable Tracing") parser.add_argument("--trace-fst", action="store_true", help="Enable FST tracing (default=VCD)") parser.add_argument("--trace-start", default="0", help="Time to start tracing (ps)") @@ -394,6 +409,7 @@ def main(): with_i2c = args.with_i2c, with_sdcard = args.with_sdcard, with_spi_flash = args.with_spi_flash, + with_gpio = args.with_gpio, sim_debug = args.sim_debug, trace_reset_on = trace_start > 0 or trace_end > 0, sdram_init = [] if args.sdram_init is None else get_mem_data(args.sdram_init, cpu.endianness),