forked from M-Labs/artiq
drtio: multilink transceiver interface
This commit is contained in:
parent
d96c2abe44
commit
a201a9abd9
|
@ -9,6 +9,22 @@ from artiq.gateware.drtio import (link_layer, aux_controller,
|
||||||
rt_packet_master, rt_controller_master)
|
rt_packet_master, rt_controller_master)
|
||||||
|
|
||||||
|
|
||||||
|
class ChannelInterface:
|
||||||
|
def __init__(self, encoder, decoders):
|
||||||
|
self.rx_ready = Signal()
|
||||||
|
self.encoder = encoder
|
||||||
|
self.decoders = decoders
|
||||||
|
|
||||||
|
|
||||||
|
class TransceiverInterface:
|
||||||
|
def __init__(self, channel_interfaces):
|
||||||
|
self.clock_domains.cd_rtio = ClockDomain()
|
||||||
|
for i in range(len(channel_interfaces)):
|
||||||
|
name = "rtio_rx" + str(i)
|
||||||
|
setattr(self.clock_domains, "cd_"+name, ClockDomain(name=name))
|
||||||
|
self.channels = channel_interfaces
|
||||||
|
|
||||||
|
|
||||||
class GenericRXSynchronizer(Module):
|
class GenericRXSynchronizer(Module):
|
||||||
"""Simple RX synchronizer based on the portable Migen elastic buffer.
|
"""Simple RX synchronizer based on the portable Migen elastic buffer.
|
||||||
|
|
||||||
|
@ -33,14 +49,14 @@ class GenericRXSynchronizer(Module):
|
||||||
|
|
||||||
|
|
||||||
class DRTIOSatellite(Module):
|
class DRTIOSatellite(Module):
|
||||||
def __init__(self, transceiver, channels, rx_synchronizer=None, fine_ts_width=3, full_ts_width=63):
|
def __init__(self, chanif, channels, rx_synchronizer=None, fine_ts_width=3, full_ts_width=63):
|
||||||
if rx_synchronizer is None:
|
if rx_synchronizer is None:
|
||||||
rx_synchronizer = GenericRXSynchronizer()
|
rx_synchronizer = GenericRXSynchronizer()
|
||||||
self.submodules += rx_synchronizer
|
self.submodules += rx_synchronizer
|
||||||
|
|
||||||
self.submodules.link_layer = link_layer.LinkLayer(
|
self.submodules.link_layer = link_layer.LinkLayer(
|
||||||
transceiver.encoder, transceiver.decoders)
|
chanif.encoder, chanif.decoders)
|
||||||
self.comb += self.link_layer.rx_ready.eq(transceiver.rx_ready)
|
self.comb += self.link_layer.rx_ready.eq(chanif.rx_ready)
|
||||||
|
|
||||||
link_layer_sync = SimpleNamespace(
|
link_layer_sync = SimpleNamespace(
|
||||||
tx_aux_frame=self.link_layer.tx_aux_frame,
|
tx_aux_frame=self.link_layer.tx_aux_frame,
|
||||||
|
@ -85,10 +101,10 @@ class DRTIOSatellite(Module):
|
||||||
|
|
||||||
|
|
||||||
class DRTIOMaster(Module):
|
class DRTIOMaster(Module):
|
||||||
def __init__(self, transceiver, channel_count=1024, fine_ts_width=3):
|
def __init__(self, chanif, channel_count=1024, fine_ts_width=3):
|
||||||
self.submodules.link_layer = link_layer.LinkLayer(
|
self.submodules.link_layer = link_layer.LinkLayer(
|
||||||
transceiver.encoder, transceiver.decoders)
|
chanif.encoder, chanif.decoders)
|
||||||
self.comb += self.link_layer.rx_ready.eq(transceiver.rx_ready)
|
self.comb += self.link_layer.rx_ready.eq(chanif.rx_ready)
|
||||||
|
|
||||||
self.submodules.link_stats = link_layer.LinkLayerStats(self.link_layer, "rtio_rx")
|
self.submodules.link_stats = link_layer.LinkLayerStats(self.link_layer, "rtio_rx")
|
||||||
self.submodules.rt_packet = rt_packet_master.RTPacketMaster(self.link_layer)
|
self.submodules.rt_packet = rt_packet_master.RTPacketMaster(self.link_layer)
|
||||||
|
|
|
@ -4,22 +4,26 @@ from migen.genlib.resetsync import AsyncResetSynchronizer
|
||||||
from misoc.cores.code_8b10b import Encoder, Decoder
|
from misoc.cores.code_8b10b import Encoder, Decoder
|
||||||
from misoc.interconnect.csr import *
|
from misoc.interconnect.csr import *
|
||||||
|
|
||||||
|
from artiq.gateware.drtio.core import TransceiverInterface, ChannelInterface
|
||||||
from artiq.gateware.drtio.transceiver.gtx_7series_init import *
|
from artiq.gateware.drtio.transceiver.gtx_7series_init import *
|
||||||
|
|
||||||
|
|
||||||
class GTX_20X(Module):
|
class GTX_20X(Module, TransceiverInterface):
|
||||||
|
# Only one channel is supported.
|
||||||
|
#
|
||||||
# The transceiver clock on clock_pads must be at the RTIO clock
|
# The transceiver clock on clock_pads must be at the RTIO clock
|
||||||
# frequency when clock_div2=False, and 2x that frequency when
|
# frequency when clock_div2=False, and 2x that frequency when
|
||||||
# clock_div2=True.
|
# clock_div2=True.
|
||||||
def __init__(self, clock_pads, tx_pads, rx_pads, sys_clk_freq,
|
def __init__(self, clock_pads, tx_pads, rx_pads, sys_clk_freq,
|
||||||
clock_div2=False):
|
clock_div2=False):
|
||||||
self.submodules.encoder = ClockDomainsRenamer("rtio")(
|
encoder = ClockDomainsRenamer("rtio")(
|
||||||
Encoder(2, True))
|
Encoder(2, True))
|
||||||
self.decoders = [ClockDomainsRenamer("rtio_rx")(
|
self.submodules += encoder
|
||||||
Decoder(True)) for _ in range(2)]
|
decoders = [ClockDomainsRenamer("rtio_rx0")(
|
||||||
self.submodules += self.decoders
|
(Decoder(True))) for _ in range(2)]
|
||||||
|
self.submodules += decoders
|
||||||
|
|
||||||
self.rx_ready = Signal()
|
TransceiverInterface.__init__(self, [ChannelInterface(encoder, decoders)])
|
||||||
|
|
||||||
# transceiver direct clock outputs
|
# transceiver direct clock outputs
|
||||||
# useful to specify clock constraints in a way palatable to Vivado
|
# useful to specify clock constraints in a way palatable to Vivado
|
||||||
|
@ -137,8 +141,8 @@ class GTX_20X(Module):
|
||||||
i_RXSYSCLKSEL=0b00,
|
i_RXSYSCLKSEL=0b00,
|
||||||
i_RXOUTCLKSEL=0b010,
|
i_RXOUTCLKSEL=0b010,
|
||||||
o_RXOUTCLK=self.rxoutclk,
|
o_RXOUTCLK=self.rxoutclk,
|
||||||
i_RXUSRCLK=ClockSignal("rtio_rx"),
|
i_RXUSRCLK=ClockSignal("rtio_rx0"),
|
||||||
i_RXUSRCLK2=ClockSignal("rtio_rx"),
|
i_RXUSRCLK2=ClockSignal("rtio_rx0"),
|
||||||
p_RXCDR_CFG=0x03000023FF10100020,
|
p_RXCDR_CFG=0x03000023FF10100020,
|
||||||
|
|
||||||
# RX Clock Correction Attributes
|
# RX Clock Correction Attributes
|
||||||
|
@ -165,7 +169,6 @@ class GTX_20X(Module):
|
||||||
tx_reset_deglitched = Signal()
|
tx_reset_deglitched = Signal()
|
||||||
tx_reset_deglitched.attr.add("no_retiming")
|
tx_reset_deglitched.attr.add("no_retiming")
|
||||||
self.sync += tx_reset_deglitched.eq(~tx_init.done)
|
self.sync += tx_reset_deglitched.eq(~tx_init.done)
|
||||||
self.clock_domains.cd_rtio = ClockDomain()
|
|
||||||
self.specials += [
|
self.specials += [
|
||||||
Instance("BUFG", i_I=self.txoutclk, o_O=self.cd_rtio.clk),
|
Instance("BUFG", i_I=self.txoutclk, o_O=self.cd_rtio.clk),
|
||||||
AsyncResetSynchronizer(self.cd_rtio, tx_reset_deglitched)
|
AsyncResetSynchronizer(self.cd_rtio, tx_reset_deglitched)
|
||||||
|
@ -173,24 +176,25 @@ class GTX_20X(Module):
|
||||||
rx_reset_deglitched = Signal()
|
rx_reset_deglitched = Signal()
|
||||||
rx_reset_deglitched.attr.add("no_retiming")
|
rx_reset_deglitched.attr.add("no_retiming")
|
||||||
self.sync.rtio += rx_reset_deglitched.eq(~rx_init.done)
|
self.sync.rtio += rx_reset_deglitched.eq(~rx_init.done)
|
||||||
self.clock_domains.cd_rtio_rx = ClockDomain()
|
|
||||||
self.specials += [
|
self.specials += [
|
||||||
Instance("BUFG", i_I=self.rxoutclk, o_O=self.cd_rtio_rx.clk),
|
Instance("BUFG", i_I=self.rxoutclk, o_O=self.cd_rtio_rx0.clk),
|
||||||
AsyncResetSynchronizer(self.cd_rtio_rx, rx_reset_deglitched)
|
AsyncResetSynchronizer(self.cd_rtio_rx0, rx_reset_deglitched)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
chan = self.channels[0]
|
||||||
self.comb += [
|
self.comb += [
|
||||||
txdata.eq(Cat(self.encoder.output[0], self.encoder.output[1])),
|
txdata.eq(Cat(chan.encoder.output[0], chan.encoder.output[1])),
|
||||||
self.decoders[0].input.eq(rxdata[:10]),
|
chan.decoders[0].input.eq(rxdata[:10]),
|
||||||
self.decoders[1].input.eq(rxdata[10:])
|
chan.decoders[1].input.eq(rxdata[10:])
|
||||||
]
|
]
|
||||||
|
|
||||||
clock_aligner = BruteforceClockAligner(0b0101111100, self.rtio_clk_freq)
|
clock_aligner = ClockDomainsRenamer({"rtio_rx": "rtio_rx0"})(
|
||||||
|
BruteforceClockAligner(0b0101111100, self.rtio_clk_freq))
|
||||||
self.submodules += clock_aligner
|
self.submodules += clock_aligner
|
||||||
self.comb += [
|
self.comb += [
|
||||||
clock_aligner.rxdata.eq(rxdata),
|
clock_aligner.rxdata.eq(rxdata),
|
||||||
rx_init.restart.eq(clock_aligner.restart),
|
rx_init.restart.eq(clock_aligner.restart),
|
||||||
self.rx_ready.eq(clock_aligner.ready)
|
chan.rx_ready.eq(clock_aligner.ready)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -199,7 +203,7 @@ class GTX_1000BASE_BX10(GTX_20X):
|
||||||
|
|
||||||
|
|
||||||
class RXSynchronizer(Module, AutoCSR):
|
class RXSynchronizer(Module, AutoCSR):
|
||||||
"""Delays the data received in the rtio_rx by a configurable amount
|
"""Delays the data received in the rtio_rx domain by a configurable amount
|
||||||
so that it meets s/h in the rtio domain, and recapture it in the rtio
|
so that it meets s/h in the rtio domain, and recapture it in the rtio
|
||||||
domain. This has fixed latency.
|
domain. This has fixed latency.
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,8 @@ class Master(MiniSoC, AMPSoC):
|
||||||
sys_clk_freq=self.clk_freq,
|
sys_clk_freq=self.clk_freq,
|
||||||
clock_div2=True)
|
clock_div2=True)
|
||||||
|
|
||||||
self.submodules.drtio0 = DRTIOMaster(self.transceiver)
|
self.submodules.drtio0 = ClockDomainsRenamer({"rtio_rx": "rtio_rx0"})(
|
||||||
|
DRTIOMaster(self.transceiver.channels[0]))
|
||||||
self.csr_devices.append("drtio0")
|
self.csr_devices.append("drtio0")
|
||||||
self.add_wb_slave(self.mem_map["drtio_aux"], 0x800,
|
self.add_wb_slave(self.mem_map["drtio_aux"], 0x800,
|
||||||
self.drtio0.aux_controller.bus)
|
self.drtio0.aux_controller.bus)
|
||||||
|
@ -69,7 +70,7 @@ class Master(MiniSoC, AMPSoC):
|
||||||
self.csr_devices.append("converter_spi")
|
self.csr_devices.append("converter_spi")
|
||||||
|
|
||||||
self.comb += [
|
self.comb += [
|
||||||
platform.request("user_sma_clock_p").eq(ClockSignal("rtio_rx")),
|
platform.request("user_sma_clock_p").eq(ClockSignal("rtio_rx0")),
|
||||||
platform.request("user_sma_clock_n").eq(ClockSignal("rtio"))
|
platform.request("user_sma_clock_n").eq(ClockSignal("rtio"))
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -54,11 +54,12 @@ class Satellite(BaseSoC):
|
||||||
tx_pads=platform.request("sfp_tx"),
|
tx_pads=platform.request("sfp_tx"),
|
||||||
rx_pads=platform.request("sfp_rx"),
|
rx_pads=platform.request("sfp_rx"),
|
||||||
sys_clk_freq=self.clk_freq)
|
sys_clk_freq=self.clk_freq)
|
||||||
self.submodules.rx_synchronizer = gtx_7series.RXSynchronizer(
|
rx0 = ClockDomainsRenamer({"rtio_rx": "rtio_rx0"})
|
||||||
self.transceiver.rtio_clk_freq, initial_phase=180.0)
|
self.submodules.rx_synchronizer0 = rx0(gtx_7series.RXSynchronizer(
|
||||||
self.submodules.drtio0 = DRTIOSatellite(
|
self.transceiver.rtio_clk_freq, initial_phase=180.0))
|
||||||
self.transceiver, rtio_channels, self.rx_synchronizer)
|
self.submodules.drtio0 = rx0(DRTIOSatellite(
|
||||||
self.csr_devices.append("rx_synchronizer")
|
self.transceiver.channels[0], rtio_channels, self.rx_synchronizer0))
|
||||||
|
self.csr_devices.append("rx_synchronizer0")
|
||||||
self.csr_devices.append("drtio0")
|
self.csr_devices.append("drtio0")
|
||||||
self.add_wb_slave(self.mem_map["drtio_aux"], 0x800,
|
self.add_wb_slave(self.mem_map["drtio_aux"], 0x800,
|
||||||
self.drtio0.aux_controller.bus)
|
self.drtio0.aux_controller.bus)
|
||||||
|
@ -71,7 +72,7 @@ class Satellite(BaseSoC):
|
||||||
si5324_clkin = platform.request("si5324_clkin")
|
si5324_clkin = platform.request("si5324_clkin")
|
||||||
self.specials += \
|
self.specials += \
|
||||||
Instance("OBUFDS",
|
Instance("OBUFDS",
|
||||||
i_I=ClockSignal("rtio_rx"),
|
i_I=ClockSignal("rtio_rx0"),
|
||||||
o_O=si5324_clkin.p, o_OB=si5324_clkin.n
|
o_O=si5324_clkin.p, o_OB=si5324_clkin.n
|
||||||
)
|
)
|
||||||
self.submodules.si5324_rst_n = gpio.GPIOOut(platform.request("si5324").rst_n)
|
self.submodules.si5324_rst_n = gpio.GPIOOut(platform.request("si5324").rst_n)
|
||||||
|
@ -89,7 +90,7 @@ class Satellite(BaseSoC):
|
||||||
self.csr_devices.append("converter_spi")
|
self.csr_devices.append("converter_spi")
|
||||||
|
|
||||||
self.comb += [
|
self.comb += [
|
||||||
platform.request("user_sma_clock_p").eq(ClockSignal("rtio_rx")),
|
platform.request("user_sma_clock_p").eq(ClockSignal("rtio_rx0")),
|
||||||
platform.request("user_sma_clock_n").eq(ClockSignal("rtio"))
|
platform.request("user_sma_clock_n").eq(ClockSignal("rtio"))
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue