diff --git a/liteeth/mac/core.py b/liteeth/mac/core.py index f1b64f7..30dc593 100644 --- a/liteeth/mac/core.py +++ b/liteeth/mac/core.py @@ -28,8 +28,8 @@ class LiteEthMACCore(Module, AutoCSR): self.source = stream.Endpoint(eth_phy_description(dw)) # Parameters. - self.core_dw = core_dw = dw - self.phy_dw = phy_dw = phy.dw + 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)) @@ -44,165 +44,160 @@ class LiteEthMACCore(Module, AutoCSR): # CSRs. if with_preamble_crc: - self.preamble_crc = CSRStatus(reset=1) - self.preamble_errors = CSRStatus(32) - self.crc_errors = CSRStatus(32) + self.preamble_crc = CSRStatus(reset=1) # TX Data-Path (Core --> PHY). # ------------------------------------------------------------------------------------------ - self.tx_datapath = tx_datapath = [] + class TXDatapath(Module, AutoCSR): + def __init__(self): + self.pipeline = [] - # Sink. - tx_datapath.append(self.sink) + def add_converter(self): + # CHECKME: Order probably needs to be adapted based on core_dw/phy_dw ratio. + # Cross Domain Crossing. + tx_cdc = stream.ClockDomainCrossing(eth_phy_description(core_dw), + cd_from = "sys", + cd_to = "eth_tx", + depth = 32) + self.submodules += tx_cdc + self.pipeline.append(tx_cdc) - # Late sys conversion. + # Converters. + if core_dw != phy_dw: + 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) + self.submodules += tx_converter + self.pipeline.append(tx_converter) + + # Delimiters. + if core_dw != 8: + tx_last_be = last_be.LiteEthMACTXLastBE(phy_dw) + tx_last_be = ClockDomainsRenamer("eth_tx")(tx_last_be) + self.submodules += tx_last_be + self.pipeline.append(tx_last_be) + + def add_padding(self): + tx_padding = padding.LiteEthMACPaddingInserter(datapath_dw, (eth_min_frame_length - eth_fcs_length)) + tx_padding = ClockDomainsRenamer(cd_tx)(tx_padding) + self.submodules += tx_padding + self.pipeline.append(tx_padding) + + def add_crc(self): + tx_crc = crc.LiteEthMACCRC32Inserter(eth_phy_description(datapath_dw)) + tx_crc = BufferizeEndpoints({"sink": DIR_SINK})(tx_crc) # FIXME: Still required? + tx_crc = ClockDomainsRenamer(cd_tx)(tx_crc) + self.submodules += tx_crc + self.pipeline.append(tx_crc) + + def add_preamble(self): + tx_preamble = preamble.LiteEthMACPreambleInserter(datapath_dw) + tx_preamble = ClockDomainsRenamer(cd_tx)(tx_preamble) + self.submodules += tx_preamble + self.pipeline.append(tx_preamble) + + def add_gap(self): + tx_gap = gap.LiteEthMACGap(datapath_dw) + tx_gap = ClockDomainsRenamer(cd_tx)(tx_gap) + self.submodules += tx_gap + self.pipeline.append(tx_gap) + + def do_finalize(self): + self.submodules += stream.Pipeline(*self.pipeline) + + tx_datapath = TXDatapath() + tx_datapath.pipeline.append(self.sink) if not with_sys_datapath: - self.add_tx_converter() - - # Padding. + tx_datapath.add_converter() if with_padding: - tx_padding = padding.LiteEthMACPaddingInserter(datapath_dw, (eth_min_frame_length - eth_fcs_length)) - tx_padding = ClockDomainsRenamer(cd_tx)(tx_padding) - self.submodules += tx_padding - tx_datapath.append(tx_padding) - - # Preamble / CRC. + tx_datapath.add_padding() if with_preamble_crc: - # CRC insert. - tx_crc = crc.LiteEthMACCRC32Inserter(eth_phy_description(datapath_dw)) - tx_crc = BufferizeEndpoints({"sink": DIR_SINK})(tx_crc) # FIXME: Still required? - tx_crc = ClockDomainsRenamer(cd_tx)(tx_crc) - self.submodules += tx_crc - tx_datapath.append(tx_crc) - - # Preamble insert. - tx_preamble = preamble.LiteEthMACPreambleInserter(datapath_dw) - tx_preamble = ClockDomainsRenamer(cd_tx)(tx_preamble) - self.submodules += tx_preamble - tx_datapath.append(tx_preamble) - - # Interpacket gap. - tx_gap = gap.LiteEthMACGap(datapath_dw) - tx_gap = ClockDomainsRenamer(cd_tx)(tx_gap) - self.submodules += tx_gap - tx_datapath.append(tx_gap) - - # Early sys conversion. + tx_datapath.add_crc() + tx_datapath.add_preamble() + tx_datapath.add_gap() if with_sys_datapath: - self.add_tx_converter(core_dw, phy_dw) - - # PHY. - tx_datapath.append(phy) - - # Data-Path. - self.submodules.tx_pipeline = stream.Pipeline(*tx_datapath) + tx_datapath.add_converter() + tx_datapath.pipeline.append(phy) + self.submodules.tx_datapath = tx_datapath # RX Data-Path (PHY --> Core). # ------------------------------------------------------------------------------------------ - self.rx_datapath = rx_datapath = [] + class RXDatapath(Module, AutoCSR): + def __init__(self): + self.pipeline = [] + if with_preamble_crc: + self.preamble_errors = CSRStatus(32) + self.crc_errors = CSRStatus(32) - # PHY. - rx_datapath.append(phy) + def add_preamble(self): + rx_preamble = preamble.LiteEthMACPreambleChecker(datapath_dw) + rx_preamble = ClockDomainsRenamer(cd_rx)(rx_preamble) + self.submodules += rx_preamble + self.pipeline.append(rx_preamble) - # Early sys conversion. + ps = PulseSynchronizer(cd_rx, "sys") + self.submodules += ps + self.comb += ps.i.eq(rx_preamble.error) + self.sync += If(ps.o, self.preamble_errors.status.eq(self.preamble_errors.status + 1)) + + def add_crc(self): + rx_crc = crc.LiteEthMACCRC32Checker(eth_phy_description(datapath_dw)) + rx_crc = BufferizeEndpoints({"sink": DIR_SINK})(rx_crc) # FIXME: Still required? + rx_crc = ClockDomainsRenamer(cd_rx)(rx_crc) + self.submodules += rx_crc + self.pipeline.append(rx_crc) + + ps = PulseSynchronizer(cd_rx, "sys") + self.submodules += ps + self.comb += ps.i.eq(rx_crc.error), + self.sync += If(ps.o, self.crc_errors.status.eq(self.crc_errors.status + 1)) + + def add_padding(self): + rx_padding = padding.LiteEthMACPaddingChecker(datapath_dw, (eth_min_frame_length - eth_fcs_length)) + rx_padding = ClockDomainsRenamer(cd_rx)(rx_padding) + self.submodules += rx_padding + self.pipeline.append(rx_padding) + + def add_converter(self): + # CHECKME: Order probably needs to be adapted based on core_dw/phy_dw ratio. + # Delimiters. + if core_dw != 8: + rx_last_be = last_be.LiteEthMACRXLastBE(phy_dw) + rx_last_be = ClockDomainsRenamer("eth_rx")(rx_last_be) + self.submodules += rx_last_be + self.pipeline.append(rx_last_be) + + # Converters. + if core_dw != phy_dw: + 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) + self.submodules += rx_converter + self.pipeline.append(rx_converter) + + # Cross Domain Crossing + rx_cdc = stream.ClockDomainCrossing(eth_phy_description(core_dw), + cd_from = "eth_rx", + cd_to = "sys", + depth = 32) + self.submodules += rx_cdc + self.pipeline.append(rx_cdc) + + def do_finalize(self): + self.submodules += stream.Pipeline(*self.pipeline) + + rx_datapath = RXDatapath() + rx_datapath.pipeline.append(phy) if with_sys_datapath: - self.add_rx_converter() - - # Preamble / CRC. + rx_datapath.add_converter() if with_preamble_crc: - # Preamble check. - rx_preamble = preamble.LiteEthMACPreambleChecker(datapath_dw) - rx_preamble = ClockDomainsRenamer(cd_rx)(rx_preamble) - self.submodules += rx_preamble - rx_datapath.append(rx_preamble) - - # Preamble error counter. - self.submodules.ps_preamble_error = PulseSynchronizer(cd_rx, "sys") - self.comb += self.ps_preamble_error.i.eq(rx_preamble.error) - self.sync += [ - If(self.ps_preamble_error.o, - self.preamble_errors.status.eq(self.preamble_errors.status + 1)) - ] - - # CRC check. - rx_crc = crc.LiteEthMACCRC32Checker(eth_phy_description(datapath_dw)) - rx_crc = BufferizeEndpoints({"sink": DIR_SINK})(rx_crc) # FIXME: Still required? - rx_crc = ClockDomainsRenamer(cd_rx)(rx_crc) - self.submodules += rx_crc - rx_datapath.append(rx_crc) - - # CRC error counter. - self.submodules.ps_crc_error = PulseSynchronizer(cd_rx, "sys") - self.comb += self.ps_crc_error.i.eq(rx_crc.error), - self.sync += [ - If(self.ps_crc_error.o, - self.crc_errors.status.eq(self.crc_errors.status + 1) - ) - ] - - # Padding. + rx_datapath.add_preamble() + rx_datapath.add_crc() if with_padding: - rx_padding = padding.LiteEthMACPaddingChecker(datapath_dw, (eth_min_frame_length - eth_fcs_length)) - rx_padding = ClockDomainsRenamer(cd_rx)(rx_padding) - self.submodules += rx_padding - rx_datapath.append(rx_padding) - - # Late sys conversion. + rx_datapath.add_padding() if not with_sys_datapath: - self.add_rx_converter() - - # Source. - rx_datapath.append(self.source) - - # Data-Path. - self.submodules.rx_pipeline = stream.Pipeline(*rx_datapath) - - def add_tx_converter(self): - # Cross Domain Crossing. - tx_cdc = stream.ClockDomainCrossing(eth_phy_description(self.core_dw), - cd_from = "sys", - cd_to = "eth_tx", - depth = 32) - self.submodules += tx_cdc - self.tx_datapath.append(tx_cdc) - - # Converters. - if self.core_dw != self.phy_dw: - tx_converter = stream.StrideConverter( - description_from = eth_phy_description(self.core_dw), - description_to = eth_phy_description(self.phy_dw)) - tx_converter = ClockDomainsRenamer("eth_tx")(tx_converter) - self.submodules += tx_converter - self.tx_datapath.append(tx_converter) - - # Delimiters. - if self.core_dw != 8: - tx_last_be = last_be.LiteEthMACTXLastBE(self.phy_dw) - tx_last_be = ClockDomainsRenamer("eth_tx")(tx_last_be) - self.submodules += tx_last_be - self.tx_datapath.append(tx_last_be) - - def add_rx_converter(self): - # Delimiters. - if self.core_dw != 8: - rx_last_be = last_be.LiteEthMACRXLastBE(self.phy_dw) - rx_last_be = ClockDomainsRenamer("eth_rx")(rx_last_be) - self.submodules += rx_last_be - self.rx_datapath.append(rx_last_be) - - # Converters. - if self.core_dw != self.phy_dw: - rx_converter = stream.StrideConverter( - description_from = eth_phy_description(self.phy_dw), - description_to = eth_phy_description(self.core_dw)) - rx_converter = ClockDomainsRenamer("eth_rx")(rx_converter) - self.submodules += rx_converter - self.rx_datapath.append(rx_converter) - - # Cross Domain Crossing - rx_cdc = stream.ClockDomainCrossing(eth_phy_description(self.core_dw), - cd_from = "eth_rx", - cd_to = "sys", - depth = 32) - self.submodules += rx_cdc - self.rx_datapath.append(rx_cdc) + rx_datapath.add_converter() + rx_datapath.pipeline.append(self.source) + self.submodules.rx_datapath = rx_datapath