serdes-transceiver/single_serdes_loopback.py

318 lines
10 KiB
Python
Raw Normal View History

2023-04-23 11:42:18 +08:00
from migen import *
from sync_serdes import *
from migen.genlib.fifo import SyncFIFO
from migen.build.platforms.sinara import kasli
from migen.genlib.misc import WaitTimer
from kasli_crg import KasliCRG
from eem_helpers import generate_pads
from uart import UART
from io_loopback import SingleIOLoopback
SEPARATOR = Constant(0b0101)
class SingleSerDesLoopBack(Module):
def __init__(self, io_pad, 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),
]
self.submodules.tx = SingleLineTX()
self.submodules.rx = SingleLineRX()
2023-04-24 06:13:05 +08:00
# Primary adjustment to master-slave bitslip
2023-04-24 03:55:01 +08:00
self.submodules.bitslip_reader = BitSlipReader()
self.submodules.slave_aligner = SlaveAligner()
self.submodules.post_align_reader = BitSlipReader()
2023-04-24 06:13:05 +08:00
# Optimal delay solver
self.submodules.phase_reader = PhaseReader()
self.submodules.delay_solver = DelayOptimizer()
2023-04-23 11:42:18 +08:00
# self.submodules.delay_optimizer = DelayOptimizer()
# The actual channel
self.submodules.channel = SingleIOLoopback(io_pad)
# 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),
# Loopback channel
self.channel.i.eq(self.tx.ser_out),
self.rx.ser_in_no_dly.eq(self.channel.o),
self.channel.t.eq(self.tx.t_out),
# 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),
]
# Route deserializer to phase_reader & the delay tap optimizer
self.comb += [
# Start the reader initially
2023-04-24 03:55:01 +08:00
self.bitslip_reader.start.eq(1),
2023-04-23 11:42:18 +08:00
# Delay tap optimizer will start after the reader is done
2023-04-24 03:55:01 +08:00
self.slave_aligner.start.eq(0),
self.post_align_reader.start.eq(0),
2023-04-24 06:13:05 +08:00
self.phase_reader.start.eq(0),
self.delay_solver.start.eq(0),
2023-04-23 11:42:18 +08:00
# RXDATA for both reader and optimzer
2023-04-24 03:55:01 +08:00
self.bitslip_reader.loopback_rxdata.eq(self.rx.rxdata),
self.slave_aligner.loopback_rxdata.eq(self.rx.rxdata),
self.post_align_reader.loopback_rxdata.eq(self.rx.rxdata),
2023-04-24 06:13:05 +08:00
self.phase_reader.loopback_rxdata.eq(self.rx.rxdata),
self.delay_solver.loopback_rxdata.eq(self.rx.rxdata),
2023-04-23 11:42:18 +08:00
# Delay tap value
2023-04-24 06:13:05 +08:00
self.phase_reader.delay_tap.eq(self.rx.cnt_out),
self.delay_solver.delay_tap.eq(self.rx.cnt_out),
2023-04-23 11:42:18 +08:00
# Increment control enable, such that phase_reader can
# increment tap value after delay measurement
# Re-assign the incremnet control to the optimizer after the optimizer has started
# If(self.delay_optimizer.start,
# self.rx.ce.eq(self.delay_optimizer.inc_en),
# ).Else(
# self.rx.ce.eq(self.phase_reader.inc_en),
# )
2023-04-24 06:13:05 +08:00
self.rx.ce.eq(
self.phase_reader.inc_en |
self.delay_solver.inc_en
),
2023-04-24 03:55:01 +08:00
self.rx.master_bitslip.eq(
self.bitslip_reader.bitslip |
self.slave_aligner.master_bitslip |
self.post_align_reader.bitslip
),
self.rx.slave_bitslip.eq(
self.bitslip_reader.bitslip |
self.slave_aligner.slave_bitslip |
self.post_align_reader.bitslip
),
2023-04-23 11:42:18 +08:00
]
# Show measured result on UART
2023-04-24 06:13:05 +08:00
delay_tap_count = Signal(6)
2023-04-24 03:55:01 +08:00
bitslip_count = Signal(3)
post_align_bitslip_count = Signal(3)
2023-04-23 11:42:18 +08:00
fsm = FSM(reset_state="WAIT_DONE")
self.submodules += fsm
fsm.act("WAIT_DONE",
2023-04-24 03:55:01 +08:00
If(self.bitslip_reader.done,
2023-04-23 11:42:18 +08:00
NextState("WRITE_UPPER"),
),
)
fsm.act("WRITE_UPPER",
# Exist state if all results are sent
2023-04-24 03:55:01 +08:00
If(bitslip_count == 5,
2023-04-24 06:13:05 +08:00
NextState("START_SLAVE_ALIGNER"),
2023-04-23 11:42:18 +08:00
).Elif(self.tx_fifo.writable,
self.tx_fifo.we.eq(1),
2023-04-24 03:55:01 +08:00
self.tx_fifo.din.eq(self.bitslip_reader.data_result[bitslip_count][8:]),
2023-04-23 11:42:18 +08:00
NextState("WRITE_LOWER"),
),
)
fsm.act("WRITE_LOWER",
self.tx_fifo.we.eq(1),
2023-04-24 03:55:01 +08:00
self.tx_fifo.din.eq(self.bitslip_reader.data_result[bitslip_count][:8]),
NextValue(bitslip_count, bitslip_count + 1),
2023-04-23 11:42:18 +08:00
NextState("WRITE_UPPER"),
)
2023-04-24 06:13:05 +08:00
fsm.act("START_SLAVE_ALIGNER",
2023-04-24 03:55:01 +08:00
self.slave_aligner.start.eq(1),
# self.rx.ce.eq(self.delay_optimizer.inc_en),
If(self.slave_aligner.done,
NextState("WRITE_DONE_UPPER"),
).Else(
2023-04-24 06:13:05 +08:00
NextState("START_SLAVE_ALIGNER")
2023-04-24 03:55:01 +08:00
)
)
fsm.act("WRITE_DONE_UPPER",
self.post_align_reader.start.eq(1),
If(self.tx_fifo.writable,
self.tx_fifo.we.eq(1),
self.tx_fifo.din.eq(0xFF),
NextState("WRITE_DONE_LOWER")
)
)
fsm.act("WRITE_DONE_LOWER",
self.post_align_reader.start.eq(1),
If(self.tx_fifo.writable,
self.tx_fifo.we.eq(1),
self.tx_fifo.din.eq(0xFF),
NextState("REREAD_BITSLIP")
)
)
fsm.act("REREAD_BITSLIP",
If(self.post_align_reader.done,
NextState("REWRITE_UPPER"),
).Else(
NextState("REREAD_BITSLIP"),
),
)
fsm.act("REWRITE_UPPER",
# Exist state if all results are sent
If(post_align_bitslip_count == 5,
2023-04-24 06:13:05 +08:00
NextState("WRITE_B2P_DIVIDER_UPPER"),
2023-04-24 03:55:01 +08:00
).Elif(self.tx_fifo.writable,
self.tx_fifo.we.eq(1),
self.tx_fifo.din.eq(self.post_align_reader.data_result[post_align_bitslip_count][8:]),
NextState("REWRITE_LOWER"),
),
)
fsm.act("REWRITE_LOWER",
self.tx_fifo.we.eq(1),
self.tx_fifo.din.eq(self.post_align_reader.data_result[post_align_bitslip_count][:8]),
NextValue(post_align_bitslip_count, post_align_bitslip_count + 1),
NextState("REWRITE_UPPER"),
)
2023-04-23 11:42:18 +08:00
2023-04-24 06:13:05 +08:00
fsm.act("WRITE_B2P_DIVIDER_UPPER",
self.phase_reader.start.eq(1),
If(self.tx_fifo.writable,
self.tx_fifo.we.eq(1),
self.tx_fifo.din.eq(0xFF),
NextState("WRITE_B2P_DIVIDER_LOWER"),
)
)
fsm.act("WRITE_B2P_DIVIDER_LOWER",
self.phase_reader.start.eq(1),
If(self.tx_fifo.writable,
self.tx_fifo.we.eq(1),
self.tx_fifo.din.eq(0xFF),
NextState("WAIT_PHASE_READER"),
)
)
fsm.act("WAIT_PHASE_READER",
If(self.phase_reader.done,
NextState("WRITE_DELAY_UPPER"),
).Else(
NextState("WAIT_PHASE_READER"),
)
)
fsm.act("WRITE_DELAY_UPPER",
If(delay_tap_count == 32,
NextState("DELAY_SOLVER_DIVIDER_UPPER")
).Elif(self.tx_fifo.writable,
self.tx_fifo.we.eq(1),
self.tx_fifo.din.eq(self.phase_reader.data_result[delay_tap_count][8:]),
NextState("WRITE_DELAY_LOWER"),
),
)
fsm.act("WRITE_DELAY_LOWER",
If(self.tx_fifo.writable,
self.tx_fifo.we.eq(1),
self.tx_fifo.din.eq(self.phase_reader.data_result[delay_tap_count][:8]),
NextValue(delay_tap_count, delay_tap_count + 1),
NextState("WRITE_DELAY_UPPER")
),
)
fsm.act("DELAY_SOLVER_DIVIDER_UPPER",
self.delay_solver.start.eq(1),
If(self.tx_fifo.writable,
self.tx_fifo.we.eq(1),
self.tx_fifo.din.eq(0xFF),
NextState("DELAY_SOLVER_DIVIDER_LOWER"),
)
)
fsm.act("DELAY_SOLVER_DIVIDER_LOWER",
self.delay_solver.start.eq(1),
If(self.tx_fifo.writable,
self.tx_fifo.we.eq(1),
self.tx_fifo.din.eq(0xFF),
NextState("WAIT_DELAY_SOLVER"),
)
)
fsm.act("WAIT_DELAY_SOLVER",
If(self.delay_solver.done,
NextState("WRITE_UPPER_ZERO"),
).Else(
NextState("WAIT_DELAY_SOLVER"),
)
)
fsm.act("WRITE_UPPER_ZERO",
If(self.tx_fifo.writable,
self.tx_fifo.we.eq(1),
self.tx_fifo.din.eq(0x00),
NextState("WRITE_LOWER_OPT"),
)
)
fsm.act("WRITE_LOWER_OPT",
If(self.tx_fifo.writable,
self.tx_fifo.we.eq(1),
self.tx_fifo.din.eq(self.delay_solver.opt_delay_tap),
NextState("TERMINATE"),
),
)
2023-04-23 11:42:18 +08:00
fsm.act("TERMINATE",
NextState("TERMINATE"),
)
# # Output control
# self.sync += [
# # Send data to FIFO if not repeated
# If(self.rxdata_r[:5] != self.rx.rxdata,
# self.rxdata_r.eq(self.rx.rxdata),
# self.tx_fifo.din.eq(self.rx.rxdata),
# self.tx_fifo.we.eq(1)
# ).Else(
# self.tx_fifo.we.eq(0)
# )
# ]
if __name__ == "__main__":
platform = kasli.Platform(hw_rev="v2.0")
# 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)
crg = KasliCRG(platform)
top = SingleSerDesLoopBack(pad, 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)