From ce1f669138d76bfdf1cb3a9a9c14c5a57e2424b4 Mon Sep 17 00:00:00 2001 From: occheung Date: Tue, 25 Apr 2023 12:17:17 +0800 Subject: [PATCH] handle group delay --- multi_serdes_loopback.py | 137 +++++++++++++++++++++++++++++---------- sync_serdes.py | 70 +++++++++++++++++++- 2 files changed, 172 insertions(+), 35 deletions(-) diff --git a/multi_serdes_loopback.py b/multi_serdes_loopback.py index 86b90e0..d56c676 100644 --- a/multi_serdes_loopback.py +++ b/multi_serdes_loopback.py @@ -45,54 +45,125 @@ class MultiSerDesLoopBack(Module): self.tx_fifo.re.eq(self.uart.tx_ack), ] - self.submodules.fsm = FSM(reset_state="WAIT_SELF_ALIGN") + self.submodules.rx_fsm = FSM(reset_state="WAIT_GROUP_ALIGN") - self.fsm.act("WAIT_SELF_ALIGN", - If(self.rx.align_done, - NextState("SAMPLE_RXDATA"), + self.rx_fsm.act("WAIT_GROUP_ALIGN", + If(self.rx.err, + NextState("WRITE_ERR_UPPER") + ).Elif(self.rx.rxdata == 0b11111111111111111111, + NextState("SAMPLE_RXDATA") ), ) - sampled_rxdata = Signal(20) - - self.fsm.act("SAMPLE_RXDATA", - NextValue(sampled_rxdata, self.rx.rxdata), - NextState("WRITE_PATTERN_FIRST_UPPER"), - ) - - self.fsm.act("WRITE_PATTERN_FIRST_UPPER", + self.rx_fsm.act("WRITE_ERR_UPPER", If(self.tx_fifo.writable, self.tx_fifo.we.eq(1), - self.tx_fifo.din.eq(sampled_rxdata[8:10]), - NextState("WRITE_PATTERN_FIRST_LOWER"), + self.tx_fifo.din.eq(0b01010101), + NextState("WRITE_ERR_LOWER"), ), ) - self.fsm.act("WRITE_PATTERN_FIRST_LOWER", + self.rx_fsm.act("WRITE_ERR_LOWER", If(self.tx_fifo.writable, self.tx_fifo.we.eq(1), - 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]), + self.tx_fifo.din.eq(0b10101010), NextState("TERMINATE"), ), ) - self.fsm.act("TERMINATE", + sampled_rxdata = Array(Signal(20) for _ in range(5)) + sample_idx = Signal(3) + + self.rx_fsm.act("SAMPLE_RXDATA", + If((sample_idx != 0) | (self.rx.rxdata != 0), + If(sample_idx == 5, + NextValue(sample_idx, 0), + NextState("WRITE_PATTERN_FIRST_UPPER"), + ).Else( + NextValue(sampled_rxdata[sample_idx], self.rx.rxdata), + NextValue(sample_idx, sample_idx + 1), + ), + ), + ) + + self.rx_fsm.act("WRITE_PATTERN_FIRST_UPPER", + If(sample_idx == 5, + NextState("TERMINATE"), + ).Elif(self.tx_fifo.writable, + self.tx_fifo.we.eq(1), + self.tx_fifo.din.eq(sampled_rxdata[sample_idx][8:10]), + NextState("WRITE_PATTERN_FIRST_LOWER"), + ), + ) + + self.rx_fsm.act("WRITE_PATTERN_FIRST_LOWER", + If(self.tx_fifo.writable, + self.tx_fifo.we.eq(1), + self.tx_fifo.din.eq(sampled_rxdata[sample_idx][:8]), + NextState("WRITE_PATTERN_SECOND_UPPER"), + ), + ) + + self.rx_fsm.act("WRITE_PATTERN_SECOND_UPPER", + If(self.tx_fifo.writable, + self.tx_fifo.we.eq(1), + self.tx_fifo.din.eq(sampled_rxdata[sample_idx][18:20]), + NextState("WRITE_PATTERN_SECOND_LOWER"), + ), + ) + + self.rx_fsm.act("WRITE_PATTERN_SECOND_LOWER", + If(self.tx_fifo.writable, + self.tx_fifo.we.eq(1), + self.tx_fifo.din.eq(sampled_rxdata[sample_idx][10:18]), + NextValue(sample_idx, sample_idx + 1), + NextState("WRITE_PATTERN_FIRST_UPPER"), + ), + ) + + self.rx_fsm.act("TERMINATE", + NextState("TERMINATE"), + ) + + self.submodules.tx_fsm = FSM(reset_state="SEND_TRAINING") + + self.tx_fsm.act("SEND_TRAINING", + self.tx.txdata.eq(0b00100001000010000100), + If(self.rx.align_done, + NextState("SEND_ZERO"), + ), + ) + + send_zero_duration = Signal(4) + + self.tx_fsm.act("SEND_ZERO", + self.tx.txdata.eq(0), + If(send_zero_duration == 0b1111, + NextState("SEND_PULSE"), + ).Else( + NextValue(send_zero_duration, send_zero_duration + 1), + ), + ) + + self.tx_fsm.act("SEND_PULSE", + self.tx.txdata.eq(0b11111111111111111111), + NextState("WAIT_GROUP_ALIGN"), + ) + + self.tx_fsm.act("WAIT_GROUP_ALIGN", + self.tx.txdata.eq(0), + If(self.rx.delay_done, + NextState("SEND_ARB_DATA"), + ), + ) + + self.tx_fsm.act("SEND_ARB_DATA", + self.tx.txdata.eq(0xDEADB), + NextState("TERMINATE"), + ) + + self.tx_fsm.act("TERMINATE", + self.tx.txdata.eq(0), NextState("TERMINATE"), ) diff --git a/sync_serdes.py b/sync_serdes.py index a5d4cfc..17cffbe 100644 --- a/sync_serdes.py +++ b/sync_serdes.py @@ -1,5 +1,6 @@ from migen import * from migen.genlib.misc import WaitTimer +from migen.genlib.fifo import SyncFIFO from util import PriorityEncoderMSB @@ -673,17 +674,82 @@ class MultiLineRX(Module): self.rxdata = Signal(20) # OUT: RXDATA from all channels are self-aligned self.align_done = Signal() + # OUT: Group delay compensated + self.delay_done = Signal() + # OUT: Group delay adjustment failed + self.err = Signal() channel_align_done = Signal(4) self.comb += self.align_done.eq(channel_align_done == 0b1111) + buffer_outflow = Signal(4) + self.comb += buffer_outflow.eq(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), + # self.rxdata[5*idx:5*(idx+1)].eq(single_rx.rxdata), channel_align_done[idx].eq(single_rx.align_done), ] + + # FIFOs for handling group delay + # Signal from each OSERDES group can have a different delay + # So, add delay to the groups that receives the pulse early + # Maximum delay = 8 + channel_buffer = SyncFIFO(5, 8) - self.submodules += single_rx + self.comb += [ + # Allow data go through the FIFO unless aligning + # Pay the memory delay cost + channel_buffer.we.eq(1), + channel_buffer.re.eq(buffer_outflow[idx]), + + # Data always flow from individual RX to the rxdata port + channel_buffer.din.eq(single_rx.rxdata), + self.rxdata[5*idx:5*(idx+1)].eq(channel_buffer.dout), + ] + + # If at any point the FIFO fills up, + # group delay can no longer be determined and compensated + self.sync += [ + If(~channel_buffer.writable, + self.err.eq(1), + ), + ] + + self.submodules += [ single_rx, channel_buffer ] + + self.submodules.fsm = FSM(reset_state="WAIT_ALIGN_DONE") + + self.fsm.act("WAIT_ALIGN_DONE", + If(self.align_done, + NextState("WAIT_ZERO"), + ), + ) + + self.fsm.act("WAIT_ZERO", + If(self.rxdata == 0, + NextState("WAIT_PULSE"), + ), + ) + + self.fsm.act("WAIT_PULSE", + # Control outflow until all channels finds the pulse + If(self.rxdata == 0b11111111111111111111, + buffer_outflow.eq(0b1111), + self.delay_done.eq(1), + NextState("GROUP_DELAY_DONE"), + ).Else( + buffer_outflow[0].eq(self.rxdata[ 0: 5] == 0), + buffer_outflow[1].eq(self.rxdata[ 5:10] == 0), + buffer_outflow[2].eq(self.rxdata[10:15] == 0), + buffer_outflow[3].eq(self.rxdata[15:20] == 0), + ), + ) + + self.fsm.act("GROUP_DELAY_DONE", + self.delay_done.eq(1), + NextState("GROUP_DELAY_DONE"), + )