mirror of https://github.com/m-labs/artiq.git
phaser: 10G line rate
This commit is contained in:
parent
42c6658ffe
commit
89150c9817
|
@ -109,7 +109,7 @@ class DACSetup(EnvExperiment):
|
||||||
|
|
||||||
self.ad9154.dac_write(AD9154_SPI_PAGEINDX, 0x3) # A and B dual
|
self.ad9154.dac_write(AD9154_SPI_PAGEINDX, 0x3) # A and B dual
|
||||||
|
|
||||||
self.ad9154.dac_write(AD9154_INTERP_MODE, 4) # 8x
|
self.ad9154.dac_write(AD9154_INTERP_MODE, 3) # 4x
|
||||||
self.ad9154.dac_write(AD9154_MIX_MODE, 0)
|
self.ad9154.dac_write(AD9154_MIX_MODE, 0)
|
||||||
self.ad9154.dac_write(AD9154_DATA_FORMAT, AD9154_BINARY_FORMAT_SET(0)) # s16
|
self.ad9154.dac_write(AD9154_DATA_FORMAT, AD9154_BINARY_FORMAT_SET(0)) # s16
|
||||||
self.ad9154.dac_write(AD9154_DATAPATH_CTRL,
|
self.ad9154.dac_write(AD9154_DATAPATH_CTRL,
|
||||||
|
@ -198,11 +198,11 @@ class DACSetup(EnvExperiment):
|
||||||
self.ad9154.dac_write(AD9154_SERDES_SPI_REG, 1)
|
self.ad9154.dac_write(AD9154_SERDES_SPI_REG, 1)
|
||||||
self.ad9154.dac_write(AD9154_CDR_OPERATING_MODE_REG_0,
|
self.ad9154.dac_write(AD9154_CDR_OPERATING_MODE_REG_0,
|
||||||
AD9154_CDR_OVERSAMP_SET(0) | AD9154_CDR_RESERVED_SET(0x2) |
|
AD9154_CDR_OVERSAMP_SET(0) | AD9154_CDR_RESERVED_SET(0x2) |
|
||||||
AD9154_ENHALFRATE_SET(0))
|
AD9154_ENHALFRATE_SET(1))
|
||||||
self.ad9154.dac_write(AD9154_CDR_RESET, 0)
|
self.ad9154.dac_write(AD9154_CDR_RESET, 0)
|
||||||
self.ad9154.dac_write(AD9154_CDR_RESET, 1)
|
self.ad9154.dac_write(AD9154_CDR_RESET, 1)
|
||||||
self.ad9154.dac_write(AD9154_REF_CLK_DIVIDER_LDO,
|
self.ad9154.dac_write(AD9154_REF_CLK_DIVIDER_LDO,
|
||||||
AD9154_SPI_CDR_OVERSAMP_SET(0x1) |
|
AD9154_SPI_CDR_OVERSAMP_SET(0x0) |
|
||||||
AD9154_SPI_LDO_BYPASS_FILT_SET(1) |
|
AD9154_SPI_LDO_BYPASS_FILT_SET(1) |
|
||||||
AD9154_SPI_LDO_REF_SEL_SET(0))
|
AD9154_SPI_LDO_REF_SEL_SET(0))
|
||||||
self.ad9154.dac_write(AD9154_LDO_FILTER_1, 0x62) # magic
|
self.ad9154.dac_write(AD9154_LDO_FILTER_1, 0x62) # magic
|
||||||
|
|
|
@ -47,17 +47,17 @@ class StartupKernel(EnvExperiment):
|
||||||
self.ad9154.clock_write(AD9516_OUT1, 0*AD9516_OUT1_POWER_DOWN |
|
self.ad9154.clock_write(AD9516_OUT1, 0*AD9516_OUT1_POWER_DOWN |
|
||||||
2*AD9516_OUT1_LVPECLDIFFERENTIAL_VOLTAGE)
|
2*AD9516_OUT1_LVPECLDIFFERENTIAL_VOLTAGE)
|
||||||
|
|
||||||
# FPGA deviceclk, dclk/4
|
# FPGA deviceclk, dclk/2
|
||||||
self.ad9154.clock_write(AD9516_DIVIDER_4_3, AD9516_DIVIDER_4_BYPASS_2)
|
self.ad9154.clock_write(AD9516_DIVIDER_4_3, AD9516_DIVIDER_4_BYPASS_2)
|
||||||
self.ad9154.clock_write(AD9516_DIVIDER_4_0,
|
self.ad9154.clock_write(AD9516_DIVIDER_4_0,
|
||||||
(4//2-1)*AD9516_DIVIDER_0_HIGH_CYCLES |
|
(2//2-1)*AD9516_DIVIDER_0_HIGH_CYCLES |
|
||||||
(4//2-1)*AD9516_DIVIDER_0_LOW_CYCLES)
|
(2//2-1)*AD9516_DIVIDER_0_LOW_CYCLES)
|
||||||
self.ad9154.clock_write(AD9516_DIVIDER_4_4, 0*AD9516_DIVIDER_4_DCCOFF)
|
self.ad9154.clock_write(AD9516_DIVIDER_4_4, 0*AD9516_DIVIDER_4_DCCOFF)
|
||||||
self.ad9154.clock_write(AD9516_OUT9, 1*AD9516_OUT9_LVDS_OUTPUT_CURRENT |
|
self.ad9154.clock_write(AD9516_OUT9, 1*AD9516_OUT9_LVDS_OUTPUT_CURRENT |
|
||||||
2*AD9516_OUT9_LVDS_CMOS_OUTPUT_POLARITY |
|
2*AD9516_OUT9_LVDS_CMOS_OUTPUT_POLARITY |
|
||||||
0*AD9516_OUT9_SELECT_LVDS_CMOS)
|
0*AD9516_OUT9_SELECT_LVDS_CMOS)
|
||||||
|
|
||||||
# sysref f_data*S/(K*F), dclk/64
|
# sysref f_data*S/(K*F), dclk/32
|
||||||
self.ad9154.clock_write(AD9516_DIVIDER_3_0, (32//2-1)*AD9516_DIVIDER_3_HIGH_CYCLES_1 |
|
self.ad9154.clock_write(AD9516_DIVIDER_3_0, (32//2-1)*AD9516_DIVIDER_3_HIGH_CYCLES_1 |
|
||||||
(32//2-1)*AD9516_DIVIDER_3_LOW_CYCLES_1)
|
(32//2-1)*AD9516_DIVIDER_3_LOW_CYCLES_1)
|
||||||
self.ad9154.clock_write(AD9516_DIVIDER_3_1, 0*AD9516_DIVIDER_3_PHASE_OFFSET_1 |
|
self.ad9154.clock_write(AD9516_DIVIDER_3_1, 0*AD9516_DIVIDER_3_PHASE_OFFSET_1 |
|
||||||
|
|
|
@ -398,19 +398,10 @@ class _PhaserCRG(Module, AutoCSR):
|
||||||
self._clock_sel = CSRStorage()
|
self._clock_sel = CSRStorage()
|
||||||
self._pll_reset = CSRStorage(reset=1)
|
self._pll_reset = CSRStorage(reset=1)
|
||||||
self._pll_locked = CSRStatus()
|
self._pll_locked = CSRStatus()
|
||||||
|
self.refclk = Signal()
|
||||||
self.clock_domains.cd_rtio = ClockDomain()
|
self.clock_domains.cd_rtio = ClockDomain()
|
||||||
self.clock_domains.cd_rtiox4 = ClockDomain(reset_less=True)
|
self.clock_domains.cd_rtiox4 = ClockDomain(reset_less=True)
|
||||||
|
|
||||||
refclk_pads = platform.request("ad9154_refclk")
|
|
||||||
platform.add_period_constraint(refclk_pads.p, 8.)
|
|
||||||
self.refclk = Signal()
|
|
||||||
self.clock_domains.cd_refclk = ClockDomain()
|
|
||||||
self.specials += [
|
|
||||||
Instance("IBUFDS_GTE2", i_CEB=0,
|
|
||||||
i_I=refclk_pads.p, i_IB=refclk_pads.n, o_O=self.refclk),
|
|
||||||
Instance("BUFG", i_I=self.refclk, o_O=self.cd_refclk.clk),
|
|
||||||
]
|
|
||||||
|
|
||||||
pll_locked = Signal()
|
pll_locked = Signal()
|
||||||
rtio_clk = Signal()
|
rtio_clk = Signal()
|
||||||
rtiox4_clk = Signal()
|
rtiox4_clk = Signal()
|
||||||
|
@ -419,13 +410,13 @@ class _PhaserCRG(Module, AutoCSR):
|
||||||
p_STARTUP_WAIT="FALSE", o_LOCKED=pll_locked,
|
p_STARTUP_WAIT="FALSE", o_LOCKED=pll_locked,
|
||||||
|
|
||||||
p_REF_JITTER1=0.01, p_REF_JITTER2=0.01,
|
p_REF_JITTER1=0.01, p_REF_JITTER2=0.01,
|
||||||
p_CLKIN1_PERIOD=8.0, p_CLKIN2_PERIOD=8.0,
|
p_CLKIN1_PERIOD=4.0, p_CLKIN2_PERIOD=4.0,
|
||||||
i_CLKIN1=rtio_internal_clk, i_CLKIN2=self.cd_refclk.clk,
|
i_CLKIN1=0, i_CLKIN2=self.refclk,
|
||||||
# Warning: CLKINSEL=0 means CLKIN2 is selected
|
# Warning: CLKINSEL=0 means CLKIN2 is selected
|
||||||
i_CLKINSEL=~self._clock_sel.storage,
|
i_CLKINSEL=~self._clock_sel.storage,
|
||||||
|
|
||||||
# VCO @ 1GHz when using 125MHz input
|
# VCO @ 1GHz when using 125MHz input
|
||||||
p_CLKFBOUT_MULT=8, p_DIVCLK_DIVIDE=1,
|
p_CLKFBOUT_MULT=8, p_DIVCLK_DIVIDE=2,
|
||||||
i_CLKFBIN=self.cd_rtio.clk,
|
i_CLKFBIN=self.cd_rtio.clk,
|
||||||
i_RST=self._pll_reset.storage,
|
i_RST=self._pll_reset.storage,
|
||||||
|
|
||||||
|
@ -436,70 +427,95 @@ class _PhaserCRG(Module, AutoCSR):
|
||||||
),
|
),
|
||||||
Instance("BUFG", i_I=rtio_clk, o_O=self.cd_rtio.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=rtiox4_clk, o_O=self.cd_rtiox4.clk),
|
||||||
|
|
||||||
AsyncResetSynchronizer(self.cd_rtio, ~pll_locked),
|
AsyncResetSynchronizer(self.cd_rtio, ~pll_locked),
|
||||||
MultiReg(pll_locked, self._pll_locked.status)
|
MultiReg(pll_locked | ~self._clock_sel.storage,
|
||||||
|
self._pll_locked.status)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class AD9154(Module, AutoCSR):
|
class AD9154JESD(Module, AutoCSR):
|
||||||
def __init__(self, platform, rtio_crg):
|
def __init__(self, platform):
|
||||||
ad9154_spi = platform.request("ad9154_spi")
|
|
||||||
self.submodules.spi = spi_csr.SPIMaster(ad9154_spi)
|
|
||||||
self.comb += [
|
|
||||||
ad9154_spi.en.eq(1),
|
|
||||||
platform.request("ad9154_txen", 0).eq(1),
|
|
||||||
platform.request("ad9154_txen", 1).eq(1),
|
|
||||||
]
|
|
||||||
|
|
||||||
sync_pads = platform.request("ad9154_sync")
|
|
||||||
jesd_sync = Signal()
|
|
||||||
self.specials += DifferentialInput(
|
|
||||||
sync_pads.p, sync_pads.n, jesd_sync)
|
|
||||||
self.jesd_sync = jesd_sync
|
|
||||||
|
|
||||||
ps = JESD204BPhysicalSettings(l=4, m=4, n=16, np=16)
|
ps = JESD204BPhysicalSettings(l=4, m=4, n=16, np=16)
|
||||||
ts = JESD204BTransportSettings(f=2, s=1, k=16, cs=1)
|
ts = JESD204BTransportSettings(f=2, s=1, k=16, cs=1)
|
||||||
jesd_settings = JESD204BSettings(ps, ts, did=0x5a, bid=0x5)
|
settings = JESD204BSettings(ps, ts, did=0x5a, bid=0x5)
|
||||||
jesd_linerate = 5e9
|
linerate = 10e9
|
||||||
jesd_refclk_freq = 125e6
|
refclk_freq = 250e6
|
||||||
rtio_freq = 125*1000*1000
|
fabric_freq = 250*1000*1000
|
||||||
jesd_qpll = GTXQuadPLL(
|
|
||||||
rtio_crg.refclk, jesd_refclk_freq, jesd_linerate)
|
sync_pads = platform.request("ad9154_sync")
|
||||||
self.submodules += jesd_qpll
|
self.jsync = Signal()
|
||||||
jesd_phys = []
|
self.refclk = Signal()
|
||||||
|
self.specials += DifferentialInput(
|
||||||
|
sync_pads.p, sync_pads.n, self.jsync)
|
||||||
|
|
||||||
|
self.clock_domains.cd_jesd = ClockDomain()
|
||||||
|
refclk_pads = platform.request("ad9154_refclk")
|
||||||
|
platform.add_period_constraint(refclk_pads.p, 1e9/refclk_freq)
|
||||||
|
|
||||||
|
self.specials += [
|
||||||
|
Instance("IBUFDS_GTE2", i_CEB=0,
|
||||||
|
i_I=refclk_pads.p, i_IB=refclk_pads.n, o_O=self.refclk),
|
||||||
|
Instance("BUFR", i_I=self.refclk, o_O=self.cd_jesd.clk),
|
||||||
|
AsyncResetSynchronizer(self.cd_jesd, ResetSignal("rio_phy")),
|
||||||
|
]
|
||||||
|
|
||||||
|
qpll = GTXQuadPLL(self.refclk, refclk_freq, linerate)
|
||||||
|
self.submodules += qpll
|
||||||
|
phys = []
|
||||||
for i in range(4):
|
for i in range(4):
|
||||||
jesd_phy = JESD204BPhyTX(
|
phy = JESD204BPhyTX(
|
||||||
jesd_qpll, platform.request("ad9154_jesd", i),
|
qpll, platform.request("ad9154_jesd", i), fabric_freq)
|
||||||
rtio_freq)
|
platform.add_period_constraint(phy.gtx.cd_tx.clk, 40*1e9/linerate)
|
||||||
platform.add_period_constraint(
|
|
||||||
jesd_phy.gtx.cd_tx.clk,
|
|
||||||
40/jesd_linerate*1e9)
|
|
||||||
platform.add_false_path_constraints(
|
platform.add_false_path_constraints(
|
||||||
rtio_crg.cd_rtio.clk,
|
self.cd_jesd.clk,
|
||||||
jesd_phy.gtx.cd_tx.clk)
|
phy.gtx.cd_tx.clk)
|
||||||
jesd_phys.append(jesd_phy)
|
phys.append(phy)
|
||||||
setattr(self.submodules, "jesd_phy"+str(i), jesd_phy)
|
to_jesd = ClockDomainsRenamer("jesd")
|
||||||
self.submodules.jesd_core = JESD204BCoreTX(
|
self.submodules.core = to_jesd(JESD204BCoreTX(phys, settings,
|
||||||
jesd_phys, jesd_settings, converter_data_width=32)
|
converter_data_width=32))
|
||||||
self.comb += self.jesd_core.start.eq(jesd_sync)
|
self.submodules.control = to_jesd(JESD204BCoreTXControl(self.core))
|
||||||
self.comb += platform.request("user_led", 3).eq(jesd_sync)
|
|
||||||
self.submodules.jesd_control = JESD204BCoreTXControl(self.jesd_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
|
# blinking leds for transceiver reset status
|
||||||
for i in range(4):
|
for i in range(4):
|
||||||
led = platform.request("user_led", 4 + i)
|
led = platform.request("user_led", 4 + i)
|
||||||
counter = Signal(32)
|
counter = Signal(max=fabric_freq//2 + 1)
|
||||||
sync = getattr(self.sync, "phy" + str(i))
|
sync = getattr(self.sync, "phy{}_tx".format(i))
|
||||||
sync += \
|
sync += \
|
||||||
If(counter == 0,
|
If(counter == 0,
|
||||||
led.eq(~led),
|
led.eq(~led),
|
||||||
counter.eq(rtio_freq//2)
|
counter.eq(fabric_freq//2)
|
||||||
).Else(
|
).Else(
|
||||||
counter.eq(counter - 1)
|
counter.eq(counter - 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=4) for i in range(4)]
|
||||||
|
self.submodules += self.sawgs
|
||||||
|
|
||||||
|
x = Signal()
|
||||||
|
y = Signal()
|
||||||
|
self.sync.jesd += x.eq(~x)
|
||||||
|
self.sync.rio_phy += y.eq(x)
|
||||||
|
for conv, ch in zip(self.jesd.core.sink.flatten(), self.sawgs):
|
||||||
|
self.comb += conv.eq(Mux(x != y, Cat(ch.o[:2]), Cat(ch.o[2:])))
|
||||||
|
|
||||||
|
|
||||||
class Phaser(_NIST_Ions):
|
class Phaser(_NIST_Ions):
|
||||||
mem_map = {
|
mem_map = {
|
||||||
"ad9154": 0x50000000,
|
"ad9154": 0x50000000,
|
||||||
|
@ -512,7 +528,10 @@ class Phaser(_NIST_Ions):
|
||||||
platform = self.platform
|
platform = self.platform
|
||||||
platform.add_extension(phaser.fmc_adapter_io)
|
platform.add_extension(phaser.fmc_adapter_io)
|
||||||
|
|
||||||
sysref_pads = platform.request("ad9154_sysref")
|
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 = []
|
rtio_channels = []
|
||||||
|
|
||||||
|
@ -525,13 +544,13 @@ class Phaser(_NIST_Ions):
|
||||||
self.submodules += phy
|
self.submodules += phy
|
||||||
rtio_channels.append(rtio.Channel.from_phy(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)
|
phy = ttl_serdes_7series.Input_8X(sysref_pads.p, sysref_pads.n)
|
||||||
self.submodules += phy
|
self.submodules += phy
|
||||||
rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=32,
|
rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=32,
|
||||||
ofifo_depth=2))
|
ofifo_depth=2))
|
||||||
|
|
||||||
jesd_sync = Signal()
|
phy = ttl_simple.Input(self.ad9154.jesd.jsync)
|
||||||
phy = ttl_simple.Input(jesd_sync)
|
|
||||||
self.submodules += phy
|
self.submodules += phy
|
||||||
rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=32,
|
rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=32,
|
||||||
ofifo_depth=2))
|
ofifo_depth=2))
|
||||||
|
@ -539,29 +558,15 @@ class Phaser(_NIST_Ions):
|
||||||
self.config["RTIO_REGULAR_TTL_COUNT"] = len(rtio_channels)
|
self.config["RTIO_REGULAR_TTL_COUNT"] = len(rtio_channels)
|
||||||
|
|
||||||
self.config["RTIO_FIRST_SAWG_CHANNEL"] = len(rtio_channels)
|
self.config["RTIO_FIRST_SAWG_CHANNEL"] = len(rtio_channels)
|
||||||
sawgs = [sawg.Channel(width=16, parallelism=4) for i in range(4)]
|
|
||||||
self.submodules += sawgs
|
|
||||||
|
|
||||||
rtio_channels.extend(rtio.Channel.from_phy(phy)
|
rtio_channels.extend(rtio.Channel.from_phy(phy)
|
||||||
for sawg in sawgs
|
for sawg in self.ad9154.sawgs
|
||||||
for phy in sawg.phys)
|
for phy in sawg.phys)
|
||||||
|
|
||||||
self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels)
|
self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels)
|
||||||
rtio_channels.append(rtio.LogChannel())
|
rtio_channels.append(rtio.LogChannel())
|
||||||
self.add_rtio(rtio_channels, _PhaserCRG(platform, self.crg.cd_sys.clk))
|
self.add_rtio(rtio_channels, _PhaserCRG(platform, self.crg.cd_sys.clk))
|
||||||
|
|
||||||
to_rtio = ClockDomainsRenamer({"sys": "rtio"})
|
self.comb += self.rtio_crg.refclk.eq(self.ad9154.jesd.refclk)
|
||||||
self.submodules.ad9154 = to_rtio(AD9154(platform, self.rtio_crg))
|
|
||||||
self.register_kernel_cpu_csrdevice("ad9154")
|
|
||||||
self.config["AD9154_DAC_CS"] = 1 << 0
|
|
||||||
self.config["AD9154_CLK_CS"] = 1 << 1
|
|
||||||
for i, ch in enumerate(sawgs):
|
|
||||||
conv = getattr(self.ad9154.jesd_core.sink,
|
|
||||||
"converter{}".format(i))
|
|
||||||
# while at 5 GBps, take every second sample... FIXME
|
|
||||||
self.comb += conv.eq(Cat(ch.o[::2]))
|
|
||||||
|
|
||||||
self.comb += jesd_sync.eq(self.ad9154.jesd_sync)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|
Loading…
Reference in New Issue