serdes-transceiver/multi_serdes_loopback.py

194 lines
5.9 KiB
Python
Raw Normal View History

2023-04-25 07:59:04 +08:00
from migen import *
2023-04-25 09:41:04 +08:00
from sync_serdes import MultiLineRX, MultiLineTX
2023-04-25 07:59:04 +08:00
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
2023-04-25 09:41:04 +08:00
from io_loopback import SingleIOLoopback, IOLoopBack
2023-04-25 07:59:04 +08:00
class MultiSerDesLoopBack(Module):
2023-04-25 09:41:04 +08:00
def __init__(self, io_pads, sys_clk_freq):
2023-04-25 07:59:04 +08:00
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),
]
2023-04-25 09:41:04 +08:00
self.submodules.tx = MultiLineTX()
self.submodules.rx = MultiLineRX()
2023-04-25 07:59:04 +08:00
# The actual channel
2023-04-25 09:41:04 +08:00
self.submodules.channel = IOLoopBack(io_pads)
2023-04-25 07:59:04 +08:00
# 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
2023-04-25 09:41:04 +08:00
# 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),
2023-04-25 07:59:04 +08:00
# Loopback channel
self.channel.i.eq(self.tx.ser_out),
self.channel.t.eq(self.tx.t_out),
2023-04-25 09:41:04 +08:00
self.rx.ser_in_no_dly.eq(self.channel.o),
2023-04-25 07:59:04 +08:00
# 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),
]
2023-04-25 12:17:17 +08:00
self.submodules.rx_fsm = FSM(reset_state="WAIT_GROUP_ALIGN")
2023-04-25 07:59:04 +08:00
2023-04-25 12:17:17 +08:00
self.rx_fsm.act("WAIT_GROUP_ALIGN",
If(self.rx.err,
NextState("WRITE_ERR_UPPER")
).Elif(self.rx.rxdata == 0b11111111111111111111,
NextState("SAMPLE_RXDATA")
2023-04-25 07:59:04 +08:00
),
)
2023-04-25 12:17:17 +08:00
self.rx_fsm.act("WRITE_ERR_UPPER",
If(self.tx_fifo.writable,
self.tx_fifo.we.eq(1),
self.tx_fifo.din.eq(0b01010101),
NextState("WRITE_ERR_LOWER"),
),
2023-04-25 07:59:04 +08:00
)
2023-04-25 12:17:17 +08:00
self.rx_fsm.act("WRITE_ERR_LOWER",
2023-04-25 07:59:04 +08:00
If(self.tx_fifo.writable,
self.tx_fifo.we.eq(1),
2023-04-25 12:17:17 +08:00
self.tx_fifo.din.eq(0b10101010),
NextState("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]),
2023-04-25 09:41:04 +08:00
NextState("WRITE_PATTERN_FIRST_LOWER"),
2023-04-25 07:59:04 +08:00
),
)
2023-04-25 12:17:17 +08:00
self.rx_fsm.act("WRITE_PATTERN_FIRST_LOWER",
2023-04-25 07:59:04 +08:00
If(self.tx_fifo.writable,
self.tx_fifo.we.eq(1),
2023-04-25 12:17:17 +08:00
self.tx_fifo.din.eq(sampled_rxdata[sample_idx][:8]),
2023-04-25 09:41:04 +08:00
NextState("WRITE_PATTERN_SECOND_UPPER"),
),
)
2023-04-25 12:17:17 +08:00
self.rx_fsm.act("WRITE_PATTERN_SECOND_UPPER",
2023-04-25 09:41:04 +08:00
If(self.tx_fifo.writable,
self.tx_fifo.we.eq(1),
2023-04-25 12:17:17 +08:00
self.tx_fifo.din.eq(sampled_rxdata[sample_idx][18:20]),
2023-04-25 09:41:04 +08:00
NextState("WRITE_PATTERN_SECOND_LOWER"),
),
)
2023-04-25 12:17:17 +08:00
self.rx_fsm.act("WRITE_PATTERN_SECOND_LOWER",
2023-04-25 09:41:04 +08:00
If(self.tx_fifo.writable,
self.tx_fifo.we.eq(1),
2023-04-25 12:17:17 +08:00
self.tx_fifo.din.eq(sampled_rxdata[sample_idx][10:18]),
NextValue(sample_idx, sample_idx + 1),
NextState("WRITE_PATTERN_FIRST_UPPER"),
2023-04-25 07:59:04 +08:00
),
)
2023-04-25 12:17:17 +08:00
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),
2023-04-25 07:59:04 +08:00
NextState("TERMINATE"),
)
if __name__ == "__main__":
platform = kasli.Platform(hw_rev="v2.0")
# Generate pads for the I/O blocks
eem = 3
generate_pads(platform, eem)
2023-04-25 09:41:04 +08:00
pads = [
platform.request("dio{}".format(eem), i) for i in range(4)
]
# pad = platform.request("dio{}".format(eem), 0)
2023-04-25 07:59:04 +08:00
crg = KasliCRG(platform)
2023-04-25 09:41:04 +08:00
top = MultiSerDesLoopBack(pads, crg.sys_clk_freq)
2023-04-25 07:59:04 +08:00
# 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)