136 lines
3.1 KiB
Python
136 lines
3.1 KiB
Python
|
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)
|