@@ -26,8 +26,10 @@ class LiteEthMACCRCEngine(LiteXModule):
2626
2727 Parameters
2828 ----------
29+ data_width : int
30+ The bit width of the data bus
2931 width : int
30- The bit width of the data bus and CRC value.
32+ The bit width of CRC value.
3133 polynom : int
3234 The polynomial used for the CRC calculation, specified as an integer (e.g., 0x04C11DB7 for IEEE 802.3).
3335 """
@@ -67,6 +69,53 @@ def optimize_xors(bits):
6769 from collections import Counter
6870 return [bit for bit , count in Counter (bits ).items () if count % 2 == 1 ]
6971
72+ def crc_calc (data_width , width , polynom , crc_prev , data ):
73+ """
74+ Calculate the next CRC value. Functionally equivalent to the migen CRCEngine, but as a python function
75+
76+ Parameters
77+ ----------
78+ data_width : int
79+ The bit width of data
80+ width : int
81+ The bit width of the CRC value
82+ polynom : int
83+ The polynomial used for the CRC calculation, specified as an integer (e.g., 0x04C11DB7 for IEEE 802.3).
84+ crc_prev : int
85+ The previous CRC value
86+ data : int
87+ The new data word
88+
89+ Returns
90+ -------
91+ int
92+ The next CRC value
93+ """
94+ # Convert crc_prev into a list of bits (LSB first) for easier bitwise operations
95+ state = [(crc_prev >> i ) & 1 for i in range (width )]
96+
97+ # Process each bit of the input data (assumed LSB-first).
98+ for n in range (data_width ):
99+ d = (data >> n ) & 1
100+ feedback = state [- 1 ] ^ d
101+ state .pop ()
102+
103+ # For each remaining bit position (positions 0 .. width-2),
104+ # if the corresponding tap (at bit position pos+1 in the polynomial)
105+ # is active, XOR the feedback into that bit.
106+ for pos in range (width - 1 ):
107+ if (polynom >> (pos + 1 )) & 1 :
108+ state [pos ] ^= feedback
109+ # Insert the feedback at the beginning of the state (this is equivalent
110+ # to shifting the register and feeding in the new bit).
111+ state .insert (0 , feedback )
112+
113+ crc_next = 0
114+ for i , bit in enumerate (state ):
115+ if bit :
116+ crc_next |= (1 << i )
117+ return crc_next
118+
70119# MAC CRC32 ----------------------------------------------------------------------------------------
71120
72121@ResetInserter ()
@@ -131,6 +180,70 @@ def __init__(self, data_width):
131180 )
132181 ]
133182
183+ # MAC CRC32 ----------------------------------------------------------------------------------------
184+
185+ @ResetInserter ()
186+ @CEInserter ()
187+ class LiteEthMACCRC32Check (LiteXModule ):
188+ """IEEE 802.3 CRC
189+
190+ Implement an IEEE 802.3 CRC checker.
191+
192+ Parameters
193+ ----------
194+ data_width : int
195+ Width of the data bus.
196+
197+ Attributes
198+ ----------
199+ data : in
200+ Data input.
201+ be : in
202+ Data byte enable (optional, defaults to full word).
203+ error : out
204+ CRC error (used for checker).
205+ """
206+ width = 32
207+ polynom = 0x04c11db7
208+ init = 2 ** width - 1
209+ check = 0xc704dd7b
210+ def __init__ (self , data_width ):
211+ self .data = Signal (data_width )
212+ self .be = Signal (data_width // 8 , reset = 2 ** data_width // 8 - 1 )
213+ self .value = Signal (self .width )
214+ self .error = Signal ()
215+
216+ check_be = [self .check ]
217+ for _ in range (1 , data_width // 8 ):
218+ check_be .append (crc_calc (8 , self .width , self .polynom , check_be [- 1 ], 0 ))
219+
220+ # # #
221+
222+ # Create a CRC Engine for the data_width
223+ self .submodules .engine = engine = LiteEthMACCRCEngine (
224+ data_width = data_width ,
225+ width = self .width ,
226+ polynom = self .polynom ,
227+ )
228+
229+ # Register Full-Word CRC Engine (last one).
230+ reg = Signal (self .width , reset = self .init )
231+ self .sync += reg .eq (engine .crc_next )
232+
233+ # Select CRC Engine/Result.
234+ self .comb += [
235+ # TODO mask data
236+ engine .data .eq (self .data ),
237+ engine .crc_prev .eq (reg ),
238+ ]
239+ for n in range (data_width // 8 ):
240+ self .comb += [
241+ If (self .be [n ],
242+ engine .data .eq (self .data & (2 ** ((n + 1 )* 8 ) - 1 )),
243+ self .error .eq (engine .crc_next != check_be [- (n + 1 )]),
244+ )
245+ ]
246+
134247# MAC CRC32 Inserter -------------------------------------------------------------------------------
135248
136249class LiteEthMACCRC32Inserter (LiteXModule ):
@@ -159,7 +272,7 @@ def __init__(self, description):
159272 # Parameters.
160273 data_width = len (sink .data )
161274 ratio = 32 // data_width
162- assert data_width in [8 , 16 , 32 , 64 ]
275+ assert data_width in [8 , 32 , 64 ]
163276
164277 # Signals.
165278 crc_packet = Signal (32 , reset_less = True )
@@ -279,10 +392,10 @@ def __init__(self, description):
279392 # Parameters.
280393 data_width = len (sink .data )
281394 ratio = ceil (32 / data_width )
282- assert data_width in [8 , 16 , 32 , 64 ]
395+ assert data_width in [8 , 32 , 64 ]
283396
284397 # CRC32 Checker.
285- self .crc = crc = LiteEthMACCRC32 (data_width )
398+ self .crc = crc = LiteEthMACCRC32Check (data_width )
286399
287400 # FIFO.
288401 self .fifo = fifo = ResetInserter ()(stream .SyncFIFO (description , ratio + 1 ))
0 commit comments