diff --git a/multi_serdes_loopback.py b/multi_serdes_loopback.py index c82c080..86b90e0 100644 --- a/multi_serdes_loopback.py +++ b/multi_serdes_loopback.py @@ -1,15 +1,15 @@ from migen import * -from sync_serdes import SyncSingleRX, SingleLineTX +from sync_serdes import MultiLineRX, MultiLineTX from migen.genlib.fifo import SyncFIFO from migen.build.platforms.sinara import kasli from kasli_crg import KasliCRG from eem_helpers import generate_pads from uart import UART -from io_loopback import SingleIOLoopback +from io_loopback import SingleIOLoopback, IOLoopBack class MultiSerDesLoopBack(Module): - def __init__(self, io_pad, sys_clk_freq): + def __init__(self, io_pads, sys_clk_freq): self.uart_rx = Signal() self.uart_tx = Signal() @@ -19,23 +19,25 @@ class MultiSerDesLoopBack(Module): self.uart_tx.eq(self.uart.phy_tx), ] - self.submodules.tx = SingleLineTX() - self.submodules.sync_rx = SyncSingleRX() + self.submodules.tx = MultiLineTX() + self.submodules.rx = MultiLineRX() # The actual channel - self.submodules.channel = SingleIOLoopback(io_pad) + self.submodules.channel = IOLoopBack(io_pads) # Attach FIFO to UART TX, send rate is too slow w.r.t sysclk self.submodules.tx_fifo = SyncFIFO(8, 64) self.comb += [ # Repetitively send 0b00100 - self.tx.txdata.eq(0b00100), + # Note: Replicate() doesn't work, 0b00100 is lowered into 3'd4 + # I need 5'd4 for the replicate operator in Verilog + self.tx.txdata.eq(0b00100001000010000100), # Loopback channel self.channel.i.eq(self.tx.ser_out), - self.sync_rx.ser_in_no_dly.eq(self.channel.o), self.channel.t.eq(self.tx.t_out), + self.rx.ser_in_no_dly.eq(self.channel.o), # TX path self.uart.tx_data.eq(self.tx_fifo.dout), @@ -46,30 +48,46 @@ class MultiSerDesLoopBack(Module): self.submodules.fsm = FSM(reset_state="WAIT_SELF_ALIGN") self.fsm.act("WAIT_SELF_ALIGN", - If(self.sync_rx.align_done, + If(self.rx.align_done, NextState("SAMPLE_RXDATA"), ), ) - sampled_rxdata = Signal(5) + sampled_rxdata = Signal(20) self.fsm.act("SAMPLE_RXDATA", - NextValue(sampled_rxdata, self.sync_rx.rxdata), - NextState("WRITE_PATTERN_UPPER"), + NextValue(sampled_rxdata, self.rx.rxdata), + NextState("WRITE_PATTERN_FIRST_UPPER"), ) - self.fsm.act("WRITE_PATTERN_UPPER", + self.fsm.act("WRITE_PATTERN_FIRST_UPPER", If(self.tx_fifo.writable, self.tx_fifo.we.eq(1), - self.tx_fifo.din.eq(sampled_rxdata), - NextState("WRITE_PATTERN_LOWER"), + self.tx_fifo.din.eq(sampled_rxdata[8:10]), + NextState("WRITE_PATTERN_FIRST_LOWER"), ), ) - self.fsm.act("WRITE_PATTERN_LOWER", + self.fsm.act("WRITE_PATTERN_FIRST_LOWER", If(self.tx_fifo.writable, self.tx_fifo.we.eq(1), - self.tx_fifo.din.eq(sampled_rxdata), + self.tx_fifo.din.eq(sampled_rxdata[:8]), + NextState("WRITE_PATTERN_SECOND_UPPER"), + ), + ) + + self.fsm.act("WRITE_PATTERN_SECOND_UPPER", + If(self.tx_fifo.writable, + self.tx_fifo.we.eq(1), + self.tx_fifo.din.eq(sampled_rxdata[18:20]), + NextState("WRITE_PATTERN_SECOND_LOWER"), + ), + ) + + self.fsm.act("WRITE_PATTERN_SECOND_LOWER", + If(self.tx_fifo.writable, + self.tx_fifo.we.eq(1), + self.tx_fifo.din.eq(sampled_rxdata[10:18]), NextState("TERMINATE"), ), ) @@ -85,13 +103,13 @@ if __name__ == "__main__": # Generate pads for the I/O blocks eem = 3 generate_pads(platform, eem) - # pads = [ - # platform.request("dio{}".format(eem), i) for i in range(4) - # ] - pad = platform.request("dio{}".format(eem), 0) + pads = [ + platform.request("dio{}".format(eem), i) for i in range(4) + ] + # pad = platform.request("dio{}".format(eem), 0) crg = KasliCRG(platform) - top = MultiSerDesLoopBack(pad, crg.sys_clk_freq) + top = MultiSerDesLoopBack(pads, crg.sys_clk_freq) # Wire up UART core to the pads uart_pads = platform.request("serial") diff --git a/sync_serdes.py b/sync_serdes.py index 1b88233..a5d4cfc 100644 --- a/sync_serdes.py +++ b/sync_serdes.py @@ -640,3 +640,50 @@ class SyncSingleRX(Module): self.align_done.eq(1), NextState("INTRA_ALIGN_DONE"), ) + + +class MultiLineTX(Module): + def __init__(self): + # Ports + # IN: Unserialized data + self.txdata = Signal(20) + # OUT: Serialized data + self.ser_out = Signal(4) + # OUT: 3-state signal output + self.t_out = Signal(4) + + for idx in range(4): + single_tx = SingleLineTX() + + self.comb += [ + self.ser_out[idx].eq(single_tx.ser_out), + self.t_out[idx].eq(single_tx.t_out), + single_tx.txdata.eq(self.txdata[5*idx:5*(idx+1)]), + ] + + self.submodules += single_tx + + +class MultiLineRX(Module): + def __init__(self): + # Ports + # IN: Undelayed serial signal + self.ser_in_no_dly = Signal(4) + # OUT: Received data after self-alignment, decimation + self.rxdata = Signal(20) + # OUT: RXDATA from all channels are self-aligned + self.align_done = Signal() + + channel_align_done = Signal(4) + self.comb += self.align_done.eq(channel_align_done == 0b1111) + + for idx in range(4): + single_rx = SyncSingleRX() + + self.comb += [ + single_rx.ser_in_no_dly.eq(self.ser_in_no_dly[idx]), + self.rxdata[5*idx:5*(idx+1)].eq(single_rx.rxdata), + channel_align_done[idx].eq(single_rx.align_done), + ] + + self.submodules += single_rx