handle group delay
This commit is contained in:
parent
f55b2593a1
commit
ce1f669138
|
@ -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"),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -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),
|
||||||
]
|
]
|
||||||
|
|
||||||
self.submodules += single_rx
|
# 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.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"),
|
||||||
|
)
|
||||||
|
|
Loading…
Reference in New Issue