drtio: multilink transceiver interface

This commit is contained in:
Sebastien Bourdeauducq 2017-07-18 13:27:33 +08:00
parent d96c2abe44
commit a201a9abd9
4 changed files with 55 additions and 33 deletions

View File

@ -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)

View File

@ -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.

View File

@ -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"))
] ]

View File

@ -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"))
] ]