artiq/artiq/gateware/targets/kc705_phaser.py

269 lines
10 KiB
Python
Executable File

#!/usr/bin/env python3
import argparse
from migen import *
from migen.genlib.resetsync import AsyncResetSynchronizer
from migen.genlib.cdc import MultiReg
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.amp 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)
external_clk = Signal()
user_sma_clock = platform.request("user_sma_clock")
platform.add_period_constraint(user_sma_clock.p, 20/3)
self.specials += Instance("IBUFDS",
i_I=user_sma_clock.p, i_IB=user_sma_clock.n,
o_O=external_clk)
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=refclk, i_CLKIN2=external_clk,
# 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._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):
self.jreset = CSRStorage(reset=1)
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
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, self.jreset.storage),
]
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.transmitter.cd_tx.clk.attr.add("keep")
platform.add_period_constraint(phy.transmitter.cd_tx.clk,
40*1e9/linerate)
platform.add_false_path_constraints(self.cd_jesd.clk,
phy.transmitter.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.core.register_jsync(platform.request("ad9154_sync"))
self.comb += [
platform.request("ad9154_txen", 0).eq(1),
platform.request("ad9154_txen", 1).eq(1),
platform.request("user_led", 3).eq(self.core.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):
self.submodules.jesd = AD9154JESD(platform)
self.sawgs = [sawg.Channel(width=16, parallelism=2) for i in range(4)]
self.submodules += self.sawgs
# self.sawgs[0].connect_y(self.sawgs[1])
# self.sawgs[1].connect_y(self.sawgs[0])
# self.sawgs[2].connect_y(self.sawgs[3])
# self.sawgs[3].connect_y(self.sawgs[2])
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 = {
"cri_con": 0x10000000,
"rtio": 0x20000000,
"rtio_dma": 0x30000000,
"mailbox": 0x70000000,
}
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,
ident=artiq_version,
ethmac_nrxslots=4,
ethmac_ntxslots=4,
**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.csr_devices.append("i2c")
self.config["I2C_BUS_COUNT"] = 1
ad9154_spi = platform.request("ad9154_spi")
self.comb += ad9154_spi.en.eq(1)
self.submodules.converter_spi = spi_csr.SPIMaster(ad9154_spi)
self.csr_devices.append("converter_spi")
self.config["CONVERTER_SPI_DAC_CS"] = 0
self.config["CONVERTER_SPI_CLK_CS"] = 1
self.config["HAS_AD9516"] = None
self.submodules.ad9154 = AD9154(platform)
self.csr_devices.append("ad9154")
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))
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["HAS_RTIO_LOG"] = None
self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels)
rtio_channels.append(rtio.LogChannel())
self.submodules.rtio_crg = _PhaserCRG(
platform, self.ad9154.jesd.cd_jesd.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.submodules.rtio_analyzer = rtio.Analyzer(self.rtio_core.cri,
self.get_native_sdram_if())
self.csr_devices.append("rtio_analyzer")
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.transmitter.cd_tx.clk)
def main():
parser = argparse.ArgumentParser(
description="ARTIQ device binary builder / KC705 phaser demo")
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()