diff --git a/src/gateware/cxp_upconn.py b/src/gateware/cxp_upconn.py new file mode 100644 index 0000000..e4c2c26 --- /dev/null +++ b/src/gateware/cxp_upconn.py @@ -0,0 +1,224 @@ +from math import ceil + +from migen import * + +from misoc.cores.code_8b10b import SingleEncoder +from misoc.interconnect import stream +from misoc.interconnect.csr import * + +from cxp_pipeline import char_layout + +@ResetInserter() +class UpConn_ClockGen(Module): + def __init__(self, sys_clk_freq): + self.clk = Signal() + self.clk_10x = Signal() # 20.83MHz 48ns or 41.66MHz 24ns + + self.freq2x_enable = Signal() + # # # + + period = 1e9/sys_clk_freq + max_count = ceil(48/period) + counter = Signal(max=max_count, reset=max_count-1) + + clk_div = Signal(max=10, reset=9) + + self.sync += [ + self.clk.eq(0), + self.clk_10x.eq(0), + + If(counter == 0, + self.clk_10x.eq(1), + If(self.freq2x_enable, + counter.eq(int(max_count/2)-1), + ).Else( + counter.eq(counter.reset), + ), + ).Else( + counter.eq(counter-1), + ), + + If(counter == 0, + If(clk_div == 0, + self.clk.eq(1), + clk_div.eq(clk_div.reset), + ).Else( + clk_div.eq(clk_div-1), + ) + ) + + ] + +@ResetInserter() +@CEInserter() +class SERDES_10bits(Module): + def __init__(self, pad): + self.oe = Signal() + self.d = Signal(10) + + # # # + + o = Signal() + tx_bitcount = Signal(max=10) + tx_reg = Signal(10) + + # DEBUG: + self.o = Signal() + self.comb += self.o.eq(o) + + self.specials += Instance("OBUF", i_I=o, o_O=pad), + + self.sync += [ + If(self.oe, + # send LSB first + o.eq(tx_reg[0]), + tx_reg.eq(Cat(tx_reg[1:], 0)), + tx_bitcount.eq(tx_bitcount + 1), + + If(tx_bitcount == 9, + tx_bitcount.eq(0), + tx_reg.eq(self.d), + ), + ).Else( + o.eq(0), + tx_bitcount.eq(0), + ) + ] + +class Debug_buffer(Module,AutoCSR): + def __init__(self, layout): + self.sink_stb = Signal() + self.sink_ack = Signal() + self.sink_data = Signal(8) + self.sink_k = Signal() + + # # # + + self.submodules.buf_out = buf_out = stream.SyncFIFO(layout, 512) + + self.sync += [ + buf_out.sink.stb.eq(self.sink_stb), + self.sink_ack.eq(buf_out.sink.ack), + buf_out.sink.data.eq(self.sink_data), + buf_out.sink.k.eq(self.sink_k), + ] + + self.inc = CSR() + self.dout_pak = CSRStatus(8) + self.kout_pak = CSRStatus() + self.dout_valid = CSRStatus() + + self.sync += [ + # output + buf_out.source.ack.eq(self.inc.re), + self.dout_pak.status.eq(buf_out.source.data), + self.kout_pak.status.eq(buf_out.source.k), + self.dout_valid.status.eq(buf_out.source.stb), + ] + + +class Transmitter(Module, AutoCSR): + def __init__(self, pad, sys_clk_freq, debug_sma, pmod_pads): + self.bitrate2x_enable = Signal() + self.clk_reset = Signal() + self.tx_enable = Signal() + + # # # + + self.sink = stream.Endpoint(char_layout) + + self.submodules.cg = cg = UpConn_ClockGen(sys_clk_freq) + self.submodules.encoder = encoder = SingleEncoder(True) + self.submodules.debug_buf = debug_buf = Debug_buffer(char_layout) + + oe = Signal() + self.sync += [ + If(self.tx_enable, + self.sink.ack.eq(0), + + # DEBUG: + debug_buf.sink_stb.eq(0), + + If(cg.clk, + oe.eq(1), + encoder.disp_in.eq(encoder.disp_out), + self.sink.ack.eq(1), + encoder.d.eq(self.sink.data), + encoder.k.eq(self.sink.k), + + # DEBUG: + If(debug_buf.sink_ack, + debug_buf.sink_stb.eq(1), + debug_buf.sink_data.eq(self.sink.data), + debug_buf.sink_k.eq(self.sink.k), + ) + ) + ).Else( + # DEBUG: + debug_buf.sink_stb.eq(0), + + # no backpressure + self.sink.ack.eq(1), + oe.eq(0), + ) + ] + + self.submodules.serdes = serdes = SERDES_10bits(pad) + + self.comb += [ + cg.reset.eq(self.clk_reset), + cg.freq2x_enable.eq(self.bitrate2x_enable), + + serdes.reset.eq(self.clk_reset), + serdes.ce.eq(cg.clk_10x), + serdes.d.eq(encoder.output), + serdes.oe.eq(oe), + ] + + # DEBUG: remove pads + + self.specials += [ + # # debug sma + # Instance("OBUF", i_I=serdes.o, o_O=debug_sma.p_tx), + Instance("OBUF", i_I=serdes.o, o_O=debug_sma.n_rx), + + + + # # pmod 0-7 pin + # Instance("OBUF", i_I=serdes.o, o_O=pmod_pads[0]), + # Instance("OBUF", i_I=cg.clk_10x, o_O=pmod_pads[1]), + # Instance("OBUF", i_I=~tx_fifos.pe.n, o_O=pmod_pads[2]), + # Instance("OBUF", i_I=prioity_0, o_O=pmod_pads[3]), + # Instance("OBUF", i_I=word_bound, o_O=pmod_pads[4]), + # Instance("OBUF", i_I=debug_buf.buf_out.sink.stb, o_O=pmod_pads[4]), + # Instance("OBUF", i_I=debug_buf.buf_out.sink.ack, o_O=pmod_pads[5]), + # Instance("OBUF", i_I=debug_buf.buf_out.source.stb, o_O=pmod_pads[6]), + # Instance("OBUF", i_I=debug_buf.buf_out.source.ack, o_O=pmod_pads[7]), + + # Instance("OBUF", i_I=scheduler.idling, o_O=pmod_pads[5]), + # # Instance("OBUF", i_I=tx_fifos.source_ack[0], o_O=pmod[6]), + # # Instance("OBUF", i_I=tx_fifos.source_ack[2], o_O=pmod[6]), + # # Instance("OBUF", i_I=tx_fifos.source_ack[1], o_O=pmod[7]), + # Instance("OBUF", i_I=p0, o_O=pmod_pads[6]), + # Instance("OBUF", i_I=p3, o_O=pmod_pads[7]), + ] + +class CXP_UpConn_PHYS(Module, AutoCSR): + def __init__(self, pads, sys_clk_freq, debug_sma, pmod_pads): + self.clk_reset = CSR() + self.bitrate2x_enable = CSRStorage() + self.tx_enable = CSRStorage() + + # # # + + + self.tx_phys = [] + for i, pad in enumerate(pads): + tx = Transmitter(pad, sys_clk_freq, debug_sma, pmod_pads) + self.tx_phys.append(tx) + setattr(self.submodules, "tx"+str(i), tx) + self.sync += [ + tx.clk_reset.eq(self.clk_reset.re), + tx.bitrate2x_enable.eq(self.bitrate2x_enable.storage), + tx.tx_enable.eq(self.tx_enable.storage), + ]