From 5e642101efe44d9f5f6cc114daa645da4463602a Mon Sep 17 00:00:00 2001 From: Fischer Moseley <42497969+fischermoseley@users.noreply.github.com> Date: Sat, 10 Feb 2024 00:48:53 -0800 Subject: [PATCH] pass Ethernet config to LiteEth core generator --- src/manta/ethernet/__init__.py | 53 +++++++++++-------- src/manta/ethernet/liteeth_gen.py | 87 +++++++++++++++++++++++++++++-- 2 files changed, 114 insertions(+), 26 deletions(-) diff --git a/src/manta/ethernet/__init__.py b/src/manta/ethernet/__init__.py index 4b16ee8..20ebf3c 100644 --- a/src/manta/ethernet/__init__.py +++ b/src/manta/ethernet/__init__.py @@ -192,38 +192,45 @@ class EthernetInterface(Elaboratable): sock.sendto(bytes_out, (self.fpga_ip_addr, self.udp_port)) def generate_liteeth_core(self): + """ + Generate a LiteEth core by calling a slightly modified form of the LiteEth + standalone core generator. This passes the contents of the 'ethernet' section + of the Manta configuration file to LiteEth, after modifying it slightly to + include the UDP ports and set a MAC address if the user didn't specify one. + """ + liteeth_config = self.config.copy() + # Randomly assign a MAC address if one is not specified in the configuration. # This will choose a MAC address in the Locally Administered, Administratively Assigned group. # For more information, see: # https://en.wikipedia.org/wiki/MAC_address#Ranges_of_group_and_locally_administered_addresses - if "mac_address" not in self.config: - mac_address = list(f"{randint(0, (2**48) - 1):012x}") - mac_address[1] = "2" - mac_address = int("".join(mac_address), 16) + if "mac_address" not in liteeth_config: + addr = list(f"{randint(0, (2**48) - 1):012x}") + addr[1] = "2" + liteeth_config["mac_address"] = int("".join(addr), 16) - else: - mac_address = self.config["mac_address"] + # Force use of DHCP + liteeth_config["dhcp"] = True - liteeth_config = { - "phy": self.config["phy"], - "vendor": self.config["vendor"], - "toolchain": self.config["toolchain"], - "refclk_freq": self.config["refclk_freq"], - "clk_freq": self.config["clk_freq"], - "mac_address": mac_address, - "dhcp": True, - "data_width": 32, - "udp_ports": { - "udp0": { - "udp_port": self.udp_port, - "data_width": 32, - "tx_fifo_depth": 64, - "rx_fifo_depth": 64, - } - }, + # Use UDP + liteeth_config["core"] = "udp" + + # Use 32-bit words. Might be redundant, as I think using DHCP forces + # LiteEth to use 32-bit words + liteeth_config["data_width"] = 32 + + # Add UDP port + liteeth_config["udp_ports"] = { + "udp0": { + "udp_port": self.udp_port, + "data_width": 32, + "tx_fifo_depth": 64, + "rx_fifo_depth": 64, + } } # Generate the core from .liteeth_gen import main + return main(liteeth_config) diff --git a/src/manta/ethernet/liteeth_gen.py b/src/manta/ethernet/liteeth_gen.py index e07481e..5ba0f22 100755 --- a/src/manta/ethernet/liteeth_gen.py +++ b/src/manta/ethernet/liteeth_gen.py @@ -230,6 +230,8 @@ def get_udp_raw_port_ios(name, data_width): # PHY Core ----------------------------------------------------------------------------------------- + + class PHYCore(SoCMini): SoCMini.csr_map = { "ctrl": 0, @@ -322,8 +324,14 @@ class PHYCore(SoCMini): qpll_settings = QPLLSettings( refclksel=0b001, - fbdiv=4, - fbdiv_45={125e6: 5, 156.25e6: 4}[refclk_freq], + fbdiv={ + liteeth_phys.A7_1000BASEX: 4, + liteeth_phys.A7_2500BASEX: 5, + }[phy], + fbdiv_45={ + 125e6: 5, + 156.25e6: 4, + }[refclk_freq], refclk_div=1, ) qpll = QPLL(ethphy_pads.refclk, qpll_settings) @@ -371,7 +379,73 @@ class PHYCore(SoCMini): ) +# MAC Core ----------------------------------------------------------------------------------------- + + +class MACCore(PHYCore): + def __init__(self, platform, core_config): + # Parameters ------------------------------------------------------------------------------- + nrxslots = core_config.get("nrxslots", 2) + ntxslots = core_config.get("ntxslots", 2) + bus_standard = core_config["core"] + tx_cdc_depth = core_config.get("tx_cdc_depth", 32) + tx_cdc_buffered = core_config.get("tx_cdc_buffered", False) + rx_cdc_depth = core_config.get("rx_cdc_depth", 32) + rx_cdc_buffered = core_config.get("rx_cdc_buffered", False) + assert bus_standard in ["wishbone", "axi-lite"] + + # PHY -------------------------------------------------------------------------------------- + PHYCore.__init__(self, platform, core_config) + + # MAC -------------------------------------------------------------------------------------- + self.ethmac = ethmac = LiteEthMAC( + phy=self.ethphy, + dw=32, + interface="wishbone", + endianness=core_config["endianness"], + nrxslots=nrxslots, + ntxslots=ntxslots, + full_memory_we=core_config.get("full_memory_we", False), + tx_cdc_depth=tx_cdc_depth, + tx_cdc_buffered=tx_cdc_buffered, + rx_cdc_depth=rx_cdc_depth, + rx_cdc_buffered=rx_cdc_buffered, + ) + + if bus_standard == "wishbone": + # Wishbone Interface ----------------------------------------------------------------------- + wb_bus = wishbone.Interface() + platform.add_extension(wb_bus.get_ios("wishbone")) + self.comb += wb_bus.connect_to_pads( + self.platform.request("wishbone"), mode="slave" + ) + self.bus.add_master(master=wb_bus) + + if bus_standard == "axi-lite": + # AXI-Lite Interface ----------------------------------------------------------------------- + axil_bus = axi.AXILiteInterface(address_width=32, data_width=32) + platform.add_extension(axil_bus.get_ios("bus")) + self.submodules += axi.Wishbone2AXILite(ethmac.bus, axil_bus) + self.comb += axil_bus.connect_to_pads( + self.platform.request("bus"), mode="slave" + ) + self.bus.add_master(master=axil_bus) + + ethmac_region_size = (nrxslots + ntxslots) * buffer_depth + ethmac_region = SoCRegion( + origin=self.mem_map.get("ethmac", None), + size=ethmac_region_size, + cached=False, + ) + self.bus.add_slave(name="ethmac", slave=ethmac.bus, region=ethmac_region) + + # Interrupt Interface ---------------------------------------------------------------------- + self.comb += self.platform.request("interrupt").eq(self.ethmac.ev.irq) + + # UDP Core ----------------------------------------------------------------------------------------- + + class UDPCore(PHYCore): def add_streamer_port(self, platform, name, port_cfg): # Use default Data-Width of 8-bit when not specified. @@ -571,6 +645,8 @@ class UDPCore(PHYCore): # Build -------------------------------------------------------------------------------------------- + + def main(core_config): # Convert YAML elements to Python/LiteX -------------------------------------------------------- for k, v in core_config.items(): @@ -598,7 +674,12 @@ def main(core_config): raise ValueError("Unsupported vendor: {}".format(core_config["vendor"])) platform.add_extension(_io) - soc = UDPCore(platform, core_config) + if core_config["core"] in ["wishbone", "axi-lite"]: + soc = MACCore(platform, core_config) + elif core_config["core"] == "udp": + soc = UDPCore(platform, core_config) + else: + raise ValueError("Unknown core: {}".format(core_config["core"])) with TemporaryDirectory() as path: builder = Builder(soc, compile_gateware=False, output_dir=path)