handle group delay

This commit is contained in:
occheung 2023-04-25 12:17:17 +08:00
parent f55b2593a1
commit ce1f669138
2 changed files with 172 additions and 35 deletions

View File

@ -45,54 +45,125 @@ class MultiSerDesLoopBack(Module):
self.tx_fifo.re.eq(self.uart.tx_ack), 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", self.rx_fsm.act("WAIT_GROUP_ALIGN",
If(self.rx.align_done, If(self.rx.err,
NextState("SAMPLE_RXDATA"), NextState("WRITE_ERR_UPPER")
).Elif(self.rx.rxdata == 0b11111111111111111111,
NextState("SAMPLE_RXDATA")
), ),
) )
sampled_rxdata = Signal(20) self.rx_fsm.act("WRITE_ERR_UPPER",
self.fsm.act("SAMPLE_RXDATA",
NextValue(sampled_rxdata, self.rx.rxdata),
NextState("WRITE_PATTERN_FIRST_UPPER"),
)
self.fsm.act("WRITE_PATTERN_FIRST_UPPER",
If(self.tx_fifo.writable, If(self.tx_fifo.writable,
self.tx_fifo.we.eq(1), self.tx_fifo.we.eq(1),
self.tx_fifo.din.eq(sampled_rxdata[8:10]), self.tx_fifo.din.eq(0b01010101),
NextState("WRITE_PATTERN_FIRST_LOWER"), NextState("WRITE_ERR_LOWER"),
), ),
) )
self.fsm.act("WRITE_PATTERN_FIRST_LOWER", self.rx_fsm.act("WRITE_ERR_LOWER",
If(self.tx_fifo.writable, If(self.tx_fifo.writable,
self.tx_fifo.we.eq(1), self.tx_fifo.we.eq(1),
self.tx_fifo.din.eq(sampled_rxdata[:8]), self.tx_fifo.din.eq(0b10101010),
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"), 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"), NextState("TERMINATE"),
) )

View File

@ -1,5 +1,6 @@
from migen import * from migen import *
from migen.genlib.misc import WaitTimer from migen.genlib.misc import WaitTimer
from migen.genlib.fifo import SyncFIFO
from util import PriorityEncoderMSB from util import PriorityEncoderMSB
@ -673,17 +674,82 @@ class MultiLineRX(Module):
self.rxdata = Signal(20) self.rxdata = Signal(20)
# OUT: RXDATA from all channels are self-aligned # OUT: RXDATA from all channels are self-aligned
self.align_done = Signal() 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) channel_align_done = Signal(4)
self.comb += self.align_done.eq(channel_align_done == 0b1111) 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): for idx in range(4):
single_rx = SyncSingleRX() single_rx = SyncSingleRX()
self.comb += [ self.comb += [
single_rx.ser_in_no_dly.eq(self.ser_in_no_dly[idx]), 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), 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"),
)