From a201a9abd944d08e49f98f382959457cc33763a8 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 18 Jul 2017 13:27:33 +0800 Subject: [PATCH] drtio: multilink transceiver interface --- artiq/gateware/drtio/core.py | 28 ++++++++++--- .../gateware/drtio/transceiver/gtx_7series.py | 40 ++++++++++--------- artiq/gateware/targets/kc705_drtio_master.py | 5 ++- .../gateware/targets/kc705_drtio_satellite.py | 15 +++---- 4 files changed, 55 insertions(+), 33 deletions(-) diff --git a/artiq/gateware/drtio/core.py b/artiq/gateware/drtio/core.py index 2c063a79d..c3da1cb51 100644 --- a/artiq/gateware/drtio/core.py +++ b/artiq/gateware/drtio/core.py @@ -9,6 +9,22 @@ from artiq.gateware.drtio import (link_layer, aux_controller, 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): """Simple RX synchronizer based on the portable Migen elastic buffer. @@ -33,14 +49,14 @@ class GenericRXSynchronizer(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: rx_synchronizer = GenericRXSynchronizer() self.submodules += rx_synchronizer self.submodules.link_layer = link_layer.LinkLayer( - transceiver.encoder, transceiver.decoders) - self.comb += self.link_layer.rx_ready.eq(transceiver.rx_ready) + chanif.encoder, chanif.decoders) + self.comb += self.link_layer.rx_ready.eq(chanif.rx_ready) link_layer_sync = SimpleNamespace( tx_aux_frame=self.link_layer.tx_aux_frame, @@ -85,10 +101,10 @@ class DRTIOSatellite(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( - transceiver.encoder, transceiver.decoders) - self.comb += self.link_layer.rx_ready.eq(transceiver.rx_ready) + chanif.encoder, chanif.decoders) + 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.rt_packet = rt_packet_master.RTPacketMaster(self.link_layer) diff --git a/artiq/gateware/drtio/transceiver/gtx_7series.py b/artiq/gateware/drtio/transceiver/gtx_7series.py index 026663fe0..7b6cfaecf 100644 --- a/artiq/gateware/drtio/transceiver/gtx_7series.py +++ b/artiq/gateware/drtio/transceiver/gtx_7series.py @@ -4,22 +4,26 @@ from migen.genlib.resetsync import AsyncResetSynchronizer from misoc.cores.code_8b10b import Encoder, Decoder from misoc.interconnect.csr import * +from artiq.gateware.drtio.core import TransceiverInterface, ChannelInterface 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 # frequency when clock_div2=False, and 2x that frequency when # clock_div2=True. def __init__(self, clock_pads, tx_pads, rx_pads, sys_clk_freq, clock_div2=False): - self.submodules.encoder = ClockDomainsRenamer("rtio")( + encoder = ClockDomainsRenamer("rtio")( Encoder(2, True)) - self.decoders = [ClockDomainsRenamer("rtio_rx")( - Decoder(True)) for _ in range(2)] - self.submodules += self.decoders + self.submodules += encoder + decoders = [ClockDomainsRenamer("rtio_rx0")( + (Decoder(True))) for _ in range(2)] + self.submodules += decoders - self.rx_ready = Signal() + TransceiverInterface.__init__(self, [ChannelInterface(encoder, decoders)]) # transceiver direct clock outputs # useful to specify clock constraints in a way palatable to Vivado @@ -137,8 +141,8 @@ class GTX_20X(Module): i_RXSYSCLKSEL=0b00, i_RXOUTCLKSEL=0b010, o_RXOUTCLK=self.rxoutclk, - i_RXUSRCLK=ClockSignal("rtio_rx"), - i_RXUSRCLK2=ClockSignal("rtio_rx"), + i_RXUSRCLK=ClockSignal("rtio_rx0"), + i_RXUSRCLK2=ClockSignal("rtio_rx0"), p_RXCDR_CFG=0x03000023FF10100020, # RX Clock Correction Attributes @@ -165,7 +169,6 @@ class GTX_20X(Module): tx_reset_deglitched = Signal() tx_reset_deglitched.attr.add("no_retiming") self.sync += tx_reset_deglitched.eq(~tx_init.done) - self.clock_domains.cd_rtio = ClockDomain() self.specials += [ Instance("BUFG", i_I=self.txoutclk, o_O=self.cd_rtio.clk), AsyncResetSynchronizer(self.cd_rtio, tx_reset_deglitched) @@ -173,24 +176,25 @@ class GTX_20X(Module): rx_reset_deglitched = Signal() rx_reset_deglitched.attr.add("no_retiming") self.sync.rtio += rx_reset_deglitched.eq(~rx_init.done) - self.clock_domains.cd_rtio_rx = ClockDomain() self.specials += [ - Instance("BUFG", i_I=self.rxoutclk, o_O=self.cd_rtio_rx.clk), - AsyncResetSynchronizer(self.cd_rtio_rx, rx_reset_deglitched) + Instance("BUFG", i_I=self.rxoutclk, o_O=self.cd_rtio_rx0.clk), + AsyncResetSynchronizer(self.cd_rtio_rx0, rx_reset_deglitched) ] + chan = self.channels[0] self.comb += [ - txdata.eq(Cat(self.encoder.output[0], self.encoder.output[1])), - self.decoders[0].input.eq(rxdata[:10]), - self.decoders[1].input.eq(rxdata[10:]) + txdata.eq(Cat(chan.encoder.output[0], chan.encoder.output[1])), + chan.decoders[0].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.comb += [ clock_aligner.rxdata.eq(rxdata), 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): - """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 domain. This has fixed latency. diff --git a/artiq/gateware/targets/kc705_drtio_master.py b/artiq/gateware/targets/kc705_drtio_master.py index 041cf035e..889258965 100755 --- a/artiq/gateware/targets/kc705_drtio_master.py +++ b/artiq/gateware/targets/kc705_drtio_master.py @@ -53,7 +53,8 @@ class Master(MiniSoC, AMPSoC): sys_clk_freq=self.clk_freq, 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.add_wb_slave(self.mem_map["drtio_aux"], 0x800, self.drtio0.aux_controller.bus) @@ -69,7 +70,7 @@ class Master(MiniSoC, AMPSoC): self.csr_devices.append("converter_spi") 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")) ] diff --git a/artiq/gateware/targets/kc705_drtio_satellite.py b/artiq/gateware/targets/kc705_drtio_satellite.py index 79da27254..b4579d50f 100755 --- a/artiq/gateware/targets/kc705_drtio_satellite.py +++ b/artiq/gateware/targets/kc705_drtio_satellite.py @@ -54,11 +54,12 @@ class Satellite(BaseSoC): tx_pads=platform.request("sfp_tx"), rx_pads=platform.request("sfp_rx"), sys_clk_freq=self.clk_freq) - self.submodules.rx_synchronizer = gtx_7series.RXSynchronizer( - self.transceiver.rtio_clk_freq, initial_phase=180.0) - self.submodules.drtio0 = DRTIOSatellite( - self.transceiver, rtio_channels, self.rx_synchronizer) - self.csr_devices.append("rx_synchronizer") + rx0 = ClockDomainsRenamer({"rtio_rx": "rtio_rx0"}) + self.submodules.rx_synchronizer0 = rx0(gtx_7series.RXSynchronizer( + self.transceiver.rtio_clk_freq, initial_phase=180.0)) + self.submodules.drtio0 = rx0(DRTIOSatellite( + self.transceiver.channels[0], rtio_channels, self.rx_synchronizer0)) + self.csr_devices.append("rx_synchronizer0") self.csr_devices.append("drtio0") self.add_wb_slave(self.mem_map["drtio_aux"], 0x800, self.drtio0.aux_controller.bus) @@ -71,7 +72,7 @@ class Satellite(BaseSoC): si5324_clkin = platform.request("si5324_clkin") self.specials += \ Instance("OBUFDS", - i_I=ClockSignal("rtio_rx"), + i_I=ClockSignal("rtio_rx0"), o_O=si5324_clkin.p, o_OB=si5324_clkin.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.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")) ]