From 481162430c05f07e7f795664d9c0dabc4149fad4 Mon Sep 17 00:00:00 2001 From: morgan Date: Fri, 28 Jun 2024 12:02:15 +0800 Subject: [PATCH] cxp upconn: add word & char boundary transmission --- src/gateware/cxp_upconn.py | 154 +++++++++++++++++++++---------------- 1 file changed, 87 insertions(+), 67 deletions(-) diff --git a/src/gateware/cxp_upconn.py b/src/gateware/cxp_upconn.py index 809925c..ae8f9ba 100644 --- a/src/gateware/cxp_upconn.py +++ b/src/gateware/cxp_upconn.py @@ -7,10 +7,12 @@ from misoc.interconnect import stream from misoc.interconnect.csr import * # CXP 2.1 section 9.2.5 -IDLE_WORDS = [ +IDLE_CHARS = [ #[data, k] [0b10111100, 1], #K28.5 [0b10111100, 1], #K28.5 + [0b10111100, 1], #K28.5 + [0b10111100, 1], #K28.5 # [0b00111100, 1], #K28.1 # [0b00111100, 1], #K28.1 # [0b10111100, 0], #D28.5 @@ -66,21 +68,30 @@ class CXP_UpConn(Module, AutoCSR): o = Signal() tx_en = Signal() tx_bitcount = Signal(max=10) + tx_wordcount = Signal() tx_reg = Signal(10) - wordidx = Signal(max=len(IDLE_WORDS)) + + disp = Signal() + tx_wordcount = Signal(max=4) + priority = Signal(max=nfifos) + idling = Signal() # startup sequence self.fsm.act("WAIT_TX_ENABLE", If(self.tx_enable.storage, - NextState("ENCODE_IDLE_WORD") + NextValue(self.encoder.d, IDLE_CHARS[0][0]), + NextValue(self.encoder.k, IDLE_CHARS[0][1]), + NextValue(self.encoder.disp_in, 0), + NextValue(tx_wordcount, 0), + NextValue(tx_bitcount, 0), + NextState("LOAD_CHAR") ) ) - self.fsm.act("ENCODE_IDLE_WORD", - NextValue(self.encoder.d, IDLE_WORDS[0][0]), - NextValue(self.encoder.k, IDLE_WORDS[0][1]), - NextValue(self.encoder.disp_in, 0), - NextValue(wordidx, 1), + self.fsm.act("LOAD_CHAR", + NextValue(idling, 1), + NextValue(tx_reg, self.encoder.output), + NextValue(disp, self.encoder.disp_out), NextState("START_TX") ) @@ -91,74 +102,78 @@ class CXP_UpConn(Module, AutoCSR): ) ) - - # 0 lv interrupt at char boundary 10bit - # other lv interrupt at word boundary 40bit - - cur_disp = Signal() - - # TODO: only allow trigger packet to do character interrupt and other priority level to only interrupt word - # ISSUE: what if 2lv is transmitting 2nd char & 1lv interrupt its? # CXP 2.1 section 9.2.4 self.sync.cxp_upconn += [ - self.tx_fifos.disp_in.eq(cur_disp), - self.encoder.disp_in.eq(cur_disp), + self.tx_fifos.disp_in.eq(disp), + self.encoder.disp_in.eq(disp), + self.encoder.d.eq(Array(IDLE_CHARS)[tx_wordcount][0]), + self.encoder.k.eq(Array(IDLE_CHARS)[tx_wordcount][1]), If(tx_en, o.eq(tx_reg[0]), tx_reg.eq(Cat(tx_reg[1:], 0)), tx_bitcount.eq(tx_bitcount + 1), - If(tx_bitcount == 8, - If(self.tx_fifos.pe.n, - self.encoder.d.eq(Array(IDLE_WORDS)[wordidx][0]), - self.encoder.k.eq(Array(IDLE_WORDS)[wordidx][1]), - If(wordidx != len(IDLE_WORDS), - wordidx.eq(wordidx + 1), - ).Else( - wordidx.eq(0), - ), - ), - ).Elif(tx_bitcount == 9, + # char boundary + If(tx_bitcount == 9, tx_bitcount.eq(0), - If(self.tx_fifos.pe.n, - # idle word - tx_reg.eq(self.encoder.output), - cur_disp.eq(self.encoder.disp_out), + If((~self.tx_fifos.pe.n) & (self.tx_fifos.pe.o == 0), + # trigger packet can interrupt at char level + 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]), ).Else( - # from fifos - tx_reg.eq(self.tx_fifos.source_data[self.tx_fifos.pe.o]), - self.tx_fifos.source_ack[self.tx_fifos.pe.o].eq(1), - cur_disp.eq(self.tx_fifos.disp_out[self.tx_fifos.pe.o]), - ), - ) + # at word boundary + If(tx_wordcount == 3, + tx_wordcount.eq(0), + # at word boundary + If(~self.tx_fifos.pe.n, + idling.eq(0), + priority.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]), + ).Else( + idling.eq(1), + tx_reg.eq(self.encoder.output), + disp.eq(self.encoder.disp_out), + ) + ).Else( + # priority zero doesn't contribute to word count + tx_wordcount.eq(tx_wordcount + 1), + If(~idling, + self.tx_fifos.source_ack[priority].eq(1), + tx_reg.eq(self.tx_fifos.source_data[priority]), + disp.eq(self.tx_fifos.disp_out[priority]), + ).Else( + tx_reg.eq(self.encoder.output), + disp.eq(self.encoder.disp_out), + ) + ), + ) + ) ).Else( o.eq(0) ) ] # DEBUG: remove pads + assert len(IDLE_CHARS) == 4 #word length must be 4 chars self.encoded_data = CSRStatus(10) self.sync.cxp_upconn +=[ - If(tx_bitcount == 9, - If(self.tx_fifos.pe.n, - # idle word - self.encoded_data.status.eq(self.encoder.output), - ).Else( - # from fifos - self.encoded_data.status.eq(self.tx_fifos.source_data[self.tx_fifos.pe.o]), - ), + If(tx_bitcount == 0, + self.encoded_data.status.eq(tx_reg), ) ] ninth_bit = Signal() - eighth_bit = Signal() + word_bound = Signal() - idle_3 = Signal() - idle_2 = Signal() + p1 = Signal() + p2 = Signal() self.comb += [ - eighth_bit.eq(tx_bitcount == 8), ninth_bit.eq(tx_bitcount == 9), - idle_3.eq(wordidx == 3), - idle_2.eq(wordidx == 2), + word_bound.eq(tx_wordcount == 3), + p1.eq(priority == 1), + p2.eq(priority == 2), ] self.specials += [ # debug sma @@ -170,24 +185,29 @@ class CXP_UpConn(Module, AutoCSR): 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=idle_2, o_O=pmod[4]), - Instance("OBUF", i_I=self.tx_fifos.source_ack[0], o_O=pmod[5]), - Instance("OBUF", i_I=idle_3, o_O=pmod[6]), - Instance("OBUF", i_I=tx_en, o_O=pmod[7]), + 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=p1, o_O=pmod[6]), + Instance("OBUF", i_I=p2, o_O=pmod[7]), ] self.symbol0 = CSR(9) self.symbol1 = CSR(9) + self.symbol2 = CSR(9) 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_stb[1].eq(self.symbol1.re), self.tx_fifos.sink_data[1].eq(self.symbol1.r), + self.tx_fifos.sink_stb[2].eq(self.symbol2.re), + self.tx_fifos.sink_data[2].eq(self.symbol2.r), ] class TxFIFOs(Module, AutoCSR): def __init__(self, nfifos, fifo_depth): - self.disp_in = Signal() self.disp_out = Array(Signal() for _ in range(nfifos)) @@ -208,23 +228,23 @@ class TxFIFOs(Module, AutoCSR): encoder = ClockDomainsRenamer("cxp_upconn")(SingleEncoder(True)) setattr(self.submodules, "tx_fifo" + str(i), fifo) setattr(self.submodules, "tx_encoder" + str(i), encoder) - self.comb += [ + 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.source_stb[i].eq(fifo.source.stb), - fifo.source.ack.eq(self.source_ack[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), - self.source_data[i].eq(encoder.output), - ] - # reset ack after asserted - self.sync.cxp_upconn += If(self.source_ack[i], self.source_ack[i].eq(0)) + self.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)), + ] # For FIFOs transmission priority self.submodules.pe = PriorityEncoder(nfifos) self.comb += self.pe.i.eq(self.source_stb)