minimal serdes communication loopback
This commit is contained in:
parent
b215dd1b57
commit
1248a46a54
|
@ -0,0 +1,242 @@
|
||||||
|
from migen import *
|
||||||
|
from sync_serdes import MultiLineRX, MultiLineTX
|
||||||
|
from migen.genlib.fifo import SyncFIFO
|
||||||
|
from migen.build.platforms.sinara import kasli, efc
|
||||||
|
from multi_coders import MultiEncoder, CrossbarDecoder
|
||||||
|
from kasli_crg import TransceiverCRG
|
||||||
|
from eem_helpers import generate_pads
|
||||||
|
from uart import UART
|
||||||
|
from io_loopback import SingleIOLoopback, IOLoopBack
|
||||||
|
|
||||||
|
|
||||||
|
class MultiTransceiverChannel(Module):
|
||||||
|
def __init__(self, io_pads, 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),
|
||||||
|
]
|
||||||
|
|
||||||
|
# SERDES impl
|
||||||
|
self.submodules.tx = MultiLineTX()
|
||||||
|
self.submodules.rx = MultiLineRX()
|
||||||
|
|
||||||
|
# 8b10b encoder & decoder
|
||||||
|
self.submodules.encoder = MultiEncoder(lsb_first=False)
|
||||||
|
decoders = [ CrossbarDecoder(lsb_first=False) for _ in range(2) ]
|
||||||
|
self.submodules += decoders
|
||||||
|
|
||||||
|
# The actual channel
|
||||||
|
self.submodules.channel = IOLoopBack(io_pads)
|
||||||
|
|
||||||
|
# FIFO to record transmission received
|
||||||
|
rx_records = SyncFIFO(16, 32)
|
||||||
|
self.submodules += rx_records
|
||||||
|
|
||||||
|
# Attach FIFO to UART TX, send rate is too slow w.r.t sysclk
|
||||||
|
self.submodules.tx_fifo = SyncFIFO(8, 64)
|
||||||
|
|
||||||
|
self.comb += [
|
||||||
|
# Loopback channel
|
||||||
|
self.channel.i.eq(self.tx.ser_out),
|
||||||
|
self.channel.t.eq(self.tx.t_out),
|
||||||
|
self.rx.ser_in_no_dly.eq(self.channel.o),
|
||||||
|
|
||||||
|
# Link decoders
|
||||||
|
decoders[0].raw_input.eq(self.rx.rxdata[:10]),
|
||||||
|
decoders[1].raw_input.eq(self.rx.rxdata[10:]),
|
||||||
|
# Default encoder linkage
|
||||||
|
self.tx.txdata.eq(Cat(self.encoder.output[0], self.encoder.output[1])),
|
||||||
|
|
||||||
|
# UART 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),
|
||||||
|
]
|
||||||
|
|
||||||
|
rx_fsm = FSM(reset_state="WAIT_GROUP_ALIGN")
|
||||||
|
self.submodules += rx_fsm
|
||||||
|
|
||||||
|
rx_fsm.act("WAIT_GROUP_ALIGN",
|
||||||
|
If(self.rx.align_done & rx_records.writable,
|
||||||
|
rx_records.din.eq(self.rx.rxdata),
|
||||||
|
rx_records.we.eq(1),
|
||||||
|
),
|
||||||
|
If(self.rx.err,
|
||||||
|
NextState("WRITE_ERR_UPPER"),
|
||||||
|
).Elif(self.rx.rxdata == 0b11111111111111111111,
|
||||||
|
decoders[0].start.eq(1),
|
||||||
|
decoders[1].start.eq(1),
|
||||||
|
NextState("RECORD_TRANSMISSION"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
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"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
rx_fsm.act("WRITE_ERR_LOWER",
|
||||||
|
If(self.tx_fifo.writable,
|
||||||
|
self.tx_fifo.we.eq(1),
|
||||||
|
self.tx_fifo.din.eq(0b10101010),
|
||||||
|
NextState("TERMINATE"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
rx_fsm.act("RECORD_TRANSMISSION",
|
||||||
|
If(rx_records.writable,
|
||||||
|
rx_records.din.eq(Cat(decoders[0].d, decoders[1].d)),
|
||||||
|
rx_records.we.eq(1),
|
||||||
|
).Else(
|
||||||
|
NextState("DUMP_TRANSMISSION_UPPER"),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
rx_fsm.act("DUMP_TRANSMISSION_UPPER",
|
||||||
|
If(rx_records.readable,
|
||||||
|
If(self.tx_fifo.writable,
|
||||||
|
self.tx_fifo.we.eq(1),
|
||||||
|
self.tx_fifo.din.eq(rx_records.dout[8:]),
|
||||||
|
NextState("DUMP_TRANSMISSION_LOWER"),
|
||||||
|
)
|
||||||
|
).Else(
|
||||||
|
NextState("TERMINATE"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
rx_fsm.act("DUMP_TRANSMISSION_LOWER",
|
||||||
|
If(self.tx_fifo.writable,
|
||||||
|
self.tx_fifo.we.eq(1),
|
||||||
|
self.tx_fifo.din.eq(rx_records.dout[:8]),
|
||||||
|
rx_records.re.eq(1),
|
||||||
|
NextState("DUMP_TRANSMISSION_UPPER"),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
rx_fsm.act("TERMINATE",
|
||||||
|
NextState("TERMINATE")
|
||||||
|
)
|
||||||
|
|
||||||
|
tx_fsm = FSM(reset_state="SEND_TRAINING")
|
||||||
|
self.submodules += tx_fsm
|
||||||
|
|
||||||
|
tx_fsm.act("SEND_TRAINING",
|
||||||
|
self.tx.txdata.eq(0b00100001000010000100),
|
||||||
|
If(self.rx.align_done,
|
||||||
|
NextState("SEND_ZERO"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
send_zero_duration = Signal(2)
|
||||||
|
|
||||||
|
tx_fsm.act("SEND_ZERO",
|
||||||
|
self.tx.txdata.eq(0),
|
||||||
|
If(send_zero_duration == 0b11,
|
||||||
|
NextState("SEND_PULSE"),
|
||||||
|
).Else(
|
||||||
|
NextValue(send_zero_duration, send_zero_duration + 1),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
tx_fsm.act("SEND_PULSE",
|
||||||
|
self.tx.txdata.eq(0b11111111111111111111),
|
||||||
|
self.encoder.start.eq(1),
|
||||||
|
NextState("WAIT_GROUP_ALIGN"),
|
||||||
|
)
|
||||||
|
|
||||||
|
tx_fsm.act("WAIT_GROUP_ALIGN",
|
||||||
|
If(self.rx.delay_done,
|
||||||
|
NextState("SEND_ARB_DATA1"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
tx_fsm.act("SEND_ARB_DATA1",
|
||||||
|
self.encoder.d[0].eq(0xDE),
|
||||||
|
self.encoder.d[1].eq(0xAD),
|
||||||
|
self.encoder.k[0].eq(0),
|
||||||
|
self.encoder.k[1].eq(0),
|
||||||
|
NextState("SEND_ARB_DATA2"),
|
||||||
|
)
|
||||||
|
|
||||||
|
tx_fsm.act("SEND_ARB_DATA2",
|
||||||
|
self.encoder.d[0].eq(0xBE),
|
||||||
|
self.encoder.d[1].eq(0xEF),
|
||||||
|
self.encoder.k[0].eq(0),
|
||||||
|
self.encoder.k[1].eq(0),
|
||||||
|
NextState("SEND_ARB_DATA3"),
|
||||||
|
)
|
||||||
|
|
||||||
|
tx_fsm.act("SEND_ARB_DATA3",
|
||||||
|
self.encoder.d[0].eq(0xBA),
|
||||||
|
self.encoder.d[1].eq(0xD0),
|
||||||
|
self.encoder.k[0].eq(0),
|
||||||
|
self.encoder.k[1].eq(0),
|
||||||
|
NextState("SEND_ARB_DATA4"),
|
||||||
|
)
|
||||||
|
|
||||||
|
tx_fsm.act("SEND_ARB_DATA4",
|
||||||
|
self.encoder.d[0].eq(0xCA),
|
||||||
|
self.encoder.d[1].eq(0xFE),
|
||||||
|
self.encoder.k[0].eq(0),
|
||||||
|
self.encoder.k[1].eq(0),
|
||||||
|
NextState("TERMINATE"),
|
||||||
|
)
|
||||||
|
|
||||||
|
tx_fsm.act("TERMINATE",
|
||||||
|
self.encoder.d[0].eq(0xAD),
|
||||||
|
self.encoder.d[1].eq(0xDE),
|
||||||
|
self.encoder.k[0].eq(0),
|
||||||
|
self.encoder.k[1].eq(0),
|
||||||
|
NextState("TERMINATE"),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument("platform")
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
platform_dict = {
|
||||||
|
"kasli": kasli.Platform(hw_rev="v2.0"),
|
||||||
|
"efc": efc.Platform(),
|
||||||
|
}
|
||||||
|
|
||||||
|
sysclk_name = {
|
||||||
|
"kasli": "clk125_gtp",
|
||||||
|
"efc": "gtp_clk",
|
||||||
|
}
|
||||||
|
|
||||||
|
platform = platform_dict[args.platform]
|
||||||
|
sysclk = platform.request(sysclk_name[args.platform])
|
||||||
|
|
||||||
|
# Generate pads for the I/O blocks
|
||||||
|
# Using EEM1 for both as both EFC and Kasli has EEM1
|
||||||
|
# EEM1 are not interconnected
|
||||||
|
eem = 0
|
||||||
|
generate_pads(platform, eem)
|
||||||
|
pads = [
|
||||||
|
platform.request("dio{}".format(eem), i) for i in range(4)
|
||||||
|
]
|
||||||
|
# pad = platform.request("dio{}".format(eem), 0)
|
||||||
|
|
||||||
|
crg = TransceiverCRG(platform, sysclk)
|
||||||
|
top = MultiTransceiverChannel(pads, 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)
|
Loading…
Reference in New Issue