impl multi serdes tx/rx
This commit is contained in:
parent
24e8e9add9
commit
f55b2593a1
|
@ -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")
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue