from migen import * from sync_serdes import MultiLineRX, MultiLineTX from migen.genlib.fifo import SyncFIFO from migen.build.platforms.sinara import kasli, efc from multi_coders import MultiEncoder, CrossbarDecoder from kasli_crg import TransceiverCRG from eem_helpers import generate_pads from uart import UART from io_loopback import SingleIOLoopback, IOLoopBack class MultiTransceiverChannel(Module): def __init__(self, io_pads, sys_clk_freq): self.uart_rx = Signal() self.uart_tx = Signal() self.submodules.uart = UART(round((115200/sys_clk_freq)*2**32)) self.comb += [ self.uart.phy_rx.eq(self.uart_rx), self.uart_tx.eq(self.uart.phy_tx), ] # SERDES impl self.submodules.tx = MultiLineTX() self.submodules.rx = MultiLineRX() # 8b10b encoder & decoder self.submodules.encoder = MultiEncoder(lsb_first=False) decoders = [ CrossbarDecoder(lsb_first=False) for _ in range(2) ] self.submodules += decoders # The actual channel self.submodules.channel = IOLoopBack(io_pads) # FIFO to record transmission received rx_records = SyncFIFO(16, 128) self.submodules += rx_records # Attach FIFO to UART TX, send rate is too slow w.r.t sysclk self.submodules.tx_fifo = SyncFIFO(8, 64) self.comb += [ # Loopback channel self.channel.i.eq(self.tx.ser_out), self.channel.t.eq(self.tx.t_out), self.rx.ser_in_no_dly.eq(self.channel.o), # Link decoders decoders[0].raw_input.eq(self.rx.rxdata[:10]), decoders[1].raw_input.eq(self.rx.rxdata[10:]), # Default encoder linkage self.tx.txdata.eq(Cat(self.encoder.output[0], self.encoder.output[1])), # UART TX path self.uart.tx_data.eq(self.tx_fifo.dout), self.uart.tx_stb.eq(self.tx_fifo.readable), self.tx_fifo.re.eq(self.uart.tx_ack), # Immediate start RX alignment procedure self.rx.start.eq(1), ] rx_fsm = FSM(reset_state="WAIT_GROUP_ALIGN") self.submodules += rx_fsm rx_fsm.act("WAIT_GROUP_ALIGN", If(self.rx.align_done & rx_records.writable, rx_records.din.eq(self.rx.rxdata), rx_records.we.eq(1), ), If(self.rx.err, NextState("WRITE_ERR_UPPER"), ).Elif(self.rx.rxdata == 0b11111111111111111111, decoders[0].start.eq(1), decoders[1].start.eq(1), NextState("RECORD_TRANSMISSION"), ), ) rx_fsm.act("WRITE_ERR_UPPER", If(self.tx_fifo.writable, self.tx_fifo.we.eq(1), self.tx_fifo.din.eq(0b01010101), NextState("WRITE_ERR_LOWER"), ), ) rx_fsm.act("WRITE_ERR_LOWER", If(self.tx_fifo.writable, self.tx_fifo.we.eq(1), self.tx_fifo.din.eq(0b10101010), NextState("TERMINATE"), ), ) rx_fsm.act("RECORD_TRANSMISSION", If(rx_records.writable, rx_records.din.eq(Cat(decoders[0].d, decoders[1].d)), rx_records.we.eq(1), ).Else( NextState("DUMP_TRANSMISSION_UPPER"), ) ) rx_fsm.act("DUMP_TRANSMISSION_UPPER", If(rx_records.readable, If(self.tx_fifo.writable, self.tx_fifo.we.eq(1), self.tx_fifo.din.eq(rx_records.dout[8:]), NextState("DUMP_TRANSMISSION_LOWER"), ) ).Else( NextState("TERMINATE"), ), ) rx_fsm.act("DUMP_TRANSMISSION_LOWER", If(self.tx_fifo.writable, self.tx_fifo.we.eq(1), self.tx_fifo.din.eq(rx_records.dout[:8]), rx_records.re.eq(1), NextState("DUMP_TRANSMISSION_UPPER"), ) ) rx_fsm.act("TERMINATE", NextState("TERMINATE") ) tx_fsm = FSM(reset_state="SEND_TRAINING") self.submodules += tx_fsm tx_fsm.act("SEND_TRAINING", self.tx.txdata.eq(0b00100001000010000100), If(self.rx.align_done, NextState("SEND_ZERO"), ), ) send_zero_duration = Signal(2) tx_fsm.act("SEND_ZERO", self.tx.txdata.eq(0), If(send_zero_duration == 0b11, NextState("SEND_PULSE"), ).Else( NextValue(send_zero_duration, send_zero_duration + 1), ), ) tx_fsm.act("SEND_PULSE", self.tx.txdata.eq(0b11111111111111111111), self.encoder.start.eq(1), NextState("WAIT_GROUP_ALIGN"), ) data = [ Signal(8) for _ in range(2) ] tx_fsm.act("WAIT_GROUP_ALIGN", If(self.rx.delay_done, NextValue(data[0], 0x80), NextValue(data[1], 0x7F), NextState("TERMINATE"), ), ) tx_fsm.act("TERMINATE", self.encoder.d[0].eq(data[0]), self.encoder.d[1].eq(data[1]), self.encoder.k[0].eq(0), self.encoder.k[1].eq(0), NextValue(data[0], data[0] + 1), NextValue(data[1], data[1] - 1), NextState("TERMINATE"), ) # tx_fsm.act("SEND_ARB_DATA1", # self.encoder.d[0].eq(0xDE), # self.encoder.d[1].eq(0xAD), # self.encoder.k[0].eq(0), # self.encoder.k[1].eq(0), # NextState("SEND_ARB_DATA2"), # ) # tx_fsm.act("SEND_ARB_DATA2", # self.encoder.d[0].eq(0xBE), # self.encoder.d[1].eq(0xEF), # self.encoder.k[0].eq(0), # self.encoder.k[1].eq(0), # NextState("SEND_ARB_DATA3"), # ) # tx_fsm.act("SEND_ARB_DATA3", # self.encoder.d[0].eq(0xBA), # self.encoder.d[1].eq(0xD0), # self.encoder.k[0].eq(0), # self.encoder.k[1].eq(0), # NextState("SEND_ARB_DATA4"), # ) # tx_fsm.act("SEND_ARB_DATA4", # self.encoder.d[0].eq(0xCA), # self.encoder.d[1].eq(0xFE), # self.encoder.k[0].eq(0), # self.encoder.k[1].eq(0), # NextState("TERMINATE"), # ) # tx_fsm.act("TERMINATE", # self.encoder.d[0].eq(0xAD), # self.encoder.d[1].eq(0xDE), # self.encoder.k[0].eq(0), # self.encoder.k[1].eq(0), # NextState("TERMINATE"), # ) if __name__ == "__main__": import argparse parser = argparse.ArgumentParser() parser.add_argument("platform") args = parser.parse_args() platform_dict = { "kasli": kasli.Platform(hw_rev="v2.0"), "efc": efc.Platform(), } sysclk_name = { "kasli": "clk125_gtp", "efc": "gtp_clk", } platform = platform_dict[args.platform] sysclk = platform.request(sysclk_name[args.platform]) # Generate pads for the I/O blocks # Using EEM1 for both as both EFC and Kasli has EEM1 # EEM1 are not interconnected eem = 4 generate_pads(platform, eem) pads = [ platform.request("dio{}".format(eem), i) for i in range(4) ] # pad = platform.request("dio{}".format(eem), 0) crg = TransceiverCRG(platform, sysclk) top = MultiTransceiverChannel(pads, crg.sys_clk_freq) # Wire up UART core to the pads uart_pads = platform.request("serial") top.comb += [ top.uart_rx.eq(uart_pads.rx), uart_pads.tx.eq(top.uart_tx), ] top.submodules += crg platform.build(top)