diff --git a/src/gateware/cxp_upconn.py b/src/gateware/cxp_upconn.py index 2cf258d..3f35fee 100644 --- a/src/gateware/cxp_upconn.py +++ b/src/gateware/cxp_upconn.py @@ -3,18 +3,16 @@ from migen.genlib.resetsync import AsyncResetSynchronizer from migen.genlib.coding import PriorityEncoder from misoc.cores.code_8b10b import SingleEncoder -from misoc.interconnect.csr import * from misoc.interconnect import stream +from misoc.interconnect.csr import * -# CXP2.1 section 9.2.5 +# CXP 2.1 section 9.2.5 IDLE_WORDS = [ - #[k, data] + #[data, k] [0b10111100, 1], #K28.5 - [0b10111100, 1], #K28.5 - # TODO: fix index error for this crap [0b00111100, 1], #K28.1 [0b00111100, 1], #K28.1 - # Cat(0b10111100, 0), #D28.5 + [0b10111100, 0], #D28.5 ] @@ -25,8 +23,6 @@ class CXP_UpConn(Module, AutoCSR): self.bitrate2x_enable = CSRStorage() self.tx_enable = CSRStorage() - self.tx_fifos = [] - # # # pll_locked = Signal() @@ -62,103 +58,76 @@ class CXP_UpConn(Module, AutoCSR): AsyncResetSynchronizer(self.cd_cxp_upconn, ~pll_locked | self.clk_reset.storage) ] - # self.submodules.phy = UpConnTXPHY(pads) - - - # FIFOs with transmission priority - # 0: Trigger packet - # 1: IO acknowledgment for trigger packet - # 2: All other packets - sinks_full = Signal(nfifos) - sources_stb = Signal(nfifos) - sources_ack = Array(Signal() for _ in range(nfifos)) - sources_data = Array(Signal(9) for _ in range(nfifos)) - for i in range(nfifos): - cdr = ClockDomainsRenamer({"write": "sys", "read": "cxp_upconn"}) - fifo = cdr(stream.AsyncFIFO([("data", 9)], fifo_depth)) - self.tx_fifos.append(fifo) - setattr(self.submodules, "tx_fifo" + str(i), fifo) - self.comb += [ - sinks_full[i].eq(fifo.sink.ack), - fifo.source.ack.eq(sources_ack[i]), - sources_stb[i].eq(fifo.source.stb), - sources_data[i].eq(fifo.source.data), - ] - # setup pulse ack - self.sync.cxp_upconn += sources_ack[i].eq(0) - - self.submodules.pe = PriorityEncoder(nfifos) - self.comb += self.pe.i.eq(sources_stb) - - idle_word_count = Signal(max=len(IDLE_WORDS)) - + self.submodules.fsm = ClockDomainsRenamer("cxp_upconn")(FSM(reset_state="WAIT_TX_ENABLE")) self.submodules.encoder = ClockDomainsRenamer("cxp_upconn")(SingleEncoder(True)) + self.submodules.tx_fifos = TxFIFOs(nfifos, fifo_depth) - fsm = ClockDomainsRenamer("cxp_upconn")(FSM(reset_state="WAIT_TX_ENABLE")) - self.submodules += fsm - o = Signal() tx_en = Signal() tx_bitcount = Signal(max=10) tx_reg = Signal(10) - - encoded = Signal() - stb = Signal() + idleidx = Signal(max=len(IDLE_WORDS)) - fsm.act("WAIT_TX_ENABLE", + # startup sequence + self.fsm.act("WAIT_TX_ENABLE", If(self.tx_enable.storage, NextState("ENCODE_IDLE_WORD") ) ) - fsm.act("ENCODE_IDLE_WORD", + 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(idle_word_count, 1), + NextValue(idleidx, 1), NextState("START_TX") ) - fsm.act("START_TX", + self.fsm.act("START_TX", tx_en.eq(1), If((~self.tx_enable.storage) & (tx_bitcount == 9), NextState("WAIT_TX_ENABLE") ) ) - - self.sync.cxp_upconn +=[ + + + # CXP 2.1 section 9.2.4 + self.sync.cxp_upconn += [ 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.pe.n, - self.encoder.d.eq(sources_data[self.pe.o][:8]), - self.encoder.k.eq(sources_data[self.pe.o][8]), - sources_ack[self.pe.o].eq(1), + # TODO: only allow trigger packet to do character interrupt and other priority level to only interrupt word + If(~self.tx_fifos.pe.n, + self.encoder.d.eq(self.tx_fifos.source_data[self.tx_fifos.pe.o][:8]), + self.encoder.k.eq(self.tx_fifos.source_data[self.tx_fifos.pe.o][8]), + self.tx_fifos.source_ack[self.tx_fifos.pe.o].eq(1), ).Else( - self.encoder.d.eq(Array(IDLE_WORDS)[idle_word_count][0]), - self.encoder.k.eq(Array(IDLE_WORDS)[idle_word_count][1]), - If(idle_word_count != len(IDLE_WORDS), - idle_word_count.eq(idle_word_count + 1) + self.encoder.d.eq(Array(IDLE_WORDS)[idleidx][0]), + self.encoder.k.eq(Array(IDLE_WORDS)[idleidx][1]), + If(idleidx != len(IDLE_WORDS), + idleidx.eq(idleidx + 1) ).Else( - idle_word_count.eq(0) + idleidx.eq(0) ) ) ).Elif(tx_bitcount == 9, - tx_bitcount.eq(0), - tx_reg.eq(self.encoder.output), - self.encoder.disp_in.eq(self.encoder.disp_out), + tx_bitcount.eq(0), + tx_reg.eq(self.encoder.output), + self.encoder.disp_in.eq(self.encoder.disp_out), ) ).Else( o.eq(0) ) ] # DEBUG: remove pads - self.idle_word_index = CSRStatus() + self.encoded_data = CSRStatus(10) self.sync.cxp_upconn +=[ - self.idle_word_index.status.eq(idle_word_count) + If(tx_bitcount == 9, + self.encoded_data.status.eq(self.encoder.output), + ) ] ninth_bit = Signal() @@ -169,8 +138,8 @@ class CXP_UpConn(Module, AutoCSR): self.comb += [ eighth_bit.eq(tx_bitcount == 8), ninth_bit.eq(tx_bitcount == 9), - idle_3.eq(idle_word_count == 3), - idle_2.eq(idle_word_count == 2), + idle_3.eq(idleidx == 3), + idle_2.eq(idleidx == 2), ] self.specials += [ # debug sma @@ -180,41 +149,53 @@ class CXP_UpConn(Module, AutoCSR): # 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=tx_en, o_O=pmod[2]), - Instance("OBUF", i_I=idle_3, o_O=pmod[3]), + 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=eighth_bit, o_O=pmod[3]), - # Instance("OBUF", i_I=ninth_bit, o_O=pmod[4]), - Instance("OBUF", i_I=encoded, o_O=pmod[5]), - Instance("OBUF", i_I=~self.pe.n, o_O=pmod[6]), + 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]), ] self.symbol0 = CSR(9) self.symbol1 = CSR(9) self.sync += [ - self.tx_fifos[0].sink.stb.eq(self.symbol0.re), - self.tx_fifos[0].sink.data.eq(self.symbol0.r), - self.tx_fifos[1].sink.stb.eq(self.symbol1.re), - self.tx_fifos[1].sink.data.eq(self.symbol1.r), - # self.fifo_full[i].eq(~fifo.sink.ack), + 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), ] -class UpConnTXPHY(Module, AutoCSR): - def __init__(self, pads): - self.sink = stream.Endpoint([("data", 9)]) +class TxFIFOs(Module, AutoCSR): + def __init__(self, nfifos, fifo_depth): + self.sink_stb = Signal(nfifos) + self.sink_ack = Signal(nfifos) + self.sink_data = [Signal(9) for _ in range(nfifos)] + + # data & ack will be used dynamically during runtime, cannot use python array + self.source_stb = Signal(nfifos) + self.source_ack = Array(Signal() for _ in range(nfifos)) + self.source_data = Array(Signal(9) for _ in range(nfifos)) # # # - self.submodules.encoder = ClockDomainsRenamer("cxp_upconn")(SingleEncoder(True)) + for i in range(nfifos): + cdr = ClockDomainsRenamer({"write": "sys", "read": "cxp_upconn"}) + fifo = cdr(stream.AsyncFIFO([("data", 9)], fifo_depth)) + setattr(self.submodules, "tx_fifo" + str(i), fifo) + self.comb += [ + 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.comb += [ - self.encoder.d.eq(self.sink.data[:8]), - self.encoder.k.eq(self.sink.data[8]) - ] + self.source_stb[i].eq(fifo.source.stb), + fifo.source.ack.eq(self.source_ack[i]), + self.source_data[i].eq(fifo.source.data), + ] + # reset ack after asserted + self.sync.cxp_upconn += 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) - o = Signal() - tx_en = Signal() - tx_bitcount = Signal(max=10) - tx_reg = Signal(10) - - self.specials += Instance("OBUF", i_I=o, o_O=pads.p_tx)