From 2aa194390f3e4b5c231b34973a1df5f53155ccc8 Mon Sep 17 00:00:00 2001 From: morgan Date: Mon, 26 Aug 2024 16:28:49 +0800 Subject: [PATCH] cxp upconn: refactor to use one encoder --- src/gateware/cxp_upconn.py | 177 ++++++++++++++++++++----------------- 1 file changed, 94 insertions(+), 83 deletions(-) diff --git a/src/gateware/cxp_upconn.py b/src/gateware/cxp_upconn.py index d9e01ec..837c81a 100644 --- a/src/gateware/cxp_upconn.py +++ b/src/gateware/cxp_upconn.py @@ -57,83 +57,96 @@ class CXP_UpConn(Module, AutoCSR): o = Signal() tx_en = Signal() tx_bitcount = Signal(max=10) - tx_wordcount = Signal(max=4) + tx_charcount = Signal(max=4) tx_reg = Signal(10) - disp = Signal() priorities = Signal(max=self.nfifos) idling = Signal() + encoder = ClockDomainsRenamer("cxp_upconn")(SingleEncoder(True)) + self.submodules += encoder + # startup sequence self.fsm.act("WAIT_TX_ENABLE", If(self.tx_enable.storage, NextValue(self.tx_idle.word_idx, 0), - NextValue(tx_wordcount, 0), - NextValue(tx_bitcount, 0), - NextState("LOAD_CHAR") + NextState("ENCODE_CHAR") ) ) + self.fsm.act("ENCODE_CHAR", + NextValue(self.tx_idle.source_ack, 1), + NextValue(encoder.d, self.tx_idle.source_data), + NextValue(encoder.k, self.tx_idle.source_k), + NextState("LOAD_CHAR"), + ) + self.fsm.act("LOAD_CHAR", NextValue(idling, 1), - NextValue(self.tx_idle.source_ack, 1), - NextValue(tx_reg, self.tx_idle.source_data), - NextValue(disp, self.tx_idle.disp_out), + NextValue(tx_charcount, 0), + NextValue(tx_bitcount, 0), + + NextValue(tx_reg, encoder.output), + NextValue(encoder.disp_in, encoder.disp_out), NextState("START_TX") ) self.fsm.act("START_TX", tx_en.eq(1), - If((~self.tx_enable.storage) & (tx_wordcount == 3), + If((~self.tx_enable.storage) & (tx_charcount == 3), NextState("WAIT_TX_ENABLE") ) ) + # OSERDESE2 is not used as PLLE2 can't output the required 2.083MHz (480ns) for the CLKDIV self.sync.cxp_upconn += [ - self.tx_fifos.disp_in.eq(disp), - self.tx_idle.disp_in.eq(disp), - If(tx_en, o.eq(tx_reg[0]), tx_reg.eq(Cat(tx_reg[1:], 0)), tx_bitcount.eq(tx_bitcount + 1), - - # char boundary If(tx_bitcount == 9, tx_bitcount.eq(0), + tx_reg.eq(encoder.output), + encoder.disp_in.eq(encoder.disp_out), + ), + + # packet insertion and idle word + If(tx_bitcount == 9, + # Section 9.2.4 (CXP-001-2021) + # trigger packets should be inserted at char boundary If((~self.tx_fifos.pe.n) & (self.tx_fifos.pe.o == 0), # trigger packets are inserted at char boundary and don't contribute to word count - tx_reg.eq(self.tx_fifos.source_data[0]), self.tx_fifos.source_ack[0].eq(1), - disp.eq(self.tx_fifos.disp_out[0]), + encoder.d.eq(self.tx_fifos.source_data[0]), + encoder.k.eq(self.tx_fifos.source_k[0]), ).Else( - # word boundary - If(tx_wordcount == 3, - tx_wordcount.eq(0), + If(tx_charcount == 3, + tx_charcount.eq(0), + + # other priorities packets are inserted at word boundary If(~self.tx_fifos.pe.n, - # priority lv 1 & 2 packets are inserted at word boundary idling.eq(0), priorities.eq(self.tx_fifos.pe.o), self.tx_fifos.source_ack[self.tx_fifos.pe.o].eq(1), - tx_reg.eq(self.tx_fifos.source_data[self.tx_fifos.pe.o]), - disp.eq(self.tx_fifos.disp_out[self.tx_fifos.pe.o]), + encoder.d.eq(self.tx_fifos.source_data[self.tx_fifos.pe.o]), + encoder.k.eq(self.tx_fifos.source_k[self.tx_fifos.pe.o]), ).Else( idling.eq(1), self.tx_idle.source_ack.eq(1), - tx_reg.eq(self.tx_idle.source_data), - disp.eq(self.tx_idle.disp_out), + encoder.d.eq(self.tx_idle.source_data), + encoder.k.eq(self.tx_idle.source_k), ) ).Else( - tx_wordcount.eq(tx_wordcount + 1), + tx_charcount.eq(tx_charcount + 1), If(~idling, self.tx_fifos.source_ack[priorities].eq(1), - tx_reg.eq(self.tx_fifos.source_data[priorities]), - disp.eq(self.tx_fifos.disp_out[priorities]), + encoder.d.eq(self.tx_fifos.source_data[priorities]), + encoder.k.eq(self.tx_fifos.source_k[priorities]), ).Else( self.tx_idle.source_ack.eq(1), - tx_reg.eq(self.tx_idle.source_data), - disp.eq(self.tx_idle.disp_out), + encoder.d.eq(self.tx_idle.source_data), + encoder.k.eq(self.tx_idle.source_k), ) ), ) @@ -150,14 +163,14 @@ class CXP_UpConn(Module, AutoCSR): ) ] - ninth_bit = Signal() + prioity_0 = Signal() word_bound = Signal() p0 = Signal() p3 = Signal() self.comb += [ - ninth_bit.eq(tx_bitcount == 9), - word_bound.eq(tx_wordcount == 3), + prioity_0.eq((~self.tx_fifos.pe.n) & (self.tx_fifos.pe.o == 0)), + word_bound.eq(tx_charcount == 3), p0.eq(self.tx_idle.word_idx == 0), p3.eq(self.tx_idle.word_idx == 3), ] @@ -167,17 +180,17 @@ class CXP_UpConn(Module, AutoCSR): # Instance("OBUF", i_I=self.cd_cxp_upconn.clk, o_O=pads.n_rx), # # pmod 0-7 pin - # Instance("OBUF", i_I=o, o_O=pmod[0]), - # Instance("OBUF", i_I=self.cd_cxp_upconn.clk, o_O=pmod[1]), - # Instance("OBUF", i_I=~self.tx_fifos.pe.n, o_O=pmod[2]), - # Instance("OBUF", i_I=ninth_bit, o_O=pmod[3]), - # Instance("OBUF", i_I=word_bound, o_O=pmod[4]), - # Instance("OBUF", i_I=idling, o_O=pmod[5]), - # # Instance("OBUF", i_I=self.tx_fifos.source_ack[0], o_O=pmod[6]), - # # Instance("OBUF", i_I=self.tx_fifos.source_ack[2], o_O=pmod[6]), - # # Instance("OBUF", i_I=self.tx_fifos.source_ack[1], o_O=pmod[7]), - # Instance("OBUF", i_I=p0, o_O=pmod[6]), - # Instance("OBUF", i_I=p3, o_O=pmod[7]), + Instance("OBUF", i_I=o, o_O=pmod[0]), + Instance("OBUF", i_I=self.cd_cxp_upconn.clk, o_O=pmod[1]), + Instance("OBUF", i_I=~self.tx_fifos.pe.n, o_O=pmod[2]), + Instance("OBUF", i_I=prioity_0, o_O=pmod[3]), + Instance("OBUF", i_I=word_bound, o_O=pmod[4]), + Instance("OBUF", i_I=idling, o_O=pmod[5]), + # Instance("OBUF", i_I=self.tx_fifos.source_ack[0], o_O=pmod[6]), + # Instance("OBUF", i_I=self.tx_fifos.source_ack[2], o_O=pmod[6]), + # Instance("OBUF", i_I=self.tx_fifos.source_ack[1], o_O=pmod[7]), + Instance("OBUF", i_I=p0, o_O=pmod[6]), + Instance("OBUF", i_I=p3, o_O=pmod[7]), ] self.symbol0 = CSR(9) self.symbol1 = CSR(9) @@ -185,66 +198,70 @@ class CXP_UpConn(Module, AutoCSR): self.sync += [ self.tx_fifos.sink_stb[0].eq(self.symbol0.re), - self.tx_fifos.sink_data[0].eq(self.symbol0.r), + self.tx_fifos.sink_data[0].eq(self.symbol0.r[:8]), + self.tx_fifos.sink_k[0].eq(self.symbol0.r[8]), + self.tx_fifos.sink_stb[1].eq(self.symbol1.re), - self.tx_fifos.sink_data[1].eq(self.symbol1.r), + self.tx_fifos.sink_data[1].eq(self.symbol1.r[:8]), + self.tx_fifos.sink_k[1].eq(self.symbol1.r[8]), + self.tx_fifos.sink_stb[2].eq(self.symbol2.re), - self.tx_fifos.sink_data[2].eq(self.symbol2.r), + self.tx_fifos.sink_data[2].eq(self.symbol2.r[:8]), + self.tx_fifos.sink_k[2].eq(self.symbol2.r[8]), ] class TxFIFOs(Module): def __init__(self, nfifos, fifo_depth): - self.disp_in = Signal() - self.disp_out = Array(Signal() for _ in range(nfifos)) - + + self.sink_full = Signal(nfifos) self.sink_stb = Signal(nfifos) - self.sink_ack = Signal(nfifos) - self.sink_data = [Signal(9) for _ in range(nfifos)] + self.sink_data = [Signal(8) for _ in range(nfifos)] + self.sink_k = [Signal() for _ in range(nfifos)] self.source_ack = Array(Signal() for _ in range(nfifos)) - self.source_data = Array(Signal(10) for _ in range(nfifos)) + self.source_data = Array(Signal(8) for _ in range(nfifos)) + self.source_k = Array(Signal() for _ in range(nfifos)) # # # - source_stb = Signal(nfifos) + non_empty = Signal(nfifos) for i in range(nfifos): cdr = ClockDomainsRenamer({"write": "sys", "read": "cxp_upconn"}) fifo = cdr(stream.AsyncFIFO([("data", 9)], fifo_depth)) - encoder = ClockDomainsRenamer("cxp_upconn")(SingleEncoder(True)) setattr(self.submodules, "tx_fifo" + str(i), fifo) - setattr(self.submodules, "tx_encoder" + str(i), encoder) + self.sync += [ fifo.sink.stb.eq(self.sink_stb[i]), - self.sink_ack[i].eq(fifo.sink.ack), - fifo.sink.data.eq(self.sink_data[i]), + self.sink_full[i].eq(fifo.sink.ack), + fifo.sink.data.eq(Cat(self.sink_data[i], self.sink_k[i])), ] - self.sync.cxp_upconn += [ - encoder.d.eq(fifo.source.data[:8]), - encoder.k.eq(fifo.source.data[8]), - encoder.disp_in.eq(self.disp_in), - self.disp_out[i].eq(encoder.disp_out), - source_stb[i].eq(fifo.source.stb), - fifo.source.ack.eq(self.source_ack[i]), - self.source_data[i].eq(encoder.output), - # reset ack after asserted - If(self.source_ack[i], self.source_ack[i].eq(0)), + self.sync.cxp_upconn += [ + If(self.source_ack[i], + # reset ack after asserted + self.source_ack[i].eq(0), + fifo.source.ack.eq(1), + ).Else( + fifo.source.ack.eq(0), + ), + + non_empty[i].eq(fifo.source.stb), + self.source_data[i].eq(fifo.source.data[:8]), + self.source_k[i].eq(fifo.source.data[8]), ] # FIFOs transmission priority self.submodules.pe = PriorityEncoder(nfifos) - self.comb += self.pe.i.eq(source_stb) + self.comb += self.pe.i.eq(non_empty) class TxIdle(Module): def __init__(self): - self.disp_in = Signal() - self.disp_out = Signal() - - self.word_idx = Signal(max=4) self.source_ack = Signal() - self.source_data = Signal(10) + self.source_data = Signal(8) + self.source_k = Signal() + self.word_idx = Signal(max=4) # # # # CXP 2.1 section 9.2.5 @@ -256,24 +273,18 @@ class TxIdle(Module): [0b10111100, 0], #D28.5 ]) - encoder = ClockDomainsRenamer("cxp_upconn")(SingleEncoder(True)) - self.submodules += encoder - self.sync.cxp_upconn += [ - encoder.d.eq(IDLE_CHARS[self.word_idx][0]), - encoder.k.eq(IDLE_CHARS[self.word_idx][1]), - encoder.disp_in.eq(self.disp_in), - self.disp_out.eq(encoder.disp_out), - self.source_data.eq(encoder.output), + self.source_data.eq(IDLE_CHARS[self.word_idx][0]), + self.source_k.eq(IDLE_CHARS[self.word_idx][1]), If(self.source_ack, # reset after asserted self.source_ack.eq(0), If(self.word_idx != 3, - self.word_idx.eq(self.word_idx + 1), + self.word_idx.eq(self.word_idx + 1), ).Else( - self.word_idx.eq(0), + self.word_idx.eq(self.word_idx.reset), ) ), ]