From d5096781d357d447d20c0c11b931813cc7708ec6 Mon Sep 17 00:00:00 2001 From: morgan Date: Thu, 29 Aug 2024 17:39:07 +0800 Subject: [PATCH] cxp pipeline: packet handling pipeline tx pipeline: add CRC32 inserter tx pipeline: add start & end of packet code inserter tx pipeline: add packet wrapper for start & stop packet indication tx pipeline: add code source for trigger & trigger ack packet tx pipeline: add packet for trigger & trigger ack tx pipeline: add tx_command_packet for firmware tx command packet: add fifo to store control packet --- src/gateware/cxp_pipeline.py | 280 +++++++++++++++++++++++++++++++++++ 1 file changed, 280 insertions(+) create mode 100644 src/gateware/cxp_pipeline.py diff --git a/src/gateware/cxp_pipeline.py b/src/gateware/cxp_pipeline.py new file mode 100644 index 0000000..7e99423 --- /dev/null +++ b/src/gateware/cxp_pipeline.py @@ -0,0 +1,280 @@ +from migen import * +from misoc.interconnect.csr import * +from misoc.interconnect import stream +from misoc.cores.liteeth_mini.mac.crc import LiteEthMACCRCEngine, LiteEthMACCRCChecker + +def K(x, y): + return ((y << 5) | x) + +class Code_Source(Module): + def __init__(self, layout, counts=4): + + self.source = stream.Endpoint(layout) + self.stb = Signal() + self.data = Signal.like(self.source.data) + self.k = Signal.like(self.source.k) + + # # # + + cnt = Signal(max=counts) + clr_cnt = Signal() + inc_cnt = Signal() + + self.sync += [ + If(clr_cnt, + cnt.eq(cnt.reset), + ).Elif(inc_cnt, + cnt.eq(cnt + 1), + ) + ] + + self.submodules.fsm = fsm = FSM(reset_state="IDLE") + + fsm.act("IDLE", + clr_cnt.eq(1), + If(self.stb, + NextState("WRITE") + ) + ) + + fsm.act("WRITE", + self.source.stb.eq(1), + self.source.data.eq(self.data), + self.source.k.eq(self.k), + If(cnt == counts - 1, + self.source.eop.eq(1), + If(self.source.ack, NextState("IDLE")) + ).Else( + inc_cnt.eq(self.source.ack) + ) + ) + + +class Code_Inserter(Module): + def __init__(self, layout, insert_infront=True, counts=4): + self.sink = sink = stream.Endpoint(layout) + self.source = source = stream.Endpoint(layout) + + self.data = Signal.like(sink.data) + self.k = Signal.like(sink.k) + + # # # + assert counts > 0 + + cnt = Signal() if counts == 1 else Signal(max=counts) + clr_cnt = Signal() + inc_cnt = Signal() + + self.sync += [ + If(clr_cnt, + cnt.eq(cnt.reset), + ).Elif(inc_cnt, + cnt.eq(cnt + 1), + ) + ] + + self.submodules.fsm = fsm = FSM(reset_state="IDLE") + + if insert_infront: + fsm.act("IDLE", + sink.ack.eq(1), + clr_cnt.eq(1), + If(sink.stb, + sink.ack.eq(0), + NextState("INSERT"), + ) + ) + + fsm.act("INSERT", + sink.ack.eq(0), + source.stb.eq(1), + source.data.eq(self.data), + source.k.eq(self.k), + If(cnt == counts - 1, + If(source.ack, NextState("COPY")) + ).Else( + inc_cnt.eq(source.ack) + ) + ) + + fsm.act("COPY", + sink.connect(source), + If(sink.stb & sink.eop & source.ack, + NextState("IDLE"), + ) + ) + + else: + fsm.act("IDLE", + sink.ack.eq(1), + clr_cnt.eq(1), + If(sink.stb, + sink.ack.eq(0), + NextState("COPY"), + ) + ) + + fsm.act("COPY", + sink.connect(source), + source.eop.eq(0), + If(sink.stb & sink.eop & source.ack, + NextState("INSERT"), + ) + ) + + fsm.act("INSERT", + sink.ack.eq(0), + source.stb.eq(1), + source.data.eq(self.data), + source.k.eq(self.k), + If(cnt == counts - 1, + source.eop.eq(1), + If(source.ack, NextState("IDLE")) + ).Else( + inc_cnt.eq(source.ack) + ), + ) + + +class Packet_Wrapper(Module): + def __init__(self, layout): + self.submodules.pak_start = pak_start = Code_Inserter(layout) + self.submodules.pak_end = pak_end = Code_Inserter(layout, insert_infront=False) + + self.sink = pak_start.sink + self.source = pak_end.source + + self.comb += [ + pak_start.data.eq(K(27, 7)), + pak_start.k.eq(1), + pak_end.data.eq(K(29, 7)), + pak_end.k.eq(1), + + pak_start.source.connect(pak_end.sink), + ] + +@ResetInserter() +@CEInserter() +class CXPCRC32(Module): + # Section 9.2.2.2 (CXP-001-2021) + width = 32 + polynom = 0x04C11DB7 + seed = 2**width-1 + check = 0x00000000 + def __init__(self, data_width): + self.data = Signal(data_width) + self.value = Signal(self.width) + self.error = Signal() + + # # # + + self.submodules.engine = LiteEthMACCRCEngine(data_width, self.width, self.polynom) + reg = Signal(self.width, reset=self.seed) + self.sync += reg.eq(self.engine.next) + self.comb += [ + self.engine.data.eq(self.data), + self.engine.last.eq(reg), + + self.value.eq(reg[::-1]), + self.error.eq(self.engine.next != self.check) + ] + +class CXPCRC32Checker(LiteEthMACCRCChecker): + def __init__(self, layout): + LiteEthMACCRCChecker.__init__(self, CXPCRC32, layout) + +class TX_Trigger(Module, AutoCSR): + def __init__(self, layout): + self.trig_stb = Signal() + self.delay = Signal(8) + self.linktrig_mode = Signal(max=4) + + # # # + + self.submodules.code_src = code_src = Code_Source(layout, counts=3) + self.comb += [ + code_src.stb.eq(self.trig_stb), + code_src.data.eq(self.delay), + code_src.k.eq(0) + ] + + self.submodules.inserter_once = inserter_once = Code_Inserter(layout, counts=1) + self.submodules.inserter_twice = inserter_twice = Code_Inserter(layout, counts=2) + self.comb += [ + inserter_once.k.eq(1), + inserter_twice.k.eq(1), + If((self.linktrig_mode == 0) | (self.linktrig_mode == 2), + inserter_once.data.eq(K(28, 2)), + inserter_twice.data.eq(K(28, 4)), + ).Else( + inserter_once.data.eq(K(28, 4)), + inserter_twice.data.eq(K(28, 2)), + ) + ] + + tx_pipeline = [ code_src, inserter_twice, inserter_once] + + for s, d in zip(tx_pipeline, tx_pipeline[1:]): + self.comb += s.source.connect(d.sink) + + self.source = tx_pipeline[-1].source + +class Trigger_ACK(Module): + def __init__(self, layout): + self.ack = Signal() + + # # # + + # Section 9.3.2 (CXP-001-2021) + # Send 4x K28.6 and 4x 0x01 as trigger packet ack + self.submodules.code_src = code_src = Code_Source(layout) + self.submodules.k_code_inserter = k_code_inserter = Code_Inserter(layout) + self.comb += [ + code_src.stb.eq(self.ack), + code_src.data.eq(0x01), + code_src.k.eq(0), + k_code_inserter.data.eq(K(28, 6)), + k_code_inserter.k.eq(1), + + code_src.source.connect(k_code_inserter.sink) + ] + + self.source = k_code_inserter.source + +class TX_Command_Packet(Module, AutoCSR): + def __init__(self, layout): + self.len = CSRStorage(6) + self.data = CSR(8) + self.writeable = CSRStatus() + + # # # + + # TODO: use RAM instead of FIFO ? + # Section 12.1.2 (CXP-001-2021) + # Max control packet size is 128 bytes + + # NOTE: The firmware will lock up if there is not enough space for the packet + self.submodules.fifo = fifo = stream.SyncFIFO(layout, 128) + self.submodules.pak_wrp = pak_wrp = Packet_Wrapper(layout) + self.source = pak_wrp.source + + self.comb += fifo.source.connect(pak_wrp.sink) + + len = Signal(6, reset=1) + self.sync += [ + self.writeable.status.eq(fifo.sink.ack), + If(fifo.sink.ack, fifo.sink.stb.eq(0)), + If(self.data.re, + fifo.sink.stb.eq(1), + fifo.sink.data.eq(self.data.r), + + fifo.sink.k.eq(0), + If(len == self.len.storage, + fifo.sink.eop.eq(1), + len.eq(len.reset), + ).Else( + fifo.sink.eop.eq(0), + len.eq(len + 1), + ), + ) + ]