2022-06-03 19:11:07 +02:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
|
|
|
#
|
|
|
|
# This file is part of LiteEth.
|
|
|
|
#
|
|
|
|
# Copyright (c) 2015-2022 Florent Kermarrec <florent@enjoy-digital.fr>
|
|
|
|
# Copyright (c) 2020 Xiretza <xiretza@xiretza.xyz>
|
|
|
|
# Copyright (c) 2020 Stefan Schrijvers <ximin@ximinity.net>
|
|
|
|
# SPDX-License-Identifier: BSD-2-Clause
|
|
|
|
|
|
|
|
import argparse
|
|
|
|
import os
|
|
|
|
import yaml
|
|
|
|
|
|
|
|
from migen import *
|
|
|
|
|
|
|
|
from litex.build.generic_platform import *
|
|
|
|
from litex.build.xilinx.platform import XilinxPlatform
|
|
|
|
from litex.build.lattice.platform import LatticePlatform
|
|
|
|
|
|
|
|
from litex.soc.interconnect import wishbone
|
|
|
|
from litex.soc.integration.soc_core import *
|
|
|
|
from litex.soc.integration.builder import *
|
|
|
|
from litex.soc.integration.soc import SoCRegion
|
|
|
|
|
|
|
|
from liteeth.common import *
|
|
|
|
|
|
|
|
from liteeth import phy as liteeth_phys
|
|
|
|
from liteeth.mac import LiteEthMAC
|
|
|
|
from liteeth.core import LiteEthUDPIPCore
|
|
|
|
|
|
|
|
# IOs ----------------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
MAC_ADDRESS = 0x00183e02a914
|
2022-06-04 21:46:16 +02:00
|
|
|
CLK_FREQ = int(80e6)
|
2022-06-03 19:11:07 +02:00
|
|
|
|
|
|
|
_io = [
|
|
|
|
# Clk / Rst
|
|
|
|
("sys_clock", 0, Pins(1)),
|
|
|
|
("sys_reset", 1, Pins(1)),
|
|
|
|
|
|
|
|
# IP/MAC Address.
|
|
|
|
("mac_address", 0, Pins(48)),
|
|
|
|
("ip_address", 0, Pins(32)),
|
|
|
|
|
|
|
|
# Interrupt
|
|
|
|
("interrupt", 0, Pins(1)),
|
|
|
|
|
|
|
|
# MII PHY Pads
|
|
|
|
("mii_eth_clocks", 0,
|
|
|
|
Subsignal("tx", Pins(1)),
|
|
|
|
Subsignal("rx", Pins(1)),
|
|
|
|
),
|
|
|
|
("mii_eth", 0,
|
|
|
|
Subsignal("rst_n", Pins(1)),
|
|
|
|
Subsignal("mdio", Pins(1)),
|
|
|
|
Subsignal("mdc", Pins(1)),
|
|
|
|
Subsignal("rx_dv", Pins(1)),
|
|
|
|
Subsignal("rx_er", Pins(1)),
|
|
|
|
Subsignal("rx_data", Pins(4)),
|
|
|
|
Subsignal("tx_en", Pins(1)),
|
|
|
|
Subsignal("tx_data", Pins(4)),
|
|
|
|
Subsignal("col", Pins(1)),
|
|
|
|
Subsignal("crs", Pins(1))
|
|
|
|
),
|
|
|
|
|
|
|
|
# RMII PHY Pads
|
|
|
|
("rmii_eth_clocks", 0,
|
|
|
|
Subsignal("ref_clk", Pins(1))
|
|
|
|
),
|
|
|
|
("rmii_eth", 0,
|
|
|
|
Subsignal("rst_n", Pins(1)),
|
|
|
|
Subsignal("rx_data", Pins(2)),
|
|
|
|
Subsignal("crs_dv", Pins(1)),
|
|
|
|
Subsignal("tx_en", Pins(1)),
|
|
|
|
Subsignal("tx_data", Pins(2)),
|
|
|
|
Subsignal("mdc", Pins(1)),
|
|
|
|
Subsignal("mdio", Pins(1)),
|
|
|
|
),
|
|
|
|
|
|
|
|
# GMII PHY Pads
|
|
|
|
("gmii_eth_clocks", 0,
|
|
|
|
Subsignal("tx", Pins(1)),
|
|
|
|
Subsignal("gtx", Pins(1)),
|
|
|
|
Subsignal("rx", Pins(1))
|
|
|
|
),
|
|
|
|
("gmii_eth", 0,
|
|
|
|
Subsignal("rst_n", Pins(1)),
|
|
|
|
Subsignal("int_n", Pins(1)),
|
|
|
|
Subsignal("mdio", Pins(1)),
|
|
|
|
Subsignal("mdc", Pins(1)),
|
|
|
|
Subsignal("rx_dv", Pins(1)),
|
|
|
|
Subsignal("rx_er", Pins(1)),
|
|
|
|
Subsignal("rx_data", Pins(8)),
|
|
|
|
Subsignal("tx_en", Pins(1)),
|
|
|
|
Subsignal("tx_er", Pins(1)),
|
|
|
|
Subsignal("tx_data", Pins(8)),
|
|
|
|
Subsignal("col", Pins(1)),
|
|
|
|
Subsignal("crs", Pins(1))
|
|
|
|
),
|
|
|
|
|
|
|
|
# RGMII PHY Pads
|
|
|
|
("rgmii_eth_clocks", 0,
|
|
|
|
Subsignal("tx", Pins(1)),
|
|
|
|
Subsignal("rx", Pins(1))
|
|
|
|
),
|
|
|
|
("rgmii_eth", 0,
|
|
|
|
Subsignal("rst_n", Pins(1)),
|
|
|
|
Subsignal("int_n", Pins(1)),
|
|
|
|
Subsignal("mdio", Pins(1)),
|
|
|
|
Subsignal("mdc", Pins(1)),
|
|
|
|
Subsignal("rx_ctl", Pins(1)),
|
|
|
|
Subsignal("rx_data", Pins(4)),
|
|
|
|
Subsignal("tx_ctl", Pins(1)),
|
|
|
|
Subsignal("tx_data", Pins(4))
|
|
|
|
),
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
def get_udp_port_ios(name, data_width):
|
|
|
|
return [
|
|
|
|
(f"{name}", 0,
|
|
|
|
Subsignal("ip_address", Pins(32)),
|
|
|
|
|
|
|
|
# Sink.
|
|
|
|
Subsignal("sink_valid", Pins(1)),
|
|
|
|
Subsignal("sink_last", Pins(1)),
|
|
|
|
Subsignal("sink_ready", Pins(1)),
|
|
|
|
Subsignal("sink_data", Pins(data_width)),
|
|
|
|
|
|
|
|
# Source.
|
|
|
|
Subsignal("source_valid", Pins(1)),
|
|
|
|
Subsignal("source_last", Pins(1)),
|
|
|
|
Subsignal("source_ready", Pins(1)),
|
|
|
|
Subsignal("source_data", Pins(data_width)),
|
|
|
|
),
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
class PHYCore(SoCMini):
|
|
|
|
def __init__(self, platform):
|
|
|
|
super().__init__(platform, clk_freq=CLK_FREQ)
|
|
|
|
|
|
|
|
# CRG --------------------------------------------------------------------------------------
|
|
|
|
self.submodules.crg = CRG(
|
|
|
|
platform.request("sys_clock"),
|
|
|
|
platform.request("sys_reset")
|
|
|
|
)
|
|
|
|
|
|
|
|
# PHY --------------------------------------------------------------------------------------
|
2022-06-03 22:17:13 +02:00
|
|
|
phy = liteeth_phys.LiteEthPHYMII
|
2022-06-03 19:11:07 +02:00
|
|
|
ethphy = phy(
|
2022-06-03 22:17:13 +02:00
|
|
|
clock_pads=platform.request("mii_eth_clocks"),
|
|
|
|
pads=platform.request("mii_eth")
|
2022-06-03 19:11:07 +02:00
|
|
|
)
|
|
|
|
self.submodules.ethphy = ethphy
|
|
|
|
|
|
|
|
# Timing constaints.
|
|
|
|
# Generate timing constraints to ensure the "keep" attribute is properly set on the various
|
|
|
|
# clocks. This also adds the constraints to the generated .xdc that can then be "imported"
|
|
|
|
# in the project using the core.
|
|
|
|
eth_rx_clk = getattr(ethphy, "crg", ethphy).cd_eth_rx.clk
|
|
|
|
eth_tx_clk = getattr(ethphy, "crg", ethphy).cd_eth_tx.clk
|
|
|
|
from liteeth.phy.model import LiteEthPHYModel
|
|
|
|
if not isinstance(ethphy, LiteEthPHYModel):
|
|
|
|
self.platform.add_period_constraint(
|
|
|
|
eth_rx_clk,
|
|
|
|
1e9/phy.rx_clk_freq
|
|
|
|
)
|
|
|
|
self.platform.add_period_constraint(
|
|
|
|
eth_tx_clk,
|
|
|
|
1e9/phy.tx_clk_freq
|
|
|
|
)
|
|
|
|
self.platform.add_false_path_constraints(
|
|
|
|
self.crg.cd_sys.clk,
|
|
|
|
eth_rx_clk,
|
|
|
|
eth_tx_clk
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
class UDPCore(PHYCore):
|
|
|
|
def __init__(self, platform):
|
|
|
|
from liteeth.frontend.stream import LiteEthUDPStreamer
|
|
|
|
|
|
|
|
super().__init__(platform)
|
|
|
|
|
|
|
|
ip_address = platform.request("ip_address")
|
|
|
|
|
|
|
|
# Core
|
|
|
|
self.submodules.core = LiteEthUDPIPCore(
|
|
|
|
self.ethphy,
|
|
|
|
mac_address=MAC_ADDRESS,
|
|
|
|
ip_address=ip_address,
|
|
|
|
clk_freq=CLK_FREQ,
|
|
|
|
dw=8,
|
|
|
|
with_sys_datapath=False,
|
|
|
|
)
|
|
|
|
|
|
|
|
# DHCP port
|
|
|
|
data_width = 32
|
|
|
|
|
|
|
|
platform.add_extension(get_udp_port_ios(
|
|
|
|
"dhcp",
|
|
|
|
data_width=data_width,
|
|
|
|
))
|
|
|
|
dhcp_ios = platform.request("dhcp")
|
|
|
|
|
|
|
|
dhcp_streamer = LiteEthUDPStreamer(
|
|
|
|
self.core.udp,
|
|
|
|
ip_address=dhcp_ios.ip_address,
|
|
|
|
udp_port=67,
|
|
|
|
data_width=data_width,
|
|
|
|
tx_fifo_depth=64,
|
|
|
|
rx_fifo_depth=64
|
|
|
|
)
|
|
|
|
self.submodules += dhcp_streamer
|
|
|
|
|
|
|
|
self.comb += [
|
|
|
|
# Connect UDP Sink IOs to UDP Steamer.
|
|
|
|
dhcp_streamer.sink.valid.eq(dhcp_ios.sink_valid),
|
|
|
|
dhcp_streamer.sink.last.eq(dhcp_ios.sink_last),
|
|
|
|
dhcp_ios.sink_ready.eq(dhcp_streamer.sink.ready),
|
|
|
|
dhcp_streamer.sink.data.eq(dhcp_ios.sink_data),
|
|
|
|
|
|
|
|
# Connect UDP Streamer to UDP Source IOs.
|
|
|
|
dhcp_ios.source_valid.eq(dhcp_streamer.source.valid),
|
|
|
|
dhcp_ios.source_last.eq(dhcp_streamer.source.last),
|
|
|
|
dhcp_streamer.source.ready.eq(dhcp_ios.source_ready),
|
|
|
|
dhcp_ios.source_data.eq(dhcp_streamer.source.data),
|
|
|
|
]
|
|
|
|
|
|
|
|
# Build --------------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
def main():
|
|
|
|
parser = argparse.ArgumentParser(
|
|
|
|
description="splink LiteEth core generator"
|
|
|
|
)
|
|
|
|
builder_args(parser)
|
|
|
|
parser.set_defaults(output_dir="build")
|
|
|
|
args = parser.parse_args()
|
|
|
|
|
|
|
|
# Generate core --------------------------------------------------------------------------------
|
|
|
|
platform = XilinxPlatform(
|
|
|
|
"xc7a35ticsg324-1L",
|
|
|
|
io=[],
|
|
|
|
toolchain="symbiflow"
|
|
|
|
)
|
|
|
|
platform.add_extension(_io)
|
|
|
|
|
|
|
|
soc = UDPCore(platform)
|
|
|
|
|
|
|
|
builder_arguments = builder_argdict(args)
|
|
|
|
builder_arguments["compile_gateware"] = False
|
|
|
|
if builder_arguments["csr_csv"] is None:
|
|
|
|
builder_arguments["csr_csv"] = os.path.join(
|
|
|
|
builder_arguments["output_dir"],
|
|
|
|
"csr.csv"
|
|
|
|
)
|
|
|
|
|
|
|
|
builder = Builder(soc, **builder_arguments)
|
|
|
|
builder.build(build_name="liteeth_core")
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
main()
|