impl multi serdes tx/rx

This commit is contained in:
occheung 2023-04-25 09:41:04 +08:00
parent 24e8e9add9
commit f55b2593a1
2 changed files with 87 additions and 22 deletions

View File

@ -1,15 +1,15 @@
from migen import * from migen import *
from sync_serdes import SyncSingleRX, SingleLineTX from sync_serdes import MultiLineRX, MultiLineTX
from migen.genlib.fifo import SyncFIFO from migen.genlib.fifo import SyncFIFO
from migen.build.platforms.sinara import kasli from migen.build.platforms.sinara import kasli
from kasli_crg import KasliCRG from kasli_crg import KasliCRG
from eem_helpers import generate_pads from eem_helpers import generate_pads
from uart import UART from uart import UART
from io_loopback import SingleIOLoopback from io_loopback import SingleIOLoopback, IOLoopBack
class MultiSerDesLoopBack(Module): class MultiSerDesLoopBack(Module):
def __init__(self, io_pad, sys_clk_freq): def __init__(self, io_pads, sys_clk_freq):
self.uart_rx = Signal() self.uart_rx = Signal()
self.uart_tx = Signal() self.uart_tx = Signal()
@ -19,23 +19,25 @@ class MultiSerDesLoopBack(Module):
self.uart_tx.eq(self.uart.phy_tx), self.uart_tx.eq(self.uart.phy_tx),
] ]
self.submodules.tx = SingleLineTX() self.submodules.tx = MultiLineTX()
self.submodules.sync_rx = SyncSingleRX() self.submodules.rx = MultiLineRX()
# The actual channel # The actual channel
self.submodules.channel = SingleIOLoopback(io_pad) self.submodules.channel = IOLoopBack(io_pads)
# Attach FIFO to UART TX, send rate is too slow w.r.t sysclk # Attach FIFO to UART TX, send rate is too slow w.r.t sysclk
self.submodules.tx_fifo = SyncFIFO(8, 64) self.submodules.tx_fifo = SyncFIFO(8, 64)
self.comb += [ self.comb += [
# Repetitively send 0b00100 # Repetitively send 0b00100
self.tx.txdata.eq(0b00100), # 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),
# Loopback channel # Loopback channel
self.channel.i.eq(self.tx.ser_out), self.channel.i.eq(self.tx.ser_out),
self.sync_rx.ser_in_no_dly.eq(self.channel.o),
self.channel.t.eq(self.tx.t_out), self.channel.t.eq(self.tx.t_out),
self.rx.ser_in_no_dly.eq(self.channel.o),
# TX path # TX path
self.uart.tx_data.eq(self.tx_fifo.dout), self.uart.tx_data.eq(self.tx_fifo.dout),
@ -46,30 +48,46 @@ class MultiSerDesLoopBack(Module):
self.submodules.fsm = FSM(reset_state="WAIT_SELF_ALIGN") self.submodules.fsm = FSM(reset_state="WAIT_SELF_ALIGN")
self.fsm.act("WAIT_SELF_ALIGN", self.fsm.act("WAIT_SELF_ALIGN",
If(self.sync_rx.align_done, If(self.rx.align_done,
NextState("SAMPLE_RXDATA"), NextState("SAMPLE_RXDATA"),
), ),
) )
sampled_rxdata = Signal(5) sampled_rxdata = Signal(20)
self.fsm.act("SAMPLE_RXDATA", self.fsm.act("SAMPLE_RXDATA",
NextValue(sampled_rxdata, self.sync_rx.rxdata), NextValue(sampled_rxdata, self.rx.rxdata),
NextState("WRITE_PATTERN_UPPER"), NextState("WRITE_PATTERN_FIRST_UPPER"),
) )
self.fsm.act("WRITE_PATTERN_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), self.tx_fifo.din.eq(sampled_rxdata[8:10]),
NextState("WRITE_PATTERN_LOWER"), NextState("WRITE_PATTERN_FIRST_LOWER"),
), ),
) )
self.fsm.act("WRITE_PATTERN_LOWER", self.fsm.act("WRITE_PATTERN_FIRST_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), 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]),
NextState("TERMINATE"), NextState("TERMINATE"),
), ),
) )
@ -85,13 +103,13 @@ if __name__ == "__main__":
# Generate pads for the I/O blocks # Generate pads for the I/O blocks
eem = 3 eem = 3
generate_pads(platform, eem) generate_pads(platform, eem)
# pads = [ pads = [
# platform.request("dio{}".format(eem), i) for i in range(4) platform.request("dio{}".format(eem), i) for i in range(4)
# ] ]
pad = platform.request("dio{}".format(eem), 0) # pad = platform.request("dio{}".format(eem), 0)
crg = KasliCRG(platform) crg = KasliCRG(platform)
top = MultiSerDesLoopBack(pad, crg.sys_clk_freq) top = MultiSerDesLoopBack(pads, crg.sys_clk_freq)
# Wire up UART core to the pads # Wire up UART core to the pads
uart_pads = platform.request("serial") uart_pads = platform.request("serial")

View File

@ -640,3 +640,50 @@ class SyncSingleRX(Module):
self.align_done.eq(1), self.align_done.eq(1),
NextState("INTRA_ALIGN_DONE"), NextState("INTRA_ALIGN_DONE"),
) )
class MultiLineTX(Module):
def __init__(self):
# Ports
# IN: Unserialized data
self.txdata = Signal(20)
# OUT: Serialized data
self.ser_out = Signal(4)
# OUT: 3-state signal output
self.t_out = Signal(4)
for idx in range(4):
single_tx = SingleLineTX()
self.comb += [
self.ser_out[idx].eq(single_tx.ser_out),
self.t_out[idx].eq(single_tx.t_out),
single_tx.txdata.eq(self.txdata[5*idx:5*(idx+1)]),
]
self.submodules += single_tx
class MultiLineRX(Module):
def __init__(self):
# Ports
# IN: Undelayed serial signal
self.ser_in_no_dly = Signal(4)
# OUT: Received data after self-alignment, decimation
self.rxdata = Signal(20)
# OUT: RXDATA from all channels are self-aligned
self.align_done = Signal()
channel_align_done = Signal(4)
self.comb += self.align_done.eq(channel_align_done == 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),
channel_align_done[idx].eq(single_rx.align_done),
]
self.submodules += single_rx