Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mac/wishbone/LiteEthMACWishboneInterface: Expose separate TX/RX Wishb… #161

Merged
merged 7 commits into from
Jun 25, 2024
29 changes: 24 additions & 5 deletions liteeth/gen.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#
# This file is part of LiteEth.
#
# Copyright (c) 2015-2023 Florent Kermarrec <florent@enjoy-digital.fr>
# Copyright (c) 2015-2024 Florent Kermarrec <florent@enjoy-digital.fr>
# Copyright (c) 2020 Xiretza <xiretza@xiretza.xyz>
# Copyright (c) 2020 Stefan Schrijvers <ximin@ximinity.net>
# Copyright (c) 2022 Victor Suarez Rovere <suarezvictor@gmail.com>
Expand Down Expand Up @@ -413,13 +413,32 @@ def __init__(self, platform, core_config):
# 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)
Expand Down
2 changes: 1 addition & 1 deletion liteeth/mac/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ def __init__(self, phy, dw,
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
Expand Down
71 changes: 43 additions & 28 deletions liteeth/mac/wishbone.py
Original file line number Diff line number Diff line change
@@ -1,67 +1,82 @@
#
# This file is part of LiteEth.
#
# Copyright (c) 2015-2021 Florent Kermarrec <florent@enjoy-digital.fr>
# Copyright (c) 2015-2024 Florent Kermarrec <florent@enjoy-digital.fr>
# Copyright (c) 2015-2016 Sebastien Bourdeauducq <sb@m-labs.hk>
# Copyright (c) 2021 Leon Schuermann <leon@is.currently.online>
# SPDX-License-Identifier: BSD-2-Clause

import math

from litex.gen import *

from liteeth.common import *
from liteeth.mac import sram

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,
):
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.sram = sram.LiteEthMACSRAM(dw, sram_depth, nrxslots, ntxslots, endianness, timestamp)
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).
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)
))
# 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 = False,
)
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,
)

# Wishbone SRAM interfaces for the reader SRAM (i.e. Ethernet TX).
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)
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 Wishbone SRAMs on a single Wishbone bus.
# CHECKME: Check Decoder width for 64-bit.
# 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))
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
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+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(bus, wb_slaves, register=True)
self.submodules += wb_con
11 changes: 6 additions & 5 deletions test/test_mac_wishbone.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,12 +102,13 @@ def __init__(self):


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

Expand All @@ -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)
Expand All @@ -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
Expand Down
Loading