mac/core: Introduce TX/RXDatapath modules to simplify code.

This commit is contained in:
Florent Kermarrec 2021-10-05 15:13:08 +02:00
parent 11555d43cb
commit a4a070af4d
1 changed files with 141 additions and 146 deletions

View File

@ -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))
@ -45,164 +45,159 @@ 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)
# 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)
# Late sys conversion.
if not with_sys_datapath:
self.add_tx_converter()
# Padding.
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.
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.
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)
# RX Data-Path (PHY --> Core).
# ------------------------------------------------------------------------------------------
self.rx_datapath = rx_datapath = []
# PHY.
rx_datapath.append(phy)
# Early sys conversion.
if with_sys_datapath:
self.add_rx_converter()
# Preamble / CRC.
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.
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.
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):
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(self.core_dw),
tx_cdc = stream.ClockDomainCrossing(eth_phy_description(core_dw),
cd_from = "sys",
cd_to = "eth_tx",
depth = 32)
self.submodules += tx_cdc
self.tx_datapath.append(tx_cdc)
self.pipeline.append(tx_cdc)
# Converters.
if self.core_dw != self.phy_dw:
if core_dw != phy_dw:
tx_converter = stream.StrideConverter(
description_from = eth_phy_description(self.core_dw),
description_to = eth_phy_description(self.phy_dw))
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.tx_datapath.append(tx_converter)
self.pipeline.append(tx_converter)
# Delimiters.
if self.core_dw != 8:
tx_last_be = last_be.LiteEthMACTXLastBE(self.phy_dw)
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.tx_datapath.append(tx_last_be)
self.pipeline.append(tx_last_be)
def add_rx_converter(self):
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:
tx_datapath.add_converter()
if with_padding:
tx_datapath.add_padding()
if with_preamble_crc:
tx_datapath.add_crc()
tx_datapath.add_preamble()
tx_datapath.add_gap()
if with_sys_datapath:
tx_datapath.add_converter()
tx_datapath.pipeline.append(phy)
self.submodules.tx_datapath = tx_datapath
# RX Data-Path (PHY --> Core).
# ------------------------------------------------------------------------------------------
class RXDatapath(Module, AutoCSR):
def __init__(self):
self.pipeline = []
if with_preamble_crc:
self.preamble_errors = CSRStatus(32)
self.crc_errors = CSRStatus(32)
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)
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 self.core_dw != 8:
rx_last_be = last_be.LiteEthMACRXLastBE(self.phy_dw)
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.rx_datapath.append(rx_last_be)
self.pipeline.append(rx_last_be)
# Converters.
if self.core_dw != self.phy_dw:
if core_dw != phy_dw:
rx_converter = stream.StrideConverter(
description_from = eth_phy_description(self.phy_dw),
description_to = eth_phy_description(self.core_dw))
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.rx_datapath.append(rx_converter)
self.pipeline.append(rx_converter)
# Cross Domain Crossing
rx_cdc = stream.ClockDomainCrossing(eth_phy_description(self.core_dw),
rx_cdc = stream.ClockDomainCrossing(eth_phy_description(core_dw),
cd_from = "eth_rx",
cd_to = "sys",
depth = 32)
self.submodules += rx_cdc
self.rx_datapath.append(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:
rx_datapath.add_converter()
if with_preamble_crc:
rx_datapath.add_preamble()
rx_datapath.add_crc()
if with_padding:
rx_datapath.add_padding()
if not with_sys_datapath:
rx_datapath.add_converter()
rx_datapath.pipeline.append(self.source)
self.submodules.rx_datapath = rx_datapath