From 1720050729d95182d961b9d0969a218b304f65cf Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 26 Mar 2024 09:59:22 +0100 Subject: [PATCH 1/8] mac/crc: Switch to LiteXModule, LiteX's Reduce and avoid OrderedDict (no longer required). --- liteeth/mac/crc.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/liteeth/mac/crc.py b/liteeth/mac/crc.py index 9f3b0eb..c0b49c2 100644 --- a/liteeth/mac/crc.py +++ b/liteeth/mac/crc.py @@ -1,25 +1,24 @@ # # This file is part of LiteEth. # -# Copyright (c) 2015-2021 Florent Kermarrec +# Copyright (c) 2015-2024 Florent Kermarrec # Copyright (c) 2015 Sebastien Bourdeauducq # Copyright (c) 2021 David Sawatzke # Copyright (c) 2017 whitequark # Copyright (c) 2018 Felix Held # SPDX-License-Identifier: BSD-2-Clause -from functools import reduce -from operator import xor -from collections import OrderedDict from math import ceil +from litex.gen import * + from liteeth.common import * from litex.gen.genlib.misc import chooser, WaitTimer # MAC CRC Engine ----------------------------------------------------------------------------------- -class LiteEthMACCRCEngine(Module): +class LiteEthMACCRCEngine(LiteXModule): """Cyclic Redundancy Check Engine Compute next CRC value from last CRC value and data input using @@ -55,7 +54,7 @@ class LiteEthMACCRCEngine(Module): remove an even numbers of XORs with the same bit replace an odd number of XORs with a single XOR """ - d = OrderedDict() + d = {} for e in l: if e in d: d[e] += 1 @@ -86,13 +85,13 @@ class LiteEthMACCRCEngine(Module): xors += [self.last[n]] elif t == "din": xors += [self.data[n]] - self.comb += self.next[i].eq(reduce(xor, xors)) + self.comb += self.next[i].eq(Reduce("XOR", xors)) # MAC CRC32 ---------------------------------------------------------------------------------------- @ResetInserter() @CEInserter() -class LiteEthMACCRC32(Module): +class LiteEthMACCRC32(LiteXModule): """IEEE 802.3 CRC Implement an IEEE 802.3 CRC generator/checker. @@ -151,7 +150,7 @@ class LiteEthMACCRC32(Module): # MAC CRC Inserter --------------------------------------------------------------------------------- -class LiteEthMACCRCInserter(Module): +class LiteEthMACCRCInserter(LiteXModule): """CRC Inserter Append a CRC at the end of each packet. @@ -266,7 +265,7 @@ class LiteEthMACCRC32Inserter(LiteEthMACCRCInserter): # MAC CRC Checker ---------------------------------------------------------------------------------- -class LiteEthMACCRCChecker(Module): +class LiteEthMACCRCChecker(LiteXModule): """CRC Checker Check CRC at the end of each packet. From aded91f8cb172df77d18bf870d7dcac071cef676 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 26 Mar 2024 10:25:22 +0100 Subject: [PATCH 2/8] mac/crc: Add optmize_xors method and better signal names. --- liteeth/mac/crc.py | 65 ++++++++++++++++------------------------------ 1 file changed, 22 insertions(+), 43 deletions(-) diff --git a/liteeth/mac/crc.py b/liteeth/mac/crc.py index c0b49c2..d27a101 100644 --- a/liteeth/mac/crc.py +++ b/liteeth/mac/crc.py @@ -19,53 +19,26 @@ from litex.gen.genlib.misc import chooser, WaitTimer # MAC CRC Engine ----------------------------------------------------------------------------------- class LiteEthMACCRCEngine(LiteXModule): - """Cyclic Redundancy Check Engine + """ + Cyclic Redundancy Check (CRC) Engine using an asynchronous LFSR. - Compute next CRC value from last CRC value and data input using - an optimized asynchronous LFSR. + This module calculates the next CRC value based on the previous CRC value and the current data input. + The CRC calculation is optimized for speed and resource efficiency. Parameters ---------- - data_width : int - Width of the data bus. width : int - Width of the CRC. + The bit width of the data bus and CRC value. polynom : int - Polynom of the CRC (ex: 0x04C11DB7 for IEEE 802.3 CRC) - - Attributes - ---------- - data : in - Data input. - last : in - last CRC value. - next : - next CRC value. + The polynomial used for the CRC calculation, specified as an integer (e.g., 0x04C11DB7 for IEEE 802.3). """ def __init__(self, data_width, width, polynom): - self.data = Signal(data_width) - self.last = Signal(width) - self.next = Signal(width) + self.data = Signal(data_width) + self.crc_prev = Signal(width) + self.crc_next = Signal(width) # # # - def _optimize_eq(l): - """ - remove an even numbers of XORs with the same bit - replace an odd number of XORs with a single XOR - """ - d = {} - for e in l: - if e in d: - d[e] += 1 - else: - d[e] = 1 - r = [] - for key, value in d.items(): - if value%2 != 0: - r.append(key) - return r - # compute and optimize the parallel implementation of the CRC's LFSR taps = [x for x in range(width) if (1 << x) & polynom] curval = [[("state", i)] for i in range(width)] @@ -74,7 +47,7 @@ class LiteEthMACCRCEngine(LiteXModule): for j in range(width-1): if j+1 in taps: curval[j] += feedback - curval[j] = _optimize_eq(curval[j]) + curval[j] = self.optimize_xors(curval[j]) curval.insert(0, feedback) # implement logic @@ -82,10 +55,16 @@ class LiteEthMACCRCEngine(LiteXModule): xors = [] for t, n in curval[i]: if t == "state": - xors += [self.last[n]] + xors += [self.crc_prev[n]] elif t == "din": xors += [self.data[n]] - self.comb += self.next[i].eq(Reduce("XOR", xors)) + self.comb += self.crc_next[i].eq(Reduce("XOR", xors)) + + @staticmethod + def optimize_xors(bits): + """Return items with odd occurrences for XOR optimization.""" + from collections import Counter + return [bit for bit, count in Counter(bits).items() if count % 2 == 1] # MAC CRC32 ---------------------------------------------------------------------------------------- @@ -140,12 +119,12 @@ class LiteEthMACCRC32(LiteXModule): self.submodules += engines reg = Signal(self.width, reset=self.init) - self.sync += reg.eq(engines[-1].next) + self.sync += reg.eq(engines[-1].crc_next) self.comb += [engines[e].data.eq(self.data[:(e+1)*8]) for e in range(dw)], - self.comb += [engines[e].last.eq(reg) for e in range(dw)] + self.comb += [engines[e].crc_prev.eq(reg) for e in range(dw)] self.comb += [If(last_be[e], - self.value.eq(reverse_bits(~engines[e].next)), - self.error.eq(engines[e].next != self.check)) + self.value.eq(reverse_bits(~engines[e].crc_next)), + self.error.eq(engines[e].crc_next != self.check)) for e in range(dw)] # MAC CRC Inserter --------------------------------------------------------------------------------- From d9f7ae48823b549894e1446da1a0d082e56a1c5b Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 26 Mar 2024 10:48:18 +0100 Subject: [PATCH 3/8] mac/crc: Another cleanup pass. --- liteeth/mac/crc.py | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/liteeth/mac/crc.py b/liteeth/mac/crc.py index d27a101..794d6f5 100644 --- a/liteeth/mac/crc.py +++ b/liteeth/mac/crc.py @@ -33,27 +33,29 @@ class LiteEthMACCRCEngine(LiteXModule): The polynomial used for the CRC calculation, specified as an integer (e.g., 0x04C11DB7 for IEEE 802.3). """ def __init__(self, data_width, width, polynom): - self.data = Signal(data_width) - self.crc_prev = Signal(width) - self.crc_next = Signal(width) + self.data = Signal(data_width) # Data (Input). + self.crc_prev = Signal(width) # CRC Previous (Input). + self.crc_next = Signal(width) # CRC Next (Output). # # # - # compute and optimize the parallel implementation of the CRC's LFSR - taps = [x for x in range(width) if (1 << x) & polynom] - curval = [[("state", i)] for i in range(width)] - for i in range(data_width): - feedback = curval.pop() + [("din", i)] - for j in range(width-1): - if j+1 in taps: - curval[j] += feedback - curval[j] = self.optimize_xors(curval[j]) - curval.insert(0, feedback) + # Determine bits affected by the polynom. + polynom_taps = [bit for bit in range(width) if (1 << bit) & polynom] - # implement logic + # Prepare the list for CRC calculation through LFSR. + crc_bits = [[("state", i)] for i in range(width)] + for n in range(data_width): + feedback = crc_bits.pop(-1) + [("din", n)] + for pos in range(width - 1): + if (pos + 1) in polynom_taps: + crc_bits[pos] += feedback + crc_bits[pos] = self.optimize_xors(crc_bits[pos]) + crc_bits.insert(0, feedback) + + # Calculate the next CRC value based on XOR operations. for i in range(width): xors = [] - for t, n in curval[i]: + for t, n in crc_bits[i]: if t == "state": xors += [self.crc_prev[n]] elif t == "din": From 5fad30cbc96920eda305329a6bee764b07679148 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 26 Mar 2024 11:07:06 +0100 Subject: [PATCH 4/8] mac/crc/LiteEthMACCRC32: Simplify last_be using reset value and merge for loops. --- liteeth/mac/crc.py | 37 ++++++++++++++++--------------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/liteeth/mac/crc.py b/liteeth/mac/crc.py index 794d6f5..18dd761 100644 --- a/liteeth/mac/crc.py +++ b/liteeth/mac/crc.py @@ -98,36 +98,31 @@ class LiteEthMACCRC32(LiteXModule): init = 2**width-1 check = 0xC704DD7B def __init__(self, data_width): - dw = data_width//8 - - self.data = Signal(data_width) - self.last_be = Signal(dw) - self.value = Signal(self.width) - self.error = Signal() - # Add a separate last_be signal, to maintain backwards compatability - last_be = Signal(data_width//8) + self.data = Signal(data_width) + self.last_be = Signal(data_width//8, reset=2**(data_width//8 - 1)) + self.value = Signal(self.width) + self.error = Signal() # # # - self.comb += [ - If(self.last_be != 0, - last_be.eq(self.last_be) - ).Else( - last_be.eq(2**(dw-1))) - ] # Since the data can end at any byte end, indicated by `last_be` # maintain separate engines for each 8 byte increment in the data word - engines = [LiteEthMACCRCEngine((e+1)*8, self.width, self.polynom) for e in range(dw)] + engines = [] + for e in range(data_width//8): + engines.append(LiteEthMACCRCEngine((e+1)*8, self.width, self.polynom)) self.submodules += engines reg = Signal(self.width, reset=self.init) self.sync += reg.eq(engines[-1].crc_next) - self.comb += [engines[e].data.eq(self.data[:(e+1)*8]) for e in range(dw)], - self.comb += [engines[e].crc_prev.eq(reg) for e in range(dw)] - self.comb += [If(last_be[e], - self.value.eq(reverse_bits(~engines[e].crc_next)), - self.error.eq(engines[e].crc_next != self.check)) - for e in range(dw)] + for e in range(data_width//8): + self.comb += [ + engines[e].data.eq(self.data[:(e+1)*8]), + engines[e].crc_prev.eq(reg), + If(self.last_be[e], + self.value.eq(reverse_bits(~engines[e].crc_next)), + self.error.eq(engines[e].crc_next != self.check), + ) + ] # MAC CRC Inserter --------------------------------------------------------------------------------- From 01abb2a60fb21d0be7f43797abe469a6c15817bc Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 26 Mar 2024 11:28:09 +0100 Subject: [PATCH 5/8] mac/crc/LiteEthMACCRC32: Rename last_be to be and add comments. --- liteeth/mac/crc.py | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/liteeth/mac/crc.py b/liteeth/mac/crc.py index 18dd761..9dc6644 100644 --- a/liteeth/mac/crc.py +++ b/liteeth/mac/crc.py @@ -86,41 +86,44 @@ class LiteEthMACCRC32(LiteXModule): ---------- data : in Data input. - last_be : in - Valid byte in data input (optional). + be : in + Data byte enable (optional, defaults to full word). value : out CRC value (used for generator). error : out CRC error (used for checker). """ width = 32 - polynom = 0x04C11DB7 + polynom = 0x04c11db7 init = 2**width-1 - check = 0xC704DD7B + check = 0xc704dd7b def __init__(self, data_width): self.data = Signal(data_width) - self.last_be = Signal(data_width//8, reset=2**(data_width//8 - 1)) + self.be = Signal(data_width//8, reset=2**data_width//8 - 1) self.value = Signal(self.width) self.error = Signal() # # # - # Since the data can end at any byte end, indicated by `last_be` - # maintain separate engines for each 8 byte increment in the data word + # Create a CRC Engine for each byte segment. + # Ex for a 32-bit Data-Path, we create 4 engines: 8, 16, 24 and 32-bit engines. engines = [] - for e in range(data_width//8): - engines.append(LiteEthMACCRCEngine((e+1)*8, self.width, self.polynom)) + for n in range(data_width//8): + engines.append(LiteEthMACCRCEngine((n + 1)*8, self.width, self.polynom)) self.submodules += engines + # Register Full-Word CRC Engine (last one). reg = Signal(self.width, reset=self.init) self.sync += reg.eq(engines[-1].crc_next) - for e in range(data_width//8): + + # Select CRC Engine/Result. + for n in range(data_width//8): self.comb += [ - engines[e].data.eq(self.data[:(e+1)*8]), - engines[e].crc_prev.eq(reg), - If(self.last_be[e], - self.value.eq(reverse_bits(~engines[e].crc_next)), - self.error.eq(engines[e].crc_next != self.check), + engines[n].data.eq(self.data[:(n + 1)*8]), + engines[n].crc_prev.eq(reg), + If(self.be[n], + self.value.eq(reverse_bits(~engines[n].crc_next)), + self.error.eq(engines[n].crc_next != self.check), ) ] @@ -170,7 +173,7 @@ class LiteEthMACCRCInserter(LiteXModule): fsm.act("COPY", crc.ce.eq(sink.valid & source.ready), crc.data.eq(sink.data), - crc.last_be.eq(sink.last_be), + crc.be.eq(sink.last_be), sink.connect(source), source.last.eq(0), source.last_be.eq(0), @@ -302,7 +305,7 @@ class LiteEthMACCRCChecker(LiteXModule): ) self.comb += [ crc.data.eq(sink.data), - crc.last_be.eq(sink.last_be), + crc.be.eq(sink.last_be), ] fsm.act("IDLE", If(sink.valid & sink.ready, From 95ff76867f966851f688525637923af44ea5f3af Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 26 Mar 2024 11:30:07 +0100 Subject: [PATCH 6/8] mac/crc: Rename dw to data_width. --- liteeth/mac/crc.py | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/liteeth/mac/crc.py b/liteeth/mac/crc.py index 9dc6644..01b1adf 100644 --- a/liteeth/mac/crc.py +++ b/liteeth/mac/crc.py @@ -147,14 +147,14 @@ class LiteEthMACCRCInserter(LiteXModule): Packet data with CRC. """ def __init__(self, crc_class, description): - self.sink = sink = stream.Endpoint(description) + self.sink = sink = stream.Endpoint(description) self.source = source = stream.Endpoint(description) # # # - dw = len(sink.data) - assert dw in [8, 32, 64] - crc = crc_class(dw) + data_width = len(sink.data) + assert data_width in [8, 32, 64] + crc = crc_class(data_width) fsm = FSM(reset_state="IDLE") self.submodules += crc, fsm @@ -182,23 +182,23 @@ class LiteEthMACCRCInserter(LiteXModule): # beginning of the crc value [If(sink.last_be[e], source.data.eq(Cat(sink.data[:(e+1)*8], - crc.value)[:dw])) for e in range(dw//8)], + crc.value)[:data_width])) for e in range(data_width//8)], # If the whole crc value fits in the last sink paket, signal the # end. This also means the next state is idle - If((dw == 64) & (sink.last_be <= 0xF), + If((data_width == 64) & (sink.last_be <= 0xF), source.last.eq(1), - source.last_be.eq(sink.last_be << (dw//8 - 4)) + source.last_be.eq(sink.last_be << (data_width//8 - 4)) ), ).Else( crc.ce.eq(sink.valid & source.ready), ), If(sink.valid & sink.last & source.ready, - If((dw == 64) & (sink.last_be <= 0xF), + If((data_width == 64) & (sink.last_be <= 0xF), NextState("IDLE"), ).Else( NextValue(crc_packet, crc.value), - If(dw == 64, + If(data_width == 64, NextValue(last_be, sink.last_be >> 4), ).Else ( NextValue(last_be, sink.last_be), @@ -207,7 +207,7 @@ class LiteEthMACCRCInserter(LiteXModule): ) ) ) - ratio = crc.width//dw + ratio = crc.width//data_width if ratio > 1: cnt = Signal(max=ratio, reset=ratio-1) cnt_done = Signal() @@ -233,7 +233,7 @@ class LiteEthMACCRCInserter(LiteXModule): source.data.eq(crc.value), source.last_be.eq(last_be), [If(last_be[e], - source.data.eq(crc_packet[-(e+1)*8:])) for e in range(dw//8)], + source.data.eq(crc_packet[-(e+1)*8:])) for e in range(data_width//8)], If(source.ready, NextState("IDLE")) ) @@ -272,11 +272,11 @@ class LiteEthMACCRCChecker(LiteXModule): # # # - dw = len(sink.data) - assert dw in [8, 32, 64] - crc = crc_class(dw) + data_width = len(sink.data) + assert data_width in [8, 32, 64] + crc = crc_class(data_width) self.submodules += crc - ratio = ceil(crc.width/dw) + ratio = ceil(crc.width/data_width) fifo = ResetInserter()(stream.SyncFIFO(description, ratio + 1)) self.submodules += fifo @@ -320,30 +320,30 @@ class LiteEthMACCRCChecker(LiteXModule): source.valid.eq(sink.valid & fifo_full), source.payload.eq(fifo.source.payload), - If(dw <= 32, + If(data_width <= 32, source.last.eq(sink.last), source.last_be.eq(sink.last_be), - # For dw == 64 bit, we need to look wether the last word contains only the crc value or both crc and data + # For data_width == 64 bit, we need to look wether the last word contains only the crc value or both crc and data # In the latter case, the last word also needs to be output # In both cases, last_be needs to be adjusted for the new end position ).Elif(sink.last_be & 0xF, source.last.eq(sink.last), - source.last_be.eq(sink.last_be << (dw//8 - 4)), + source.last_be.eq(sink.last_be << (data_width//8 - 4)), ).Else( NextValue(last_be, sink.last_be >> 4), NextValue(crc_error, crc.error), ), - # `source.error` has a width > 1 for dw > 8, but since the crc error + # `source.error` has a width > 1 for data_width > 8, but since the crc error # applies to the whole ethernet packet, all the bytes are marked as # containing an error. This way later reducing the data width # doesn't run into issues with missing the error - source.error.eq(sink.error | Replicate(crc.error & sink.last, dw//8)), + source.error.eq(sink.error | Replicate(crc.error & sink.last, data_width//8)), self.error.eq(sink.valid & sink.last & crc.error), If(sink.valid & sink.ready, crc.ce.eq(1), - # Can only happen for dw == 64 + # Can only happen for data_width == 64 If(sink.last & (sink.last_be > 0xF), NextState("COPY_LAST"), ).Elif(sink.last, @@ -353,10 +353,10 @@ class LiteEthMACCRCChecker(LiteXModule): ) # If the last sink word contains both data and the crc value, shift out - # the last value here. Can only happen for dw == 64 + # the last value here. Can only happen for data_width == 64 fsm.act("COPY_LAST", fifo.source.connect(source), - source.error.eq(fifo.source.error | Replicate(crc_error, dw//8)), + source.error.eq(fifo.source.error | Replicate(crc_error, data_width//8)), source.last_be.eq(last_be), If(source.valid & source.ready, NextState("RESET") From b22ac619ab4b373f9f3f50eeb723b43dc56c5842 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 26 Mar 2024 11:36:43 +0100 Subject: [PATCH 7/8] mac/crc: Avoid dummy CRC classes since we only have one CRC Engine implementation. --- liteeth/mac/crc.py | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/liteeth/mac/crc.py b/liteeth/mac/crc.py index 01b1adf..d3e71c4 100644 --- a/liteeth/mac/crc.py +++ b/liteeth/mac/crc.py @@ -127,9 +127,9 @@ class LiteEthMACCRC32(LiteXModule): ) ] -# MAC CRC Inserter --------------------------------------------------------------------------------- +# MAC CRC32 Inserter ------------------------------------------------------------------------------- -class LiteEthMACCRCInserter(LiteXModule): +class LiteEthMACCRC32Inserter(LiteXModule): """CRC Inserter Append a CRC at the end of each packet. @@ -146,7 +146,7 @@ class LiteEthMACCRCInserter(LiteXModule): source : out Packet data with CRC. """ - def __init__(self, crc_class, description): + def __init__(self, description): self.sink = sink = stream.Endpoint(description) self.source = source = stream.Endpoint(description) @@ -154,7 +154,7 @@ class LiteEthMACCRCInserter(LiteXModule): data_width = len(sink.data) assert data_width in [8, 32, 64] - crc = crc_class(data_width) + crc = LiteEthMACCRC32(data_width) fsm = FSM(reset_state="IDLE") self.submodules += crc, fsm @@ -237,14 +237,9 @@ class LiteEthMACCRCInserter(LiteXModule): If(source.ready, NextState("IDLE")) ) +# MAC CRC32 Checker -------------------------------------------------------------------------------- -class LiteEthMACCRC32Inserter(LiteEthMACCRCInserter): - def __init__(self, description): - LiteEthMACCRCInserter.__init__(self, LiteEthMACCRC32, description) - -# MAC CRC Checker ---------------------------------------------------------------------------------- - -class LiteEthMACCRCChecker(LiteXModule): +class LiteEthMACCRC32Checker(LiteXModule): """CRC Checker Check CRC at the end of each packet. @@ -264,7 +259,7 @@ class LiteEthMACCRCChecker(LiteXModule): error : out Pulses every time a CRC error is detected. """ - def __init__(self, crc_class, description): + def __init__(self, description): self.sink = sink = stream.Endpoint(description) self.source = source = stream.Endpoint(description) @@ -274,7 +269,7 @@ class LiteEthMACCRCChecker(LiteXModule): data_width = len(sink.data) assert data_width in [8, 32, 64] - crc = crc_class(data_width) + crc = LiteEthMACCRC32(data_width) self.submodules += crc ratio = ceil(crc.width/data_width) @@ -362,8 +357,3 @@ class LiteEthMACCRCChecker(LiteXModule): NextState("RESET") ) ) - - -class LiteEthMACCRC32Checker(LiteEthMACCRCChecker): - def __init__(self, description): - LiteEthMACCRCChecker.__init__(self, LiteEthMACCRC32, description) From bbdd6835aa0061939abaadb6fb636a4fbe6022ac Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 26 Mar 2024 11:55:05 +0100 Subject: [PATCH 8/8] mac/crc: Cleanup and try to move data-path connection outside of FSM for timings. --- liteeth/mac/crc.py | 65 ++++++++++++++++++++++++++-------------------- 1 file changed, 37 insertions(+), 28 deletions(-) diff --git a/liteeth/mac/crc.py b/liteeth/mac/crc.py index d3e71c4..7e37b5c 100644 --- a/liteeth/mac/crc.py +++ b/liteeth/mac/crc.py @@ -152,16 +152,20 @@ class LiteEthMACCRC32Inserter(LiteXModule): # # # + # Parameters. data_width = len(sink.data) + ratio = 32//data_width assert data_width in [8, 32, 64] - crc = LiteEthMACCRC32(data_width) - fsm = FSM(reset_state="IDLE") - self.submodules += crc, fsm - # crc packet checksum - crc_packet = Signal(crc.width) - last_be = Signal().like(sink.last_be) + # Signals. + crc_packet = Signal(32) + last_be = Signal(data_width//8) + # CRC32 Generator. + self.crc = crc = LiteEthMACCRC32(data_width) + + # FSM. + self.fsm = fsm = FSM(reset_state="IDLE") fsm.act("IDLE", crc.reset.eq(1), sink.ready.eq(1), @@ -170,22 +174,23 @@ class LiteEthMACCRC32Inserter(LiteXModule): NextState("COPY"), ) ) - fsm.act("COPY", - crc.ce.eq(sink.valid & source.ready), + self.comb += [ crc.data.eq(sink.data), crc.be.eq(sink.last_be), + ] + fsm.act("COPY", + crc.ce.eq(sink.valid & source.ready), sink.connect(source), source.last.eq(0), source.last_be.eq(0), If(sink.last, - # Fill the empty space of the last data word with the - # beginning of the crc value + # Fill the empty space of the last data word with the beginning of the CRC value. [If(sink.last_be[e], source.data.eq(Cat(sink.data[:(e+1)*8], crc.value)[:data_width])) for e in range(data_width//8)], - # If the whole crc value fits in the last sink paket, signal the - # end. This also means the next state is idle - If((data_width == 64) & (sink.last_be <= 0xF), + # If the whole crc value fits in the last sink packet, signal the end. This also + # means the next state is idle + If((data_width == 64) & (sink.last_be <= 0xf), source.last.eq(1), source.last_be.eq(sink.last_be << (data_width//8 - 4)) ), @@ -194,7 +199,7 @@ class LiteEthMACCRC32Inserter(LiteXModule): ), If(sink.valid & sink.last & source.ready, - If((data_width == 64) & (sink.last_be <= 0xF), + If((data_width == 64) & (sink.last_be <= 0xf), NextState("IDLE"), ).Else( NextValue(crc_packet, crc.value), @@ -207,16 +212,17 @@ class LiteEthMACCRC32Inserter(LiteXModule): ) ) ) - ratio = crc.width//data_width if ratio > 1: - cnt = Signal(max=ratio, reset=ratio-1) + cnt = Signal(max=ratio, reset=ratio-1) cnt_done = Signal() fsm.act("CRC", source.valid.eq(1), chooser(crc_packet, cnt, source.data, reverse=True), If(cnt_done, source.last.eq(1), - If(source.ready, NextState("IDLE")) + If(source.ready, + NextState("IDLE") + ) ) ) self.comb += cnt_done.eq(cnt == 0) @@ -234,7 +240,9 @@ class LiteEthMACCRC32Inserter(LiteXModule): source.last_be.eq(last_be), [If(last_be[e], source.data.eq(crc_packet[-(e+1)*8:])) for e in range(data_width//8)], - If(source.ready, NextState("IDLE")) + If(source.ready, + NextState("IDLE") + ) ) # MAC CRC32 Checker -------------------------------------------------------------------------------- @@ -267,17 +275,16 @@ class LiteEthMACCRC32Checker(LiteXModule): # # # + # Parameters. data_width = len(sink.data) + ratio = ceil(32/data_width) assert data_width in [8, 32, 64] - crc = LiteEthMACCRC32(data_width) - self.submodules += crc - ratio = ceil(crc.width/data_width) - fifo = ResetInserter()(stream.SyncFIFO(description, ratio + 1)) - self.submodules += fifo + # CRC32 Checker. + self.crc = crc = LiteEthMACCRC32(data_width) - fsm = FSM(reset_state="RESET") - self.submodules += fsm + # FIFO. + self.fifo = fifo = ResetInserter()(stream.SyncFIFO(description, ratio + 1)) fifo_in = Signal() fifo_out = Signal() @@ -293,6 +300,8 @@ class LiteEthMACCRC32Checker(LiteXModule): self.sink.ready.eq(fifo_in), ] + # FSM. + self.fsm = fsm = FSM(reset_state="RESET") fsm.act("RESET", crc.reset.eq(1), fifo.reset.eq(1), @@ -308,12 +317,12 @@ class LiteEthMACCRC32Checker(LiteXModule): NextState("COPY") ) ) - last_be = Signal().like(sink.last_be) + last_be = Signal().like(sink.last_be) crc_error = Signal() + self.comb += fifo.source.connect(source, omit={"valid", "ready", "last", "last_be"}) fsm.act("COPY", fifo.source.ready.eq(fifo_out), source.valid.eq(sink.valid & fifo_full), - source.payload.eq(fifo.source.payload), If(data_width <= 32, source.last.eq(sink.last), @@ -350,7 +359,7 @@ class LiteEthMACCRC32Checker(LiteXModule): # If the last sink word contains both data and the crc value, shift out # the last value here. Can only happen for data_width == 64 fsm.act("COPY_LAST", - fifo.source.connect(source), + fifo.source.connect(source, keep={"valid", "ready", "last"}), source.error.eq(fifo.source.error | Replicate(crc_error, data_width//8)), source.last_be.eq(last_be), If(source.valid & source.ready,