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