#!/usr/bin/env python3.5 import argparse from migen import * from migen.genlib.resetsync import AsyncResetSynchronizer from migen.genlib.cdc import MultiReg from migen.genlib.io import DifferentialInput from jesd204b.common import (JESD204BTransportSettings, JESD204BPhysicalSettings, JESD204BSettings) from jesd204b.phy.gtx import GTXQuadPLL from jesd204b.phy import JESD204BPhyTX from jesd204b.core import JESD204BCoreTX from jesd204b.core import JESD204BCoreTXControl from misoc.interconnect.csr import * from misoc.cores import gpio from misoc.cores import spi as spi_csr from misoc.targets.kc705 import MiniSoC, soc_kc705_args, soc_kc705_argdict from misoc.integration.builder import builder_args, builder_argdict from artiq.gateware.soc import AMPSoC, build_artiq_soc from artiq.gateware import rtio from artiq.gateware.ad9154_fmc_ebz import ad9154_fmc_ebz from artiq.gateware.rtio.phy import (ttl_simple, ttl_serdes_7series, sawg) from artiq import __version__ as artiq_version class _PhaserCRG(Module, AutoCSR): def __init__(self, platform, refclk): 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) pll_locked = Signal() rtio_clk = Signal() rtiox4_clk = Signal() self.specials += [ Instance("PLLE2_ADV", p_STARTUP_WAIT="FALSE", o_LOCKED=pll_locked, p_REF_JITTER1=0.01, p_REF_JITTER2=0.01, p_CLKIN1_PERIOD=20/3, p_CLKIN2_PERIOD=20/3, i_CLKIN1=0, i_CLKIN2=refclk, # Warning: CLKINSEL=0 means CLKIN2 is selected i_CLKINSEL=~self._clock_sel.storage, # VCO @ 1.2GHz when using 150MHz 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, ), Instance("BUFG", i_I=rtio_clk, o_O=self.cd_rtio.clk), Instance("BUFG", i_I=rtiox4_clk, o_O=self.cd_rtiox4.clk), AsyncResetSynchronizer(self.cd_rtio, ~pll_locked), MultiReg(pll_locked | ~self._clock_sel.storage, self._pll_locked.status) ] self.cd_rtio.clk.attr.add("keep") platform.add_period_constraint(self.cd_rtio.clk, 20/3) class AD9154JESD(Module, AutoCSR): def __init__(self, platform): ps = JESD204BPhysicalSettings(l=4, m=4, n=16, np=16) ts = JESD204BTransportSettings(f=2, s=1, k=16, cs=1) settings = JESD204BSettings(ps, ts, did=0x5a, bid=0x5) linerate = 6e9 refclk_freq = 150e6 fabric_freq = 150*1000*1000 sync_pads = platform.request("ad9154_sync") self.jsync = Signal() self.specials += DifferentialInput( sync_pads.p, sync_pads.n, self.jsync) refclk = Signal() self.clock_domains.cd_jesd = ClockDomain() refclk_pads = platform.request("ad9154_refclk") self.specials += [ Instance("IBUFDS_GTE2", i_CEB=0, i_I=refclk_pads.p, i_IB=refclk_pads.n, o_O=refclk), Instance("BUFG", i_I=refclk, o_O=self.cd_jesd.clk), AsyncResetSynchronizer(self.cd_jesd, ResetSignal("rio_phy")), ] self.cd_jesd.clk.attr.add("keep") platform.add_period_constraint(self.cd_jesd.clk, 1e9/refclk_freq) qpll = GTXQuadPLL(refclk, refclk_freq, linerate) self.submodules += qpll self.phys = [] for i in range(4): phy = JESD204BPhyTX( qpll, platform.request("ad9154_jesd", i), fabric_freq) phy.gtx.cd_tx.clk.attr.add("keep") platform.add_period_constraint(phy.gtx.cd_tx.clk, 40*1e9/linerate) platform.add_false_path_constraints(self.cd_jesd.clk, phy.gtx.cd_tx.clk) self.phys.append(phy) to_jesd = ClockDomainsRenamer("jesd") self.submodules.core = to_jesd(JESD204BCoreTX(self.phys, settings, converter_data_width=32)) self.submodules.control = to_jesd(JESD204BCoreTXControl(self.core)) self.comb += [ platform.request("ad9154_txen", 0).eq(1), platform.request("ad9154_txen", 1).eq(1), self.core.start.eq(self.jsync), platform.request("user_led", 3).eq(self.jsync), ] # blinking leds for transceiver reset status for i in range(4): counter = Signal(max=fabric_freq) self.comb += platform.request("user_led", 4 + i).eq(counter[-1]) sync = getattr(self.sync, "phy{}_tx".format(i)) sync += [ counter.eq(counter - 1), If(counter == 0, counter.eq(fabric_freq - 1) ) ] class AD9154(Module, AutoCSR): def __init__(self, platform): ad9154_spi = platform.request("ad9154_spi") self.comb += ad9154_spi.en.eq(1) self.submodules.spi = spi_csr.SPIMaster(ad9154_spi) self.submodules.jesd = AD9154JESD(platform) self.sawgs = [sawg.Channel(width=16, parallelism=2) for i in range(4)] self.submodules += self.sawgs for conv, ch in zip(self.jesd.core.sink.flatten(), self.sawgs): self.sync.jesd += conv.eq(Cat(ch.o)) class Phaser(MiniSoC, AMPSoC): mem_map = { "timer_kernel": 0x10000000, # (shadow @0x90000000) "rtio": 0x20000000, # (shadow @0xa0000000) "i2c": 0x30000000, # (shadow @0xb0000000) "mailbox": 0x70000000, # (shadow @0xf0000000) "ad9154": 0x50000000, } mem_map.update(MiniSoC.mem_map) def __init__(self, cpu_type="or1k", **kwargs): MiniSoC.__init__(self, cpu_type=cpu_type, sdram_controller_type="minicon", l2_size=128*1024, with_timer=False, ident=artiq_version, **kwargs) AMPSoC.__init__(self) self.platform.toolchain.bitstream_commands.extend([ "set_property BITSTREAM.GENERAL.COMPRESS True [current_design]", ]) platform = self.platform platform.add_extension(ad9154_fmc_ebz) self.submodules.leds = gpio.GPIOOut(Cat( platform.request("user_led", 0), platform.request("user_led", 1))) self.csr_devices.append("leds") i2c = platform.request("i2c") self.submodules.i2c = gpio.GPIOTristate([i2c.scl, i2c.sda]) self.register_kernel_cpu_csrdevice("i2c") self.config["I2C_BUS_COUNT"] = 1 self.submodules.ad9154 = AD9154(platform) self.register_kernel_cpu_csrdevice("ad9154") self.config["AD9154_DAC_CS"] = 1 << 0 self.config["AD9154_CLK_CS"] = 1 << 1 rtio_channels = [] phy = ttl_serdes_7series.Inout_8X( platform.request("user_sma_gpio_n")) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=128)) phy = ttl_simple.Output(platform.request("user_led", 2)) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) sysref_pads = platform.request("ad9154_sysref") phy = ttl_serdes_7series.Input_8X(sysref_pads.p, sysref_pads.n) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=32, ofifo_depth=2)) phy = ttl_simple.Input(self.ad9154.jesd.jsync) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=32, ofifo_depth=2)) self.config["RTIO_REGULAR_TTL_COUNT"] = len(rtio_channels) self.config["RTIO_FIRST_SAWG_CHANNEL"] = len(rtio_channels) rtio_channels.extend(rtio.Channel.from_phy(phy) for sawg in self.ad9154.sawgs for phy in sawg.phys) self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels) rtio_channels.append(rtio.LogChannel()) self.config["RTIO_FIRST_DDS_CHANNEL"] = len(rtio_channels) self.config["RTIO_DDS_COUNT"] = 1 self.config["DDS_CHANNELS_PER_BUS"] = 1 self.config["DDS_AD9914"] = None self.config["DDS_ONEHOT_SEL"] = None self.config["DDS_RTIO_CLK_RATIO"] = 8 self.submodules.rtio_crg = _PhaserCRG( platform, self.ad9154.jesd.cd_jesd.clk) self.csr_devices.append("rtio_crg") self.submodules.rtio = rtio.RTIO(rtio_channels) self.register_kernel_cpu_csrdevice("rtio") self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) self.csr_devices.append("rtio_moninj") self.submodules.rtio_analyzer = rtio.Analyzer( self.rtio, self.get_native_sdram_if()) self.csr_devices.append("rtio_analyzer") self.config["RTIO_FINE_TS_WIDTH"] = self.rtio.fine_ts_width platform.add_false_path_constraints( self.crg.cd_sys.clk, self.rtio_crg.cd_rtio.clk) platform.add_false_path_constraints( self.crg.cd_sys.clk, self.ad9154.jesd.cd_jesd.clk) for phy in self.ad9154.jesd.phys: platform.add_false_path_constraints( self.crg.cd_sys.clk, phy.gtx.cd_tx.clk) def main(): parser = argparse.ArgumentParser( description="ARTIQ core device builder for " "KC705+AD9154 hardware") builder_args(parser) soc_kc705_args(parser) args = parser.parse_args() soc = Phaser(**soc_kc705_argdict(args)) build_artiq_soc(soc, builder_argdict(args)) if __name__ == "__main__": main()