--- /dev/null
+from migen.fhdl.std import *
+from migen.genlib.fsm import FSM, NextState
+from migen.genlib.record import *
+from migen.genlib.misc import chooser
+from migen.genlib.crc import *
+from migen.flow.actor import Sink, Source
+
+class CRCInserter(Module):
+ """CRC Inserter
+
+ Append a CRC at the end of each packet.
+
+ Parameters
+ ----------
+ layout : layout
+ Layout of the dataflow.
+
+ Attributes
+ ----------
+ sink : in
+ Packets input without CRC.
+ source : out
+ Packets output with CRC.
+ """
+ def __init__(self, crc_class, layout):
+ self.sink = Sink(layout, True)
+ self.source = Source(layout, True)
+ self.busy = Signal()
+
+ ###
+
+ dw = flen(self.sink.payload.d)
+ self.submodules.crc = crc_class(dw)
+ self.submodules.fsm = fsm = FSM(reset_state="IDLE")
+
+ fsm.act("IDLE",
+ self.crc.reset.eq(1),
+ self.sink.ack.eq(1),
+ If(self.sink.stb & self.sink.sop,
+ self.sink.ack.eq(0),
+ NextState("COPY"),
+ )
+ )
+ fsm.act("COPY",
+ self.crc.ce.eq(self.sink.stb & self.source.ack),
+ self.crc.d.eq(self.sink.payload.d),
+ Record.connect(self.sink, self.source),
+ self.source.eop.eq(0),
+ If(self.sink.stb & self.sink.eop & self.source.ack,
+ NextState("INSERT"),
+ )
+ )
+ ratio = self.crc.width//dw
+ cnt = Signal(max=ratio, reset=ratio-1)
+ cnt_done = Signal()
+ fsm.act("INSERT",
+ self.source.stb.eq(1),
+ chooser(self.crc.value, cnt, self.source.payload.d, reverse=True),
+ If(cnt_done,
+ self.source.eop.eq(1),
+ If(self.source.ack, NextState("IDLE"))
+ )
+ )
+ self.comb += cnt_done.eq(cnt == 0)
+ self.sync += \
+ If(fsm.ongoing("IDLE"),
+ cnt.eq(cnt.reset)
+ ).Elif(fsm.ongoing("INSERT") & ~cnt_done,
+ cnt.eq(cnt - self.source.ack)
+ )
+ self.comb += self.busy.eq(~fsm.ongoing("IDLE"))
+
+class CRC32Inserter(CRCInserter):
+ def __init__(self, layout):
+ CRCInserter.__init__(self, CRC32, layout)
+
+class CRCChecker(Module):
+ """CRC Checker
+
+ Check CRC at the end of each packet.
+
+ Parameters
+ ----------
+ layout : layout
+ Layout of the dataflow.
+
+ Attributes
+ ----------
+ sink : in
+ Packets input with CRC.
+ source : out
+ Packets output with CRC and "discarded" set to 0
+ on eop if CRC OK / set to 1 is CRC KO.
+ """
+ def __init__(self, crc_class, layout):
+ self.sink = Sink(layout, True)
+ self.source = Source(layout, True)
+ self.busy = Signal()
+
+ ###
+
+ dw = flen(self.sink.payload.d)
+ self.submodules.crc = crc_class(dw)
+
+ fsm = FSM(reset_state="IDLE")
+ self.submodules += fsm
+
+ fsm.act("IDLE",
+ self.crc.reset.eq(1),
+ self.sink.ack.eq(self.sink.stb),
+ If(self.sink.stb & self.sink.sop,
+ self.sink.ack.eq(0),
+ NextState("COPY")
+ )
+ )
+ fsm.act("COPY",
+ Record.connect(self.sink, self.source),
+ self.crc.ce.eq(self.sink.stb & (self.sink.ack | self.sink.eop)),
+ self.crc.d.eq(self.sink.payload.d),
+ If(self.sink.stb & self.sink.eop,
+ self.sink.ack.eq(0),
+ self.source.stb.eq(0),
+ NextState("CHECK")
+ )
+ )
+ fsm.act("CHECK",
+ Record.connect(self.sink, self.source),
+ self.source.discarded.eq(self.crc.error),
+ If(self.source.stb & self.source.ack, NextState("IDLE"))
+ )
+ self.comb += self.busy.eq(~fsm.ongoing("IDLE"))
+
+class CRC32Checker(CRCChecker):
+ def __init__(self, layout):
+ CRCChecker.__init__(self, CRC32, layout)
--- /dev/null
+from migen.fhdl.std import *
+from migen.genlib.misc import optree
+
+class CRCEngine(Module):
+ """Cyclic Redundancy Check Engine
+
+ Compute next CRC value from last CRC value and data input using
+ an optimized asynchronous LFSR.
+
+ Parameters
+ ----------
+ dat_width : int
+ Width of the data bus.
+ width : int
+ Width of the CRC.
+ polynom : int
+ Polynom of the CRC (ex: 0x04C11DB7 for IEEE 802.3 CRC)
+
+ Attributes
+ ----------
+ d : in
+ Data input.
+ last : in
+ last CRC value.
+ next :
+ next CRC value.
+ """
+ def __init__(self, dat_width, width, polynom):
+ self.d = Signal(dat_width)
+ self.last = Signal(width)
+ self.next = Signal(width)
+
+ ###
+
+ def _optimize_eq(l):
+ """
+ Replace even numbers of XORs in the equation
+ with an equivalent 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 CRC's LFSR
+ curval = [[("state", i)] for i in range(width)]
+ for i in range(dat_width):
+ feedback = curval.pop() + [("din", i)]
+ curval.insert(0, feedback)
+ for j in range(1, width-1):
+ if (polynom&(1<<j)):
+ curval[j] += feedback
+ curval[j] = _optimize_eq(curval[j])
+
+ # implement logic
+ for i in range(width):
+ xors = []
+ for t, n in curval[i]:
+ if t == "state":
+ xors += [self.last[n]]
+ elif t == "din":
+ xors += [self.d[n]]
+ self.comb += self.next[i].eq(optree("^", xors))
+
+@DecorateModule(InsertReset)
+@DecorateModule(InsertCE)
+class CRC32(Module):
+ """IEEE 802.3 CRC
+
+ Implement an IEEE 802.3 CRC generator/checker.
+
+ Parameters
+ ----------
+ dat_width : int
+ Width of the data bus.
+
+ Attributes
+ ----------
+ d : in
+ Data input.
+ value : out
+ CRC value (used for generator).
+ error : out
+ CRC error (used for checker).
+ """
+ width = 32
+ polynom = 0x04C11DB7
+ check = 0xC704DD7B
+ def __init__(self, dat_width):
+ self.d = Signal(dat_width)
+ self.value = Signal(self.width)
+ self.error = Signal()
+
+ ###
+
+ self.submodules.engine = CRCEngine(dat_width, self.width, self.polynom)
+ reg = Signal(self.width, reset=2**self.width-1)
+ self.sync += reg.eq(self.engine.next)
+ self.comb += [
+ self.engine.d.eq(self.d),
+ self.engine.last.eq(reg),
+
+ self.value.eq(~reg[::-1]),
+ self.error.eq(reg != self.check)
+ ]