forked from M-Labs/artiq
Sebastien Bourdeauducq
440e19b8f9
SFP1 PCB routing has some issues. Also use SFP1 LED for DRTIO in both master and satellite.
405 lines
15 KiB
Python
Executable File
405 lines
15 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 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
|
|
from misoc.cores.a7_gtp import *
|
|
from misoc.targets.kasli import (BaseSoC, MiniSoC,
|
|
soc_kasli_args, soc_kasli_argdict)
|
|
from misoc.integration.builder import builder_args, builder_argdict
|
|
|
|
from artiq.gateware.amp import AMPSoC
|
|
from artiq.gateware import rtio
|
|
from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_7series, spi
|
|
from artiq.gateware.drtio.transceiver import gtp_7series
|
|
from artiq.gateware.drtio import DRTIOMaster, DRTIOSatellite
|
|
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):
|
|
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)
|
|
|
|
rtio_external_clk = Signal()
|
|
clk_synth_se = Signal()
|
|
clk_synth = platform.request("si5324_clkout_fabric")
|
|
platform.add_period_constraint(clk_synth.p, 8.0)
|
|
self.specials += [
|
|
Instance("IBUFGDS",
|
|
p_DIFF_TERM="TRUE", p_IBUF_LOW_PWR="TRUE",
|
|
i_I=clk_synth.p, i_IB=clk_synth.n, o_O=clk_synth_se),
|
|
Instance("BUFG", i_I=clk_synth_se, 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),
|
|
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)
|
|
]
|
|
|
|
|
|
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)
|
|
|
|
self.submodules.leds = gpio.GPIOOut(Cat(
|
|
self.platform.request("user_led", 0)))
|
|
self.csr_devices.append("leds")
|
|
|
|
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
|
|
|
|
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")
|
|
|
|
|
|
def _eem_signal(i):
|
|
n = "d{}".format(i)
|
|
if i == 0:
|
|
n += "_cc"
|
|
return n
|
|
|
|
|
|
def _dio(eem):
|
|
return [(eem, i,
|
|
Subsignal("p", Pins("{}:{}_p".format(eem, _eem_signal(i)))),
|
|
Subsignal("n", Pins("{}:{}_n".format(eem, _eem_signal(i)))),
|
|
IOStandard("LVDS_25"))
|
|
for i in range(8)]
|
|
|
|
|
|
class Opticlock(_StandaloneBase):
|
|
"""
|
|
Opticlock extension variant configuration
|
|
"""
|
|
def __init__(self, **kwargs):
|
|
_StandaloneBase.__init__(self, **kwargs)
|
|
|
|
platform = self.platform
|
|
platform.add_extension(_dio("eem0"))
|
|
platform.add_extension(_dio("eem1"))
|
|
platform.add_extension(_dio("eem2"))
|
|
# platform.add_extension(_urukul("eem3", "eem4"))
|
|
# platform.add_extension(_novogorny("eem5"))
|
|
|
|
# EEM clock fan-out from Si5324, not MMCX
|
|
self.comb += platform.request("clk_sel").eq(1)
|
|
|
|
rtio_channels = []
|
|
for eem in "eem0 eem1 eem2".split():
|
|
for i in range(8):
|
|
phy = ttl_serdes_7series.Output_8X(
|
|
platform.request(eem, i))
|
|
self.submodules += phy
|
|
rtio_channels.append(rtio.Channel.from_phy(phy))
|
|
|
|
for i in (1, 2):
|
|
sfp_ctl = platform.request("sfp_ctl", i)
|
|
phy = ttl_simple.Output(sfp_ctl.led)
|
|
self.submodules += phy
|
|
rtio_channels.append(rtio.Channel.from_phy(phy))
|
|
|
|
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 Master(MiniSoC, AMPSoC):
|
|
mem_map = {
|
|
"cri_con": 0x10000000,
|
|
"rtio": 0x20000000,
|
|
"rtio_dma": 0x30000000,
|
|
"drtio_aux": 0x50000000,
|
|
"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)
|
|
|
|
platform = self.platform
|
|
rtio_clk_freq = 150e6
|
|
|
|
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.config["SI5324_SOFT_RESET"] = None
|
|
self.config["SI5324_FREE_RUNNING"] = None
|
|
|
|
self.comb += platform.request("sfp_ctl", 2).tx_disable.eq(0)
|
|
self.submodules.transceiver = gtp_7series.GTP(
|
|
qpll_channel=self.drtio_qpll_channel,
|
|
data_pads=[platform.request("sfp", 2)],
|
|
sys_clk_freq=self.clk_freq,
|
|
rtio_clk_freq=rtio_clk_freq)
|
|
|
|
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)
|
|
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"])
|
|
|
|
rtio_clk_period = 1e9/rtio_clk_freq
|
|
for gtp in self.transceiver.gtps:
|
|
platform.add_period_constraint(gtp.txoutclk, rtio_clk_period)
|
|
platform.add_period_constraint(gtp.rxoutclk, rtio_clk_period)
|
|
platform.add_false_path_constraints(
|
|
self.crg.cd_sys.clk,
|
|
gtp.txoutclk, gtp.rxoutclk)
|
|
|
|
rtio_channels = []
|
|
phy = ttl_simple.Output(platform.request("user_led", 0))
|
|
self.submodules += phy
|
|
rtio_channels.append(rtio.Channel.from_phy(phy))
|
|
phy = ttl_simple.Output(platform.request("sfp_ctl", 1).led)
|
|
self.submodules += phy
|
|
rtio_channels.append(rtio.Channel.from_phy(phy))
|
|
|
|
self.submodules.rtio_moninj = rtio.MonInj(rtio_channels)
|
|
self.csr_devices.append("rtio_moninj")
|
|
|
|
self.submodules.rtio_core = rtio.Core(rtio_channels, glbl_fine_ts_width=3)
|
|
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.drtio0.cri])
|
|
self.register_kernel_cpu_csrdevice("cri_con")
|
|
|
|
# Never running out of stupid features, GTs on A7 make you pack
|
|
# unrelated transceiver PLLs into one GTPE2_COMMON yourself.
|
|
def create_qpll(self):
|
|
si5324_clkout = self.platform.request("si5324_clkout")
|
|
si5324_clkout_buf = Signal()
|
|
self.specials += Instance("IBUFDS_GTE2",
|
|
i_CEB=0,
|
|
i_I=si5324_clkout.p, i_IB=si5324_clkout.n,
|
|
o_O=si5324_clkout_buf)
|
|
# Note precisely the rules Xilinx made up:
|
|
# refclksel=0b001 GTREFCLK0 selected
|
|
# refclksel=0b010 GTREFCLK1 selected
|
|
# but if only one clock used, then it must be 001.
|
|
qpll_drtio_settings = QPLLSettings(
|
|
refclksel=0b001,
|
|
fbdiv=4,
|
|
fbdiv_45=5,
|
|
refclk_div=1)
|
|
qpll_eth_settings = QPLLSettings(
|
|
refclksel=0b010,
|
|
fbdiv=4,
|
|
fbdiv_45=5,
|
|
refclk_div=1)
|
|
qpll = QPLL(si5324_clkout_buf, qpll_drtio_settings,
|
|
self.crg.clk125_buf, qpll_eth_settings)
|
|
self.submodules += qpll
|
|
self.drtio_qpll_channel, self.ethphy_qpll_channel = qpll.channels
|
|
|
|
|
|
class Satellite(BaseSoC):
|
|
mem_map = {
|
|
"drtio_aux": 0x50000000,
|
|
}
|
|
mem_map.update(BaseSoC.mem_map)
|
|
|
|
def __init__(self, **kwargs):
|
|
BaseSoC.__init__(self,
|
|
cpu_type="or1k",
|
|
sdram_controller_type="minicon",
|
|
l2_size=128*1024,
|
|
ident=artiq_version,
|
|
**kwargs)
|
|
|
|
platform = self.platform
|
|
rtio_clk_freq = 150e6
|
|
|
|
rtio_channels = []
|
|
phy = ttl_simple.Output(platform.request("user_led", 0))
|
|
self.submodules += phy
|
|
rtio_channels.append(rtio.Channel.from_phy(phy))
|
|
phy = ttl_simple.Output(platform.request("sfp_ctl", 1).led)
|
|
self.submodules += phy
|
|
rtio_channels.append(rtio.Channel.from_phy(phy))
|
|
|
|
self.submodules.rtio_moninj = rtio.MonInj(rtio_channels)
|
|
self.csr_devices.append("rtio_moninj")
|
|
|
|
si5324_clkout = platform.request("si5324_clkout")
|
|
si5324_clkout_buf = Signal()
|
|
self.specials += Instance("IBUFDS_GTE2",
|
|
i_CEB=0,
|
|
i_I=si5324_clkout.p, i_IB=si5324_clkout.n,
|
|
o_O=si5324_clkout_buf)
|
|
qpll_drtio_settings = QPLLSettings(
|
|
refclksel=0b001,
|
|
fbdiv=4,
|
|
fbdiv_45=5,
|
|
refclk_div=1)
|
|
qpll = QPLL(si5324_clkout_buf, qpll_drtio_settings)
|
|
self.submodules += qpll
|
|
|
|
self.comb += platform.request("sfp_ctl", 0).tx_disable.eq(0)
|
|
self.submodules.transceiver = gtp_7series.GTP(
|
|
qpll_channel=qpll.channels[0],
|
|
data_pads=[platform.request("sfp", 0)],
|
|
sys_clk_freq=self.clk_freq,
|
|
rtio_clk_freq=rtio_clk_freq)
|
|
rx0 = ClockDomainsRenamer({"rtio_rx": "rtio_rx0"})
|
|
self.submodules.drtio0 = rx0(DRTIOSatellite(
|
|
self.transceiver.channels[0], rtio_channels))
|
|
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(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
|
|
)
|
|
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.config["SI5324_SOFT_RESET"] = None
|
|
|
|
rtio_clk_period = 1e9/rtio_clk_freq
|
|
gtp = self.transceiver.gtps[0]
|
|
platform.add_period_constraint(gtp.txoutclk, rtio_clk_period)
|
|
platform.add_period_constraint(gtp.rxoutclk, rtio_clk_period)
|
|
platform.add_false_path_constraints(
|
|
self.crg.cd_sys.clk,
|
|
gtp.txoutclk, gtp.rxoutclk)
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(
|
|
description="ARTIQ device binary builder for Kasli systems")
|
|
builder_args(parser)
|
|
soc_kasli_args(parser)
|
|
parser.add_argument("-V", "--variant", default="opticlock",
|
|
help="variant: opticlock/master/satellite "
|
|
"(default: %(default)s)")
|
|
args = parser.parse_args()
|
|
|
|
variant = args.variant.lower()
|
|
if variant == "opticlock":
|
|
cls = Opticlock
|
|
elif variant == "master":
|
|
cls = Master
|
|
elif variant == "satellite":
|
|
cls = Satellite
|
|
else:
|
|
raise SystemExit("Invalid variant (-V/--variant)")
|
|
|
|
soc = cls(**soc_kasli_argdict(args))
|
|
build_artiq_soc(soc, builder_argdict(args))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|