uartbone+crossover: add dynamic mux so that programs can boot into full-bandwidth UART, but enable debuggability as needed

This commit is contained in:
Joshua Wise 2024-05-20 22:05:14 -04:00
parent 76a704377f
commit a47bbb28f5
3 changed files with 65 additions and 17 deletions

View File

@ -474,12 +474,53 @@ class UARTCrossover(UART):
Creates a fully compatible UART that can be used by the CPU as a regular UART and adds a second
UART, cross-connected to the main one to allow terminal emulation over a Wishbone bridge.
If a pad_phy is provided, a debug_en register is created that enables a
mux to interpose the pads. When debug_en is 0, then the internal UART
is routed to the pads (and the crossover UART is unused); when debug_en
is 1, then the pad_phy is passed through to its original destination,
and the crossover is also passed through as usual (i.e., the behavior as
if no pad_phy were provided).
"""
def __init__(self, **kwargs):
def __init__(self, pad_phy=None, **kwargs):
assert kwargs.get("phy", None) == None
UART.__init__(self, **kwargs)
self.xover = UART(tx_fifo_depth=1, rx_fifo_depth=16, rx_fifo_rx_we=True)
self.comb += [
self.source.connect(self.xover.sink),
self.xover.source.connect(self.sink)
]
if pad_phy is not None:
# Steal the pads from the pad_phy.
replaced_source = stream.Endpoint([("data", 8)])
replaced_sink = stream.Endpoint([("data", 8)])
self.debug_en = CSRStorage(1, reset=1)
# debug_en = 0:
# pad_phy <-> self
# xover dangles, uartbone_phy dangles
# debug_en = 1:
# xover <-> self
# pad_phy <-> uartbone_phy
self.comb += If(self.debug_en.storage == 0,
pad_phy.source.connect(self.sink),
self.source.connect(pad_phy.sink),
self.xover.source.ready.eq(0),
self.xover.sink.valid.eq(0),
replaced_source.valid.eq(0),
replaced_sink.ready.eq(0),
).Else(
replaced_source.valid.eq(pad_phy.source.valid),
replaced_source.data.eq(pad_phy.source.data),
pad_phy.source.ready.eq(replaced_source.ready),
pad_phy.sink.valid.eq(replaced_sink.valid),
pad_phy.sink.data.eq(replaced_sink.data),
replaced_sink.ready.eq(pad_phy.sink.ready),
self.source.connect(self.xover.sink),
self.xover.source.connect(self.sink),
)
pad_phy.source = replaced_source
pad_phy.sink = replaced_sink
else:
self.comb += [
self.source.connect(self.xover.sink),
self.xover.source.connect(self.sink)
]

View File

@ -1512,8 +1512,7 @@ class LiteXSoC(SoC):
# Crossover + UARTBone.
elif uart_name in ["crossover+uartbone"]:
self.add_uartbone(baudrate=baudrate)
uart = UARTCrossover(**uart_kwargs)
uart = self.add_uartbone(baudrate=baudrate, with_crossover=True, **uart_kwargs)
# JTAG UART.
elif uart_name in ["jtag_uart"]:
@ -1566,16 +1565,21 @@ class LiteXSoC(SoC):
self.add_constant("UART_POLLING")
# Add UARTbone ---------------------------------------------------------------------------------
def add_uartbone(self, name="uartbone", uart_name="serial", clk_freq=None, baudrate=115200, cd="sys"):
def add_uartbone(self, name="uartbone", uart_name="serial", clk_freq=None, baudrate=115200, cd="sys", with_crossover=False, **uart_kwargs):
# Imports.
from litex.soc.cores import uart
# Core.
if clk_freq is None:
clk_freq = self.sys_clk_freq
self.check_if_exists(name)
uartbone_phy = uart.UARTPHY(self.platform.request(uart_name), clk_freq, baudrate)
uartbone = uart.UARTBone(
if with_crossover:
crossover = uart.UARTCrossover(pad_phy=uartbone_phy, **uart_kwargs)
uartbone = uart.UARTBone(
phy = uartbone_phy,
clk_freq = clk_freq,
cd = cd,
@ -1584,6 +1588,9 @@ class LiteXSoC(SoC):
self.add_module(name=name, module=uartbone)
self.bus.add_master(name=name, master=uartbone.wishbone)
if with_crossover:
return crossover
# Add JTAGbone ---------------------------------------------------------------------------------
def add_jtagbone(self, name="jtagbone", chain=1):
# Imports.

View File

@ -187,14 +187,14 @@ class SoCCore(LiteXSoC):
if with_uart:
# crossover+uartbone is kept as backward compatibility
if uart_name == "crossover+uartbone":
self.logger.warning("{} UART: is deprecated {}".format(
colorer(uart_name, color="yellow"),
colorer("please use --uart-name=\"crossover\" --with-uartbone", color="red")))
time.sleep(2)
# Already configured.
self._uartbone = True
uart_name = "crossover"
#if uart_name == "crossover+uartbone":
# self.logger.warning("{} UART: is deprecated {}".format(
# colorer(uart_name, color="yellow"),
# colorer("please use --uart-name=\"crossover\" --with-uartbone", color="red")))
# time.sleep(2)
# # Already configured.
# self._uartbone = True
# uart_name = "crossover"
# JTAGBone and jtag_uart can't be used at the same time.
assert not (with_jtagbone and uart_name == "jtag_uart")