gen.py: Add UDP raw mode

This commit is contained in:
rowanG077 2023-07-10 17:07:38 +02:00
parent 70a89eafaa
commit b8745ff99a
3 changed files with 187 additions and 57 deletions

View File

@ -0,0 +1,44 @@
--- # PHY ----------------------------------------------------------------------
# Copyright (c) 2023 LumiGuide Fietsdetectie B.V. <goemansrowan@gmail.com>
# License: BSD
phy: LiteEthECP5PHYRGMII
phy_tx_delay: 0e-9
phy_rx_delay: 2e-9
device: LFE5U-25F-6BG256C
vendor: lattice
toolchain: trellis
# Core -------------------------------------------------------------------------
clk_freq: 125e6
core: udp
mac_address: 0x10e2d5000000
ip_address: 172.30.0.1
tx_cdc_depth: 16
tx_cdc_buffered: True
rx_cdc_depth: 16
rx_cdc_buffered: True
# UDP Ports --------------------------------------------------------------------
# mode `raw` vs `streamer` mode:
# The streamer mode is a convenience wrapper around a `raw` UDP port. A raw UDP
# port receives and requires the full UDP header information without filtering.
# In addition, when transmitting packets, it's required to make sure the user
# can burst a full packet without issuing a stall.
# The `streamer` mode on the other hand, allows a port to be specified to
# receive/transmit on. There is also a FIFO between the raw port and the
# streamer port. This means the user is not required to be able to burst packet
# into the core. But a limitation of this is that the user relinquishes
# control of transmitted UDP packet sizes.
udp_ports:
raw:
data_width: 32
mode: raw
streamer1:
data_width: 32
port: 1337
mode: streamer
streamer2:
data_width: 32
port: 6077
mode: streamer

View File

@ -50,6 +50,7 @@ from liteeth.mac import LiteEthMAC
from liteeth.core import LiteEthUDPIPCore
from liteeth.core.dhcp import LiteEthDHCP
from liteeth.frontend.stream import LiteEthUDPStreamer
from liteeth.frontend.etherbone import LiteEthEtherbone
# IOs ----------------------------------------------------------------------------------------------
@ -178,6 +179,36 @@ def get_udp_port_ios(name, data_width, dynamic_params=False):
),
]
def get_udp_raw_port_ios(name, data_width):
return [
(f"{name}", 0,
# Sink.
Subsignal("sink_ip_address", Pins(32)),
Subsignal("sink_src_port", Pins(16)),
Subsignal("sink_dst_port", Pins(16)),
Subsignal("sink_valid", Pins(1)),
Subsignal("sink_length", Pins(16)),
Subsignal("sink_last", Pins(1)),
Subsignal("sink_ready", Pins(1)),
Subsignal("sink_data", Pins(data_width)),
Subsignal("sink_last_be", Pins(data_width//8)),
# Source.
Subsignal("source_ip_address", Pins(32)),
Subsignal("source_src_port", Pins(16)),
Subsignal("source_dst_port", Pins(16)),
Subsignal("source_valid", Pins(1)),
Subsignal("source_length", Pins(16)),
Subsignal("source_last", Pins(1)),
Subsignal("source_ready", Pins(1)),
Subsignal("source_data", Pins(data_width)),
Subsignal("source_last_be", Pins(data_width//8)),
Subsignal("source_error", Pins(1)),
),
]
# PHY Core -----------------------------------------------------------------------------------------
class PHYCore(SoCMini):
@ -335,9 +366,107 @@ class MACCore(PHYCore):
# UDP Core -----------------------------------------------------------------------------------------
class UDPCore(PHYCore):
def __init__(self, platform, core_config):
from liteeth.frontend.stream import LiteEthUDPStreamer
def add_streamer_port(self, platform, name, port_cfg):
# Use default Data-Width of 8-bit when not specified.
data_width = port_cfg.get("data_width", 8)
# Used dynamic UDP-Port/IP-Address when not specified.
dynamic_params = port_cfg.get("ip_address", None) is None
# FIFO Depth.
tx_fifo_depth = port_cfg.get("tx_fifo_depth", 64)
rx_fifo_depth = port_cfg.get("rx_fifo_depth", 64)
# Create/Add IOs.
# ---------------
platform.add_extension(get_udp_port_ios(name,
data_width = data_width,
dynamic_params = dynamic_params
))
port_ios = platform.request(name)
if dynamic_params:
ip_address = port_ios.ip_address
udp_port = port_ios.udp_port
else:
ip_address = port_cfg.get("ip_address")
udp_port = port_cfg.get("udp_port")
# Create UDPStreamer.
# -------------------
udp_streamer = LiteEthUDPStreamer(self.core.udp,
ip_address = ip_address,
udp_port = udp_port,
data_width = data_width,
tx_fifo_depth = tx_fifo_depth,
rx_fifo_depth = rx_fifo_depth
)
self.submodules += udp_streamer
# Connect IOs.
# ------------
# Connect UDP Sink IOs to UDP Steamer.
self.comb += [
udp_streamer.sink.valid.eq(port_ios.sink_valid),
udp_streamer.sink.last.eq(port_ios.sink_last),
port_ios.sink_ready.eq(udp_streamer.sink.ready),
udp_streamer.sink.data.eq(port_ios.sink_data)
]
# Connect UDP Streamer to UDP Source IOs.
self.comb += [
port_ios.source_valid.eq(udp_streamer.source.valid),
port_ios.source_last.eq(udp_streamer.source.last),
udp_streamer.source.ready.eq(port_ios.source_ready),
port_ios.source_data.eq(udp_streamer.source.data),
port_ios.source_error.eq(udp_streamer.source.error),
]
def add_raw_port(self, platform, name, port_cfg):
# Use default Data-Width of 8-bit when not specified.
data_width = port_cfg.get("data_width", 8)
# Create/Add IOs.
# ---------------
platform.add_extension(get_udp_raw_port_ios(name,
data_width = data_width,
))
port_ios = platform.request(name)
raw_port = self.core.udp.crossbar.get_port(port_ios.sink_dst_port, dw=data_width)
# Connect IOs.
# ------------
# Connect UDP Sink IOs to UDP.
self.comb += [
raw_port.sink.valid.eq(port_ios.sink_valid),
raw_port.sink.last.eq(port_ios.sink_last),
raw_port.sink.dst_port.eq(port_ios.sink_dst_port),
raw_port.sink.src_port.eq(port_ios.sink_src_port),
raw_port.sink.ip_address.eq(port_ios.sink_ip_address),
raw_port.sink.length.eq(port_ios.sink_length),
port_ios.sink_ready.eq(raw_port.sink.ready),
raw_port.sink.data.eq(port_ios.sink_data),
raw_port.sink.last_be.eq(port_ios.sink_last_be),
]
# Connect UDP to UDP Source IOs.
self.comb += [
port_ios.source_valid.eq(raw_port.source.valid),
port_ios.source_last.eq(raw_port.source.last),
port_ios.source_dst_port.eq(raw_port.source.dst_port),
port_ios.source_src_port.eq(raw_port.source.src_port),
port_ios.source_ip_address.eq(raw_port.source.ip_address),
port_ios.source_length.eq(raw_port.source.length),
raw_port.source.ready.eq(port_ios.source_ready),
port_ios.source_data.eq(raw_port.source.data),
port_ios.source_last_be.eq(raw_port.source.last_be),
port_ios.source_error.eq(raw_port.source.error),
]
def __init__(self, platform, core_config):
# Config -----------------------------------------------------------------------------------
tx_cdc_depth = core_config.get("tx_cdc_depth", 32)
tx_cdc_buffered = core_config.get("tx_cdc_buffered", False)
@ -413,63 +542,16 @@ class UDPCore(PHYCore):
self.comb += axil_bus.connect_to_pads(platform.request("mmap"), mode="master")
# UDP Ports --------------------------------------------------------------------------------
for name, port in core_config["udp_ports"].items():
# Parameters.
# -----------
for name, port_cfg in core_config["udp_ports"].items():
# mode either `raw` or `stream`, default to streamer to be backwards compatible
mode = port_cfg.get("mode", "streamer")
assert mode == "raw" or mode == "streamer"
# Use default Data-Width of 8-bit when not specified.
data_width = port.get("data_width", 8)
if mode == "streamer":
self.add_streamer_port(platform, name, port_cfg)
elif mode == "raw":
self.add_raw_port(platform, name, port_cfg)
# Used dynamic UDP-Port/IP-Address when not specified.
dynamic_params = port.get("ip_address", None) is None
# FIFO Depth.
tx_fifo_depth = port.get("tx_fifo_depth", 64)
rx_fifo_depth = port.get("rx_fifo_depth", 64)
# Create/Add IOs.
# ---------------
platform.add_extension(get_udp_port_ios(name,
data_width = data_width,
dynamic_params = dynamic_params
))
port_ios = platform.request(name)
# Create UDPStreamer.
# -------------------
if dynamic_params:
ip_address = port_ios.ip_address
udp_port = port_ios.udp_port
else:
ip_address = port.get("ip_address")
udp_port = port.get("udp_port")
udp_streamer = LiteEthUDPStreamer(self.core.udp,
ip_address = ip_address,
udp_port = udp_port,
data_width = data_width,
tx_fifo_depth = tx_fifo_depth,
rx_fifo_depth = rx_fifo_depth
)
self.submodules += udp_streamer
# Connect IOs.
# ------------
# Connect UDP Sink IOs to UDP Steamer.
self.comb += [
udp_streamer.sink.valid.eq(port_ios.sink_valid),
udp_streamer.sink.last.eq(port_ios.sink_last),
port_ios.sink_ready.eq(udp_streamer.sink.ready),
udp_streamer.sink.data.eq(port_ios.sink_data)
]
# Connect UDP Streamer to UDP Source IOs.
self.comb += [
port_ios.source_valid.eq(udp_streamer.source.valid),
port_ios.source_last.eq(udp_streamer.source.last),
udp_streamer.source.ready.eq(port_ios.source_ready),
port_ios.source_data.eq(udp_streamer.source.data),
port_ios.source_error.eq(udp_streamer.source.error),
]
# Build --------------------------------------------------------------------------------------------

View File

@ -23,3 +23,7 @@ class TestExamples(unittest.TestCase):
def test_wishbone_mii(self):
errors = build_config("wishbone_mii")
self.assertEqual(errors, 0)
def test_udp_raw_rgmii(self):
errors = build_config("udp_raw_ecp5rgmii")
self.assertEqual(errors, 0)