From d0608e6756e4017662a3b8fde4954f106505cd0b Mon Sep 17 00:00:00 2001 From: David Sawatzke Date: Wed, 11 Dec 2024 10:59:23 +0100 Subject: [PATCH] mac/core: Allow using core_dw smaller than phy_dw Especially for XGMII PHYs with 64 bit width, a 32 bit datapath uses much less resources --- liteeth/mac/core.py | 71 +++++++++++++++++++++++---------------------- 1 file changed, 37 insertions(+), 34 deletions(-) diff --git a/liteeth/mac/core.py b/liteeth/mac/core.py index 6d35697..a7fb3bc 100644 --- a/liteeth/mac/core.py +++ b/liteeth/mac/core.py @@ -12,6 +12,7 @@ from litex.gen import * from liteeth.common import * from liteeth.mac import gap, preamble, crc, padding, last_be +from liteeth.mac.common import * from migen.genlib.cdc import PulseSynchronizer @@ -37,8 +38,7 @@ class LiteEthMACCore(LiteXModule): # Parameters. core_dw = dw phy_dw = phy.dw - if core_dw < phy_dw: - raise ValueError("Core data width({}) must be larger than PHY data width({})".format(core_dw, phy_dw)) + if with_sys_datapath: cd_tx = "sys" cd_rx = "sys" @@ -64,8 +64,8 @@ class LiteEthMACCore(LiteXModule): def __init__(self): self.pipeline = [] - def add_cdc(self): - tx_cdc = stream.ClockDomainCrossing(eth_phy_description(core_dw), + def add_cdc(self, dw): + tx_cdc = stream.ClockDomainCrossing(eth_phy_description(dw), cd_from = "sys", cd_to = "eth_tx", depth = tx_cdc_depth, @@ -74,11 +74,11 @@ class LiteEthMACCore(LiteXModule): self.submodules += tx_cdc self.pipeline.append(tx_cdc) - def add_converter(self): + def add_converter(self, cd): tx_converter = stream.StrideConverter( description_from = eth_phy_description(core_dw), description_to = eth_phy_description(phy_dw)) - tx_converter = ClockDomainsRenamer("eth_tx")(tx_converter) + tx_converter = ClockDomainsRenamer(cd)(tx_converter) self.submodules += tx_converter self.pipeline.append(tx_converter) @@ -113,30 +113,30 @@ class LiteEthMACCore(LiteXModule): self.submodules += tx_gap self.pipeline.append(tx_gap) + def add_domain_switch(self): + dw = core_dw + if core_dw < phy_dw: + dw = phy_dw + self.add_converter("sys") + self.add_cdc(dw) + if core_dw > phy_dw: + self.add_converter("eth_tx") + self.add_last_be() + def do_finalize(self): self.submodules += stream.Pipeline(*self.pipeline) self.tx_datapath = tx_datapath = TXDatapath() tx_datapath.pipeline.append(self.sink) if not with_sys_datapath: - # CHECKME: Verify converter/cdc order for the different cases. - tx_datapath.add_cdc() - if core_dw != phy_dw: - tx_datapath.add_converter() - if core_dw != 8: - tx_datapath.add_last_be() + tx_datapath.add_domain_switch() if with_padding: tx_datapath.add_padding() if with_preamble_crc: tx_datapath.add_crc() tx_datapath.add_preamble() if with_sys_datapath: - # CHECKME: Verify converter/cdc order for the different cases. - tx_datapath.add_cdc() - if core_dw != phy_dw: - tx_datapath.add_converter() - if core_dw != 8: - tx_datapath.add_last_be() + tx_datapath.add_domain_switch() # Gap insertion has to occurr in phy tx domain to ensure gap is correctly maintained. if not getattr(phy, "integrated_ifg_inserter", False): tx_datapath.add_gap() @@ -186,16 +186,16 @@ class LiteEthMACCore(LiteXModule): self.submodules += rx_last_be self.pipeline.append(rx_last_be) - def add_converter(self): + def add_converter(self, cd): rx_converter = stream.StrideConverter( description_from = eth_phy_description(phy_dw), description_to = eth_phy_description(core_dw)) - rx_converter = ClockDomainsRenamer("eth_rx")(rx_converter) + rx_converter = ClockDomainsRenamer(cd)(rx_converter) self.submodules += rx_converter self.pipeline.append(rx_converter) - def add_cdc(self): - rx_cdc = stream.ClockDomainCrossing(eth_phy_description(core_dw), + def add_cdc(self, dw): + rx_cdc = stream.ClockDomainCrossing(eth_phy_description(dw), cd_from = "eth_rx", cd_to = "sys", depth = rx_cdc_depth, @@ -204,28 +204,31 @@ class LiteEthMACCore(LiteXModule): self.submodules += rx_cdc self.pipeline.append(rx_cdc) + def add_domain_switch(self): + dw = phy_dw + if phy_dw < core_dw: + dw = core_dw + self.add_last_be() + self.add_converter("eth_rx") + self.add_cdc(dw) + if phy_dw > core_dw: + self.add_converter("sys") + last_handler = LiteEthLastHandler(eth_phy_description(core_dw)) + self.submodules += last_handler + self.pipeline.append(last_handler) + def do_finalize(self): self.submodules += stream.Pipeline(*self.pipeline) self.rx_datapath = rx_datapath = RXDatapath() rx_datapath.pipeline.append(phy) if with_sys_datapath: - if core_dw != 8: - rx_datapath.add_last_be() - # CHECKME: Verify converter/cdc order for the different cases. - if core_dw != phy_dw: - rx_datapath.add_converter() - rx_datapath.add_cdc() + rx_datapath.add_domain_switch() if with_preamble_crc: rx_datapath.add_preamble() rx_datapath.add_crc() if with_padding: rx_datapath.add_padding() if not with_sys_datapath: - if core_dw != 8: - rx_datapath.add_last_be() - # CHECKME: Verify converter/cdc order for the different cases. - if core_dw != phy_dw: - rx_datapath.add_converter() - rx_datapath.add_cdc() + rx_datapath.add_domain_switch() rx_datapath.pipeline.append(self.source)