diff --git a/artiq/gateware/drtio/transceiver/gtx_7series.py b/artiq/gateware/drtio/transceiver/gtx_7series.py index 7b6cfaecf..e2b1378a9 100644 --- a/artiq/gateware/drtio/transceiver/gtx_7series.py +++ b/artiq/gateware/drtio/transceiver/gtx_7series.py @@ -5,17 +5,18 @@ 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.clock_aligner import BruteforceClockAligner from artiq.gateware.drtio.transceiver.gtx_7series_init import * 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): + # Settings: + # * GTX reference clock (at clock_pads) @ 125MHz == coarse RTIO frequency + # * GTX data width = 20 + # * GTX PLL frequency @ 2.5GHz + # * GTX line rate (TX & RX) @ 2.5Gb/s + # * GTX TX/RX USRCLK @ 125MHz == coarse RTIO frequency + def __init__(self, clock_pads, tx_pads, rx_pads, sys_clk_freq): encoder = ClockDomainsRenamer("rtio")( Encoder(2, True)) self.submodules += encoder @@ -33,21 +34,17 @@ class GTX_20X(Module, TransceiverInterface): # # # refclk = Signal() - if clock_div2: - self.specials += Instance("IBUFDS_GTE2", - i_CEB=0, - i_I=clock_pads.p, - i_IB=clock_pads.n, - o_ODIV2=refclk - ) - else: - self.specials += Instance("IBUFDS_GTE2", - i_CEB=0, - i_I=clock_pads.p, - i_IB=clock_pads.n, - o_O=refclk - ) + stable_clkin_n = Signal() + self.stable_clkin.storage.attr.add("no_retiming") + self.comb += stable_clkin_n.eq(~self.stable_clkin.storage) + self.specials += Instance("IBUFDS_GTE2", + i_CEB=stable_clkin_n, + i_I=clock_pads.p, + i_IB=clock_pads.n, + o_O=refclk + ) + cpllreset = Signal() cplllock = Signal() # TX generates RTIO clock, init must be in system domain tx_init = GTXInit(sys_clk_freq, False) @@ -55,8 +52,11 @@ class GTX_20X(Module, TransceiverInterface): rx_init = ClockDomainsRenamer("rtio")( GTXInit(self.rtio_clk_freq, True)) self.submodules += tx_init, rx_init - self.comb += tx_init.cplllock.eq(cplllock), \ - rx_init.cplllock.eq(cplllock) + self.comb += [ + cpllreset.eq(tx_init.cpllreset), + tx_init.cplllock.eq(cplllock), + rx_init.cplllock.eq(cplllock) + ] txdata = Signal(20) rxdata = Signal(20) @@ -64,12 +64,11 @@ class GTX_20X(Module, TransceiverInterface): Instance("GTXE2_CHANNEL", # PMA Attributes p_PMA_RSV=0x00018480, - p_PMA_RSV2=0x2050, + p_PMA_RSV2=0x2050, # PMA_RSV2[5] = 0: Eye scan feature disabled p_PMA_RSV3=0, - p_PMA_RSV4=0, - p_RX_BIAS_CFG=0b100, - p_RX_CM_TRIM=0b010, - p_RX_OS_CFG=0b10000000, + p_PMA_RSV4=1, # PMA_RSV[4],RX_CM_TRIM[2:0] = 0b1010: Common mode 800mV + p_RX_BIAS_CFG=0b000000000100, + p_RX_OS_CFG=0b0000010000000, p_RX_CLK25_DIV=5, p_TX_CLK25_DIV=5, @@ -85,6 +84,8 @@ class GTX_20X(Module, TransceiverInterface): p_CPLL_REFCLK_DIV=1, p_RXOUT_DIV=2, p_TXOUT_DIV=2, + i_CPLLRESET=cpllreset, + i_CPLLPD=cpllreset, o_CPLLLOCK=cplllock, i_CPLLLOCKEN=1, i_CPLLREFCLKSEL=0b001, @@ -105,6 +106,9 @@ class GTX_20X(Module, TransceiverInterface): o_TXDLYSRESETDONE=tx_init.Xxdlysresetdone, o_TXPHALIGNDONE=tx_init.Xxphaligndone, i_TXUSERRDY=tx_init.Xxuserrdy, + p_TXPMARESET_TIME=1, + p_TXPCSRESET_TIME=1, + i_TXINHIBIT=~self.txenable.storage, # TX data p_TX_DATA_WIDTH=20, @@ -126,24 +130,36 @@ class GTX_20X(Module, TransceiverInterface): o_RXDLYSRESETDONE=rx_init.Xxdlysresetdone, o_RXPHALIGNDONE=rx_init.Xxphaligndone, i_RXUSERRDY=rx_init.Xxuserrdy, + p_RXPMARESET_TIME=1, + p_RXPCSRESET_TIME=1, # RX AFE p_RX_DFE_XYD_CFG=0, + p_RX_CM_SEL=0b11, # RX_CM_SEL = 0b11: Common mode is programmable + p_RX_CM_TRIM=0b010, # PMA_RSV[4],RX_CM_TRIM[2:0] = 0b1010: Common mode 800mV i_RXDFEXYDEN=1, i_RXDFEXYDHOLD=0, i_RXDFEXYDOVRDEN=0, - i_RXLPMEN=0, + i_RXLPMEN=0, # RXLPMEN = 0: DFE mode is enabled + p_RX_DFE_GAIN_CFG=0x0207EA, + p_RX_DFE_VP_CFG=0b00011111100000011, + p_RX_DFE_UT_CFG=0b10001000000000000, + p_RX_DFE_KL_CFG=0b0000011111110, + p_RX_DFE_KL_CFG2=0x3788140A, + p_RX_DFE_H2_CFG=0b000110000000, + p_RX_DFE_H3_CFG=0b000110000000, + p_RX_DFE_H4_CFG=0b00011100000, + p_RX_DFE_H5_CFG=0b00011100000, + p_RX_DFE_LPM_CFG=0x0904, # RX_DFE_LPM_CFG = 0x0904: linerate <= 6.6Gb/s + # = 0x0104: linerate > 6.6Gb/s # RX clock - p_RXBUF_EN="FALSE", - p_RX_XCLK_SEL="RXUSR", i_RXDDIEN=1, i_RXSYSCLKSEL=0b00, i_RXOUTCLKSEL=0b010, o_RXOUTCLK=self.rxoutclk, i_RXUSRCLK=ClockSignal("rtio_rx0"), i_RXUSRCLK2=ClockSignal("rtio_rx0"), - p_RXCDR_CFG=0x03000023FF10100020, # RX Clock Correction Attributes p_CLK_CORRECT_USE="FALSE", @@ -159,11 +175,77 @@ class GTX_20X(Module, TransceiverInterface): o_RXCHARISK=Cat(rxdata[8], rxdata[18]), o_RXDATA=Cat(rxdata[:8], rxdata[10:18]), + # RX Byte and Word Alignment Attributes + p_ALIGN_COMMA_DOUBLE="FALSE", + p_ALIGN_COMMA_ENABLE=0b1111111111, + p_ALIGN_COMMA_WORD=1, + p_ALIGN_MCOMMA_DET="TRUE", + p_ALIGN_MCOMMA_VALUE=0b1010000011, + p_ALIGN_PCOMMA_DET="TRUE", + p_ALIGN_PCOMMA_VALUE=0b0101111100, + p_SHOW_REALIGN_COMMA="FALSE", + p_RXSLIDE_AUTO_WAIT=7, + p_RXSLIDE_MODE="PCS", + p_RX_SIG_VALID_DLY=10, + + # RX 8B/10B Decoder Attributes + p_RX_DISPERR_SEQ_MATCH="FALSE", + p_DEC_MCOMMA_DETECT="TRUE", + p_DEC_PCOMMA_DETECT="TRUE", + p_DEC_VALID_COMMA_ONLY="FALSE", + + # RX Buffer Attributes + p_RXBUF_ADDR_MODE="FAST", + p_RXBUF_EIDLE_HI_CNT=0b1000, + p_RXBUF_EIDLE_LO_CNT=0b0000, + p_RXBUF_EN="FALSE", + p_RX_BUFFER_CFG=0b000000, + p_RXBUF_RESET_ON_CB_CHANGE="TRUE", + p_RXBUF_RESET_ON_COMMAALIGN="FALSE", + p_RXBUF_RESET_ON_EIDLE="FALSE", # RXBUF_RESET_ON_EIDLE = FALSE: OOB is disabled + p_RXBUF_RESET_ON_RATE_CHANGE="TRUE", + p_RXBUFRESET_TIME=0b00001, + p_RXBUF_THRESH_OVFLW=61, + p_RXBUF_THRESH_OVRD="FALSE", + p_RXBUF_THRESH_UNDFLW=4, + p_RXDLY_CFG=0x001F, + p_RXDLY_LCFG=0x030, + p_RXDLY_TAP_CFG=0x0000, + p_RXPH_CFG=0xC00002, + p_RXPHDLY_CFG=0x084020, + p_RXPH_MONITOR_SEL=0b00000, + p_RX_XCLK_SEL="RXUSR", + p_RX_DDI_SEL=0b000000, + p_RX_DEFER_RESET_BUF_EN="TRUE", + + # CDR Attributes + p_RXCDR_CFG=0x03000023FF20400020, # DFE @ <= 6.6Gb/s, scrambled, CDR setting < +/- 200ppm + # (See UG476 (v1.12.1), p.206) + p_RXCDR_FR_RESET_ON_EIDLE=0b0, + p_RXCDR_HOLD_DURING_EIDLE=0b0, + p_RXCDR_PH_RESET_ON_EIDLE=0b0, + p_RXCDR_LOCK_CFG=0b010101, + + # # RX Initialization and Reset Attributes + # p_RXCDRFREQRESET_TIME=0b00001, + # p_RXCDRPHRESET_TIME=0b00001, + # p_RXISCANRESET_TIME=0b00001, + # p_RXPCSRESET_TIME=0b00001, + # p_RXPMARESET_TIME=0b00011, + # Pads i_GTXRXP=rx_pads.p, i_GTXRXN=rx_pads.n, o_GTXTXP=tx_pads.p, o_GTXTXN=tx_pads.n, + + # Other parameters + p_PCS_RSVD_ATTR=0x000, # PCS_RSVD_ATTR[1] = 0: TX Single Lane Auto Mode + # [2] = 0: RX Single Lane Auto Mode + # [8] = 0: OOB is disabled + i_RXELECIDLEMODE=0b11, # RXELECIDLEMODE = 0b11: OOB is disabled + p_RX_DFE_LPM_HOLD_DURING_EIDLE=0b0, + p_ES_EYE_SCAN_EN="TRUE", # Must be TRUE for GTX ) tx_reset_deglitched = Signal() @@ -199,7 +281,7 @@ class GTX_20X(Module, TransceiverInterface): class GTX_1000BASE_BX10(GTX_20X): - rtio_clk_freq = 62.5e6 + rtio_clk_freq = 125e6 class RXSynchronizer(Module, AutoCSR): diff --git a/artiq/gateware/drtio/transceiver/gtx_7series_init.py b/artiq/gateware/drtio/transceiver/gtx_7series_init.py index 2b7ae39bc..6598f2892 100644 --- a/artiq/gateware/drtio/transceiver/gtx_7series_init.py +++ b/artiq/gateware/drtio/transceiver/gtx_7series_init.py @@ -16,6 +16,7 @@ class GTXInit(Module): # GTX signals self.cplllock = Signal() + self.cpllreset = Signal() self.gtXxreset = Signal() self.Xxresetdone = Signal() self.Xxdlysreset = Signal() @@ -53,6 +54,12 @@ class GTXInit(Module): startup_timer = WaitTimer(startup_cycles) self.submodules += startup_timer + # PLL reset should be 1 period of refclk + # (i.e. 1/(125MHz) for the case of RTIO @ 125MHz) + pll_reset_cycles = ceil(sys_clk_freq/125e6) + pll_reset_timer = WaitTimer(pll_reset_cycles) + self.submodules += pll_reset_timer + startup_fsm = FSM(reset_state="INITIAL") self.submodules += startup_fsm @@ -67,27 +74,29 @@ class GTXInit(Module): startup_fsm.act("INITIAL", startup_timer.wait.eq(1), - If(startup_timer.done, NextState("RESET_GTX")) + If(startup_timer.done, NextState("RESET_ALL")) ) - startup_fsm.act("RESET_GTX", + startup_fsm.act("RESET_ALL", gtXxreset.eq(1), - NextState("WAIT_CPLL") + self.cpllreset.eq(1), + pll_reset_timer.wait.eq(1), + If(pll_reset_timer.done, NextState("RELEASE_PLL_RESET")) ) - startup_fsm.act("WAIT_CPLL", + startup_fsm.act("RELEASE_PLL_RESET", gtXxreset.eq(1), - If(cplllock, NextState("RELEASE_RESET")) + If(cplllock, NextState("RELEASE_GTH_RESET")) ) # Release GTX reset and wait for GTX resetdone # (from UG476, GTX is reset on falling edge # of gttxreset) if rx: - startup_fsm.act("RELEASE_RESET", + startup_fsm.act("RELEASE_GTH_RESET", Xxuserrdy.eq(1), cdr_stable_timer.wait.eq(1), If(Xxresetdone & cdr_stable_timer.done, NextState("ALIGN")) ) else: - startup_fsm.act("RELEASE_RESET", + startup_fsm.act("RELEASE_GTH_RESET", Xxuserrdy.eq(1), If(Xxresetdone, NextState("ALIGN")) ) @@ -115,7 +124,7 @@ class GTXInit(Module): startup_fsm.act("READY", Xxuserrdy.eq(1), self.done.eq(1), - If(self.restart, NextState("RESET_GTX")) + If(self.restart, NextState("RESET_ALL")) ) diff --git a/artiq/gateware/targets/kc705_drtio_satellite.py b/artiq/gateware/targets/kc705_drtio_satellite.py index 0f318a0d3..048b1153e 100755 --- a/artiq/gateware/targets/kc705_drtio_satellite.py +++ b/artiq/gateware/targets/kc705_drtio_satellite.py @@ -5,6 +5,9 @@ import os from migen import * from migen.build.generic_platform import * +from migen.build.xilinx.vivado import XilinxVivadoToolchain +from migen.build.xilinx.ise import XilinxISEToolchain + from misoc.cores import spi as spi_csr from misoc.cores import gpio from misoc.integration.builder import * @@ -13,27 +16,101 @@ from misoc.targets.kc705 import BaseSoC, soc_kc705_args, soc_kc705_argdict from artiq.gateware import rtio from artiq.gateware.rtio.phy import ttl_simple from artiq.gateware.drtio.transceiver import gtx_7series -from artiq.gateware.drtio import DRTIOSatellite -from artiq import __version__ as artiq_version -from artiq import __artiq_dir__ as artiq_dir +from artiq.gateware.drtio.siphaser import SiPhaser7Series +from artiq.gateware.drtio.rx_synchronizer import XilinxRXSynchronizer +from artiq.gateware.drtio import * +from artiq.build_soc import * + +# DEBUG +from microscope import * class Satellite(BaseSoC): mem_map = { - "drtio_aux": 0x50000000, + "drtioaux": 0x50000000, } mem_map.update(BaseSoC.mem_map) - def __init__(self, **kwargs): + def __init__(self, gateware_identifier_str=None, **kwargs): BaseSoC.__init__(self, cpu_type="or1k", sdram_controller_type="minicon", l2_size=128*1024, - ident=artiq_version, + integrated_sram_size=8192, **kwargs) + add_identifier(self, gateware_identifier_str=gateware_identifier_str) + + if isinstance(self.platform.toolchain, XilinxVivadoToolchain): + self.platform.toolchain.bitstream_commands.extend([ + "set_property BITSTREAM.GENERAL.COMPRESS True [current_design]", + ]) + if isinstance(self.platform.toolchain, XilinxISEToolchain): + self.platform.toolchain.bitgen_opt += " -g compress" platform = self.platform + self.comb += platform.request("sfp_tx_disable_n").eq(1) + tx_pads = platform.request("sfp_tx") + rx_pads = platform.request("sfp_rx") + + # 1000BASE_BX10 Ethernet compatible, 125MHz RTIO clock + self.submodules.drtio_transceiver = gtx_7series.GTX_1000BASE_BX10( + clock_pads=platform.request("si5324_clkout"), + tx_pads=tx_pads, + rx_pads=rx_pads, + sys_clk_freq=self.clk_freq) + self.csr_devices.append("drtio_transceiver") + + self.submodules.rtio_tsc = rtio.TSC("sync", glbl_fine_ts_width=3) + cdr = ClockDomainsRenamer({"rtio_rx": "rtio_rx0"}) + + self.submodules.rx_synchronizer = cdr(XilinxRXSynchronizer()) + self.submodules.drtiosat = cdr(DRTIOSatellite( + self.rtio_tsc, self.drtio_transceiver.channels[0], self.rx_synchronizer)) + self.csr_devices.append("drtiosat") + + self.submodules.drtioaux0 = cdr(DRTIOAuxController( + self.drtiosat.link_layer)) + self.csr_devices.append("drtioaux0") + self.add_wb_slave(self.mem_map["drtioaux"], 0x800, + self.drtioaux0.bus) + self.add_memory_region("drtioaux0_mem", self.mem_map["drtioaux"] | self.shadow_base, 0x800) + + self.config["HAS_DRTIO"] = None + self.add_csr_group("drtio", ["drtiosat"]) + self.add_csr_group("drtioaux", ["drtioaux0"]) + self.add_memory_group("drtioaux_mem", ["drtioaux0_mem"]) + + self.config["RTIO_FREQUENCY"] = str(self.drtio_transceiver.rtio_clk_freq/1e6) + # Si5324 Phaser + self.submodules.siphaser = SiPhaser7Series( + si5324_clkin=platform.request("si5324_clkin"), + rx_synchronizer=self.rx_synchronizer, + ultrascale=False, + rtio_clk_freq=self.drtio_transceiver.rtio_clk_freq) + platform.add_false_path_constraints( + self.crg.cd_sys.clk, self.siphaser.mmcm_freerun_output) + self.csr_devices.append("siphaser") + self.submodules.si5324_rst_n = gpio.GPIOOut(platform.request("si5324").rst_n) + self.csr_devices.append("si5324_rst_n") + i2c = self.platform.request("i2c") + self.submodules.i2c = gpio.GPIOTristate([i2c.scl, i2c.sda]) + self.csr_devices.append("i2c") + self.config["I2C_BUS_COUNT"] = 1 + self.config["HAS_SI5324"] = None + + self.comb += [ + platform.request("user_sma_clock_p").eq(ClockSignal("rtio_rx0")), + platform.request("user_sma_clock_n").eq(ClockSignal("rtio")) + ] + + rtio_clk_period = 1e9/self.drtio_transceiver.rtio_clk_freq + platform.add_period_constraint(self.drtio_transceiver.txoutclk, rtio_clk_period) + platform.add_period_constraint(self.drtio_transceiver.rxoutclk, rtio_clk_period) + platform.add_false_path_constraints( + self.crg.cd_sys.clk, + self.drtio_transceiver.txoutclk, self.drtio_transceiver.rxoutclk) + rtio_channels = [] for i in range(8): phy = ttl_simple.Output(platform.request("user_led", i)) @@ -47,54 +124,9 @@ class Satellite(BaseSoC): self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) self.csr_devices.append("rtio_moninj") - self.comb += platform.request("sfp_tx_disable_n").eq(1) - - # 1000BASE_BX10 Ethernet compatible, 62.5MHz RTIO clock - self.submodules.transceiver = gtx_7series.GTX_1000BASE_BX10( - clock_pads=platform.request("si5324_clkout"), - tx_pads=platform.request("sfp_tx"), - rx_pads=platform.request("sfp_rx"), - sys_clk_freq=self.clk_freq) - 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) - self.add_memory_region("drtio0_aux", self.mem_map["drtio_aux"] | self.shadow_base, 0x800) - self.config["HAS_DRTIO"] = None - self.add_csr_group("drtio", ["drtio0"]) - self.add_memory_group("drtio_aux", ["drtio0_aux"]) - - self.config["RTIO_FREQUENCY"] = str(self.transceiver.rtio_clk_freq/1e6) - si5324_clkin = platform.request("si5324_clkin") - self.specials += \ - Instance("OBUFDS", - 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) - self.csr_devices.append("si5324_rst_n") - i2c = self.platform.request("i2c") - self.submodules.i2c = gpio.GPIOTristate([i2c.scl, i2c.sda]) - self.csr_devices.append("i2c") - self.config["I2C_BUS_COUNT"] = 1 - self.config["HAS_SI5324"] = None - - self.comb += [ - platform.request("user_sma_clock_p").eq(ClockSignal("rtio_rx0")), - platform.request("user_sma_clock_n").eq(ClockSignal("rtio")) - ] - - rtio_clk_period = 1e9/self.transceiver.rtio_clk_freq - platform.add_period_constraint(self.transceiver.txoutclk, rtio_clk_period) - platform.add_period_constraint(self.transceiver.rxoutclk, rtio_clk_period) - platform.add_false_path_constraints( - platform.lookup_request("clk200"), - self.transceiver.txoutclk, self.transceiver.rxoutclk) + self.submodules.local_io = SyncRTIO(self.rtio_tsc, rtio_channels) + self.comb += self.drtiosat.async_errors.eq(self.local_io.async_errors) + self.comb += self.drtiosat.cri.connect(self.local_io.cri) def main(): @@ -102,12 +134,11 @@ def main(): description="ARTIQ device binary builder / KC705 DRTIO satellite") builder_args(parser) soc_kc705_args(parser) + parser.set_defaults(output_dir="artiq_kc705/satellite") args = parser.parse_args() soc = Satellite(**soc_kc705_argdict(args)) - builder = Builder(soc, **builder_argdict(args)) - builder.add_software_package("satman", os.path.join(artiq_dir, "firmware", "satman")) - builder.build() + build_artiq_soc(soc, builder_argdict(args)) if __name__ == "__main__":