diff --git a/examples/basic/crc.py b/examples/basic/crc.py new file mode 100644 index 000000000..c74b8b094 --- /dev/null +++ b/examples/basic/crc.py @@ -0,0 +1,13 @@ +from migen.fhdl.std import * +from migen.genlib.crc import CRC32 +from migen.fhdl import verilog + +class Example(Module): + def __init__(self, width): + crc32 = CRC32(width) + self.submodules += crc32 + self.ios = {crc32.reset, crc32.ce, + crc32.d, crc32.value, crc32.error} + +example = Example(8) +print(verilog.convert(example, example.ios)) diff --git a/migen/actorlib/crc.py b/migen/actorlib/crc.py new file mode 100644 index 000000000..58097a6ae --- /dev/null +++ b/migen/actorlib/crc.py @@ -0,0 +1,135 @@ +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) diff --git a/migen/genlib/crc.py b/migen/genlib/crc.py new file mode 100644 index 000000000..afd40fd5e --- /dev/null +++ b/migen/genlib/crc.py @@ -0,0 +1,112 @@ +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<