mac: add crossbar for sharing PHY between HW ethernet cores and Wishbone

This commit is contained in:
Piotr Binkowski 2020-03-10 17:07:48 +01:00
parent 32d4af1148
commit ac9f6d9f05
1 changed files with 152 additions and 1 deletions

View File

@ -10,7 +10,9 @@ class LiteEthMAC(Module, AutoCSR):
endianness="big", endianness="big",
with_preamble_crc=True, with_preamble_crc=True,
nrxslots=2, nrxslots=2,
ntxslots=2): ntxslots=2,
cpu_dw=32,
hw_mac=None):
self.submodules.core = LiteEthMACCore(phy, dw, endianness, with_preamble_crc) self.submodules.core = LiteEthMACCore(phy, dw, endianness, with_preamble_crc)
self.csrs = [] self.csrs = []
if interface == "crossbar": if interface == "crossbar":
@ -31,8 +33,157 @@ class LiteEthMAC(Module, AutoCSR):
self.comb += Port.connect(self.interface, self.core) self.comb += Port.connect(self.interface, self.core)
self.ev, self.bus = self.interface.sram.ev, self.interface.bus self.ev, self.bus = self.interface.sram.ev, self.interface.bus
self.csrs = self.interface.get_csrs() + self.core.get_csrs() self.csrs = self.interface.get_csrs() + self.core.get_csrs()
elif interface == "hybrid":
# Wishbone MAC
self.rx_slots = CSRConstant(nrxslots)
self.tx_slots = CSRConstant(ntxslots)
self.slot_size = CSRConstant(2**bits_for(eth_mtu))
self.submodules.interface = LiteEthMACWishboneInterface(cpu_dw, nrxslots, ntxslots, endianness)
# HW accelerated MAC
self.submodules.crossbar = LiteEthMACCrossbar(dw)
# MAC crossbar
self.submodules.mac_crossbar = LiteEthMACCoreCrossbar(self.core, self.crossbar, self.interface, dw, cpu_dw, endianness, hw_mac)
# Connections
self.ev, self.bus = self.interface.sram.ev, self.interface.bus
self.csrs = self.interface.get_csrs() + self.core.get_csrs()
else: else:
raise NotImplementedError raise NotImplementedError
def get_csrs(self): def get_csrs(self):
return self.csrs return self.csrs
class LiteEthMACCoreCrossbar(Module):
def __init__(self, core, crossbar, interface, dw, cpu_dw, endianness, hw_mac=None):
fifo_depth = 2048
wishbone_rx_fifo = stream.SyncFIFO(eth_phy_description(dw), fifo_depth, buffered=True)
wishbone_tx_fifo = stream.SyncFIFO(eth_phy_description(dw), fifo_depth, buffered=True)
crossbar_rx_fifo = stream.SyncFIFO(eth_phy_description(dw), fifo_depth, buffered=True)
crossbar_tx_fifo = stream.SyncFIFO(eth_phy_description(dw), fifo_depth, buffered=True)
self.submodules += wishbone_rx_fifo, wishbone_tx_fifo, crossbar_rx_fifo, crossbar_tx_fifo
rx_ready = Signal()
rx_valid = Signal()
reverse = endianness == "big"
tx_pipe = []
rx_pipe = []
if cpu_dw != 8:
tx_last_be = last_be.LiteEthMACTXLastBE(dw)
rx_last_be = last_be.LiteEthMACRXLastBE(dw)
tx_pipe += [tx_last_be]
rx_pipe += [rx_last_be]
self.submodules += tx_last_be, rx_last_be
if dw != cpu_dw:
tx_converter = stream.StrideConverter(eth_phy_description(cpu_dw),
eth_phy_description(dw),
reverse=reverse)
rx_converter = stream.StrideConverter(eth_phy_description(dw),
eth_phy_description(cpu_dw),
reverse=reverse)
rx_pipe += [rx_converter]
tx_pipe += [tx_converter]
self.submodules += tx_converter, rx_converter
# SoftCPU packet processing
self.submodules.tx_pipe = stream.Pipeline(*reversed(tx_pipe))
self.submodules.rx_pipe = stream.Pipeline(*rx_pipe)
# IP core packet processing
self.submodules.packetizer = LiteEthMACPacketizer(dw)
self.submodules.depacketizer = LiteEthMACDepacketizer(dw)
self.comb += [
# SoftCPU output path
# interface -> tx_pipe -> tx_fifo
interface.source.connect(self.tx_pipe.sink),
self.tx_pipe.source.connect(wishbone_tx_fifo.sink),
# SoftCPU input path
# rx_fifo -> rx_pipe -> interface
wishbone_rx_fifo.source.connect(self.rx_pipe.sink),
self.rx_pipe.source.connect(interface.sink),
# HW input path
# rx_fifo -> depacketizer -> crossbar
crossbar_rx_fifo.source.connect(self.depacketizer.sink),
self.depacketizer.source.connect(crossbar.master.sink),
# HW output path
# crossbar -> packetizer -> tx_fifo
crossbar.master.source.connect(self.packetizer.sink),
self.packetizer.source.connect(crossbar_tx_fifo.sink),
]
# MAC filtering
if hw_mac is not None:
depacketizer = LiteEthMACDepacketizer(dw)
hw_packetizer = LiteEthMACPacketizer(dw)
cpu_packetizer = LiteEthMACPacketizer(dw)
fifo_depth = 4
hw_fifo = stream.SyncFIFO(eth_mac_description(dw), fifo_depth, buffered=True)
cpu_fifo = stream.SyncFIFO(eth_mac_description(dw), fifo_depth, buffered=True)
self.submodules += depacketizer, cpu_packetizer, hw_packetizer, hw_fifo, cpu_fifo
self.comb += [
core.source.connect(depacketizer.sink),
hw_fifo.source.connect(hw_packetizer.sink),
hw_packetizer.source.connect(crossbar_rx_fifo.sink),
cpu_fifo.source.connect(cpu_packetizer.sink),
cpu_packetizer.source.connect(wishbone_rx_fifo.sink),
]
# RX packetizer broadcast
mac_match = Signal()
self.comb += [
mac_match.eq(hw_mac == depacketizer.source.payload.target_mac),
rx_ready.eq(hw_fifo.sink.ready & (cpu_fifo.sink.ready | mac_match)),
rx_valid.eq(rx_ready & depacketizer.source.valid),
depacketizer.source.connect(hw_fifo.sink, omit={"ready", "valid"}),
depacketizer.source.connect(cpu_fifo.sink, omit={"ready", "valid"}),
depacketizer.source.ready.eq(rx_ready),
hw_fifo.sink.valid.eq(rx_valid),
cpu_fifo.sink.valid.eq(rx_valid & ~mac_match),
]
else:
# RX broadcast
self.comb += [
rx_ready.eq(wishbone_rx_fifo.sink.ready & crossbar_rx_fifo.sink.ready),
rx_valid.eq(rx_ready & core.source.valid),
core.source.connect(wishbone_rx_fifo.sink, omit={"ready", "valid"}),
core.source.connect(crossbar_rx_fifo.sink, omit={"ready", "valid"}),
core.source.ready.eq(rx_ready),
wishbone_rx_fifo.sink.valid.eq(rx_valid),
crossbar_rx_fifo.sink.valid.eq(rx_valid),
]
# TX arbiter
self.submodules.tx_arbiter_fsm = fsm = FSM(reset_state="IDLE")
fsm.act("IDLE",
If(wishbone_tx_fifo.source.valid,
wishbone_tx_fifo.source.connect(core.sink),
NextState("WISHBONE")
).Else(
If(crossbar_tx_fifo.source.valid,
crossbar_tx_fifo.source.connect(core.sink),
NextState("CROSSBAR")
)
),
)
fsm.act("WISHBONE",
wishbone_tx_fifo.source.connect(core.sink),
If(wishbone_tx_fifo.source.valid & core.sink.ready & wishbone_tx_fifo.source.last,
NextState("IDLE")
),
)
fsm.act("CROSSBAR",
crossbar_tx_fifo.source.connect(core.sink),
If(crossbar_tx_fifo.source.valid & core.sink.ready & crossbar_tx_fifo.source.last,
NextState("IDLE")
),
)