mac: add crossbar for sharing PHY between HW ethernet cores and Wishbone
This commit is contained in:
parent
32d4af1148
commit
ac9f6d9f05
|
@ -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")
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
Loading…
Reference in New Issue