#!/usr/bin/env python3 import argparse from migen import * from migen.genlib.resetsync import AsyncResetSynchronizer from migen.genlib.cdc import MultiReg from migen.build.generic_platform import * from migen.build.xilinx.vivado import XilinxVivadoToolchain from migen.build.xilinx.ise import XilinxISEToolchain from misoc.interconnect.csr import * from misoc.cores import gpio, timer from misoc.targets.kc705 import MiniSoC, soc_kc705_args, soc_kc705_argdict from misoc.integration.builder import builder_args, builder_argdict from artiq.gateware.amp import AMPSoC from artiq.gateware import rtio, nist_clock, nist_qc2 from artiq.gateware.rtio.phy import (ttl_simple, ttl_serdes_7series, dds, spi2, ad53xx_monitor) from artiq.build_soc import build_artiq_soc from artiq import __version__ as artiq_version class _RTIOCRG(Module, AutoCSR): def __init__(self, platform, rtio_internal_clk, use_sma=True): self._clock_sel = CSRStorage() self._pll_reset = CSRStorage(reset=1) self._pll_locked = CSRStatus() self.clock_domains.cd_rtio = ClockDomain() self.clock_domains.cd_rtiox4 = ClockDomain(reset_less=True) # 100 MHz when using 125MHz input self.clock_domains.cd_ext_clkout = ClockDomain(reset_less=True) platform.add_period_constraint(self.cd_ext_clkout.clk, 5.0) if use_sma: ext_clkout = platform.request("user_sma_gpio_p_33") self.sync.ext_clkout += ext_clkout.eq(~ext_clkout) rtio_external_clk = Signal() if use_sma: user_sma_clock = platform.request("user_sma_clock") platform.add_period_constraint(user_sma_clock.p, 8.0) self.specials += Instance("IBUFDS", i_I=user_sma_clock.p, i_IB=user_sma_clock.n, o_O=rtio_external_clk) pll_locked = Signal() rtio_clk = Signal() rtiox4_clk = Signal() ext_clkout_clk = Signal() self.specials += [ Instance("PLLE2_ADV", p_STARTUP_WAIT="FALSE", o_LOCKED=pll_locked, p_REF_JITTER1=0.01, p_CLKIN1_PERIOD=8.0, p_CLKIN2_PERIOD=8.0, i_CLKIN1=rtio_internal_clk, i_CLKIN2=rtio_external_clk, # Warning: CLKINSEL=0 means CLKIN2 is selected i_CLKINSEL=~self._clock_sel.storage, # VCO @ 1GHz when using 125MHz input p_CLKFBOUT_MULT=8, p_DIVCLK_DIVIDE=1, i_CLKFBIN=self.cd_rtio.clk, i_RST=self._pll_reset.storage, o_CLKFBOUT=rtio_clk, p_CLKOUT0_DIVIDE=2, p_CLKOUT0_PHASE=0.0, o_CLKOUT0=rtiox4_clk, p_CLKOUT1_DIVIDE=5, p_CLKOUT1_PHASE=0.0, o_CLKOUT1=ext_clkout_clk), Instance("BUFG", i_I=rtio_clk, o_O=self.cd_rtio.clk), Instance("BUFG", i_I=rtiox4_clk, o_O=self.cd_rtiox4.clk), Instance("BUFG", i_I=ext_clkout_clk, o_O=self.cd_ext_clkout.clk), AsyncResetSynchronizer(self.cd_rtio, ~pll_locked), MultiReg(pll_locked, self._pll_locked.status) ] # The default user SMA voltage on KC705 is 2.5V, and the Migen platform # follows this default. But since the SMAs are on the same bank as the DDS, # which is set to 3.3V by reprogramming the KC705 power ICs, we need to # redefine them here. _sma33_io = [ ("user_sma_gpio_p_33", 0, Pins("Y23"), IOStandard("LVCMOS33")), ("user_sma_gpio_n_33", 0, Pins("Y24"), IOStandard("LVCMOS33")), ] _ams101_dac = [ ("ams101_dac", 0, Subsignal("ldac", Pins("XADC:GPIO0")), Subsignal("clk", Pins("XADC:GPIO1")), Subsignal("mosi", Pins("XADC:GPIO2")), Subsignal("cs_n", Pins("XADC:GPIO3")), IOStandard("LVTTL") ) ] _sdcard_spi_33 = [ ("sdcard_spi_33", 0, Subsignal("miso", Pins("AC20"), Misc("PULLUP=TRUE")), Subsignal("clk", Pins("AB23")), Subsignal("mosi", Pins("AB22")), Subsignal("cs_n", Pins("AC21")), IOStandard("LVCMOS33") ) ] _zotino = [ ("fmcdio_dirctl", 0, Subsignal("clk", Pins("HPC:LA32_N")), Subsignal("ser", Pins("HPC:LA33_P")), Subsignal("latch", Pins("HPC:LA32_P")), IOStandard("LVCMOS25") ), ("zotino_spi_p", 0, Subsignal("clk", Pins("HPC:LA08_P")), Subsignal("mosi", Pins("HPC:LA09_P")), Subsignal("miso", Pins("HPC:LA10_P")), Subsignal("cs_n", Pins("HPC:LA11_P")), IOStandard("LVDS_25") ), ("zotino_spi_n", 0, Subsignal("clk", Pins("HPC:LA08_N")), Subsignal("mosi", Pins("HPC:LA09_N")), Subsignal("miso", Pins("HPC:LA10_N")), Subsignal("cs_n", Pins("HPC:LA11_N")), IOStandard("LVDS_25") ), ("zotino_ldac", 0, Subsignal("p", Pins("HPC:LA13_P")), Subsignal("n", Pins("HPC:LA13_N")), IOStandard("LVDS_25"), Misc("DIFF_TERM=TRUE") ) ] # FMC DIO 32ch LVDS a v1.2 on HPC to VHDCI-Carrier v1.1 # uring the upper/right VHDCI connector: LVDS7 and LVDS8 # using the lower/left VHDCI connector: LVDS3 and LVDS4 _urukul = [ ("urukul_spi_p", 0, Subsignal("clk", Pins("HPC:LA17_CC_P")), Subsignal("mosi", Pins("HPC:LA16_P")), Subsignal("miso", Pins("HPC:LA24_P")), Subsignal("cs_n", Pins("HPC:LA19_P HPC:LA20_P HPC:LA21_P")), IOStandard("LVDS_25"), ), ("urukul_spi_n", 0, Subsignal("clk", Pins("HPC:LA17_CC_N")), Subsignal("mosi", Pins("HPC:LA16_N")), Subsignal("miso", Pins("HPC:LA24_N")), Subsignal("cs_n", Pins("HPC:LA19_N HPC:LA20_N HPC:LA21_N")), IOStandard("LVDS_25"), ), ("urukul_io_update", 0, Subsignal("p", Pins("HPC:LA22_P")), Subsignal("n", Pins("HPC:LA22_N")), IOStandard("LVDS_25"), ), ("urukul_dds_reset", 0, Subsignal("p", Pins("HPC:LA23_P")), Subsignal("n", Pins("HPC:LA23_N")), IOStandard("LVDS_25"), ), ("urukul_sync_clk", 0, Subsignal("p", Pins("HPC:LA18_CC_P")), Subsignal("n", Pins("HPC:LA18_CC_N")), IOStandard("LVDS_25"), ), ("urukul_sync_in", 0, Subsignal("p", Pins("HPC:LA25_P")), Subsignal("n", Pins("HPC:LA25_N")), IOStandard("LVDS_25"), ), ("urukul_io_update_ret", 0, Subsignal("p", Pins("HPC:LA26_P")), Subsignal("n", Pins("HPC:LA26_N")), IOStandard("LVDS_25"), ), ("urukul_sw0", 0, Subsignal("p", Pins("HPC:LA28_P")), Subsignal("n", Pins("HPC:LA28_N")), IOStandard("LVDS_25"), ), ("urukul_sw1", 0, Subsignal("p", Pins("HPC:LA29_P")), Subsignal("n", Pins("HPC:LA29_N")), IOStandard("LVDS_25"), ), ("urukul_sw2", 0, Subsignal("p", Pins("HPC:LA30_P")), Subsignal("n", Pins("HPC:LA30_N")), IOStandard("LVDS_25"), ), ("urukul_sw3", 0, Subsignal("p", Pins("HPC:LA31_P")), Subsignal("n", Pins("HPC:LA31_N")), IOStandard("LVDS_25"), ) ] class _StandaloneBase(MiniSoC, AMPSoC): mem_map = { "cri_con": 0x10000000, "rtio": 0x20000000, "rtio_dma": 0x30000000, "mailbox": 0x70000000 } mem_map.update(MiniSoC.mem_map) def __init__(self, **kwargs): MiniSoC.__init__(self, cpu_type="or1k", sdram_controller_type="minicon", l2_size=128*1024, ident=artiq_version, ethmac_nrxslots=4, ethmac_ntxslots=4, **kwargs) AMPSoC.__init__(self) 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" self.submodules.timer1 = timer.Timer() self.csr_devices.append("timer1") self.interrupt_devices.append("timer1") self.submodules.leds = gpio.GPIOOut(Cat( self.platform.request("user_led", 0), self.platform.request("user_led", 1))) self.csr_devices.append("leds") self.platform.add_extension(_sma33_io) self.platform.add_extension(_ams101_dac) self.platform.add_extension(_sdcard_spi_33) self.platform.add_extension(_zotino) self.platform.add_extension(_urukul) 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_DDS"] = None def add_rtio(self, rtio_channels): self.submodules.rtio_crg = _RTIOCRG(self.platform, self.crg.cd_sys.clk) self.csr_devices.append("rtio_crg") self.submodules.rtio_core = rtio.Core(rtio_channels) self.csr_devices.append("rtio_core") self.submodules.rtio = rtio.KernelInitiator() self.submodules.rtio_dma = ClockDomainsRenamer("sys_kernel")( rtio.DMA(self.get_native_sdram_if())) self.register_kernel_cpu_csrdevice("rtio") self.register_kernel_cpu_csrdevice("rtio_dma") self.submodules.cri_con = rtio.CRIInterconnectShared( [self.rtio.cri, self.rtio_dma.cri], [self.rtio_core.cri]) self.register_kernel_cpu_csrdevice("cri_con") self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) self.csr_devices.append("rtio_moninj") self.platform.add_period_constraint(self.rtio_crg.cd_rtio.clk, 8.) self.platform.add_false_path_constraints( self.crg.cd_sys.clk, self.rtio_crg.cd_rtio.clk) self.submodules.rtio_analyzer = rtio.Analyzer(self.rtio_core.cri, self.get_native_sdram_if()) self.csr_devices.append("rtio_analyzer") class NIST_CLOCK(_StandaloneBase): """ NIST clock hardware, with old backplane and 11 DDS channels """ def __init__(self, **kwargs): _StandaloneBase.__init__(self, **kwargs) platform = self.platform platform.add_extension(nist_clock.fmc_adapter_io) rtio_channels = [] for i in range(16): if i % 4 == 3: phy = ttl_serdes_7series.InOut_8X(platform.request("ttl", i)) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=512)) else: phy = ttl_serdes_7series.Output_8X(platform.request("ttl", i)) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) for i in range(2): phy = ttl_serdes_7series.InOut_8X(platform.request("pmt", i)) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=512)) phy = ttl_serdes_7series.InOut_8X(platform.request("user_sma_gpio_n_33")) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=512)) phy = ttl_simple.Output(platform.request("user_led", 2)) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) ams101_dac = self.platform.request("ams101_dac", 0) phy = ttl_simple.Output(ams101_dac.ldac) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) phy = ttl_simple.ClockGen(platform.request("la32_p")) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) phy = spi2.SPIMaster(ams101_dac) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy( phy, ififo_depth=4)) for i in range(3): phy = spi2.SPIMaster(self.platform.request("spi", i)) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy( phy, ififo_depth=128)) phy = spi2.SPIMaster(platform.request("sdcard_spi_33")) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy( phy, ififo_depth=4)) fmcdio_dirctl = self.platform.request("fmcdio_dirctl") for s in fmcdio_dirctl.clk, fmcdio_dirctl.ser, fmcdio_dirctl.latch: phy = ttl_simple.Output(s) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) sdac_phy = spi2.SPIMaster(self.platform.request("zotino_spi_p"), self.platform.request("zotino_spi_n")) self.submodules += sdac_phy rtio_channels.append(rtio.Channel.from_phy(sdac_phy, ififo_depth=4)) pads = platform.request("zotino_ldac") ldac_phy = ttl_serdes_7series.Output_8X(pads.p, pads.n) self.submodules += ldac_phy rtio_channels.append(rtio.Channel.from_phy(ldac_phy)) dac_monitor = ad53xx_monitor.AD53XXMonitor(sdac_phy.rtlink, ldac_phy.rtlink) self.submodules += dac_monitor sdac_phy.probes.extend(dac_monitor.probes) phy = spi2.SPIMaster(self.platform.request("urukul_spi_p"), self.platform.request("urukul_spi_n")) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) for signal in "io_update dds_reset sw0 sw1 sw2 sw3".split(): pads = platform.request("urukul_{}".format(signal)) phy = ttl_serdes_7series.Output_8X(pads.p, pads.n) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) phy = dds.AD9914(platform.request("dds"), 11, onehot=True) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) self.config["HAS_RTIO_LOG"] = None self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels) rtio_channels.append(rtio.LogChannel()) self.add_rtio(rtio_channels) class NIST_QC2(_StandaloneBase): """ NIST QC2 hardware, as used in Quantum I and Quantum II, with new backplane and 24 DDS channels. Two backplanes are used. """ def __init__(self, **kwargs): _StandaloneBase.__init__(self, **kwargs) platform = self.platform platform.add_extension(nist_qc2.fmc_adapter_io) rtio_channels = [] clock_generators = [] # All TTL channels are In+Out capable for i in range(40): phy = ttl_serdes_7series.InOut_8X( platform.request("ttl", i)) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=512)) # CLK0, CLK1 are for clock generators, on backplane SMP connectors for i in range(2): phy = ttl_simple.ClockGen( platform.request("clkout", i)) self.submodules += phy clock_generators.append(rtio.Channel.from_phy(phy)) # user SMA on KC705 board phy = ttl_serdes_7series.InOut_8X(platform.request("user_sma_gpio_n_33")) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=512)) phy = ttl_simple.Output(platform.request("user_led", 2)) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) # AMS101 DAC on KC705 XADC header - optional ams101_dac = self.platform.request("ams101_dac", 0) phy = ttl_simple.Output(ams101_dac.ldac) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) # add clock generators after TTLs rtio_channels += clock_generators phy = spi2.SPIMaster(ams101_dac) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy( phy, ififo_depth=4)) for i in range(4): phy = spi2.SPIMaster(self.platform.request("spi", i)) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy( phy, ififo_depth=128)) for backplane_offset in range(2): phy = dds.AD9914( platform.request("dds", backplane_offset), 12, onehot=True) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) self.config["HAS_RTIO_LOG"] = None self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels) rtio_channels.append(rtio.LogChannel()) self.add_rtio(rtio_channels) _sma_spi = [ ("sma_spi", 0, Subsignal("clk", Pins("Y23")), # user_sma_gpio_p Subsignal("cs_n", Pins("Y24")), # user_sma_gpio_n Subsignal("mosi", Pins("L25")), # user_sma_clk_p Subsignal("miso", Pins("K25")), # user_sma_clk_n IOStandard("LVCMOS25")), ] class SMA_SPI(_StandaloneBase): """ SPI on 4 SMA for PDQ2 test/demo. """ def __init__(self, **kwargs): _StandaloneBase.__init__(self, **kwargs) platform = self.platform self.platform.add_extension(_sma_spi) rtio_channels = [] phy = ttl_simple.Output(platform.request("user_led", 2)) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) ams101_dac = self.platform.request("ams101_dac", 0) phy = ttl_simple.Output(ams101_dac.ldac) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) phy = spi2.SPIMaster(ams101_dac) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy( phy, ififo_depth=4)) phy = spi2.SPIMaster(self.platform.request("sma_spi")) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy( phy, ififo_depth=128)) self.config["HAS_RTIO_LOG"] = None self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels) rtio_channels.append(rtio.LogChannel()) self.add_rtio(rtio_channels) def add_rtio(self, rtio_channels): self.submodules.rtio_crg = _RTIOCRG(self.platform, self.crg.cd_sys.clk, use_sma=False) self.csr_devices.append("rtio_crg") self.submodules.rtio_core = rtio.Core(rtio_channels) self.csr_devices.append("rtio_core") self.submodules.rtio = rtio.KernelInitiator() self.submodules.rtio_dma = ClockDomainsRenamer("sys_kernel")( rtio.DMA(self.get_native_sdram_if())) self.register_kernel_cpu_csrdevice("rtio") self.register_kernel_cpu_csrdevice("rtio_dma") self.submodules.cri_con = rtio.CRIInterconnectShared( [self.rtio.cri, self.rtio_dma.cri], [self.rtio_core.cri]) self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) self.csr_devices.append("rtio_moninj") self.platform.add_period_constraint(self.rtio_crg.cd_rtio.clk, 8.) self.platform.add_false_path_constraints( self.crg.cd_sys.clk, self.rtio_crg.cd_rtio.clk) self.submodules.rtio_analyzer = rtio.Analyzer(self.rtio_core.cri, self.get_native_sdram_if()) self.csr_devices.append("rtio_analyzer") def main(): parser = argparse.ArgumentParser( description="KC705 gateware and firmware builder") builder_args(parser) soc_kc705_args(parser) parser.set_defaults(output_dir="artiq_kc705") parser.add_argument("-V", "--variant", default="nist_clock", help="variant: " "nist_clock/nist_qc2/sma_spi " "(default: %(default)s)") args = parser.parse_args() variant = args.variant.lower() if variant == "nist_clock": cls = NIST_CLOCK elif variant == "nist_qc2": cls = NIST_QC2 elif variant == "sma_spi": cls = SMA_SPI else: raise SystemExit("Invalid variant (-V/--variant)") soc = cls(**soc_kc705_argdict(args)) build_artiq_soc(soc, builder_argdict(args)) if __name__ == "__main__": main()