diff --git a/src/gateware/cxp_upconn.py b/src/gateware/cxp_upconn.py index d8dfecd..5d9fec7 100644 --- a/src/gateware/cxp_upconn.py +++ b/src/gateware/cxp_upconn.py @@ -6,15 +6,6 @@ from misoc.cores.code_8b10b import SingleEncoder from misoc.interconnect import stream from misoc.interconnect.csr import * -# CXP 2.1 section 9.2.5 -IDLE_CHARS = [ - #[data, k] - [0b10111100, 1], #K28.5 - [0b00111100, 1], #K28.1 - [0b00111100, 1], #K28.1 - [0b10111100, 0], #D28.5 -] - class CXP_UpConn(Module, AutoCSR): def __init__(self, pads, sys_clk_freq, pmod, nfifos=3, fifo_depth=32): @@ -59,8 +50,8 @@ class CXP_UpConn(Module, AutoCSR): ] 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) + self.submodules.tx_idle = TxIdle() o = Signal() tx_en = Signal() @@ -75,11 +66,11 @@ class CXP_UpConn(Module, AutoCSR): # startup sequence self.fsm.act("WAIT_TX_ENABLE", + NextValue(self.tx_idle.disp_in, 0), + NextValue(self.tx_idle.word_idx, 0), + If(self.tx_enable.storage, - 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, 1), + NextValue(tx_wordcount, 0), NextValue(tx_bitcount, 0), NextState("LOAD_CHAR") ) @@ -87,44 +78,33 @@ class CXP_UpConn(Module, AutoCSR): self.fsm.act("LOAD_CHAR", NextValue(idling, 1), - NextValue(tx_reg, self.encoder.output), - NextValue(disp, self.encoder.disp_out), + NextValue(self.tx_idle.source_ack, 1), + NextValue(tx_reg, self.tx_idle.source_data), + NextValue(disp, self.tx_idle.disp_out), NextState("START_TX") ) self.fsm.act("START_TX", tx_en.eq(1), - If((~self.tx_enable.storage) & (tx_bitcount == 9), + If((~self.tx_enable.storage) & (tx_wordcount == 3), NextState("WAIT_TX_ENABLE") ) ) - idle_ack = Signal() - # CXP 2.1 section 9.2.4 # Higher priority packet can be inserted into a lower priority packet during transmission # Priority lv 0 can be inserted in char boundary of the packet # Priority lv 1-2 need to be inserted in word boundary of the packet 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), - self.tx_fifos.disp_in.eq(disp), - self.encoder.disp_in.eq(disp), - If(idle_ack, - # reset after asserted - idle_ack.eq(0), - If(tx_wordcount == 3, - self.encoder.d.eq(Array(IDLE_CHARS)[0][0]), - self.encoder.k.eq(Array(IDLE_CHARS)[0][1]), - ).Else( - self.encoder.d.eq(Array(IDLE_CHARS)[tx_wordcount + 1][0]), - self.encoder.k.eq(Array(IDLE_CHARS)[tx_wordcount + 1][1]), - ) - ), # char boundary If(tx_bitcount == 9, @@ -154,9 +134,9 @@ class CXP_UpConn(Module, AutoCSR): ).Else( idling.eq(1), - idle_ack.eq(1), - tx_reg.eq(self.encoder.output), - disp.eq(self.encoder.disp_out), + self.tx_idle.source_ack.eq(1), + tx_reg.eq(self.tx_idle.source_data), + disp.eq(self.tx_idle.disp_out), ) ).Else( If(~idling, @@ -164,9 +144,9 @@ class CXP_UpConn(Module, AutoCSR): tx_reg.eq(self.tx_fifos.source_data[priority]), disp.eq(self.tx_fifos.disp_out[priority]), ).Else( - idle_ack.eq(1), - tx_reg.eq(self.encoder.output), - disp.eq(self.encoder.disp_out), + self.tx_idle.source_ack.eq(1), + tx_reg.eq(self.tx_idle.source_data), + disp.eq(self.tx_idle.disp_out), ) ), ) @@ -176,7 +156,6 @@ class CXP_UpConn(Module, AutoCSR): ) ] # 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 == 0, @@ -187,13 +166,13 @@ class CXP_UpConn(Module, AutoCSR): ninth_bit = Signal() word_bound = Signal() - p1 = Signal() - p2 = Signal() + p0 = Signal() + p3 = Signal() self.comb += [ ninth_bit.eq(tx_bitcount == 9), word_bound.eq(tx_wordcount == 3), - p1.eq(priority == 1), - p2.eq(priority == 2), + p0.eq(self.tx_idle.word_idx == 0), + p3.eq(self.tx_idle.word_idx == 3), ] self.specials += [ # debug sma @@ -210,8 +189,8 @@ class CXP_UpConn(Module, AutoCSR): # 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]), + 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) @@ -226,7 +205,7 @@ class CXP_UpConn(Module, AutoCSR): self.tx_fifos.sink_data[2].eq(self.symbol2.r), ] -class TxFIFOs(Module, AutoCSR): +class TxFIFOs(Module): def __init__(self, nfifos, fifo_depth): self.disp_in = Signal() self.disp_out = Array(Signal() for _ in range(nfifos)) @@ -235,13 +214,13 @@ class TxFIFOs(Module, AutoCSR): 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(10) for _ in range(nfifos)) # # # + source_stb = Signal(nfifos) + for i in range(nfifos): cdr = ClockDomainsRenamer({"write": "sys", "read": "cxp_upconn"}) fifo = cdr(stream.AsyncFIFO([("data", 9)], fifo_depth)) @@ -259,13 +238,54 @@ class TxFIFOs(Module, AutoCSR): encoder.disp_in.eq(self.disp_in), self.disp_out[i].eq(encoder.disp_out), - self.source_stb[i].eq(fifo.source.stb), + 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 + # FIFOs transmission priority self.submodules.pe = PriorityEncoder(nfifos) - self.comb += self.pe.i.eq(self.source_stb) + self.comb += self.pe.i.eq(source_stb) +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) + + # # # + + # CXP 2.1 section 9.2.5 + IDLE_CHARS = Array([ + #[data, k] + [0b10111100, 1], #K28.5 + [0b00111100, 1], #K28.1 + [0b00111100, 1], #K28.1 + [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), + + 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), + ).Else( + self.word_idx.eq(0), + ) + ), + ]