From 151b421a2c5d9deaee8cb91ef5ebd0f62cd61116 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 25 Jun 2024 17:36:18 +0200 Subject: [PATCH 1/7] mac/wishbone/LiteEthMACWishboneInterface: Expose separate TX/RX Wishbone buses to allow simultaneous TX/RX SRAM accesses. Useful in some designs to optimize throughput. --- liteeth/mac/__init__.py | 2 +- liteeth/mac/wishbone.py | 48 ++++++++++++++++++++++++++++------------- 2 files changed, 34 insertions(+), 16 deletions(-) diff --git a/liteeth/mac/__init__.py b/liteeth/mac/__init__.py index e451904..bfb94b4 100644 --- a/liteeth/mac/__init__.py +++ b/liteeth/mac/__init__.py @@ -77,7 +77,7 @@ class LiteEthMAC(Module, AutoCSR): if full_memory_we: wishbone_interface = FullMemoryWE()(wishbone_interface) self.submodules.interface = wishbone_interface - self.ev, self.bus = self.interface.sram.ev, self.interface.bus + self.ev, self.bus_rx, self.bus_tx = self.interface.sram.ev, self.interface.bus_rx, self.interface.bus_tx self.csrs = self.interface.get_csrs() + self.core.get_csrs() if interface == "hybrid": # Hardware MAC diff --git a/liteeth/mac/wishbone.py b/liteeth/mac/wishbone.py index 1eeffbf..db6dcfe 100644 --- a/liteeth/mac/wishbone.py +++ b/liteeth/mac/wishbone.py @@ -22,46 +22,64 @@ class LiteEthMACWishboneInterface(Module, AutoCSR): ): self.sink = stream.Endpoint(eth_phy_description(dw)) self.source = stream.Endpoint(eth_phy_description(dw)) - self.bus = wishbone.Interface(data_width=dw) + self.bus_rx = wishbone.Interface(data_width=dw) + self.bus_tx = wishbone.Interface(data_width=dw) # # # # Storage in SRAM. + # ---------------- sram_depth = math.ceil(eth_mtu/(dw//8)) self.submodules.sram = sram.LiteEthMACSRAM(dw, sram_depth, nrxslots, ntxslots, endianness, timestamp) - self.comb += self.sink.connect(self.sram.sink) - self.comb += self.sram.source.connect(self.source) + self.comb += [ + self.sink.connect(self.sram.sink), + self.sram.source.connect(self.source), + ] - # Wishbone SRAM interfaces for the writer SRAM (i.e. Ethernet RX). + # Ethernet RX Wishbone SRAM interfaces. + # ------------------------------------- + + # RX SRAMs. wb_rx_sram_ifs = [] for n in range(nrxslots): wb_rx_sram_ifs.append(wishbone.SRAM( mem_or_size = self.sram.writer.mems[n], read_only = rxslots_read_only, - bus = wishbone.Interface(data_width = dw) + bus = wishbone.Interface(data_width=dw) )) - # Wishbone SRAM interfaces for the reader SRAM (i.e. Ethernet TX). + # Expose RX SRAMs on RX Bus. + wb_slaves = [] + decoderoffset = log2_int(sram_depth, need_pow2=False) + rx_decoderbits = log2_int(len(wb_rx_sram_ifs)) + for n, wb_sram_if in enumerate(wb_rx_sram_ifs): + def slave_filter(a, v=n): + return a[decoderoffset:decoderoffset+rx_decoderbits] == v + wb_slaves.append((slave_filter, wb_sram_if.bus)) + self.submodules += wb_sram_if + wb_con = wishbone.Decoder(self.bus_rx, wb_slaves, register=True) + self.submodules += wb_con + + # Ethernet TX Wishbone SRAM interfaces. + # ------------------------------------- + + # TX SRAMs. wb_tx_sram_ifs = [] for n in range(ntxslots): wb_tx_sram_ifs.append(wishbone.SRAM( mem_or_size = self.sram.reader.mems[n], write_only = txslots_write_only, - bus = wishbone.Interface(data_width = dw) + bus = wishbone.Interface(data_width=dw) )) - # Expose Wishbone SRAMs on a single Wishbone bus. - # CHECKME: Check Decoder width for 64-bit. + # Expose TX SRAMs on TX Bus. wb_slaves = [] decoderoffset = log2_int(sram_depth, need_pow2=False) - rx_decoderbits = log2_int(len(wb_rx_sram_ifs)) tx_decoderbits = log2_int(len(wb_tx_sram_ifs)) - decoderbits = max(rx_decoderbits, tx_decoderbits) + 1 - wb_sram_ifs = wb_rx_sram_ifs + wb_tx_sram_ifs - for n, wb_sram_if in enumerate(wb_sram_ifs): + for n, wb_sram_if in enumerate(wb_tx_sram_ifs): def slave_filter(a, v=n): - return a[decoderoffset:decoderoffset+decoderbits] == v + return a[decoderoffset:decoderoffset+tx_decoderbits] == v wb_slaves.append((slave_filter, wb_sram_if.bus)) self.submodules += wb_sram_if - wb_con = wishbone.Decoder(self.bus, wb_slaves, register=True) + wb_con = wishbone.Decoder(self.bus_tx, wb_slaves, register=True) self.submodules += wb_con From 20e892c214e04f65c1957bddaf4e3105ecf4ed02 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 25 Jun 2024 17:56:12 +0200 Subject: [PATCH 2/7] mac/wishbone: Add _expose_wishbone_sram_interfaces to avoid duplicating code between TX and RX. --- liteeth/mac/wishbone.py | 69 +++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 37 deletions(-) diff --git a/liteeth/mac/wishbone.py b/liteeth/mac/wishbone.py index db6dcfe..9734bfb 100644 --- a/liteeth/mac/wishbone.py +++ b/liteeth/mac/wishbone.py @@ -36,50 +36,45 @@ class LiteEthMACWishboneInterface(Module, AutoCSR): self.sram.source.connect(self.source), ] - # Ethernet RX Wishbone SRAM interfaces. - # ------------------------------------- + # Ethernet Wishbone SRAM interfaces exposure. + # ------------------------------------------- + self._expose_wishbone_sram_interfaces( + bus = self.bus_rx, + dw = dw, + mems = self.sram.writer.mems, + nslots = nrxslots, + read_only = rxslots_read_only, + write_only = True, + ) + self._expose_wishbone_sram_interfaces( + bus = self.bus_tx, + dw = dw, + mems = self.sram.reader.mems, + nslots = ntxslots, + read_only = False, + write_only = txslots_write_only, + ) - # RX SRAMs. - wb_rx_sram_ifs = [] - for n in range(nrxslots): - wb_rx_sram_ifs.append(wishbone.SRAM( - mem_or_size = self.sram.writer.mems[n], - read_only = rxslots_read_only, + def _expose_wishbone_sram_interfaces(self, bus, dw, mems, nslots, read_only, write_only): + # SRAMs. + wb_sram_ifs = [] + for n in range(nslots): + wb_sram_ifs.append(wishbone.SRAM( + mem_or_size = mems[n], + read_only = read_only, + write_only = write_only, bus = wishbone.Interface(data_width=dw) )) - # Expose RX SRAMs on RX Bus. + # Expose SRAMs on Bus. wb_slaves = [] + sram_depth = math.ceil(eth_mtu/(dw//8)) decoderoffset = log2_int(sram_depth, need_pow2=False) - rx_decoderbits = log2_int(len(wb_rx_sram_ifs)) - for n, wb_sram_if in enumerate(wb_rx_sram_ifs): + decoderbits = log2_int(len(wb_sram_ifs)) + for n, wb_sram_if in enumerate(wb_sram_ifs): def slave_filter(a, v=n): - return a[decoderoffset:decoderoffset+rx_decoderbits] == v + return a[decoderoffset:decoderoffset+decoderbits] == v wb_slaves.append((slave_filter, wb_sram_if.bus)) self.submodules += wb_sram_if - wb_con = wishbone.Decoder(self.bus_rx, wb_slaves, register=True) - self.submodules += wb_con - - # Ethernet TX Wishbone SRAM interfaces. - # ------------------------------------- - - # TX SRAMs. - wb_tx_sram_ifs = [] - for n in range(ntxslots): - wb_tx_sram_ifs.append(wishbone.SRAM( - mem_or_size = self.sram.reader.mems[n], - write_only = txslots_write_only, - bus = wishbone.Interface(data_width=dw) - )) - - # Expose TX SRAMs on TX Bus. - wb_slaves = [] - decoderoffset = log2_int(sram_depth, need_pow2=False) - tx_decoderbits = log2_int(len(wb_tx_sram_ifs)) - for n, wb_sram_if in enumerate(wb_tx_sram_ifs): - def slave_filter(a, v=n): - return a[decoderoffset:decoderoffset+tx_decoderbits] == v - wb_slaves.append((slave_filter, wb_sram_if.bus)) - self.submodules += wb_sram_if - wb_con = wishbone.Decoder(self.bus_tx, wb_slaves, register=True) + wb_con = wishbone.Decoder(bus, wb_slaves, register=True) self.submodules += wb_con From 591b77e991ad4499a48677d6fa8c858f51ee70eb Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 25 Jun 2024 17:57:16 +0200 Subject: [PATCH 3/7] mac/wishbone: Switch to LiteXModule. --- liteeth/mac/wishbone.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/liteeth/mac/wishbone.py b/liteeth/mac/wishbone.py index 9734bfb..2d6ef1a 100644 --- a/liteeth/mac/wishbone.py +++ b/liteeth/mac/wishbone.py @@ -8,6 +8,8 @@ import math +from litex.gen import * + from liteeth.common import * from liteeth.mac import sram @@ -15,7 +17,7 @@ from litex.soc.interconnect import wishbone # MAC Wishbone Interface --------------------------------------------------------------------------- -class LiteEthMACWishboneInterface(Module, AutoCSR): +class LiteEthMACWishboneInterface(LiteXModule): def __init__(self, dw, nrxslots=2, ntxslots=2, endianness="big", timestamp=None, rxslots_read_only = True, txslots_write_only = False, @@ -30,7 +32,7 @@ class LiteEthMACWishboneInterface(Module, AutoCSR): # Storage in SRAM. # ---------------- sram_depth = math.ceil(eth_mtu/(dw//8)) - self.submodules.sram = sram.LiteEthMACSRAM(dw, sram_depth, nrxslots, ntxslots, endianness, timestamp) + self.sram = sram.LiteEthMACSRAM(dw, sram_depth, nrxslots, ntxslots, endianness, timestamp) self.comb += [ self.sink.connect(self.sram.sink), self.sram.source.connect(self.source), From 0e3e645b44448b8508b570fd65743fc4b00ec637 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 25 Jun 2024 18:16:47 +0200 Subject: [PATCH 4/7] test/test_mac_wishbone: Update with TX/RX slot changes. --- test/test_mac_wishbone.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/test/test_mac_wishbone.py b/test/test_mac_wishbone.py index d05c6b7..a3e4abf 100644 --- a/test/test_mac_wishbone.py +++ b/test/test_mac_wishbone.py @@ -102,12 +102,13 @@ class DUT(Module): def main_generator(dut): - wishbone_master = WishboneMaster(dut.ethmac.bus) + wishbone_tx_master = WishboneMaster(dut.ethmac.bus_tx) + wishbone_rx_master = WishboneMaster(dut.ethmac.bus_rx) sram_reader_driver = SRAMReaderDriver(dut.ethmac.interface.sram.reader) sram_writer_driver = SRAMWriterDriver(dut.ethmac.interface.sram.writer) sram_writer_slots_offset = [0x000, 0x200] - sram_reader_slots_offset = [0x400, 0x600] + sram_reader_slots_offset = [0x000, 0x200] length = 150+2 @@ -121,7 +122,7 @@ def main_generator(dut): # fill tx memory for i in range(length//4+1): dat = int.from_bytes(tx_payload[4*i:4*(i+1)], "big") - yield from wishbone_master.write(sram_reader_slots_offset[slot]+i, dat) + yield from wishbone_tx_master.write(sram_reader_slots_offset[slot]+i, dat) # send tx payload & wait yield from sram_reader_driver.start(slot, length) @@ -135,8 +136,8 @@ def main_generator(dut): # get rx payload (loopback on PHY Model) rx_payload = [] for i in range(length//4+1): - yield from wishbone_master.read(sram_writer_slots_offset[slot]+i) - dat = wishbone_master.dat + yield from wishbone_tx_master.read(sram_writer_slots_offset[slot]+i) + dat = wishbone_tx_master.dat rx_payload += list(dat.to_bytes(4, byteorder='big')) # check results From ec05e9c35c7b5c95601a09991bc1d88b3702f8fa Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 25 Jun 2024 18:17:02 +0200 Subject: [PATCH 5/7] liteeth/mac/wishbone: Update copyrights. --- liteeth/mac/wishbone.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/liteeth/mac/wishbone.py b/liteeth/mac/wishbone.py index 2d6ef1a..21bdd8b 100644 --- a/liteeth/mac/wishbone.py +++ b/liteeth/mac/wishbone.py @@ -1,7 +1,7 @@ # # This file is part of LiteEth. # -# Copyright (c) 2015-2021 Florent Kermarrec +# Copyright (c) 2015-2024 Florent Kermarrec # Copyright (c) 2015-2016 Sebastien Bourdeauducq # Copyright (c) 2021 Leon Schuermann # SPDX-License-Identifier: BSD-2-Clause From 80bded4ffc71f68962689d3d6c0be41ff9f846d0 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 25 Jun 2024 18:26:20 +0200 Subject: [PATCH 6/7] liteeth/mac/wishbone: Fix write_only mode on RX. --- liteeth/mac/wishbone.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/liteeth/mac/wishbone.py b/liteeth/mac/wishbone.py index 21bdd8b..1be58de 100644 --- a/liteeth/mac/wishbone.py +++ b/liteeth/mac/wishbone.py @@ -46,7 +46,7 @@ class LiteEthMACWishboneInterface(LiteXModule): mems = self.sram.writer.mems, nslots = nrxslots, read_only = rxslots_read_only, - write_only = True, + write_only = False, ) self._expose_wishbone_sram_interfaces( bus = self.bus_tx, From a118dd146f8c60605a03aa8303c3b3031d078431 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 25 Jun 2024 18:53:42 +0200 Subject: [PATCH 7/7] liteeth/gen: Update MACCore with EthMAC changes. --- liteeth/gen.py | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/liteeth/gen.py b/liteeth/gen.py index 21dd72f..fc1ca1d 100755 --- a/liteeth/gen.py +++ b/liteeth/gen.py @@ -3,7 +3,7 @@ # # This file is part of LiteEth. # -# Copyright (c) 2015-2023 Florent Kermarrec +# Copyright (c) 2015-2024 Florent Kermarrec # Copyright (c) 2020 Xiretza # Copyright (c) 2020 Stefan Schrijvers # Copyright (c) 2022 Victor Suarez Rovere @@ -413,13 +413,32 @@ class MACCore(PHYCore): # 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) + ethmac_rx_region_size = ethmac.rx_slots.constant*ethmac.slot_size.constant + ethmac_tx_region_size = ethmac.tx_slots.constant*ethmac.slot_size.constant + ethmac_region_size = ethmac_rx_region_size + ethmac_tx_region_size + self.bus.add_region("ethmac", SoCRegion( + origin = self.mem_map.get("ethmac", None), + size = ethmac_region_size, + linker = True, + cached = False, + )) + ethmac_rx_region = SoCRegion( + origin = self.bus.regions["ethmac"].origin + 0, + size = ethmac_rx_region_size, + linker = True, + cached = False, + ) + self.bus.add_slave(name="ethmac_rx", slave=ethmac.bus_rx, region=ethmac_rx_region) + ethmac_tx_region = SoCRegion( + origin = self.bus.regions["ethmac"].origin + ethmac_rx_region_size, + size = ethmac_tx_region_size, + linker = True, + cached = False, + ) + self.bus.add_slave(name="ethmac_tx", slave=ethmac.bus_tx, region=ethmac_tx_region) # Interrupt Interface ---------------------------------------------------------------------- self.comb += self.platform.request("interrupt").eq(self.ethmac.ev.irq)