clean up
[litex.git] / liteeth / mac / core / crc.py
1 from liteeth.common import *
2
3 class LiteEthMACCRCEngine(Module):
4 """Cyclic Redundancy Check Engine
5
6 Compute next CRC value from last CRC value and data input using
7 an optimized asynchronous LFSR.
8
9 Parameters
10 ----------
11 data_width : int
12 Width of the data bus.
13 width : int
14 Width of the CRC.
15 polynom : int
16 Polynom of the CRC (ex: 0x04C11DB7 for IEEE 802.3 CRC)
17
18 Attributes
19 ----------
20 data : in
21 Data input.
22 last : in
23 last CRC value.
24 next :
25 next CRC value.
26 """
27 def __init__(self, data_width, width, polynom):
28 self.data = Signal(data_width)
29 self.last = Signal(width)
30 self.next = Signal(width)
31
32 ###
33
34 def _optimize_eq(l):
35 """
36 Replace even numbers of XORs in the equation
37 with an equivalent XOR
38 """
39 d = OrderedDict()
40 for e in l:
41 if e in d:
42 d[e] += 1
43 else:
44 d[e] = 1
45 r = []
46 for key, value in d.items():
47 if value%2 != 0:
48 r.append(key)
49 return r
50
51 # compute and optimize CRC's LFSR
52 curval = [[("state", i)] for i in range(width)]
53 for i in range(data_width):
54 feedback = curval.pop() + [("din", i)]
55 for j in range(width-1):
56 if (polynom & (1<<(j+1))):
57 curval[j] += feedback
58 curval[j] = _optimize_eq(curval[j])
59 curval.insert(0, feedback)
60
61 # implement logic
62 for i in range(width):
63 xors = []
64 for t, n in curval[i]:
65 if t == "state":
66 xors += [self.last[n]]
67 elif t == "din":
68 xors += [self.data[n]]
69 self.comb += self.next[i].eq(optree("^", xors))
70
71 @DecorateModule(InsertReset)
72 @DecorateModule(InsertCE)
73 class LiteEthMACCRC32(Module):
74 """IEEE 802.3 CRC
75
76 Implement an IEEE 802.3 CRC generator/checker.
77
78 Parameters
79 ----------
80 data_width : int
81 Width of the data bus.
82
83 Attributes
84 ----------
85 d : in
86 Data input.
87 value : out
88 CRC value (used for generator).
89 error : out
90 CRC error (used for checker).
91 """
92 width = 32
93 polynom = 0x04C11DB7
94 init = 2**width-1
95 check = 0xC704DD7B
96 def __init__(self, data_width):
97 self.data = Signal(data_width)
98 self.value = Signal(self.width)
99 self.error = Signal()
100
101 ###
102
103 self.submodules.engine = LiteEthMACCRCEngine(data_width, self.width, self.polynom)
104 reg = Signal(self.width, reset=self.init)
105 self.sync += reg.eq(self.engine.next)
106 self.comb += [
107 self.engine.data.eq(self.data),
108 self.engine.last.eq(reg),
109
110 self.value.eq(~reg[::-1]),
111 self.error.eq(self.engine.next != self.check)
112 ]
113
114 class LiteEthMACCRCInserter(Module):
115 """CRC Inserter
116
117 Append a CRC at the end of each packet.
118
119 Parameters
120 ----------
121 description : description
122 description of the dataflow.
123
124 Attributes
125 ----------
126 sink : in
127 Packets input without CRC.
128 source : out
129 Packets output with CRC.
130 """
131 def __init__(self, crc_class, description):
132 self.sink = sink = Sink(description)
133 self.source = source = Source(description)
134 self.busy = Signal()
135
136 ###
137
138 dw = flen(sink.data)
139 crc = crc_class(dw)
140 fsm = FSM(reset_state="IDLE")
141 self.submodules += crc, fsm
142
143 fsm.act("IDLE",
144 crc.reset.eq(1),
145 sink.ack.eq(1),
146 If(sink.stb & sink.sop,
147 sink.ack.eq(0),
148 NextState("COPY"),
149 )
150 )
151 fsm.act("COPY",
152 crc.ce.eq(sink.stb & source.ack),
153 crc.data.eq(sink.data),
154 Record.connect(sink, source),
155 source.eop.eq(0),
156 If(sink.stb & sink.eop & source.ack,
157 NextState("INSERT"),
158 )
159 )
160 ratio = crc.width//dw
161 if ratio > 1:
162 cnt = Signal(max=ratio, reset=ratio-1)
163 cnt_done = Signal()
164 fsm.act("INSERT",
165 source.stb.eq(1),
166 chooser(crc.value, cnt, source.data, reverse=True),
167 If(cnt_done,
168 source.eop.eq(1),
169 If(source.ack, NextState("IDLE"))
170 )
171 )
172 self.comb += cnt_done.eq(cnt == 0)
173 self.sync += \
174 If(fsm.ongoing("IDLE"),
175 cnt.eq(cnt.reset)
176 ).Elif(fsm.ongoing("INSERT") & ~cnt_done,
177 cnt.eq(cnt - source.ack)
178 )
179 else:
180 fsm.act("INSERT",
181 source.stb.eq(1),
182 source.eop.eq(1),
183 source.data.eq(crc.value),
184 If(source.ack, NextState("IDLE"))
185 )
186 self.comb += self.busy.eq(~fsm.ongoing("IDLE"))
187
188 class LiteEthMACCRC32Inserter(LiteEthMACCRCInserter):
189 def __init__(self, description):
190 LiteEthMACCRCInserter.__init__(self, LiteEthMACCRC32, description)
191
192 class LiteEthMACCRCChecker(Module):
193 """CRC Checker
194
195 Check CRC at the end of each packet.
196
197 Parameters
198 ----------
199 description : description
200 description of the dataflow.
201
202 Attributes
203 ----------
204 sink : in
205 Packets input with CRC.
206 source : out
207 Packets output without CRC and "error" set to 0
208 on eop when CRC OK / set to 1 when CRC KO.
209 """
210 def __init__(self, crc_class, description):
211 self.sink = sink = Sink(description)
212 self.source = source = Source(description)
213 self.busy = Signal()
214
215 ###
216
217 dw = flen(sink.data)
218 crc = crc_class(dw)
219 self.submodules += crc
220 ratio = crc.width//dw
221
222 error = Signal()
223 fifo = InsertReset(SyncFIFO(description, ratio + 1))
224 self.submodules += fifo
225
226 fsm = FSM(reset_state="RESET")
227 self.submodules += fsm
228
229 fifo_in = Signal()
230 fifo_out = Signal()
231 fifo_full = Signal()
232
233 self.comb += [
234 fifo_full.eq(fifo.fifo.level == ratio),
235 fifo_in.eq(sink.stb & (~fifo_full | fifo_out)),
236 fifo_out.eq(source.stb & source.ack),
237
238 Record.connect(sink, fifo.sink),
239 fifo.sink.stb.eq(fifo_in),
240 self.sink.ack.eq(fifo_in),
241
242 source.stb.eq(sink.stb & fifo_full),
243 source.sop.eq(fifo.source.sop),
244 source.eop.eq(sink.eop),
245 fifo.source.ack.eq(fifo_out),
246 source.payload.eq(fifo.source.payload),
247
248 source.error.eq(sink.error | crc.error),
249 ]
250
251 fsm.act("RESET",
252 crc.reset.eq(1),
253 fifo.reset.eq(1),
254 NextState("IDLE"),
255 )
256 fsm.act("IDLE",
257 crc.data.eq(sink.data),
258 If(sink.stb & sink.sop & sink.ack,
259 crc.ce.eq(1),
260 NextState("COPY")
261 )
262 )
263 fsm.act("COPY",
264 crc.data.eq(sink.data),
265 If(sink.stb & sink.ack,
266 crc.ce.eq(1),
267 If(sink.eop,
268 NextState("RESET")
269 )
270 )
271 )
272 self.comb += self.busy.eq(~fsm.ongoing("IDLE"))
273
274 class LiteEthMACCRC32Checker(LiteEthMACCRCChecker):
275 def __init__(self, description):
276 LiteEthMACCRCChecker.__init__(self, LiteEthMACCRC32, description)