From ac9f6d9f058825de9c770375b10b47013534f9c3 Mon Sep 17 00:00:00 2001 From: Piotr Binkowski Date: Tue, 10 Mar 2020 17:07:48 +0100 Subject: [PATCH] mac: add crossbar for sharing PHY between HW ethernet cores and Wishbone --- liteeth/mac/__init__.py | 153 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 152 insertions(+), 1 deletion(-) diff --git a/liteeth/mac/__init__.py b/liteeth/mac/__init__.py index 4bb1d9a..bee5263 100644 --- a/liteeth/mac/__init__.py +++ b/liteeth/mac/__init__.py @@ -10,7 +10,9 @@ class LiteEthMAC(Module, AutoCSR): endianness="big", with_preamble_crc=True, nrxslots=2, - ntxslots=2): + ntxslots=2, + cpu_dw=32, + hw_mac=None): self.submodules.core = LiteEthMACCore(phy, dw, endianness, with_preamble_crc) self.csrs = [] if interface == "crossbar": @@ -31,8 +33,157 @@ class LiteEthMAC(Module, AutoCSR): self.comb += Port.connect(self.interface, self.core) self.ev, self.bus = self.interface.sram.ev, self.interface.bus 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: raise NotImplementedError def get_csrs(self): 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") + ), + )