commit
32de4f041e
|
@ -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
|
196
liteeth/gen.py
196
liteeth/gen.py
|
@ -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 ----------------------------------------------------------------------------------------------
|
||||
|
@ -179,6 +180,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):
|
||||
|
@ -339,9 +370,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)
|
||||
|
@ -417,63 +546,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 --------------------------------------------------------------------------------------------
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue