def test_upscaler(): i = axi.Interface() dw = i.data_width dut = stream.Converter(8, dw) source, sink = dut.source, dut.sink write = partial(write_data, sink) read = partial(read_data, source) def testbench_upscaler(): def push(): yield from write(0x11) yield from write(0x22) yield from write(0x33) yield from write(0x44) yield from write(0x55) yield from write(0x66) yield from write(0x77) yield from write(0x88) yield from write(0x99, eop=1) def pull(): yield source.ack.eq(1) assert (yield from read()) == 0x44332211 yield assert (yield from read()) == 0x88776655 yield assert (yield from read()) & 0xff == 0x99 return [ push(), pull(), ] run_simulation(dut, testbench_upscaler())
def __init__(self, kcsrs, rtio_counter, membus, fifo_depth=128): # shutdown procedure: set enable to 0, wait until busy=0 self.enable = CSRStorage() self.busy = CSRStatus() self.submodules.message_encoder = MessageEncoder( kcsrs, rtio_counter, self.enable.storage) self.submodules.fifo = stream.SyncFIFO([("data", message_len)], fifo_depth, True) self.submodules.converter = stream.Converter( message_len, len(membus.dat_w), reverse=True, report_valid_token_count=True) self.submodules.dma = DMAWriter(membus) enable_r = Signal() self.sync += [ enable_r.eq(self.enable.storage), If(self.enable.storage & ~enable_r, self.busy.status.eq(1)), If(self.dma.sink.stb & self.dma.sink.ack & self.dma.sink.eop, self.busy.status.eq(0)) ] self.comb += [ self.message_encoder.source.connect(self.fifo.sink), self.fifo.source.connect(self.converter.sink), self.converter.source.connect(self.dma.sink) ]
def __init__(self, pads, mode="master"): self.refclk = Signal() # # # # In Master mode, generate the linerate/10 clock. Slave will re-multiply it. if mode == "master": converter = stream.Converter(40, 8) self.submodules += converter self.comb += [ converter.sink.stb.eq(1), converter.source.ack.eq(1), converter.sink.data.eq( Replicate(Signal(10, reset=0b1111100000), 4)), ] self.specials += [ Instance("OSERDESE3", p_DATA_WIDTH=8, p_INIT=0, p_IS_CLK_INVERTED=0, p_IS_CLKDIV_INVERTED=0, p_IS_RST_INVERTED=0, o_OQ=self.refclk, i_RST=ResetSignal("sys"), i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal("sys"), i_D=converter.source.data), DifferentialOutput(self.refclk, pads.clk_p, pads.clk_n) ] # In Slave mode, multiply the clock provided by Master with a PLL/MMCM elif mode == "slave": self.specials += DifferentialInput(pads.clk_p, pads.clk_n, self.refclk)
def __init__(self, pads, mode="master"): # Control self.idle = idle = Signal() self.comma = comma = Signal() # Datapath self.ce = ce = Signal() self.k = k = Signal(4) self.d = d = Signal(32) # # # # 8b10b encoder self.submodules.encoder = encoder = CEInserter()(Encoder(4, True)) self.comb += encoder.ce.eq(ce) # 40 --> 8 converter converter = stream.Converter(40, 8) self.submodules += converter self.comb += [ converter.sink.stb.eq(1), converter.source.ack.eq(1), # Enable pipeline when converter accepts the 40 bits ce.eq(converter.sink.ack), # If not idle, connect encoder to converter If(~idle, converter.sink.data.eq(Cat(*[encoder.output[i] for i in range(4)])) ), # If comma, send K28.5 If(comma, encoder.k[0].eq(1), encoder.d[0].eq(K(28,5)), # Else connect TX to encoder ).Else( encoder.k[0].eq(k[0]), encoder.k[1].eq(k[1]), encoder.k[2].eq(k[2]), encoder.k[3].eq(k[3]), encoder.d[0].eq(d[0:8]), encoder.d[1].eq(d[8:16]), encoder.d[2].eq(d[16:24]), encoder.d[3].eq(d[24:32]) ) ] # Data output (DDR with sys4x) data = Signal() self.specials += [ Instance("OSERDESE3", p_DATA_WIDTH=8, p_INIT=0, p_IS_CLK_INVERTED=0, p_IS_CLKDIV_INVERTED=0, p_IS_RST_INVERTED=0, o_OQ=data, i_RST=ResetSignal("sys"), i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal("sys"), i_D=converter.source.data ), DifferentialOutput(data, pads.tx_p, pads.tx_n) ]
def __init__(self, pads, mode="master"): # Control self.idle = idle = Signal() self.comma = comma = Signal() # Datapath self.ce = ce = Signal() self.k = k = Signal(4) self.d = d = Signal(32) # # # # 8b10b encoder self.submodules.encoder = encoder = CEInserter()(Encoder(4, True)) self.comb += encoder.ce.eq(ce) # 40 --> 1 converter converter = stream.Converter(40, 1) self.submodules += converter self.comb += [ converter.sink.stb.eq(1), converter.source.ack.eq(1), # Enable pipeline when converter accepts the 40 bits ce.eq(converter.sink.ack), # If not idle, connect encoder to converter If(~idle, converter.sink.data.eq(Cat(*[encoder.output[i] for i in range(4)])) ), # If comma, send K28.5 If(comma, encoder.k[0].eq(1), encoder.d[0].eq(K(28,5)), # Else connect TX to encoder ).Else( encoder.k[0].eq(k[0]), encoder.k[1].eq(k[1]), encoder.k[2].eq(k[2]), encoder.k[3].eq(k[3]), encoder.d[0].eq(d[0:8]), encoder.d[1].eq(d[8:16]), encoder.d[2].eq(d[16:24]), encoder.d[3].eq(d[24:32]) ) ] # Data output (on rising edge of sys_clk) data = Signal() self.sync += data.eq(converter.source.data) self.specials += DifferentialOutput(data, pads.tx_p, pads.tx_n)
def __init__(self, pads): self.source = source = stream.Endpoint(eth_phy_layout(8)) # # # converter = stream.Converter(4, 8) converter = ResetInserter()(converter) self.submodules += converter self.sync += [ converter.reset.eq(~pads.dv), converter.sink.stb.eq(1), converter.sink.data.eq(pads.rx_data) ] self.comb += [converter.sink.eop.eq(~pads.dv)] self.comb += converter.source.connect(source)
def __init__(self, pads): self.sink = sink = stream.Endpoint(eth_phy_layout(8)) # # # if hasattr(pads, "tx_er"): self.sync += pads.tx_er.eq(0) converter = stream.Converter(8, 4) self.submodules += converter self.comb += [ converter.sink.stb.eq(sink.stb), converter.sink.data.eq(sink.data), sink.ack.eq(converter.sink.ack), converter.source.ack.eq(1) ] self.sync += [ pads.tx_en.eq(converter.source.stb), pads.tx_data.eq(converter.source.data) ]
def __init__(self, pads, mode="master"): self.refclk = Signal() # # # # In Master mode, generate the linerate/10 clock. Slave will re-multiply it. if mode == "master": converter = stream.Converter(40, 8) self.submodules += converter self.comb += [ converter.sink.stb.eq(1), converter.source.ack.eq(1), converter.sink.data.eq( Replicate(Signal(10, reset=0b1111100000), 4)), ] self.specials += [ Instance("OSERDESE2", p_DATA_WIDTH=8, p_TRISTATE_WIDTH=1, p_DATA_RATE_OQ="DDR", p_DATA_RATE_TQ="BUF", p_SERDES_MODE="MASTER", o_OQ=self.refclk, i_OCE=1, i_RST=ResetSignal("sys"), i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal("sys"), i_D1=converter.source.data[0], i_D2=converter.source.data[1], i_D3=converter.source.data[2], i_D4=converter.source.data[3], i_D5=converter.source.data[4], i_D6=converter.source.data[5], i_D7=converter.source.data[6], i_D8=converter.source.data[7]), DifferentialOutput(self.refclk, pads.clk_p, pads.clk_n) ] # In Slave mode, multiply the clock provided by Master with a PLL/MMCM elif mode == "slave": self.specials += DifferentialInput(pads.clk_p, pads.clk_n, self.refclk)
def test_downscaler(): i = axi.Interface() dw = i.data_width dut = stream.Converter(dw, 8) source, sink = dut.source, dut.sink write = partial(write_data, sink) read = partial(read_data, source) def testbench_downscaler(): def push(): yield from write(0x44332211) yield from write(0x88776655, eop=True) def pull(): yield source.ack.eq(1) assert (yield from read()) == 0x11 yield assert (yield from read()) == 0x22 yield assert (yield from read()) == 0x33 yield assert (yield from read()) == 0x44 yield assert (yield from read()) == 0x55 yield assert (yield from read()) == 0x66 yield assert (yield from read()) == 0x77 yield assert (yield from read()) == 0x88 assert (yield source.eop) == 1 return [ push(), pull(), ] run_simulation(dut, testbench_downscaler(), vcd_name=file_tmp_folder("test_downscaler.vcd"))
def test_reader(): i = axi.Interface() dw = i.data_width dut = Reader(i) dut.submodules.downscaler = stream.Converter(dw, 8) dut.comb += dut.source.connect(dut.downscaler.sink) source, sink = dut.downscaler.source, dut.sink request = partial(request_addr, sink) read = partial(read_data, source) def testbench_reader(): def push_addr(): yield from request(0x11223344, eop=True) def pull_data(): yield source.ack.eq(1) assert (yield from read()) == 0x04 yield assert (yield from read()) == 0x03 yield assert (yield from read()) == 0x02 yield assert (yield from read()) == 0x01 assert (yield source.eop) == 1 def ar_and_r_channel(): assert (yield from i.read_ar()).addr == 0x11223344 yield from i.write_r(0x55, 0x01020304, last=1) return [ push_addr(), pull_data(), ar_and_r_channel(), ] run_simulation(dut, testbench_reader(), vcd_name=file_tmp_folder("test_reader.vcd"))
def __init__(self, bus, nbits_source=None, fifo_depth=None): ar, r = operator.attrgetter("ar", "r")(bus) dw = bus.data_width alignment_bits = bits_for(dw // 8) - 1 if nbits_source: if nbits_source % 8: raise ValueError("nbits_source must be a multiple of 8") if nbits_source > dw: raise ValueError("nbits_source must be <= bus.data_width") nbits_source = nbits_source or dw counter_bits = bits_for( (2**len(bus.ar.addr) - 1) // (nbits_source // 8)) self.sink = stream.Endpoint( pipe(rec_layout(ar, {"addr"}), juxt([ identity, R.always([("n", counter_bits)]), ]), concat, list)) self.source = stream.Endpoint([("data", nbits_source)]) ### sink_consume = Signal() self.comb += sink_consume.eq(self.sink.stb & self.sink.ack) remaining = Countdown(counter_bits) self.submodules += remaining self.comb += [ remaining.count_w.eq(self.sink.n), remaining.we.eq(sink_consume), remaining.ce.eq(self.source.stb & self.source.ack), ] eop_consumed = Signal() self.sync += [ If( sink_consume, eop_consumed.eq(0), ).Elif(self.source.stb & self.source.ack & self.source.eop, eop_consumed.eq(1)) ] converter = stream.Converter(dw, nbits_source) self.submodules += converter self.comb += [ converter.source.ack.eq(self.source.ack | eop_consumed), self.source.stb.eq(converter.source.stb & ~eop_consumed), self.source.eop.eq(remaining.done), self.source.data.eq(converter.source.data), ] fifo_depth = min(fifo_depth or BURST_LENGTH, BURST_LENGTH) if fifo_depth % (dw // 8): raise ValueError("fifo_depth shall be a multiple of wordsize") rfifo = stream.SyncFIFO(rec_layout(r, {"data"}), depth=fifo_depth) self.submodules += rfifo self.comb += rfifo.source.connect(converter.sink) burst_done = Signal() self.sync += burst_done.eq(r.valid & r.ready & r.last) # ar channel ar_acked = Signal(reset=1) sink_acked = Signal() self.sync += [ If(sink_consume, sink_acked.eq(1)).Elif(remaining.done, sink_acked.eq(0)) ] self.sync += [ If( sink_consume, ar_acked.eq(0), ar.addr[alignment_bits:].eq(self.sink.addr[alignment_bits:]), ).Else( If(burst_done & ~remaining.done, ar_acked.eq(0), ar.addr.eq(ar.addr + fifo_depth * dw // 8)), If(ar.valid & ar.ready, ar_acked.eq(1))), ] self.comb += [ self.sink.ack.eq(~sink_acked & remaining.done), ar.len.eq(fifo_depth - 1), ar.size.eq(burst_size(dw // 8)), ar.burst.eq(Burst.incr.value), # ensure FIFO is clear to not stall the bus ar.valid.eq(~ar_acked & ~rfifo.source.stb) ] # r channel self.comb += [ remaining.ce.eq(rfifo.sink.stb & rfifo.sink.ack), rfifo.sink.data.eq(r.data), rfifo.sink.stb.eq(r.valid), r.ready.eq(rfifo.sink.ack), ]
def __init__(self, pads, mode="master"): # Control self.delay_rst = Signal() self.delay_inc = Signal() self.bitslip_value = bitslip_value = Signal(6) # Status self.idle = idle = Signal() self.comma = comma = Signal() # Datapath self.ce = ce = Signal() self.k = k = Signal(4) self.d = d = Signal(32) # # # # Data input (DDR with sys4x) data_nodelay = Signal() data_delayed = Signal() data_deserialized = Signal(8) self.specials += [ DifferentialInput(pads.rx_p, pads.rx_n, data_nodelay), Instance("IDELAYE2", p_DELAY_SRC="IDATAIN", p_SIGNAL_PATTERN="DATA", p_CINVCTRL_SEL="FALSE", p_HIGH_PERFORMANCE_MODE="TRUE", p_REFCLK_FREQUENCY=200.0, p_PIPE_SEL="FALSE", p_IDELAY_TYPE="VARIABLE", p_IDELAY_VALUE=0, i_C=ClockSignal(), i_LD=self.delay_rst, i_CE=self.delay_inc, i_LDPIPEEN=0, i_INC=1, i_IDATAIN=data_nodelay, o_DATAOUT=data_delayed), Instance("ISERDESE2", p_DATA_WIDTH=8, p_DATA_RATE="DDR", p_SERDES_MODE="MASTER", p_INTERFACE_TYPE="NETWORKING", p_NUM_CE=1, p_IOBDELAY="IFD", i_DDLY=data_delayed, i_CE1=1, i_RST=ResetSignal("sys"), i_CLK=ClockSignal("sys4x"), i_CLKB=~ClockSignal("sys4x"), i_CLKDIV=ClockSignal("sys"), i_BITSLIP=0, o_Q8=data_deserialized[0], o_Q7=data_deserialized[1], o_Q6=data_deserialized[2], o_Q5=data_deserialized[3], o_Q4=data_deserialized[4], o_Q3=data_deserialized[5], o_Q2=data_deserialized[6], o_Q1=data_deserialized[7]) ] # 8 --> 40 converter and bitslip converter = stream.Converter(8, 40) self.submodules += converter bitslip = CEInserter()(BitSlip(40)) self.submodules += bitslip self.comb += [ converter.sink.stb.eq(1), converter.source.ack.eq(1), # Enable pipeline when converter outputs the 40 bits ce.eq(converter.source.stb), # Connect input data to converter converter.sink.data.eq(data_deserialized), # Connect converter to bitslip bitslip.ce.eq(ce), bitslip.value.eq(bitslip_value), bitslip.i.eq(converter.source.data) ] # 8b10b decoder self.submodules.decoders = decoders = [ CEInserter()(Decoder(True)) for _ in range(4) ] self.comb += [decoders[i].ce.eq(ce) for i in range(4)] self.comb += [ # Connect bitslip to decoder decoders[0].input.eq(bitslip.o[0:10]), decoders[1].input.eq(bitslip.o[10:20]), decoders[2].input.eq(bitslip.o[20:30]), decoders[3].input.eq(bitslip.o[30:40]), # Connect decoder to output self.k.eq(Cat(*[decoders[i].k for i in range(4)])), self.d.eq(Cat(*[decoders[i].d for i in range(4)])), ] # Status idle_timer = WaitTimer(256) self.submodules += idle_timer self.comb += [ idle_timer.wait.eq(1), self.idle.eq(idle_timer.done & ((bitslip.o == 0) | (bitslip.o == (2**40 - 1)))), self.comma.eq((decoders[0].k == 1) & (decoders[0].d == K(28, 5)) & (decoders[1].k == 0) & (decoders[1].d == 0) & (decoders[2].k == 0) & (decoders[2].d == 0) & (decoders[3].k == 0) & (decoders[3].d == 0)) ]
def __init__(self, pads, mode="master"): if mode == "slave": self.refclk = Signal() self.tx_ce = Signal() self.tx_k = Signal(4) self.tx_d = Signal(32) self.rx_ce = Signal() self.rx_k = Signal(4) self.rx_d = Signal(32) self.tx_idle = Signal() self.tx_comma = Signal() self.rx_idle = Signal() self.rx_comma = Signal() self.rx_bitslip_value = Signal(6) self.rx_delay_rst = Signal() self.rx_delay_inc = Signal() self.rx_delay_en_vtc = Signal() # # # self.submodules.encoder = encoder = CEInserter()(Encoder(4, True)) self.comb += encoder.ce.eq(self.tx_ce) self.submodules.decoders = decoders = [ CEInserter()(Decoder(True)) for _ in range(4) ] self.comb += [decoders[i].ce.eq(self.rx_ce) for i in range(4)] # clocking: # In master mode: # - linerate/10 refclk generated on clk_pads # In Slave mode: # - linerate/10 refclk provided by clk_pads # tx clock (linerate/10) if mode == "master": clk_converter = stream.Converter(40, 8) self.submodules += clk_converter self.comb += [ clk_converter.sink.stb.eq(1), clk_converter.sink.data.eq( Replicate(Signal(10, reset=0b1111100000), 4)), clk_converter.source.ack.eq(1) ] clk_o = Signal() self.specials += [ Instance("OSERDESE3", p_DATA_WIDTH=8, p_INIT=0, p_IS_CLK_INVERTED=0, p_IS_CLKDIV_INVERTED=0, p_IS_RST_INVERTED=0, o_OQ=clk_o, i_RST=ResetSignal("sys"), i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal("sys"), i_D=clk_converter.source.data), Instance("OBUFDS", i_I=clk_o, o_O=pads.clk_p, o_OB=pads.clk_n) ] # tx datapath # tx_data -> encoders -> converter -> serdes self.submodules.tx_converter = tx_converter = stream.Converter(40, 8) self.comb += [ tx_converter.sink.stb.eq(1), self.tx_ce.eq(tx_converter.sink.ack), tx_converter.source.ack.eq(1), If(self.tx_idle, tx_converter.sink.data.eq(0)).Else( tx_converter.sink.data.eq( Cat(*[encoder.output[i] for i in range(4)]))), If( self.tx_comma, encoder.k[0].eq(1), encoder.d[0].eq(K(28, 5)), ).Else(encoder.k[0].eq(self.tx_k[0]), encoder.k[1].eq( self.tx_k[1]), encoder.k[2].eq(self.tx_k[2]), encoder.k[3].eq(self.tx_k[3]), encoder.d[0].eq(self.tx_d[0:8]), encoder.d[1].eq(self.tx_d[8:16]), encoder.d[2].eq(self.tx_d[16:24]), encoder.d[3].eq(self.tx_d[24:32])) ] serdes_o = Signal() self.specials += [ Instance("OSERDESE3", p_DATA_WIDTH=8, p_INIT=0, p_IS_CLK_INVERTED=0, p_IS_CLKDIV_INVERTED=0, p_IS_RST_INVERTED=0, o_OQ=serdes_o, i_RST=ResetSignal("sys"), i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal("sys"), i_D=tx_converter.source.data), Instance("OBUFDS", i_I=serdes_o, o_O=pads.tx_p, o_OB=pads.tx_n) ] # rx clock use_bufr = True if mode == "slave": clk_i = Signal() clk_i_bufg = Signal() self.specials += [ Instance("IBUFDS", i_I=pads.clk_p, i_IB=pads.clk_n, o_O=clk_i) ] if use_bufr: clk_i_bufr = Signal() self.specials += [ Instance("BUFR", i_I=clk_i, o_O=clk_i_bufr), Instance("BUFG", i_I=clk_i_bufr, o_O=clk_i_bufg) ] else: self.specials += Instance("BUFG", i_I=clk_i, o_O=clk_i_bufg) self.comb += self.refclk.eq(clk_i_bufg) # rx datapath # serdes -> converter -> bitslip -> decoders -> rx_data self.submodules.rx_converter = rx_converter = stream.Converter(8, 40) self.comb += [ self.rx_ce.eq(rx_converter.source.stb), rx_converter.source.ack.eq(1) ] self.submodules.rx_bitslip = rx_bitslip = CEInserter()(BitSlip(40)) self.comb += rx_bitslip.ce.eq(self.rx_ce) serdes_i_nodelay = Signal() self.specials += [ Instance("IBUFDS_DIFF_OUT", i_I=pads.rx_p, i_IB=pads.rx_n, o_O=serdes_i_nodelay) ] serdes_i_delayed = Signal() serdes_q = Signal(8) self.specials += [ Instance("IDELAYE3", p_CASCADE="NONE", p_UPDATE_MODE="ASYNC", p_REFCLK_FREQUENCY=200.0, p_IS_CLK_INVERTED=0, p_IS_RST_INVERTED=0, p_DELAY_FORMAT="COUNT", p_DELAY_SRC="IDATAIN", p_DELAY_TYPE="VARIABLE", p_DELAY_VALUE=0, i_CLK=ClockSignal("sys"), i_RST=self.rx_delay_rst, i_LOAD=0, i_INC=1, i_EN_VTC=self.rx_delay_en_vtc, i_CE=self.rx_delay_inc, i_IDATAIN=serdes_i_nodelay, o_DATAOUT=serdes_i_delayed), Instance( "ISERDESE3", p_IS_CLK_INVERTED=0, p_IS_CLK_B_INVERTED=1, p_DATA_WIDTH=8, i_D=serdes_i_delayed, i_RST=ResetSignal("sys"), i_FIFO_RD_CLK=0, i_FIFO_RD_EN=0, i_CLK=ClockSignal("sys4x"), i_CLK_B=ClockSignal("sys4x"), # locally inverted i_CLKDIV=ClockSignal("sys"), o_Q=serdes_q) ] self.comb += [ rx_converter.sink.stb.eq(1), rx_converter.sink.data.eq(serdes_q), rx_bitslip.value.eq(self.rx_bitslip_value), rx_bitslip.i.eq(rx_converter.source.data), decoders[0].input.eq(rx_bitslip.o[0:10]), decoders[1].input.eq(rx_bitslip.o[10:20]), decoders[2].input.eq(rx_bitslip.o[20:30]), decoders[3].input.eq(rx_bitslip.o[30:40]), self.rx_k.eq(Cat(*[decoders[i].k for i in range(4)])), self.rx_d.eq(Cat(*[decoders[i].d for i in range(4)])), self.rx_comma.eq((decoders[0].k == 1) & (decoders[0].d == K(28, 5)) & (decoders[1].k == 0) & (decoders[1].d == 0) & (decoders[2].k == 0) & (decoders[2].d == 0) & (decoders[3].k == 0) & (decoders[3].d == 0)) ] idle_timer = WaitTimer(32) self.submodules += idle_timer self.comb += idle_timer.wait.eq(1) self.sync += self.rx_idle.eq(idle_timer.done & (rx_bitslip.o == 0))
def __init__(self, pads, mode="master"): # Control self.delay_rst = Signal() self.delay_inc = Signal() self.bitslip_value = bitslip_value = Signal(6) # Status self.idle = idle = Signal() self.comma = comma = Signal() # Datapath self.ce = ce = Signal() self.k = k = Signal(4) self.d = d = Signal(32) # # # # Data input (DDR with sys4x) data_nodelay = Signal() data_delayed = Signal() data_deserialized = Signal(8) self.specials += [ DifferentialInput(pads.rx_p, pads.rx_n, data_nodelay), Instance("IDELAYE3", p_CASCADE="NONE", p_UPDATE_MODE="ASYNC", p_REFCLK_FREQUENCY=200.0, p_IS_CLK_INVERTED=0, p_IS_RST_INVERTED=0, p_DELAY_FORMAT="COUNT", p_DELAY_SRC="IDATAIN", p_DELAY_TYPE="VARIABLE", p_DELAY_VALUE=0, i_CLK=ClockSignal("sys"), i_RST=self.delay_rst, i_LOAD=0, i_INC=1, i_EN_VTC=0, i_CE=self.delay_inc, i_IDATAIN=data_nodelay, o_DATAOUT=data_delayed ), Instance("ISERDESE3", p_IS_CLK_INVERTED=0, p_IS_CLK_B_INVERTED=1, p_DATA_WIDTH=8, i_D=data_delayed, i_RST=ResetSignal("sys"), i_FIFO_RD_CLK=0, i_FIFO_RD_EN=0, i_CLK=ClockSignal("sys4x"), i_CLK_B=ClockSignal("sys4x"), # locally inverted i_CLKDIV=ClockSignal("sys"), o_Q=data_deserialized ) ] # 8 --> 40 converter and bitslip converter = stream.Converter(8, 40) self.submodules += converter bitslip = CEInserter()(BitSlip(40)) self.submodules += bitslip self.comb += [ converter.sink.stb.eq(1), converter.source.ack.eq(1), # Enable pipeline when converter outputs the 40 bits ce.eq(converter.source.stb), # Connect input data to converter converter.sink.data.eq(data_deserialized), # Connect converter to bitslip bitslip.ce.eq(ce), bitslip.value.eq(bitslip_value), bitslip.i.eq(converter.source.data) ] # 8b10b decoder self.submodules.decoders = decoders = [CEInserter()(Decoder(True)) for _ in range(4)] self.comb += [decoders[i].ce.eq(ce) for i in range(4)] self.comb += [ # Connect bitslip to decoder decoders[0].input.eq(bitslip.o[0:10]), decoders[1].input.eq(bitslip.o[10:20]), decoders[2].input.eq(bitslip.o[20:30]), decoders[3].input.eq(bitslip.o[30:40]), # Connect decoder to output self.k.eq(Cat(*[decoders[i].k for i in range(4)])), self.d.eq(Cat(*[decoders[i].d for i in range(4)])), ] # Status idle_timer = WaitTimer(256) self.submodules += idle_timer self.comb += [ idle_timer.wait.eq(1), self.idle.eq(idle_timer.done & ((bitslip.o == 0) | (bitslip.o == (2**40-1)))), self.comma.eq( (decoders[0].k == 1) & (decoders[0].d == K(28,5)) & (decoders[1].k == 0) & (decoders[1].d == 0) & (decoders[2].k == 0) & (decoders[2].d == 0) & (decoders[3].k == 0) & (decoders[3].d == 0)) ]
def __init__(self, pads, mode="master"): # Control self.bitslip_value = bitslip_value = Signal(6) # Status self.idle = idle = Signal() self.comma = comma = Signal() # Datapath self.ce = ce = Signal() self.k = k = Signal(4) self.d = d = Signal(32) # # # # Input data (on rising edge of sys_clk) data = Signal() data_d = Signal() self.specials += DifferentialInput(pads.rx_p, pads.rx_n, data) self.sync += data_d.eq(data) # 1 --> 40 converter and bitslip converter = stream.Converter(1, 40) self.submodules += converter bitslip = CEInserter()(BitSlip(40)) self.submodules += bitslip self.comb += [ converter.sink.stb.eq(1), converter.source.ack.eq(1), # Enable pipeline when converter outputs the 40 bits ce.eq(converter.source.stb), # Connect input data to converter converter.sink.data.eq(data), # Connect converter to bitslip bitslip.ce.eq(ce), bitslip.value.eq(bitslip_value), bitslip.i.eq(converter.source.data) ] # 8b10b decoder self.submodules.decoders = decoders = [CEInserter()(Decoder(True)) for _ in range(4)] self.comb += [decoders[i].ce.eq(ce) for i in range(4)] self.comb += [ # Connect bitslip to decoder decoders[0].input.eq(bitslip.o[0:10]), decoders[1].input.eq(bitslip.o[10:20]), decoders[2].input.eq(bitslip.o[20:30]), decoders[3].input.eq(bitslip.o[30:40]), # Connect decoder to output self.k.eq(Cat(*[decoders[i].k for i in range(4)])), self.d.eq(Cat(*[decoders[i].d for i in range(4)])), ] # Status idle_timer = WaitTimer(256) self.submodules += idle_timer self.comb += [ idle_timer.wait.eq(1), self.idle.eq(idle_timer.done & ((bitslip.o == 0) | (bitslip.o == (2**40-1)))), self.comma.eq( (decoders[0].k == 1) & (decoders[0].d == K(28,5)) & (decoders[1].k == 0) & (decoders[1].d == 0) & (decoders[2].k == 0) & (decoders[2].d == 0) & (decoders[3].k == 0) & (decoders[3].d == 0)) ]
def __init__(self, link_layer, min_mem_dw): self.aux_rx_length = CSRStatus(bits_for(max_packet)) self.aux_rx_present = CSR() self.aux_rx_error = CSR() ll_dw = len(link_layer.rx_aux_data) mem_dw = max(min_mem_dw, ll_dw) self.specials.mem = Memory(mem_dw, max_packet//(mem_dw//8)) converter = ClockDomainsRenamer("rtio_rx")( stream.Converter(ll_dw, mem_dw)) self.submodules += converter # when continuously drained, the Converter accepts data continuously frame_r = Signal() self.sync.rtio_rx += [ If(link_layer.rx_aux_stb, frame_r.eq(link_layer.rx_aux_frame), converter.sink.data.eq(link_layer.rx_aux_data) ) ] self.comb += [ converter.sink.stb.eq(link_layer.rx_aux_stb & frame_r), converter.sink.eop.eq(converter.sink.stb & ~link_layer.rx_aux_frame) ] mem_port = self.mem.get_port(write_capable=True, clock_domain="rtio_rx") self.specials += mem_port frame_counter_nbits = bits_for(max_packet) - log2_int(mem_dw//8) frame_counter = Signal(frame_counter_nbits) self.comb += [ mem_port.adr.eq(frame_counter), mem_port.dat_w.eq(converter.source.data), converter.source.ack.eq(1) ] frame_counter.attr.add("no_retiming") frame_counter_sys = Signal(frame_counter_nbits) self.specials += MultiReg(frame_counter, frame_counter_sys) self.comb += self.aux_rx_length.status.eq(frame_counter_sys << log2_int(mem_dw//8)) signal_frame = PulseSynchronizer("rtio_rx", "sys") frame_ack = PulseSynchronizer("sys", "rtio_rx") signal_error = PulseSynchronizer("rtio_rx", "sys") self.submodules += signal_frame, frame_ack, signal_error self.sync += [ If(self.aux_rx_present.re, self.aux_rx_present.w.eq(0)), If(signal_frame.o, self.aux_rx_present.w.eq(1)), If(self.aux_rx_error.re, self.aux_rx_error.w.eq(0)), If(signal_error.o, self.aux_rx_error.w.eq(1)) ] self.comb += frame_ack.i.eq(self.aux_rx_present.re) fsm = ClockDomainsRenamer("rtio_rx")(FSM(reset_state="IDLE")) self.submodules += fsm sop = Signal(reset=1) self.sync.rtio_rx += \ If(converter.source.stb, If(converter.source.eop, sop.eq(1) ).Else( sop.eq(0) ) ) fsm.act("IDLE", If(converter.source.stb & sop, NextValue(frame_counter, frame_counter + 1), mem_port.we.eq(1), If(converter.source.eop, NextState("SIGNAL_FRAME") ).Else( NextState("FRAME") ) ).Else( NextValue(frame_counter, 0) ) ) fsm.act("FRAME", If(converter.source.stb, NextValue(frame_counter, frame_counter + 1), mem_port.we.eq(1), If(frame_counter == max_packet, mem_port.we.eq(0), signal_error.i.eq(1), NextState("IDLE") # discard the rest of the frame ), If(converter.source.eop, NextState("SIGNAL_FRAME") ) ) ) fsm.act("SIGNAL_FRAME", signal_frame.i.eq(1), NextState("WAIT_ACK"), If(converter.source.stb, signal_error.i.eq(1)) ) fsm.act("WAIT_ACK", If(frame_ack.o, NextValue(frame_counter, 0), NextState("IDLE") ), If(converter.source.stb, signal_error.i.eq(1)) )
def __init__(self, link_layer, min_mem_dw): ll_dw = len(link_layer.tx_aux_data) mem_dw = max(min_mem_dw, ll_dw) self.aux_tx_length = CSRStorage(bits_for(max_packet), alignment_bits=log2_int(mem_dw//8)) self.aux_tx = CSR() self.specials.mem = Memory(mem_dw, max_packet//(mem_dw//8)) converter = ClockDomainsRenamer("rtio")( stream.Converter(mem_dw, ll_dw)) self.submodules += converter # when continuously fed, the Converter outputs data continuously self.comb += [ converter.source.ack.eq(link_layer.tx_aux_ack), link_layer.tx_aux_frame.eq(converter.source.stb), link_layer.tx_aux_data.eq(converter.source.data) ] seen_eop_rst = Signal() frame_r = Signal() seen_eop = Signal() self.sync.rtio += [ If(link_layer.tx_aux_ack, frame_r.eq(link_layer.tx_aux_frame), If(frame_r & ~link_layer.tx_aux_frame, seen_eop.eq(1)) ), If(seen_eop_rst, seen_eop.eq(0)) ] mem_port = self.mem.get_port(clock_domain="rtio") self.specials += mem_port self.aux_tx_length.storage.attr.add("no_retiming") tx_length = Signal(bits_for(max_packet)) self.specials += MultiReg(self.aux_tx_length.storage, tx_length, "rtio") frame_counter_nbits = bits_for(max_packet) - log2_int(mem_dw//8) frame_counter = Signal(frame_counter_nbits) frame_counter_next = Signal(frame_counter_nbits) frame_counter_ce = Signal() frame_counter_rst = Signal() self.comb += [ frame_counter_next.eq(frame_counter), If(frame_counter_rst, frame_counter_next.eq(0) ).Elif(frame_counter_ce, frame_counter_next.eq(frame_counter + 1) ), mem_port.adr.eq(frame_counter_next), converter.sink.data.eq(mem_port.dat_r) ] self.sync.rtio += frame_counter.eq(frame_counter_next) start_tx = PulseSynchronizer("sys", "rtio") tx_done = PulseSynchronizer("rtio", "sys") self.submodules += start_tx, tx_done self.comb += start_tx.i.eq(self.aux_tx.re) self.sync += [ If(tx_done.o, self.aux_tx.w.eq(0)), If(self.aux_tx.re, self.aux_tx.w.eq(1)) ] fsm = ClockDomainsRenamer("rtio")(FSM(reset_state="IDLE")) self.submodules += fsm fsm.act("IDLE", frame_counter_rst.eq(1), seen_eop_rst.eq(1), If(start_tx.o, NextState("TRANSMIT")) ) fsm.act("TRANSMIT", converter.sink.stb.eq(1), If(converter.sink.ack, frame_counter_ce.eq(1) ), If(frame_counter_next == tx_length, NextState("WAIT_INTERFRAME")) ) fsm.act("WAIT_INTERFRAME", If(seen_eop, tx_done.i.eq(1), NextState("IDLE") ) )
def __init__(self, pads, mode="master"): if mode == "slave": self.refclk = Signal() self.tx_ce = Signal() self.tx_k = Signal(4) self.tx_d = Signal(32) self.rx_ce = Signal() self.rx_k = Signal(4) self.rx_d = Signal(32) self.tx_idle = Signal() self.tx_comma = Signal() self.rx_idle = Signal() self.rx_comma = Signal() self.rx_bitslip_value = Signal(6) self.rx_delay_rst = Signal() self.rx_delay_inc = Signal() # # # self.submodules.encoder = encoder = CEInserter()(Encoder(4, True)) self.comb += encoder.ce.eq(self.tx_ce) self.submodules.decoders = decoders = [ CEInserter()(Decoder(True)) for _ in range(4) ] self.comb += [decoders[i].ce.eq(self.rx_ce) for i in range(4)] # clocking: # In Master mode: # - linerate/10 refclk is generated on clk_pads # In Slave mode: # - linerate/10 refclk is provided by clk_pads # tx clock (linerate/10) if mode == "master": clk_converter = stream.Converter(40, 8) self.submodules += clk_converter self.comb += [ clk_converter.sink.stb.eq(1), clk_converter.sink.data.eq( Replicate(Signal(10, reset=0b1111100000), 4)), clk_converter.source.ack.eq(1) ] clk_o = Signal() self.specials += [ Instance("OSERDESE2", p_DATA_WIDTH=8, p_TRISTATE_WIDTH=1, p_DATA_RATE_OQ="DDR", p_DATA_RATE_TQ="BUF", p_SERDES_MODE="MASTER", o_OQ=clk_o, i_OCE=1, i_RST=ResetSignal("sys"), i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal("sys"), i_D1=clk_converter.source.data[0], i_D2=clk_converter.source.data[1], i_D3=clk_converter.source.data[2], i_D4=clk_converter.source.data[3], i_D5=clk_converter.source.data[4], i_D6=clk_converter.source.data[5], i_D7=clk_converter.source.data[6], i_D8=clk_converter.source.data[7]), Instance("OBUFDS", i_I=clk_o, o_O=pads.clk_p, o_OB=pads.clk_n) ] # tx datapath # tx_data -> encoders -> converter -> serdes self.submodules.tx_converter = tx_converter = stream.Converter(40, 8) self.comb += [ tx_converter.sink.stb.eq(1), self.tx_ce.eq(tx_converter.sink.ack), tx_converter.source.ack.eq(1), If(self.tx_idle, tx_converter.sink.data.eq(0)).Else( tx_converter.sink.data.eq( Cat(*[encoder.output[i] for i in range(4)]))), If( self.tx_comma, encoder.k[0].eq(1), encoder.d[0].eq(K(28, 5)), ).Else(encoder.k[0].eq(self.tx_k[0]), encoder.k[1].eq( self.tx_k[1]), encoder.k[2].eq(self.tx_k[2]), encoder.k[3].eq(self.tx_k[3]), encoder.d[0].eq(self.tx_d[0:8]), encoder.d[1].eq(self.tx_d[8:16]), encoder.d[2].eq(self.tx_d[16:24]), encoder.d[3].eq(self.tx_d[24:32])) ] serdes_o = Signal() self.specials += [ Instance("OSERDESE2", p_DATA_WIDTH=8, p_TRISTATE_WIDTH=1, p_DATA_RATE_OQ="DDR", p_DATA_RATE_TQ="BUF", p_SERDES_MODE="MASTER", o_OQ=serdes_o, i_OCE=1, i_RST=ResetSignal("sys"), i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal("sys"), i_D1=tx_converter.source.data[0], i_D2=tx_converter.source.data[1], i_D3=tx_converter.source.data[2], i_D4=tx_converter.source.data[3], i_D5=tx_converter.source.data[4], i_D6=tx_converter.source.data[5], i_D7=tx_converter.source.data[6], i_D8=tx_converter.source.data[7]), Instance("OBUFDS", i_I=serdes_o, o_O=pads.tx_p, o_OB=pads.tx_n) ] # rx clock use_bufr = True if mode == "slave": clk_i = Signal() clk_i_bufg = Signal() self.specials += [ Instance("IBUFDS", i_I=pads.clk_p, i_IB=pads.clk_n, o_O=clk_i) ] if use_bufr: clk_i_bufr = Signal() self.specials += [ Instance("BUFR", i_I=clk_i, o_O=clk_i_bufr), Instance("BUFG", i_I=clk_i_bufr, o_O=clk_i_bufg) ] else: self.specials += Instance("BUFG", i_I=clk_i, o_O=clk_i_bufg) self.comb += self.refclk.eq(clk_i_bufg) # rx datapath # serdes -> converter -> bitslip -> decoders -> rx_data self.submodules.rx_converter = rx_converter = stream.Converter(8, 40) self.comb += [ self.rx_ce.eq(rx_converter.source.stb), rx_converter.source.ack.eq(1) ] self.submodules.rx_bitslip = rx_bitslip = CEInserter()(BitSlip(40)) self.comb += rx_bitslip.ce.eq(self.rx_ce) serdes_i_nodelay = Signal() self.specials += [ Instance("IBUFDS_DIFF_OUT", i_I=pads.rx_p, i_IB=pads.rx_n, o_O=serdes_i_nodelay) ] serdes_i_delayed = Signal() serdes_q = Signal(8) self.specials += [ Instance("IDELAYE2", p_DELAY_SRC="IDATAIN", p_SIGNAL_PATTERN="DATA", p_CINVCTRL_SEL="FALSE", p_HIGH_PERFORMANCE_MODE="TRUE", p_REFCLK_FREQUENCY=200.0, p_PIPE_SEL="FALSE", p_IDELAY_TYPE="VARIABLE", p_IDELAY_VALUE=0, i_C=ClockSignal(), i_LD=self.rx_delay_rst, i_CE=self.rx_delay_inc, i_LDPIPEEN=0, i_INC=1, i_IDATAIN=serdes_i_nodelay, o_DATAOUT=serdes_i_delayed), Instance("ISERDESE2", p_DATA_WIDTH=8, p_DATA_RATE="DDR", p_SERDES_MODE="MASTER", p_INTERFACE_TYPE="NETWORKING", p_NUM_CE=1, p_IOBDELAY="IFD", i_DDLY=serdes_i_delayed, i_CE1=1, i_RST=ResetSignal("sys"), i_CLK=ClockSignal("sys4x"), i_CLKB=~ClockSignal("sys4x"), i_CLKDIV=ClockSignal("sys"), i_BITSLIP=0, o_Q8=serdes_q[0], o_Q7=serdes_q[1], o_Q6=serdes_q[2], o_Q5=serdes_q[3], o_Q4=serdes_q[4], o_Q3=serdes_q[5], o_Q2=serdes_q[6], o_Q1=serdes_q[7]) ] self.comb += [ rx_converter.sink.stb.eq(1), rx_converter.sink.data.eq(serdes_q), rx_bitslip.value.eq(self.rx_bitslip_value), rx_bitslip.i.eq(rx_converter.source.data), decoders[0].input.eq(rx_bitslip.o[0:10]), decoders[1].input.eq(rx_bitslip.o[10:20]), decoders[2].input.eq(rx_bitslip.o[20:30]), decoders[3].input.eq(rx_bitslip.o[30:40]), self.rx_k.eq(Cat(*[decoders[i].k for i in range(4)])), self.rx_d.eq(Cat(*[decoders[i].d for i in range(4)])), self.rx_comma.eq((decoders[0].k == 1) & (decoders[0].d == K(28, 5)) & (decoders[1].k == 0) & (decoders[1].d == 0) & (decoders[2].k == 0) & (decoders[2].d == 0) & (decoders[3].k == 0) & (decoders[3].d == 0)) ] idle_timer = WaitTimer(32) self.submodules += idle_timer self.comb += idle_timer.wait.eq(1) self.sync += self.rx_idle.eq(idle_timer.done & (rx_bitslip.o == 0))